BITFALL/Assets/Artists/Scripts/Entities/Movement/MotionBasedMovement.cs

252 lines
6.0 KiB
C#

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<IMotionBasedState>,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<Collider> _colliders=new();
internal Collider[] colliders
{
get
{
if(_optional.Allow)
return _optional.Value;
_optional.SetValueThenAllow(_colliders.ToArray());
return _optional.Value;
}
}
private Optional<Collider[]> _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<Walk>();
}
else
{
TransitionState<Empty>();
}
}
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 is {IsOvering:true})
{
var animatorTransform = animancerComponent.Animator.transform;
var velocity = animancerComponent.Animator.velocity;
var animator = animancerComponent.Animator;
if (agent.enabled)
{
agent.velocity = animator.velocity;
Rotation*=animator.deltaRotation;
Position = agent.nextPosition;
}
else
{
animator.ApplyBuiltinRootMotion();
}
if (_isAnimatorRoot is false)
{
Position = animatorTransform.position;
Rotation = animatorTransform.rotation;
animatorTransform.localPosition = default;
animatorTransform.localRotation = default;
}
agent.velocity = velocity;
}
else
{
CurrentState?.OnAnimatorMove();
}
}
IEntityMovementState IStateMachine<IEntityMovementState>.CurrentState
{
get => CurrentState;
set => CurrentState = value as IMotionBasedState;
}
event Action<IEntityMovementState, IEntityMovementState> IStateMachine<IEntityMovementState>.OnStateChanged
{
add => OnStateChanged += value;
remove => OnStateChanged -= value;
}
public event Action<IEntityMovementState> OnStateRegistered;
public event Action<IEntityMovementState> OnStateUnRegistered;
IDictionary<Type, IEntityMovementState> IStateMachine<IEntityMovementState>.StateDictionary => throw new NotImplementedException();
void IStateMachine<IEntityMovementState>.Initialize()=> throw new NotImplementedException();
void IStateMachine<IEntityMovementState>.TransitionState<State>()
{
var state = StateDictionary[typeof(State)];
TransitionState(state);
}
void IStateMachine<IEntityMovementState>.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>(T command = default)
{
OnCommand?.Invoke(command);
}
public event Action<object> OnCommand;
private void OnTriggerEnter(Collider other)
{
_colliders.Add(other);
_optional.Clear();
}
private void OnTriggerExit(Collider other)
{
_colliders.Remove(other);
_optional.Clear();
}
}
}