Files
Hasebe/Assets/Code/OfficeGame/BattleMode/Actions/HoloCopy/HoloCop.cs
T
2026-10-28 20:19:28 +03:00

105 lines
3.4 KiB
C#

using System;
using System.Threading;
using Code.Game.Gameplay.Player;
using Code.OfficeGame.BattleMode.Timeline;
using Cysharp.Threading.Tasks;
using KinematicCharacterController;
using UnityEngine;
using UnityEngine.Serialization;
namespace Code.OfficeGame.BattleMode.Actions.HoloCopy
{
public class HoloCop : MonoBehaviour
{
private static readonly int VelocityForward = Animator.StringToHash("VelocityForward");
private Func<HoloCop, float, bool> _action;
[SerializeField] private MovementController movementController;
[SerializeField] private KinematicCharacterMotor motor;
[SerializeField] private KinematicCharacterMotor originMotor;
[SerializeField] private Animator animator;
[SerializeField] private Animator originAnimator;
public MovementController Controller => movementController;
public Animator Animator => animator;
private Vector3 _initialMotorPosition;
private Quaternion _initialMotorRotation;
private int _initialAnimationState;
private float _initialNormalizedTime;
private void Snapshot()
{
_initialMotorPosition = originMotor.TransientPosition;
_initialMotorRotation = originMotor.TransientRotation;
AnimatorStateInfo stateInfo = originAnimator.GetCurrentAnimatorStateInfo(0);
_initialAnimationState = stateInfo.shortNameHash;
_initialNormalizedTime = stateInfo.normalizedTime;
animator.SetFloat(VelocityForward, originAnimator.GetFloat(VelocityForward));
animator.Play(_initialAnimationState, 0, _initialNormalizedTime);
animator.Update(0f);
}
private void ReturnToSnapshot()
{
bool prevRootMotion = animator.applyRootMotion;
animator.Play(_initialAnimationState, 0, _initialNormalizedTime);
animator.Update(0f);
animator.transform.localPosition = Vector3.zero;
animator.transform.localRotation = Quaternion.identity;
originMotor.SetPositionAndRotation(_initialMotorPosition, _initialMotorRotation);
Physics.SyncTransforms();
}
public async UniTask Simulate(Func<HoloCop, float, bool> action, CancellationToken ctx)
{
_action = action;
float accumulator = 0f;
Snapshot();
try
{
gameObject.SetActive(true);
while (!ctx.IsCancellationRequested)
{
await UniTask.Yield(PlayerLoopTiming.Update, ctx);
accumulator += Time.unscaledDeltaTime;
while (accumulator >= BattleTimeline.TickDelta)
{
accumulator -= BattleTimeline.TickDelta;
if (_action == null) return;
bool result = _action(this, BattleTimeline.TickDelta);
animator.Update(BattleTimeline.TickDelta);
Physics.Simulate(BattleTimeline.TickDelta);
Physics.SyncTransforms();
if (result) ReturnToSnapshot();
}
}
}
finally
{
ReturnToSnapshot();
gameObject.SetActive(false);
}
}
}
}