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(IEntityMovement))] [CustomType(typeof(MotionBasedMovement))] public sealed class MotionBasedMovement : StateBasedBehavior,IEntityMovement { [SerializeField] private Vector3 viewCenter; [Header(Constant.Header.Components)] [SerializeField] private NavMeshAgent agent; [SerializeField] private AnimancerComponent animancerComponent; [Inject] private IEntityOverride _override; [Inject] private IHealth _health; private bool _isAnimatorRoot; private readonly List _colliders=new(); internal Collider[] colliders { get { if(_optional.Allow) return _optional.Value; _optional.SetValueThenAllow(_colliders.ToArray()); return _optional.Value; } } private Optional _optional = new(); private IEntityMovement _entityMovementImplementation => this; 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 && _override.IsOvering is false) { 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 is {IsOvering:true}) { var animator = animancerComponent.Animator; var nextPosition =Position+animator.deltaPosition; if ( NavMesh.SamplePosition(nextPosition, out var hit, agent.height * 2, NavMesh.AllAreas) ) { Position = hit.position; } Rotation*=animator.deltaRotation; agent.speed = 0; agent.velocity = 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; } public event Action OnStateRegistered; public event Action OnStateUnRegistered; 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; public Vector3 ViewForward => Transform.forward; public Vector3 ViewCenter => viewCenter; public Vector3 FocusPoint { get; } = Vector3.up; public Quaternion ViewRotation => Rotation; public Vector3 LocomotionBasedVelocity => Transform.InverseTransformPoint(agent.velocity); public Vector3 Velocity => agent.velocity; public Vector3 GroundVelocity => agent.velocity; public Vector3 AngularVelocity => throw new NotImplementedException(); public bool IsGrounded => agent.isOnNavMesh && agent.isOnOffMeshLink is false; 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; private void OnTriggerEnter(Collider other) { _colliders.Add(other); _optional.Clear(); } private void OnTriggerExit(Collider other) { _colliders.Remove(other); _optional.Clear(); } } }