using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Animancer; using BITFALL.Movement.MotionBased.States; using BITKit; using BITKit.Entities; using BITKit.StateMachine; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; namespace BITFALL.Movement.MotionBased { public interface IMotionBasedState : IEntityMovementState { void OnAnimatorMove(); } public interface IMotionBasedAnimationState:ICloneable { } public interface IMotionBasedAnimationClip{} public abstract class MotionBasedAnimationState { } [CustomType(typeof(MotionBasedMovement))] public sealed class MotionBasedMovement : StateBasedBehavior,IEntityMovement { [SerializeField] private NavMeshAgent agent; [SerializeField] private AnimancerComponent animancerComponent; [Inject] private IEntityOverride _override; [Inject] private IHealth _health; private bool _isAnimatorRoot; public override void Initialize(IEntity entity) { if (entity is IUnityEntity _unityEntity) { _unityEntity.AddService(animancerComponent); _unityEntity.AddService(agent); } base.Initialize(entity); } public override void OnStart() { base.OnStart(); agent.updatePosition = false; agent.updateRotation = false; _health.OnSetAlive += OnSetAlive; _override.OnOverride += OnOverride; _isAnimatorRoot = animancerComponent.Animator.transform == transform; } private void OnSetAlive(bool obj) { if (obj) { TransitionState(); } else { TransitionState(); } } private void OnOverride(bool obj) { agent.isStopped = obj; } public override void OnFixedUpdate(float deltaTime) { if (_override.IsOvering) return; if (_health.IsAlive is false) return; base.OnFixedUpdate(deltaTime); CurrentState?.BeforeUpdateMovement(deltaTime); UpdateState(deltaTime); var currentVelocity = agent.velocity; var currentRotation = agent.transform.rotation; if (CurrentState is not null) { CurrentState.UpdateVelocity(ref currentVelocity, deltaTime); CurrentState.UpdateRotation(ref currentRotation, deltaTime); agent.velocity = currentVelocity; agent.transform.rotation = currentRotation; } CurrentState?.AfterUpdateMovement(deltaTime); } private void OnAnimatorMove() { if (_override.IsOvering) { var animatorTransform = animancerComponent.Animator.transform; animancerComponent.Animator.ApplyBuiltinRootMotion(); if (_isAnimatorRoot is false) { Position = animatorTransform.position; Rotation = animatorTransform.rotation; animatorTransform.localPosition = default; animatorTransform.localRotation = default; } agent.velocity = animancerComponent.Animator.velocity; } else { CurrentState?.OnAnimatorMove(); } } IEntityMovementState IStateMachine.CurrentState { get => CurrentState; set => CurrentState = value as IMotionBasedState; } event Action IStateMachine.OnStateChanged { add => OnStateChanged += value; remove => OnStateChanged -= value; } IDictionary IStateMachine.StateDictionary => throw new NotImplementedException(); void IStateMachine.Initialize()=> throw new NotImplementedException(); void IStateMachine.TransitionState() { var state = StateDictionary[typeof(State)]; TransitionState(state); } void IStateMachine.TransitionState(IEntityMovementState state) { TransitionState(state as IMotionBasedState); } public Vector3 Position { get => Transform.position; set => Transform.position = value; } public Quaternion Rotation { get => Transform.rotation; set => Transform.rotation = value; } public Vector3 Forward => Rotation * Vector3.forward; Vector3 IEntityMovement.ViewForward => Transform.forward; Vector3 IEntityMovement.ViewCenter { get; } = Vector3.up; Vector3 IEntityMovement.FocusPoint { get; } = Vector3.up; Quaternion IEntityMovement.ViewRotation => Rotation; Vector3 IEntityMovement.LocomotionBasedVelocity => Transform.InverseTransformPoint(agent.velocity); Vector3 IEntityMovement.Velocity => agent.velocity; Vector3 IEntityMovement.GroundVelocity => agent.velocity; Vector3 IEntityMovement.AngularVelocity => throw new NotImplementedException(); bool IEntityMovement.IsGrounded => agent.isOnOffMeshLink; void IEntityMovement.SyncMovement(Vector3 velocity, Vector3 position, Quaternion rotation, bool isGrounded) { throw new NotImplementedException(); } void IEntityMovement.OnMovement(Vector3 relativeVector) { throw new NotImplementedException(); } void IEntityMovement.OnMovement(InputAction.CallbackContext context) { throw new NotImplementedException(); } void IEntityMovement.ExecuteCommand(T command = default) { OnCommand?.Invoke(command); } public event Action OnCommand; } }