You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
328 lines
12 KiB
328 lines
12 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using Animancer;
|
|
using AOT;
|
|
using GAS.Runtime;
|
|
using UnityEngine;
|
|
using UnityEngine.Playables;
|
|
using xFrame;
|
|
using YooAsset;
|
|
|
|
namespace CoreGame.Render
|
|
{
|
|
[Combat]
|
|
public class AnimationProxy : ProxyBase
|
|
{
|
|
public class AnimacerData : ISptPool
|
|
{
|
|
public NamedAnimancerComponent animComponent;
|
|
public AssetHandle actionLayerMaskHandle;
|
|
public bool layerInited;
|
|
public FName animPrefix;
|
|
public FName animPathParam;
|
|
|
|
public void Reset()
|
|
{
|
|
// actionLayerMaskHandle?.Release();
|
|
actionLayerMaskHandle = null;
|
|
animComponent = null;
|
|
animPrefix = default;
|
|
animPathParam = default;
|
|
layerInited = false;
|
|
}
|
|
}
|
|
|
|
public struct PlayParam
|
|
{
|
|
public FName stateName;
|
|
public float speed;
|
|
public bool needClear;
|
|
public bool isForce; // 权限最高
|
|
public bool isFromStart;
|
|
|
|
public static bool operator ==(in PlayParam left, in PlayParam right)
|
|
{
|
|
return left.stateName.comparisonIndex == right.stateName.comparisonIndex && Mathf.Approximately(left.speed, right.speed) &&
|
|
left.isForce == right.isForce;
|
|
}
|
|
|
|
public static bool operator !=(in PlayParam left, in PlayParam right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return stateName.GetDisplayString() + " speed: " + speed + " isForce: " + isForce + " isFromStart: " + isFromStart;
|
|
}
|
|
}
|
|
|
|
private bool m_HasActionLayer;
|
|
private Dictionary<int, int> m_AnimsDict;
|
|
private List<AnimacerData> m_AnimList;
|
|
private readonly PlayParam[] m_WantLayerState = new PlayParam[2];
|
|
internal readonly PlayParam[] currLayerState = new PlayParam[2];
|
|
|
|
protected override void Initialize(GameObject go, CombatEntity ent)
|
|
{
|
|
m_HasActionLayer = false;
|
|
m_AnimsDict = DictionaryPool<int, int>.Pop();
|
|
m_AnimList = ListPool<AnimacerData>.Pop();
|
|
Array.Clear(m_WantLayerState, 0, m_WantLayerState.Length);
|
|
Array.Clear(currLayerState, 0, currLayerState.Length);
|
|
}
|
|
|
|
protected override void OnReset()
|
|
{
|
|
for (int i = 0; i < m_AnimList.Count; i++)
|
|
{
|
|
var animParam = m_AnimList[i];
|
|
// Object.Destroy(animParam.animComponent);
|
|
SptPool<AnimacerData>.Free(ref animParam);
|
|
}
|
|
|
|
ListPool<AnimacerData>.Push(ref m_AnimList);
|
|
DictionaryPool<int, int>.Push(ref m_AnimsDict);
|
|
}
|
|
|
|
public void PushMainAnimancer(in SubAssetData subAssetData, in SkinParam skinParam)
|
|
{
|
|
PushPartAnimancer(subAssetData, skinParam);
|
|
}
|
|
|
|
public bool PopPartAnimancer(in SubAssetData subAssetData, in SkinParam skinParam)
|
|
{
|
|
if (m_AnimsDict.TryGetValue((int)skinParam.bpType, out int anim))
|
|
{
|
|
var param = m_AnimList[anim];
|
|
SptPool<AnimacerData>.Free(ref param);
|
|
m_AnimList.RemoveAt(anim);
|
|
m_AnimsDict.Remove((int)skinParam.bpType);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void PushPartAnimancer(in SubAssetData subAssetData, in SkinParam skinParam)
|
|
{
|
|
if (m_AnimsDict.TryGetValue((int)skinParam.bpType, out int anim))
|
|
{
|
|
var param = m_AnimList[anim];
|
|
SptPool<AnimacerData>.Free(ref param);
|
|
m_AnimList.RemoveAt(anim);
|
|
m_AnimsDict.Remove((int)skinParam.bpType);
|
|
}
|
|
|
|
var malloc = SptPool<AnimacerData>.Malloc();
|
|
var subGo = subAssetData.reuseGoData.go;
|
|
// 缓存一下吧,go的组件,和怪物角色类型绑定的
|
|
if (subGo.TryGetComponent<NamedAnimancerComponent>(out var animComponent) == false)
|
|
{
|
|
var animator = subGo.GetComponentInChildren<Animator>();
|
|
if (!animator)
|
|
{
|
|
XLog.LogWarning("No Animator Component");
|
|
SptPool<AnimacerData>.Free(ref malloc);
|
|
return;
|
|
}
|
|
animComponent = subGo.AddComponent<NamedAnimancerComponent>();
|
|
animator.runtimeAnimatorController = null;
|
|
animComponent.Animator = animator;
|
|
animComponent.Playable.UpdateMode = DirectorUpdateMode.Manual; // 目前只有主角的,主动画有动作层
|
|
if (skinParam.bpType == BindPointType.Main)
|
|
{
|
|
malloc.actionLayerMaskHandle = AnimationSrv.GetMaskHandle(skinParam.animPrefix, skinParam.path);
|
|
}
|
|
}
|
|
|
|
malloc.animComponent = animComponent;
|
|
malloc.animPrefix = skinParam.animPrefix;
|
|
malloc.animPathParam = skinParam.path;
|
|
|
|
m_AnimList.Add(malloc);
|
|
m_AnimsDict.Add((int)skinParam.bpType, m_AnimList.Count - 1);
|
|
}
|
|
|
|
// isForce 权限最高,低优先级可中断高优先级动作
|
|
public void Play(in FName stateName, float speed = 1f, bool isForce = false, bool isFromStart = false)
|
|
{
|
|
var fName = stateName;
|
|
var tbAnim = AnimationSrv.StatePriorityDescMap[fName];
|
|
if (tbAnim == null)
|
|
return;
|
|
if (isForce == false)
|
|
{
|
|
// 也要有互斥
|
|
var canTransformState = AnimationSrv.CanTransformState(m_WantLayerState[tbAnim.layer].stateName, fName, 0, isFromStart);
|
|
if (!canTransformState)
|
|
return;
|
|
}
|
|
m_WantLayerState[tbAnim.layer] = new PlayParam { stateName = fName, speed = speed, isForce = m_WantLayerState[tbAnim.layer].isForce || isForce , isFromStart = isFromStart};
|
|
}
|
|
|
|
|
|
public void Tick(float deltaTime)
|
|
{
|
|
for (int i = 0; i < m_WantLayerState.Length; i++)
|
|
m_WantLayerState[i].needClear = true;
|
|
|
|
// 部件很少了,就一把枪
|
|
for (int i = 0; i < m_AnimList.Count; i++)
|
|
{
|
|
var mAnimacerData = m_AnimList[i];
|
|
InitAvatarMask(mAnimacerData);
|
|
|
|
for (int j = 0; j < m_WantLayerState.Length; j++)
|
|
{
|
|
var needChangeState = Do(mAnimacerData, j);
|
|
m_WantLayerState[j].needClear &= needChangeState;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < m_WantLayerState.Length; i++)
|
|
{
|
|
if (m_WantLayerState[i].needClear)
|
|
m_WantLayerState[i] = new PlayParam();
|
|
}
|
|
|
|
// 自旋
|
|
for (var index = 0; index < m_AnimList.Count; index++)
|
|
{
|
|
var animComponent = m_AnimList[index].animComponent;
|
|
animComponent.Evaluate(deltaTime);
|
|
|
|
if (ent.isDead) // 死亡不stop
|
|
continue;
|
|
|
|
var animComponentLayers = animComponent.Layers;
|
|
// 中断已播放到末尾,非loop的动画
|
|
for (int i = 0; i < animComponentLayers.Count; i++)
|
|
{
|
|
var layer = animComponentLayers.GetLayer(i);
|
|
var layerCurrentState = layer.CurrentState;
|
|
if (layerCurrentState == null)
|
|
continue;
|
|
if (layerCurrentState.NormalizedTime >= 1 && layerCurrentState.IsLooping == false)
|
|
{
|
|
layer.Stop();
|
|
currLayerState[i] = new PlayParam();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitAvatarMask(AnimacerData animacerData)
|
|
{
|
|
if (animacerData.layerInited == false)
|
|
{
|
|
if (animacerData.actionLayerMaskHandle != null
|
|
&& animacerData.actionLayerMaskHandle.IsDone)
|
|
{
|
|
if (animacerData.actionLayerMaskHandle.AssetObject is AvatarMask mask)
|
|
{
|
|
animacerData.animComponent.Layers[1].SetMask(mask);
|
|
m_HasActionLayer = true;
|
|
}
|
|
|
|
animacerData.layerInited = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool Do(AnimacerData animacerData, int idx)
|
|
{
|
|
ref var wantParam = ref m_WantLayerState[idx];
|
|
if (wantParam.stateName.IsValid() == false)
|
|
return false;
|
|
|
|
if (!m_HasActionLayer) idx = 0;
|
|
|
|
var assetHandle = AnimationSrv.GetClipAndLoadHandle(animacerData.animPrefix, wantParam.stateName,
|
|
animacerData.animPathParam);
|
|
// 没动画的话,就不处理了
|
|
if (assetHandle == null || !assetHandle.IsDone)
|
|
{
|
|
return false;
|
|
}
|
|
if (assetHandle.AssetObject is not AnimationClip clip)
|
|
{
|
|
return true;
|
|
}
|
|
var tbAnimationStatePriority = AnimationSrv.StatePriorityDescMap[wantParam.stateName];
|
|
// 获取层级
|
|
var layer = 0;
|
|
if (tbAnimationStatePriority.layer <= animacerData.animComponent.Layers.Count - 1)
|
|
{
|
|
layer = tbAnimationStatePriority.layer;
|
|
}
|
|
//当前动画层
|
|
var currLayer = animacerData.animComponent.Layers[layer];
|
|
// 相同状态,变速
|
|
var currLayerCurrentState = currLayer.CurrentState;
|
|
do
|
|
{
|
|
if (currLayerCurrentState == null)
|
|
break;
|
|
|
|
// 自己在播
|
|
var isCurrPlaying = currLayerCurrentState.Clip == clip && (currLayerCurrentState.IsLooping || currLayerCurrentState.NormalizedTime < 0.99f);
|
|
if (isCurrPlaying)
|
|
{
|
|
if (wantParam.isFromStart)
|
|
{
|
|
// Debug.LogError(layer + animacerData.animComponent.gameObject.name + " " + wantParam.stateName.GetDisplayString());
|
|
currLayerCurrentState.NormalizedTime = 0;
|
|
// currLayer.Play(clip, 0, FadeMode.FromStart);
|
|
currLayerCurrentState.Speed = wantParam.speed;
|
|
// wantParam.isFromStart = false;
|
|
return true;
|
|
}
|
|
if (Mathf.Approximately(wantParam.speed, currLayerCurrentState.Speed))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for (var index = 0; index < m_AnimList.Count; index++)
|
|
{
|
|
var anim = m_AnimList[index];
|
|
anim.animComponent.Layers[layer].CurrentState.Speed = wantParam.speed;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// if (currLayerCurrentState.NormalizedTime < 0.99f)
|
|
{
|
|
var tags = ent.TagCountContainer;
|
|
if (tags != null)
|
|
{
|
|
// 要有互斥规则
|
|
if (wantParam.stateName.GetDisplayString() != "die" && tags.HasTag(GTagLib.State_Death))
|
|
return false;
|
|
}
|
|
|
|
var normalizedTime = currLayerCurrentState.NormalizedTime;
|
|
if (currLayerCurrentState.IsLooping)
|
|
normalizedTime = 0;
|
|
|
|
if (wantParam.isForce)
|
|
break;
|
|
|
|
// 判断是否可以切换动画
|
|
if (!AnimationSrv.CanTransformState(currLayerState[idx].stateName, wantParam.stateName,
|
|
normalizedTime, wantParam.isFromStart))
|
|
return false;
|
|
}
|
|
} while (false);
|
|
|
|
// for (var index = 0; index < m_AnimList.Count; index++)
|
|
{
|
|
currLayer.Play(clip);
|
|
// wantParam.isFromStart = false;
|
|
currLayerState[idx] = wantParam;
|
|
currLayer.CurrentState.Speed = wantParam.speed;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|