using BITKit.StateMachine; using Project.B.CharacterController; using Unity.Mathematics; using UnityEngine; namespace Net.Project.B.AI { public abstract class NpcCharacterStates :ICharacterState { public virtual bool Enabled { get; set; } public virtual void Initialize() { } public virtual void OnStateEntry(IState old) { } public virtual void OnStateUpdate(float deltaTime) { } public virtual void OnStateExit(IState old, IState newState) { } public virtual void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { } public virtual void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { } public virtual void BeforeUpdateVelocity(float deltaTime) { } public virtual void AfterUpdateVelocity(float deltaTime) { } } public abstract class NpcCharacterMotionState:NpcCharacterStates { protected readonly NpcCharacterController Self; protected NpcCharacterMotionState(NpcCharacterController self) { Self = self; } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { currentVelocity =Vector3.ProjectOnPlane( Self.NavMeshAgentController.Velocity, Vector3.up); } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); while (Self.NavMeshAgentController.QueuedDeltaRotation.TryDequeue(out var deltaRotation)) { currentRotation *= deltaRotation; } } } public class NpcCharacterStateIdle : NpcCharacterMotionState, ICharacterStateIdle { public NpcCharacterStateIdle(NpcCharacterController self) : base(self) { } public override void OnStateUpdate(float deltaTime) { if (!Self.Agent.pathPending && Self.Agent.remainingDistance > Self.Agent.stoppingDistance) { Self.TransitionState(); } } } public class NpcCharacterStateWalk : NpcCharacterMotionState, ICharacterStateWalk { public NpcCharacterStateWalk(NpcCharacterController self) : base(self) { } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (!Self.Agent.pathPending && Self.Agent.remainingDistance <= Self.Agent.stoppingDistance) { Self.TransitionState(); } } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { var vectors = Self.Agent.path.corners; base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); if (Self.AllowMovement.Allow && Self.Agent.remainingDistance>Self.Agent.stoppingDistance && Self.AllowMovement.Allow && vectors.Length > 1) { var target = vectors[1]; var distance= Vector3.Distance(Self.Transform.position, target); if (distance < 1 &&vectors.Length > 2) { target = vectors[2]; } var dir = Vector3.ProjectOnPlane(target - Self.Transform.position, Vector3.up); var angle = Quaternion.Angle(Quaternion.LookRotation(dir), currentRotation); if (angle < 1) return; var rot = Quaternion.LookRotation(dir); rot = Quaternion.Lerp(currentRotation, rot, 8 * deltaTime); currentRotation = rot; } else { var dir =Vector3.ProjectOnPlane( Self.Agent.destination - (Vector3)Self.Position,Vector3.up); if(dir.sqrMagnitude<0.1f)return; currentRotation=Quaternion.Lerp(currentRotation, Quaternion.LookRotation(dir), 8 * deltaTime); } } } public class NpcCharacterStateAnimation : NpcCharacterMotionState,ICharacterStateAnimation { public NpcCharacterStateAnimation(NpcCharacterController self) : base(self) { } public bool AllowCollision { get; set; } } }