-
-
Save csumsky3/9916618e5095b2b6bf176c3aefa2d97d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using Spine; | |
using Spine.Unity; | |
using Spine.Unity.Modules.AttachmentTools; | |
using UnityEngine; | |
public class BAgentAnimator : MonoBehaviour | |
{ | |
const string footstepEventName = "footstep"; | |
const float distanceThreshold = 50f; //this might could even be lowered | |
[SerializeField] SkeletonAnimation frontAnimation = null; | |
[SerializeField] SkeletonAnimation backAnimation = null; | |
[SerializeField] SkeletonAnimation leftAnimation = null; | |
[SerializeField] SkeletonAnimation rightAnimation = null; | |
[SerializeField] bool listenForFootsteps = false; | |
MeshRenderer frontMesh; | |
MeshRenderer backMesh; | |
MeshRenderer leftMesh; | |
MeshRenderer rightMesh; | |
Slot frontCarrySlot; | |
Slot backCarrySlot; | |
Slot leftCarrySlot; | |
Slot rightCarrySlot; | |
bool isSpriteling; | |
bool isRendering; | |
public bool IsPaused { get; private set; } | |
public LockState AnimationLock = new LockState(); | |
#region Monobehaviour | |
void Awake() | |
{ | |
frontMesh = frontAnimation.GetComponent<MeshRenderer>(); | |
backMesh = backAnimation.GetComponent<MeshRenderer>(); | |
leftMesh = leftAnimation.GetComponent<MeshRenderer>(); | |
rightMesh = rightAnimation.GetComponent<MeshRenderer>(); | |
if (frontMesh == null || backMesh == null || leftMesh == null || rightMesh == null) { | |
Debug.LogWarning("This agent doesn't have all its meshes assigned!"); | |
} | |
isSpriteling = GetComponent<BSpriteling>(); | |
isRendering = true; | |
} | |
void Start() | |
{ | |
const string carrySlotName = "carry_slot"; | |
frontCarrySlot = frontAnimation.skeleton.FindSlot(carrySlotName); | |
backCarrySlot = backAnimation.skeleton.FindSlot(carrySlotName); | |
leftCarrySlot = leftAnimation.skeleton.FindSlot(carrySlotName); | |
rightCarrySlot = rightAnimation.skeleton.FindSlot(carrySlotName); | |
if (listenForFootsteps) { | |
assignFootstepListeners(frontAnimation); | |
assignFootstepListeners(backAnimation); | |
assignFootstepListeners(leftAnimation); | |
assignFootstepListeners(rightAnimation); | |
} | |
} | |
void Update() | |
{ | |
if (isSpriteling) { | |
var distanceToPlayer = Vector3.Distance(transform.position, BGameManager.Instance.Player.transform.position); | |
if (isRendering && distanceToPlayer > distanceThreshold) { | |
setAnimationsEnabled(false); | |
} else if (!isRendering && distanceToPlayer <= distanceThreshold) { | |
setAnimationsEnabled(true); | |
} | |
} | |
} | |
void OnDestroy() | |
{ | |
if (listenForFootsteps) { | |
frontAnimation.AnimationState.Event -= HandleEvent; | |
} | |
} | |
#endregion | |
#region public functions | |
//TODO there's something wrong with he _onEnd call if a _nextAnim gets passed in. I think something to do with default mix duration? | |
public void SetAnimation(string _animationName, string _nextAnimation = "", bool _attachCarryableToSkel = false, System.Action _onEnd = null, float _mixDuration = 0.2f) | |
{ | |
if (AnimationLock.Locked) { | |
return; | |
} | |
//First, if the agent is carrying something, check if they have unique carrying anims, and update the anim name if so | |
if (_attachCarryableToSkel && (_animationName == "Idle" || _animationName == "Walk")) { | |
const string prefixToUse = "Carry_"; | |
string updatedAnimationName = string.Format("{0}{1}", prefixToUse, _animationName); | |
//Only check the frontAnim since we'll assume that all animation meshes will have a carry, if the agent should have one | |
if (frontAnimation.HasClip(updatedAnimationName)) { | |
_animationName = updatedAnimationName; | |
} | |
} | |
//Now set the proper new animation to play, if the skel has it | |
if (frontAnimation.AnimationName != _animationName && frontAnimation.HasClip(_animationName)) { | |
var playNextAnim = !string.IsNullOrEmpty(_nextAnimation) && frontAnimation.HasClip(_nextAnimation); | |
var te = frontAnimation.state.SetAnimation(0, _animationName, !playNextAnim); | |
te.MixDuration = _mixDuration; | |
te.Complete += delegate { | |
_onEnd?.Invoke(); | |
}; | |
if (playNextAnim) { | |
frontAnimation.state.AddAnimation(0, _nextAnimation, true, 0); | |
} | |
} | |
if (backAnimation.AnimationName != _animationName && backAnimation.HasClip(_animationName)) { | |
var playNextAnim = !string.IsNullOrEmpty(_nextAnimation) && backAnimation.HasClip(_nextAnimation); | |
var te = backAnimation.state.SetAnimation(0, _animationName, !playNextAnim); | |
te.MixDuration = _mixDuration; | |
te.Complete += delegate { | |
_onEnd?.Invoke(); | |
}; | |
if (playNextAnim) { | |
backAnimation.state.AddAnimation(0, _nextAnimation, true, 0); | |
} | |
} | |
if (leftAnimation.AnimationName != _animationName && leftAnimation.HasClip(_animationName)) { | |
var playNextAnim = !string.IsNullOrEmpty(_nextAnimation) && leftAnimation.HasClip(_nextAnimation); | |
var te = leftAnimation.state.SetAnimation(0, _animationName, !playNextAnim); | |
te.MixDuration = _mixDuration; | |
te.Complete += delegate { | |
_onEnd?.Invoke(); | |
}; | |
if (playNextAnim) { | |
leftAnimation.state.AddAnimation(0, _nextAnimation, true, 0); | |
} | |
} | |
if (rightAnimation.AnimationName != _animationName && rightAnimation.HasClip(_animationName)) { | |
var playNextAnim = !string.IsNullOrEmpty(_nextAnimation) && rightAnimation.HasClip(_nextAnimation); | |
var te = rightAnimation.state.SetAnimation(0, _animationName, !playNextAnim); | |
te.MixDuration = _mixDuration; | |
te.Complete += delegate { | |
_onEnd?.Invoke(); | |
}; | |
if (playNextAnim) { | |
rightAnimation.state.AddAnimation(0, _nextAnimation, true, 0); | |
} | |
} | |
} | |
public float GetDurationForAnimation(string _animation, FacingDirection _direction) | |
{ | |
switch (_direction) { | |
case FacingDirection.Down: | |
return frontAnimation != null ? frontAnimation.GetTimeForClip(_animation) : -1f; | |
case FacingDirection.Left: | |
return leftAnimation != null ? leftAnimation.GetTimeForClip(_animation) : -1f; | |
case FacingDirection.Up: | |
return backAnimation != null ? backAnimation.GetTimeForClip(_animation) : -1f; | |
case FacingDirection.Right: | |
return rightAnimation != null ? rightAnimation.GetTimeForClip(_animation) : -1f; | |
} | |
return -1f; | |
} | |
public string[] GetAllAnimations() | |
{ | |
var collection = new HashSet<string>(); | |
foreach (var anim in frontAnimation.skeleton.Data.animations.Items) { | |
collection.Add(anim.name); | |
} | |
foreach (var anim in backAnimation.skeleton.Data.animations.Items) { | |
collection.Add(anim.name); | |
} | |
foreach (var anim in leftAnimation.skeleton.Data.animations.Items) { | |
collection.Add(anim.name); | |
} | |
foreach (var anim in rightAnimation.skeleton.Data.animations.Items) { | |
collection.Add(anim.name); | |
} | |
return collection.ToArray(); | |
} | |
public void Pause() | |
{ | |
//Now set the proper new animation to play, if the skel has it | |
if (!IsPaused) { | |
IsPaused = true; | |
frontAnimation.timeScale = 0f; | |
backAnimation.timeScale = 0f; | |
leftAnimation.timeScale = 0f; | |
rightAnimation.timeScale = 0f; | |
} | |
} | |
public void Unpause() | |
{ | |
//Now set the proper new animation to play, if the skel has it | |
if (IsPaused) { | |
IsPaused = false; | |
frontAnimation.timeScale = 1f; | |
backAnimation.timeScale = 1f; | |
leftAnimation.timeScale = 1f; | |
rightAnimation.timeScale = 1f; | |
} | |
} | |
public void TogglePause() | |
{ | |
//Now set the proper new animation to play, if the skel has it | |
if (!IsPaused) { | |
IsPaused = true; | |
frontAnimation.timeScale = 0f; | |
backAnimation.timeScale = 0f; | |
leftAnimation.timeScale = 0f; | |
rightAnimation.timeScale = 0f; | |
} else { | |
IsPaused = false; | |
frontAnimation.timeScale = 1f; | |
backAnimation.timeScale = 1f; | |
leftAnimation.timeScale = 1f; | |
rightAnimation.timeScale = 1f; | |
} | |
} | |
public void SetMeshForFacing(FacingDirection _direction) | |
{ | |
if (isRendering) { | |
setFrontEnabled(_direction == FacingDirection.Down); | |
setBackEnabled(_direction == FacingDirection.Up); | |
setLeftEnabled(_direction == FacingDirection.Left); | |
setRightEnabled(_direction == FacingDirection.Right); | |
} | |
} | |
public bool AttachCarryableToSkel(System.Enum _carryableType) | |
{ | |
var sprite = getCarryableSpriteFromType(_carryableType); | |
if (sprite != null) { | |
attachSpriteToSkeleton(frontAnimation, frontMesh, frontCarrySlot, sprite); | |
attachSpriteToSkeleton(backAnimation, backMesh, backCarrySlot, sprite); | |
attachSpriteToSkeleton(leftAnimation, leftMesh, leftCarrySlot, sprite); | |
attachSpriteToSkeleton(rightAnimation, rightMesh, rightCarrySlot, sprite); | |
return true; | |
} else { | |
return false; | |
} | |
} | |
public void UnattachCarryableFromSkel() | |
{ | |
unattachSpriteFromSkeleton(frontAnimation, frontCarrySlot); | |
unattachSpriteFromSkeleton(backAnimation, backCarrySlot); | |
unattachSpriteFromSkeleton(leftAnimation, leftCarrySlot); | |
unattachSpriteFromSkeleton(rightAnimation, rightCarrySlot); | |
} | |
public void SetTimeScale(float _timeScale) | |
{ | |
frontAnimation.AnimationState.TimeScale = _timeScale; | |
backAnimation.AnimationState.TimeScale = _timeScale; | |
leftAnimation.AnimationState.TimeScale = _timeScale; | |
rightAnimation.AnimationState.TimeScale = _timeScale; | |
} | |
#endregion | |
#region private helpers | |
Sprite getCarryableSpriteFromType(System.Enum _carryableType) => Resources.Load<Sprite>(string.Format("Sprites/{0}", _carryableType.ToString())); | |
void attachSpriteToSkeleton(SkeletonAnimation _skelAnim, MeshRenderer _mesh, Slot _slot, Sprite _sprite) | |
{ | |
//Get handle to a few things that we'll be using it a lot | |
Skeleton skel = _skelAnim.skeleton; | |
string slotName = _slot.Data.Name; | |
string newAttachmentName = _sprite.name; | |
//All attachment changes will be applied to the skin. We use a clone so other instances will not be affected. | |
Skin newSkin = skel.UnshareSkin(true, false); | |
//Create an attachment from a Unity Sprite | |
RegionAttachment newAttachment = _sprite.ToRegionAttachmentPMAClone(_mesh.material); | |
//Add the attachement to the slot | |
int slotIndex = _skelAnim.skeleton.FindSlotIndex(slotName); | |
newSkin.AddAttachment(slotIndex, newAttachmentName, newAttachment); | |
//Set the skin to the one we made, and then make our attachments visible. | |
//Note that any keying to the slot in the anim will still be recognized, so make sure that's all good to go! | |
skel.SetSkin(newSkin); | |
skel.SetToSetupPose(); | |
skel.SetAttachment(slotName, newAttachmentName); | |
} | |
void unattachSpriteFromSkeleton(SkeletonAnimation _skelAnim, Slot _slot) | |
{ | |
Skeleton skel = _skelAnim.skeleton; | |
skel.SetSlotAttachmentToSetupPose(skel.FindSlotIndex(_slot.Data.Name)); | |
} | |
void assignFootstepListeners(SkeletonAnimation _skelAnim) | |
{ | |
_skelAnim.AnimationState.Event += HandleEvent; | |
} | |
void HandleEvent(TrackEntry trackEntry, Spine.Event e) | |
{ | |
// Play some sound if the event named "footstep" fired. | |
if (e.Data.Name == footstepEventName) { | |
BFMODInterfacer.Instance.PlayPCFootstep(); | |
} | |
} | |
void setAnimationsEnabled(bool _enabled) | |
{ | |
setFrontEnabled(_enabled); | |
setBackEnabled(_enabled); | |
setLeftEnabled(_enabled); | |
setRightEnabled(_enabled); | |
isRendering = _enabled; | |
} | |
void setFrontEnabled(bool _enabled) | |
{ | |
frontMesh.enabled = _enabled; | |
frontAnimation.enabled = _enabled; | |
} | |
void setBackEnabled(bool _enabled) | |
{ | |
backMesh.enabled = _enabled; | |
backAnimation.enabled = _enabled; | |
} | |
void setLeftEnabled(bool _enabled) | |
{ | |
leftMesh.enabled = _enabled; | |
leftAnimation.enabled = _enabled; | |
} | |
void setRightEnabled(bool _enabled) | |
{ | |
rightMesh.enabled = _enabled; | |
rightAnimation.enabled = _enabled; | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment