173 lines
6.7 KiB
C#
173 lines
6.7 KiB
C#
using UnityEngine;
|
|
|
|
namespace Code.OfficeGame.BattleMode.Actions
|
|
{
|
|
public struct EntitySnapshot
|
|
{
|
|
public Vector3 Position;
|
|
public Quaternion Rotation;
|
|
public AnimatorSnapshot AnimatorSnapshot;
|
|
|
|
public static EntitySnapshot GetSnapshot(EntityProperties entityProperties)
|
|
{
|
|
return new EntitySnapshot
|
|
{
|
|
Position = entityProperties.KinematicCharacterMotor.TransientPosition,
|
|
Rotation = entityProperties.KinematicCharacterMotor.TransientRotation,
|
|
AnimatorSnapshot = AnimatorSnapshot.GetSnapshot(entityProperties.animator)
|
|
};
|
|
}
|
|
|
|
public static void RestoreSnapshot(EntityProperties entityProperties, EntitySnapshot snapshot)
|
|
{
|
|
// 1. Возвращаем капсулу KCC
|
|
entityProperties.KinematicCharacterMotor.SetPositionAndRotation(snapshot.Position, snapshot.Rotation);
|
|
entityProperties.KinematicCharacterMotor.BaseVelocity = Vector3.zero;
|
|
|
|
// 2. Возвращаем позу и локальное смещение меша
|
|
snapshot.AnimatorSnapshot.RestoreTo(entityProperties.animator);
|
|
|
|
// 3. Синхронизируем физику
|
|
Physics.SyncTransforms();
|
|
}
|
|
}
|
|
|
|
public struct AnimatorSnapshot
|
|
{
|
|
public struct LayerStateSnapshot
|
|
{
|
|
public int FullPathHash;
|
|
public float NormalizedTime;
|
|
public float LayerWeight;
|
|
}
|
|
|
|
public struct ParameterSnapshot
|
|
{
|
|
public int NameHash;
|
|
public AnimatorControllerParameterType Type;
|
|
public float FloatValue;
|
|
public int IntValue;
|
|
public bool BoolValue;
|
|
}
|
|
|
|
private LayerStateSnapshot[] _layers;
|
|
private ParameterSnapshot[] _parameters;
|
|
private Vector3 _localPosition;
|
|
private Quaternion _localRotation;
|
|
private float _speed;
|
|
|
|
public static AnimatorSnapshot GetSnapshot(Animator animator)
|
|
{
|
|
var snapshot = new AnimatorSnapshot();
|
|
snapshot.CaptureFrom(animator);
|
|
return snapshot;
|
|
}
|
|
|
|
public void CaptureFrom(Animator animator)
|
|
{
|
|
if (animator == null) return;
|
|
|
|
Transform animTransform = animator.transform;
|
|
_localPosition = animTransform.localPosition;
|
|
_localRotation = animTransform.localRotation;
|
|
_speed = animator.speed;
|
|
|
|
int layerCount = animator.layerCount;
|
|
if (_layers == null || _layers.Length != layerCount)
|
|
_layers = new LayerStateSnapshot[layerCount];
|
|
|
|
for (int i = 0; i < layerCount; i++)
|
|
{
|
|
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i);
|
|
_layers[i] = new LayerStateSnapshot
|
|
{
|
|
FullPathHash = stateInfo.fullPathHash,
|
|
NormalizedTime = stateInfo.normalizedTime,
|
|
LayerWeight = animator.GetLayerWeight(i)
|
|
};
|
|
}
|
|
|
|
int paramCount = animator.parameterCount;
|
|
if (_parameters == null || _parameters.Length != paramCount)
|
|
_parameters = new ParameterSnapshot[paramCount];
|
|
|
|
for (int i = 0; i < paramCount; i++)
|
|
{
|
|
AnimatorControllerParameter param = animator.GetParameter(i);
|
|
int hash = param.nameHash;
|
|
var paramSnapshot = new ParameterSnapshot { NameHash = hash, Type = param.type };
|
|
|
|
switch (param.type)
|
|
{
|
|
case AnimatorControllerParameterType.Float:
|
|
paramSnapshot.FloatValue = animator.GetFloat(hash);
|
|
break;
|
|
case AnimatorControllerParameterType.Int:
|
|
paramSnapshot.IntValue = animator.GetInteger(hash);
|
|
break;
|
|
case AnimatorControllerParameterType.Bool:
|
|
case AnimatorControllerParameterType.Trigger:
|
|
paramSnapshot.BoolValue = animator.GetBool(hash);
|
|
break;
|
|
}
|
|
_parameters[i] = paramSnapshot;
|
|
}
|
|
}
|
|
|
|
public void RestoreTo(Animator targetAnimator)
|
|
{
|
|
if (targetAnimator == null || _layers == null) return;
|
|
|
|
targetAnimator.Rebind();
|
|
|
|
// Отключаем applyRootMotion на время Update(0f), чтобы Play() не начислил дельту смещения
|
|
bool prevRootMotion = targetAnimator.applyRootMotion;
|
|
targetAnimator.applyRootMotion = false;
|
|
targetAnimator.speed = _speed;
|
|
|
|
if (_parameters != null)
|
|
{
|
|
for (int i = 0; i < _parameters.Length; i++)
|
|
{
|
|
var p = _parameters[i];
|
|
if (targetAnimator.IsParameterControlledByCurve(p.NameHash))
|
|
continue;
|
|
|
|
switch (p.Type)
|
|
{
|
|
case AnimatorControllerParameterType.Float:
|
|
targetAnimator.SetFloat(p.NameHash, p.FloatValue);
|
|
break;
|
|
case AnimatorControllerParameterType.Int:
|
|
targetAnimator.SetInteger(p.NameHash, p.IntValue);
|
|
break;
|
|
case AnimatorControllerParameterType.Bool:
|
|
targetAnimator.SetBool(p.NameHash, p.BoolValue);
|
|
break;
|
|
case AnimatorControllerParameterType.Trigger:
|
|
if (p.BoolValue) targetAnimator.SetTrigger(p.NameHash);
|
|
else targetAnimator.ResetTrigger(p.NameHash);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int layerCount = Mathf.Min(_layers.Length, targetAnimator.layerCount);
|
|
for (int i = 0; i < layerCount; i++)
|
|
{
|
|
var layer = _layers[i];
|
|
targetAnimator.SetLayerWeight(i, layer.LayerWeight);
|
|
targetAnimator.Play(layer.FullPathHash, i, layer.NormalizedTime);
|
|
}
|
|
|
|
targetAnimator.Update(0f);
|
|
|
|
// ОБЯЗАТЕЛЬНО восстанавливаем сохраненные локальные координаты меша после Update(0f)!
|
|
Transform targetTransform = targetAnimator.transform;
|
|
targetTransform.localPosition = _localPosition;
|
|
targetTransform.localRotation = _localRotation;
|
|
|
|
targetAnimator.applyRootMotion = prevRootMotion;
|
|
}
|
|
}
|
|
} |