299 lines
9.5 KiB
C#
299 lines
9.5 KiB
C#
using System;
|
||
using Cysharp.Threading.Tasks;
|
||
using System.Collections.Generic;
|
||
using PhxhSDK;
|
||
using UnityEngine;
|
||
using Constants = Framework.Constants;
|
||
|
||
namespace Gameplay.Character
|
||
{
|
||
public class CharacterAnim
|
||
{
|
||
|
||
public readonly Character owner;
|
||
|
||
public string targetUpAnim;
|
||
|
||
public string targetDownAnim;
|
||
|
||
public string targetFullAnim;
|
||
|
||
public bool noFade = false;
|
||
|
||
public string currentUpAnim { get; private set; }
|
||
public string currentDownAnim { get; private set; }
|
||
public string currentFullAnim { get; private set; }
|
||
|
||
public readonly Animator rawAnim;
|
||
|
||
private bool _lastIsFullControl = false;
|
||
public bool isFullControl = false;
|
||
|
||
private Dictionary<int, LTAnimLayerInfo> _layerDict;
|
||
|
||
private float _splitScaleNormalShoot = 1;
|
||
public float splitScaleNormalShoot
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleNormalShoot;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleNormalShoot - value) < 0.01f) return;
|
||
_splitScaleNormalShoot = value;
|
||
rawAnim.SetFloat(EAnimParamConst.AttackScaleNormal, value);
|
||
}
|
||
}
|
||
|
||
private float _splitScaleLowShoot = 1;
|
||
public float splitScaleLowShoot
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleLowShoot;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleLowShoot - value) < 0.01f) return;
|
||
_splitScaleLowShoot = value;
|
||
rawAnim.SetFloat(EAnimParamConst.AttackScaleLow, value);
|
||
}
|
||
}
|
||
|
||
private float _splitScaleNormalReload = 1;
|
||
public float splitScaleNormalReload
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleNormalReload;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleNormalReload - value) < 0.01f) return;
|
||
_splitScaleNormalReload = value;
|
||
rawAnim.SetFloat(EAnimParamConst.ReloadScaleNormal, value);
|
||
}
|
||
}
|
||
private float _splitScaleLowReload = 1;
|
||
public float splitScaleLowReload
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleLowReload;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleLowReload - value) < 0.01f) return;
|
||
_splitScaleLowReload = value;
|
||
rawAnim.SetFloat(EAnimParamConst.ReloadScaleLow, value);
|
||
}
|
||
}
|
||
|
||
private float _splitScaleNormalMove = 1;
|
||
public float splitScaleNormalMove
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleNormalMove;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleNormalMove - value) < 0.01f) return;
|
||
_splitScaleNormalMove = value;
|
||
rawAnim.SetFloat(EAnimParamConst.MoveScaleNormal, value);
|
||
}
|
||
}
|
||
private float _splitScaleLowMove = 1;
|
||
public float splitScaleLowMove
|
||
{
|
||
get
|
||
{
|
||
return _splitScaleLowMove;
|
||
}
|
||
set
|
||
{
|
||
if (Math.Abs(_splitScaleLowMove - value) < 0.01f) return;
|
||
_splitScaleLowMove = value;
|
||
rawAnim.SetFloat(EAnimParamConst.MoveScaleLow, value);
|
||
}
|
||
}
|
||
|
||
public float NORMAL_MOVESPEED = 3f;
|
||
public float LOW_MOVESPEED = 0.6f;
|
||
|
||
public CharacterAnim(Character owner)
|
||
{
|
||
this.owner = owner;
|
||
rawAnim = owner.RawAnimator;
|
||
|
||
_lastIsFullControl = false;
|
||
isFullControl = false;
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Full, 0);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Up, 1);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Down, 1);
|
||
|
||
}
|
||
|
||
public async UniTask Init()
|
||
{
|
||
await _InitAnimInfo();
|
||
ResetAnim();
|
||
}
|
||
|
||
private async UniTask _InitAnimInfo()
|
||
{
|
||
_layerDict = new Dictionary<int, LTAnimLayerInfo>();
|
||
|
||
var fileName = owner.runtimeData.configData.nameId;
|
||
var animInfoPath = string.Format(Constants.ANIMATOR_CONFIG_FORMAT_PATH, fileName);
|
||
var loadAsset = await AssetManager.Instance.LoadAssetAsync<TextAsset>(animInfoPath);
|
||
if (loadAsset == null)
|
||
{
|
||
DebugUtil.LogError("[AnimatorInfoExporter] Load animator info failed: {0}", animInfoPath);
|
||
return;
|
||
}
|
||
var json = loadAsset.text;
|
||
var result = JsonUtility.FromJson<SaveAnimatorData>(json);
|
||
var layers = result.layers;
|
||
|
||
// 遍历每个 Layer,获取其中的所有动画状态信息
|
||
for (var i = 0; i < layers.Count; ++i)
|
||
{
|
||
var layer = layers[i];
|
||
GetAllStates(layer, i);
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 该方法需要在动画速度发生改变时进行调用
|
||
/// </summary>
|
||
public void ResetAnim()
|
||
{
|
||
ResetReloadAnim();
|
||
ResetShootAnim();
|
||
}
|
||
|
||
public void ResetReloadAnim()
|
||
{
|
||
// reload时间
|
||
var reloadTime = owner.fightData.reloadTime;
|
||
var reloadAnimLength = GetStateLength(EAnimUpState.S_RELOAD, EAnimStateIndex.Up);
|
||
splitScaleNormalReload = reloadAnimLength / reloadTime;
|
||
var cReloadAnimLength = GetStateLength(EAnimUpState.S_C_RELOAD, EAnimStateIndex.Up);
|
||
splitScaleLowReload = cReloadAnimLength / reloadTime;
|
||
}
|
||
|
||
public void ResetShootAnim()
|
||
{
|
||
// 开枪时间
|
||
var shootTime = owner.fightData.shootCd;
|
||
var shootAnimLength = GetStateLength(EAnimUpState.S_ATTACK, EAnimStateIndex.Up);
|
||
splitScaleNormalShoot = shootAnimLength / shootTime;
|
||
|
||
var cShootAnimLength = GetStateLength(EAnimUpState.S_C_ATTACK, EAnimStateIndex.Up);
|
||
splitScaleLowShoot = cShootAnimLength / shootTime;
|
||
}
|
||
|
||
private void GetAllStates(SaveLayerData stateMachine, int layerIndex)
|
||
{
|
||
// 获取 stateMachine 中的所有动画状态信息
|
||
var states = stateMachine.states;
|
||
var newLayer = new LTAnimLayerInfo(layerIndex);
|
||
_layerDict.Add(layerIndex, newLayer);
|
||
// 遍历每个动画状态信息并处理
|
||
foreach (var state in states)
|
||
{
|
||
var newStateInfo = new LTAnimStateInfo();
|
||
newStateInfo.stateName = state.stateName;
|
||
newStateInfo.clipName = state.clipName;
|
||
newStateInfo.clipLength = state.clipLength;
|
||
|
||
newLayer.stateMap.Add(state.stateName, newStateInfo);
|
||
}
|
||
|
||
}
|
||
|
||
public void ViewUpdate(float dt)
|
||
{
|
||
if (isFullControl != _lastIsFullControl)
|
||
{
|
||
// 控制状态发生改变
|
||
if (isFullControl)
|
||
{
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Full, 1);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Up, 0);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Down, 0);
|
||
}
|
||
else
|
||
{
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Full, 0);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Up, 1);
|
||
rawAnim.SetLayerWeight(EAnimStateIndex.Down, 1);
|
||
}
|
||
_lastIsFullControl = isFullControl;
|
||
currentDownAnim = null;
|
||
currentUpAnim = null;
|
||
currentFullAnim = null;
|
||
}
|
||
|
||
|
||
if (currentFullAnim != targetFullAnim)
|
||
{
|
||
if (currentFullAnim == null || noFade)
|
||
{
|
||
rawAnim.Play(targetFullAnim, EAnimStateIndex.Full, 0);
|
||
}
|
||
else
|
||
{
|
||
rawAnim.CrossFade(targetFullAnim, 0.1f, EAnimStateIndex.Full, 0);
|
||
}
|
||
currentFullAnim = targetFullAnim;
|
||
}
|
||
|
||
if (currentUpAnim != targetUpAnim)
|
||
{
|
||
if (currentUpAnim == null || noFade)
|
||
{
|
||
rawAnim.Play(targetUpAnim, EAnimStateIndex.Up, 0);
|
||
}
|
||
else
|
||
{
|
||
rawAnim.CrossFade(targetUpAnim, 0.1f, EAnimStateIndex.Up, 0);
|
||
}
|
||
currentUpAnim = targetUpAnim;
|
||
}
|
||
|
||
if (currentDownAnim != targetDownAnim)
|
||
{
|
||
// TODO: 下半身融合看着比较奇怪,暂时不用
|
||
if (currentDownAnim == null || noFade)
|
||
{
|
||
rawAnim.Play(targetDownAnim, EAnimStateIndex.Down, 0);
|
||
}
|
||
else
|
||
{
|
||
rawAnim.CrossFade(targetDownAnim, 0.05f, EAnimStateIndex.Down, 0);
|
||
}
|
||
currentDownAnim = targetDownAnim;
|
||
}
|
||
}
|
||
|
||
public float GetStateLength(string stateName, int layerIndex)
|
||
{
|
||
var layer = _layerDict[layerIndex];
|
||
var stateInfo = layer.stateMap[stateName];
|
||
return stateInfo.clipLength;
|
||
}
|
||
|
||
//public void SetStateSpeed(string stateName, int layerIndex, float speed)
|
||
//{
|
||
// var layer = _layerDict[layerIndex];
|
||
// var stateInfo = layer.stateMap[stateName];
|
||
// stateInfo.rawState.speed = speed;
|
||
//}
|
||
|
||
}
|
||
}
|