252 lines
6.0 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|