using System.Linq; using BITKit; using BITKit.Entities; using BITKit.Physics; using BITKit.StateMachine; using DrawXXL; using Kinemation.MotionWarping.Runtime.Core; using Kinemation.MotionWarping.Runtime.Utility; using Lightbug.CharacterControllerPro.Core; using Microsoft.Extensions.Logging; using Net.Project.B.Inventory; using Net.Project.B.World; using Net.Project.B.WorldNode; using Project.B.Player; using Unity.Mathematics; using UnityEngine; using UnityEngine.InputSystem; namespace Project.B.CharacterController { public abstract class CharacterStateBase:ICharacterState,ICharacterStateData { protected readonly PlayerCharacterController Self; protected CharacterStateBase(ICharacterController characterController) { Self=characterController as PlayerCharacterController; } public virtual float BaseHeight { get; set; } = 1.6f; public virtual float BaseSpeed { get; set; } = 2.5f; public virtual float2 ViewOffset { get; set; } = new float2(1.4f, 0.16f); public bool Enabled { get; set; } protected IState EntryState { get; private set; } public virtual void Initialize() { } public virtual void OnStateEntry(IState old) { EntryState = 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) { } protected virtual void Exit() { Self.TransitionState(EntryState as ICharacterState); } } public abstract class CharacterMovementState : CharacterStateBase { protected readonly ICharacterController CharacterController; protected virtual bool UseViewPosition => false; protected virtual bool UseViewRotation => true; private Quaternion _viewCameraRotation=Quaternion.identity; private Quaternion _lastRotation=Quaternion.identity; private Quaternion _targetAdditiveRotation = Quaternion.identity; private Quaternion _currentAdditiveRotation = Quaternion.identity; private Optional _lastDynamicRotation=new(); protected CharacterMovementState(ICharacterController characterController) : base(characterController) { CharacterController = characterController; } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation,ref quaternion viewRotation, float deltaTime) { var isTps = false; if (CharacterController is PlayerCharacterController playerCharacterController) { isTps = playerCharacterController.AllowTpsCamera.Allow; } else { playerCharacterController = null; } var rotation = new Vector3(Self.InputView.y, Self.InputView.x); var actorRot = Quaternion.LookRotation(Vector3.ProjectOnPlane(Quaternion.Euler(0,Self.InputView.x,0) * Vector3.forward, Vector3.up)); var currentPos = Self.PlayerView.transform.localPosition; Vector3.Lerp(currentPos, new Vector3(0, Self.CurrentStateData.ViewOffset.x, Self.CurrentStateData.ViewOffset.y), Time.deltaTime * 5); if (isTps) { var input = playerCharacterController.InputDirection; var direction = actorRot * new Vector3(input.x,0,input.y); if (direction.sqrMagnitude > 0.16f) { currentRotation = Quaternion.Lerp(currentRotation, Quaternion.LookRotation(direction), 16 * deltaTime) ; } } else { currentRotation = actorRot ; } _currentAdditiveRotation = Quaternion.Lerp(_currentAdditiveRotation,UseViewRotation || Self.ForceRootMotion.Allow ? _targetAdditiveRotation : Quaternion.identity, 8 * deltaTime *Self.PlayerSettings.Value.ViewCameraMovementIntensity); viewRotation = Quaternion.Euler(rotation) * Quaternion.Lerp(quaternion.identity, _currentAdditiveRotation,0.64f) ; var newPos = new float3(0,ViewOffset.x,ViewOffset.y); if (UseViewPosition || Self.ForceRootMotion.Allow) { if (Self.PlayerAnimationView) { newPos = Self.Transform.InverseTransformPoint(Self.PlayerAnimationView .position); } } localPosition = Vector3.Lerp(localPosition, newPos, 32*deltaTime); if (playerCharacterController is{LimitedViewAngle:{Count:>0}} && Self.AllowTpsCamera.Allow is false) { var max = playerCharacterController.LimitedViewAngle.Min(); var currentViewRotation = playerCharacterController.PlayerAnimationView.rotation; float angleDifference = Quaternion.Angle(Quaternion.Euler(rotation), currentViewRotation); // 如果角度差大于最大允许角度差,进行限制 if (angleDifference > max) { //将当前旋转限制在最大允许角度差的范围内 var clampRotation = Quaternion.Lerp( Quaternion.Euler(rotation), Quaternion.RotateTowards(currentViewRotation,Quaternion.Euler(rotation) , max), 64 * Time.deltaTime ); //rotation = Quaternion.RotateTowards(FpvRotation, rotation, LimitViewAngle); var newView = MathV.TransientRotationAxis(clampRotation.eulerAngles); playerCharacterController.InputView = new(newView.y,newView.x); } } if (Self.CharacterActor.supportDynamicGround && Self.CharacterActor.GroundCollider3D is {attachedRigidbody:{} groundRigidbody} && groundRigidbody) { var dynamicRotation = groundRigidbody.rotation; if (_lastDynamicRotation.Allow) { if (dynamicRotation != _lastDynamicRotation.Value) { var d = Quaternion.Inverse(dynamicRotation) * _lastDynamicRotation; Self.InputView-=new float2(d.eulerAngles.y,0); _lastDynamicRotation.SetValueThenAllow(dynamicRotation); } } else { _lastDynamicRotation.SetValueThenAllow(dynamicRotation); } } else { _lastDynamicRotation.Clear(); } } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { var rot = Quaternion.Euler(new Vector3(Self.InputView.y, Self.InputView.x)); rot = Quaternion.LookRotation(Vector3.ProjectOnPlane(rot * Vector3.forward, Vector3.up)); if (Self.PlayerAnimationView) { _viewCameraRotation = Self.PlayerAnimationView.rotation; var relativeRotation = Quaternion.Inverse(_viewCameraRotation) * Self.Rotation; _targetAdditiveRotation = Quaternion.Inverse(relativeRotation) * _lastRotation; _lastRotation = relativeRotation; } var moveVelocity = rot * new Vector3( Self.InputDirection.x, 0, Self.InputDirection.y ) * (Self.CurrentStateData?.BaseSpeed ?? 1); if (Self.CharacterActor.IsGrounded) { var effectiveGroundNormal =Self.CharacterActor.GroundStableNormal; var inputRight = Vector3.Cross(moveVelocity, Vector3.up); var reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * moveVelocity.magnitude; var targetMovementVelocity = reorientedInput; //* initialSpeed; // Smooth movement Velocity var newVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1f - Mathf.Exp(-12 * deltaTime)); currentVelocity = newVelocity; if (Self.RequestJump && Self.JumpedThisTime is false) { Self.CharacterActor.ForceNotGrounded(); // if (characterController.landFreeze.AllowUpdateWithoutReset is false) // { // currentVelocity = Vector3.Lerp(currentVelocity, default, 0.8f); // } currentVelocity.y+= 5f; if (this is ICharacterSliding ) { currentVelocity += currentVelocity; var normal = (float3)Self.CharacterActor.GroundStableNormal; normal.y = Mathf.Abs(normal.y); currentVelocity += normal; } Self.JumpedThisTime = true; } } else { if (moveVelocity.sqrMagnitude > 0f /* && self.landFreeze.AllowUpdateWithoutReset */) { var addedVelocity = moveVelocity * (3 * deltaTime); var currentVelocityOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity, Vector3.up); // Limit air velocity from inputs if (currentVelocityOnInputsPlane.magnitude < 5) { // clamp addedVel to make total vel not exceed max vel on inputs plane Vector3 newTotal = Vector3.ClampMagnitude(currentVelocityOnInputsPlane + addedVelocity, 5); addedVelocity = newTotal - currentVelocityOnInputsPlane; } else { // Make sure added vel doesn't go in the direction of the already-exceeding velocity if (Vector3.Dot(currentVelocityOnInputsPlane, addedVelocity) > 0f) { addedVelocity = Vector3.ProjectOnPlane(addedVelocity, currentVelocityOnInputsPlane.normalized); } } // Prevent air-climbing sloped walls if (Self.CharacterActor.WallCollision) { if (Vector3.Dot(currentVelocity + (float3)addedVelocity, addedVelocity) > 0f) { var perpenticularObstructionNormal = Vector3 .Cross(Vector3.Cross(Vector3.up, Self.CharacterActor.GroundContactNormal), Vector3.up).normalized; addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal); } } // Apply added velocity currentVelocity += (float3)addedVelocity; } else { var tempVelocity = currentVelocity; tempVelocity = Vector3.Lerp(tempVelocity, default, 2*deltaTime); currentVelocity.x = tempVelocity.x; currentVelocity.z = tempVelocity.z; } // Gravity currentVelocity += (float3)(-Vector3.up * (30 * deltaTime)); // Drag currentVelocity *= (1f / (1f + 0.1f * deltaTime)); } } } public class CharacterWalkState : CharacterMovementState,ICharacterStateWalk { private IMicroStateMachine _controlMode; protected override bool UseViewRotation => false; protected override bool UseViewPosition => false; public CharacterWalkState(ICharacterController characterController, IMicroStateMachine controlMode) : base(characterController) { _controlMode = controlMode; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); _controlMode.TransitionState(); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if(Self.DisableStateTransition.Allow)return; if (Self.InputDirection is {x:0,y:0}) { CharacterController.TransitionState(); } } } public class CharacterAnimationState:CharacterMovementState,ICharacterStateAnimation { public CharacterAnimationState(ICharacterController characterController) : base(characterController) { } protected override bool UseViewPosition => true; protected override bool UseViewRotation => true; public bool AllowCollision { get; set; } public override float BaseSpeed => 0; public override void OnStateEntry(IState old) { base.OnStateEntry(old); Self.CharacterActor.UseRootMotion = true; } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); Self.CharacterActor.UseRootMotion = false; } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); } } public class CharacterIdleState : CharacterMovementState,ICharacterStateIdle { private IMicroStateMachine _controlMode; protected override bool UseViewRotation => false; protected override bool UseViewPosition => false; public CharacterIdleState(ICharacterController characterController, IMicroStateMachine controlMode) : base(characterController) { _controlMode = controlMode; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); _controlMode.TransitionState(); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if(Self.DisableStateTransition.Allow)return; switch (Self.InputDirection) { case {x:not 0}: case {y:not 0}: CharacterController.TransitionState(); break; } } } public class CharacterCrouchedState : CharacterMovementState,ICharacterStateCrouched { public override float BaseHeight { get; set; } = 1.0f; public override float2 ViewOffset { get; set; } = new float2(1.0f, 0.32f); public override float BaseSpeed { get; set; } = 1; protected override bool UseViewRotation => false; public CharacterCrouchedState(ICharacterController characterController) : base(characterController) { } } public class CharacterRunState:CharacterMovementState,ICharacterStateRun { public override float BaseSpeed { get; set; } = 4.5f; public CharacterRunState(ICharacterController characterController) : base(characterController) { } } public class CharacterSprintState:CharacterMovementState,ICharacterSprint { public override float BaseSpeed { get; set; } = 6; private float _consumedStamina; public CharacterSprintState(ICharacterController characterController) : base(characterController) { } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { var length = MathV.GetLength(currentVelocity); if (length > 3) { _consumedStamina += 32 * deltaTime; if (_consumedStamina > 1 && Self.IsGrounded) { var consumed = (int)_consumedStamina; _consumedStamina -= consumed; Self.Stamina -= consumed; } } if (Self.Stamina is 0) { Self.TransitionState(); return; } base.UpdateVelocity(ref currentVelocity, deltaTime); } } public class CharacterVaultState : CharacterMovementState, ICharacterStateVault,IWarpPointProvider { protected readonly IPlayerWeaponInventory _weaponInventory; protected override bool UseViewPosition => true; protected override bool UseViewRotation => true; private readonly MotionWarpingAsset _motionWarpingAsset; private Quaternion _forward; public CharacterVaultState(ICharacterController characterController, IPlayerWeaponInventory weaponInventory) : base(characterController) { _weaponInventory = weaponInventory; _motionWarpingAsset = Self.EntitiesService.QueryComponents().ToArray() .First(x => x.name == "motion_wrapping_vault"); } public override void OnStateEntry(IState old) { base.OnStateEntry(old); Vector3 samplePos = Self.ViewPosition; samplePos.y = Self.SyncPosition.y; if (Self.SyncCollider.Raycast(new(samplePos, Self.SyncPosition - samplePos), out var hit, int.MaxValue)) { _forward =Quaternion.LookRotation( Quaternion.LookRotation(Vector3.ProjectOnPlane(hit.normal, Vector3.up)) * Vector3.back); } else { _forward = Self.Rotation; } Self.MotionWarping.onWarpEnded.AddListener(Exit); Self.MotionWarping.Interact(this); Self.AllowOverride.AddElement(Self.MotionWarping); if (old is ICharacterStateClimb) { _weaponInventory.AllowWeapon.AddDisableElements(this); } } public override void OnStateExit(IState old, IState newState) { Self.AllowOverride.RemoveElement(Self.MotionWarping); base.OnStateExit(old, newState); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } protected override void Exit() { Self.MotionWarping.onWarpEnded.RemoveListener(Exit); base.Exit(); } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { base.UpdateVelocity(ref currentVelocity, deltaTime); currentVelocity = default; } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); currentRotation = _forward; } public WarpInteractionResult Interact(GameObject instigator) { var syncTransform = Self.SyncCollider.transform; var result = new WarpInteractionResult() { points = new[] { new WarpPoint() { transform = syncTransform, position = syncTransform.InverseTransformPoint(Self.SyncPosition), rotation = Quaternion.Inverse(syncTransform.rotation) * _forward } }, asset = _motionWarpingAsset, success = true }; return result; } } public class CharacterStepUpState:CharacterMovementState,ICharacterStateStepUp,IWarpPointProvider { private readonly MotionWarpingAsset _motionWarpingAsset; public CharacterStepUpState(ICharacterController characterController, Animator animator, IPlayerWeaponInventory weaponInventory) : base(characterController) { _animator = animator; _weaponInventory = weaponInventory; _motionWarpingAsset = Self.EntitiesService.QueryComponents().ToArray() .First(x => x.name == "motion_wrapping_step_up"); } public override float BaseHeight => 0.24f; protected override bool UseViewPosition => true; protected override bool UseViewRotation => true; private readonly IPlayerWeaponInventory _weaponInventory; private readonly Animator _animator; private readonly float _lerpFactor = 2; private readonly IntervalUpdate _cancelInterval = new(0.16f); private Transform _ignore; private Quaternion _forward; private bool _needInit; public override void OnStateEntry(IState old) { Vector3 samplePos = Self.ViewPosition; samplePos.y = Self.SyncPosition.y; if (Self.SyncCollider.Raycast(new(samplePos, Self.SyncPosition - samplePos), out var hit, int.MaxValue)) { _forward =Quaternion.LookRotation( Quaternion.LookRotation(Vector3.ProjectOnPlane(hit.normal, Vector3.up)) * Vector3.back); } else { _forward = Self.Rotation; } _ignore = Self.SyncCollider.transform; //Self.CharacterActor.PhysicsComponent.IgnoreCollision(_ignore,true); base.OnStateEntry(old); Self.CharacterActor.alwaysNotGrounded = true; Self.CharacterActor.ForceNotGrounded(); _cancelInterval.Reset(); _needInit = true; Self.LimitedViewAngle.Add(80); var velocity = CharacterController.SelfVelocity; //velocity.x = Mathf.Clamp(velocity.x, -0.5f, 0.5f); velocity.y = Mathf.Clamp(velocity.y, 3, 8); CharacterController.Velocity = velocity; if (old is ICharacterStateClimb) { _weaponInventory.AllowWeapon.AddDisableElements(this); } Self.MotionWarping.onWarpEnded.AddListener(Exit); Self.AllowOverride.AddElement(Self.MotionWarping); Self.MotionWarping.Interact(this); } protected override void Exit() { switch (EntryState) { case ICharacterStateClimb: CharacterController.TransitionState(); break; default: base.Exit(); break; } } public override void OnStateUpdate(float deltaTime) { return; if (_cancelInterval.AllowUpdate && Self.CharacterActor.Velocity.sqrMagnitude<=0.16f && Self.CharacterActor.Position.y > Self.SyncPosition.y ) { //Exit(); return; } var direction = Self.Transform.InverseTransformPoint(Self.SyncPosition); switch (direction) { case { z: < 0, y: <= 0 }: case {} when direction.GetLength()<0.1f: Self.TransitionState(); break; case { z: > 0, y: < 0 }: break; } if (_ignore && _ignore.TryGetComponent(out var collider) && collider is not MeshCollider{convex:false}) { var currentPosition = Self.Position; var closePoint = collider.ClosestPoint(currentPosition); if (closePoint.y > currentPosition.y) { currentPosition.y = closePoint.y; Self.Position = currentPosition; } } } public override void OnStateExit(IState old, IState newState) { Self.AllowOverride.RemoveElement(Self.MotionWarping); Self.MotionWarping.onWarpEnded.RemoveListener(Exit); // Self.CharacterActor.PhysicsComponent.IgnoreCollision(_ignore,false); Self.CharacterActor.alwaysNotGrounded = false; //Self._characterActor.ColliderComponent.enabled = true; Self.CharacterActor.ForceGrounded(); Self.LimitedViewAngle.TryRemove(80); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { currentVelocity = default; return; if (_needInit) { currentVelocity.y = 0; _needInit = false; } var velocity =(Self.SyncPosition - Self.CharacterActor.Position).normalized * _animator.velocity.GetLength(); velocity += _animator.velocity; //velocity += (float3)((self.Rotation * (Vector3)((Vector2)self.InputDirection).normalized) * 1.0f); //currentVelocity = Vector3.Lerp(currentVelocity,velocity,_lerpFactor*deltaTime); var selfVelocity = Self.Transform.InverseTransformDirection(velocity); //selfVelocity.x = 0; selfVelocity.z = math.max(3, velocity.z); selfVelocity.y = math.max(1.6f,selfVelocity.y); velocity = Self.Transform.TransformDirection(selfVelocity); currentVelocity = velocity; } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); // currentRotation = _forward; } public WarpInteractionResult Interact(GameObject instigator) { var syncTransform = Self.SyncCollider.transform; var result = new WarpInteractionResult() { points = new[] { new WarpPoint() { transform = syncTransform, position = syncTransform.InverseTransformPoint(Self.SyncPosition), rotation = Quaternion.Inverse(syncTransform.rotation) * _forward } }, asset = _motionWarpingAsset, success = true }; return result; } } public sealed class CharacterKnockedState : CharacterMovementState, ICharacterKnocked { public CharacterKnockedState(ICharacterController characterController) : base(characterController) { } protected override bool UseViewRotation => true; protected override bool UseViewPosition => true; public override float BaseSpeed => 0.5f; public override float BaseHeight => 0.45f; public override float2 ViewOffset { get; set; } = new(0.4f, 0f); public override void OnStateEntry(IState old) { base.OnStateEntry(old); Self.LimitedViewAngle.Add(50); } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { var currentRot = currentRotation; base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); viewRotation *= Quaternion.Euler(0, 0, 3); if (MathV.GetLength(Self.Velocity) > 0.1f) { currentRotation = Quaternion.Lerp(currentRot, currentRotation, deltaTime); } else { currentRotation = currentRot; } } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); Self.LimitedViewAngle.Remove(50); } } public sealed class CharacterSlidingState : CharacterMovementState, ICharacterSliding { private readonly CharacterActor _actor; private readonly PlayerCharacterController _playerCharacterController; protected override bool UseViewPosition => true; public CharacterSlidingState(ICharacterController characterController, CharacterActor actor) : base(characterController) { _actor = actor; _playerCharacterController = characterController as PlayerCharacterController; } public override float BaseHeight { get; set; } = 1.2f; public override float2 ViewOffset { get; set; } = new float2(0.8f, 0.32f); public override float BaseSpeed { get; set; } = 1; private const float AdditiveSpeed = 4f; private const float Damping = 1.8f; private const float StopSpeed = 1.2f; private bool _alwaysSlide; private bool _addedVelocity; private Quaternion _entryRotation; public override void OnStateEntry(IState old) { base.OnStateEntry(old); // self.ExpectCrouch.being = true; // self.ExpectCrouch.shouldBe = true; // self.ExecuteCommand(); _playerCharacterController.CancelRun(); _addedVelocity = false; _entryRotation = _actor.Rotation; _playerCharacterController.LimitedViewAngle.Add(60); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); _playerCharacterController.LimitedViewAngle.Remove(60); } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); currentRotation = _entryRotation; } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { if (_alwaysSlide && _actor.IsGrounded is false) { base.UpdateVelocity(ref currentVelocity, deltaTime); } else { if (_addedVelocity is false) { currentVelocity += (float3)((Vector3)currentVelocity).normalized * AdditiveSpeed; _addedVelocity = true; } else { currentVelocity = Vector3.Lerp(currentVelocity, Vector3.zero, deltaTime * Damping); if (_actor.IsGrounded) { var normal = _actor.GroundStableNormal; normal = Vector3.ProjectOnPlane(normal, Vector3.up); currentVelocity += (float3)normal; } } } } protected override void Exit() { //base.Exit(); CharacterController.TransitionState(); } public override void AfterUpdateVelocity(float deltaTime) { if(_actor.Velocity.sqrMagnitude <= StopSpeed) { Exit(); return; } if(_actor.IsGrounded is false) { Exit(); return; } } } public sealed class CharacterClimbState : CharacterMovementState, ICharacterStateClimb { private readonly IPlayerWeaponInventory _weaponInventory; protected override bool UseViewPosition => true; public CharacterClimbState(ICharacterController characterController, IPlayerWeaponInventory weaponInventory) : base(characterController) { _weaponInventory = weaponInventory; } private const float LerpFactor = 2; private Transform _ignore; private Quaternion _forward; private bool _needInit; private Vector3 FixedSyncPosition =>Self.SyncPosition+_forward * new Vector3(0, -1.3f,- 0.5f); private readonly IntervalUpdate _freeTurn = new(0.2f); public override void OnStateEntry(IState old) { Vector3 samplePos = Self.Position; samplePos.y = Self.SyncPosition.y; if (Self.SyncCollider.TryGetClosestPointFromCollider(samplePos, out var closestPoint)) { DrawBasics.Point(closestPoint,text:"Climb Point", durationInSec:8); DrawBasics.Line(samplePos,closestPoint,durationInSec:8); if (Self.SyncCollider.Raycast(new Ray(samplePos, closestPoint - samplePos), out var hit, int.MaxValue)) { _forward = Quaternion.LookRotation( Quaternion.LookRotation(Vector3.ProjectOnPlane(hit.normal, Vector3.up)) * Vector3.back); } else { Debug.LogWarning("未检测到正面"); _forward = Self.Rotation; } } else { Debug.LogWarning("未找到最近点"); _forward = Self.Rotation; } _ignore = Self.SyncCollider.transform; Self.CharacterActor.PhysicsComponent.IgnoreCollision(_ignore,true); base.OnStateEntry(old); Self.CharacterActor.alwaysNotGrounded = true; Self.CharacterActor.ForceNotGrounded(); _needInit = true; Self.LimitedViewAngle.Add(80); _weaponInventory.AllowWeapon.AddDisableElements(this); } public override void OnStateExit(IState old, IState newState) { Self.CharacterActor.PhysicsComponent.IgnoreCollision(_ignore,false); Self.CharacterActor.alwaysNotGrounded = false; //Self.CharacterActor.ForceGrounded(); Self.LimitedViewAngle.TryRemove(80); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); Self.Position = Vector3.Lerp(Self.Position, FixedSyncPosition, 5 * deltaTime); } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { currentVelocity = default; if (_needInit) { CharacterController.Position = Vector3.MoveTowards(CharacterController.Position, FixedSyncPosition, 5 * deltaTime); if (Vector3.Distance(CharacterController.Position, FixedSyncPosition) < 0.05f) { _needInit = false; CharacterController.Position = FixedSyncPosition; return; } return; } var desiredVelocity = _forward * Vector3.right * Self.MoveInput.x; var newPosition= Self.SyncPosition + desiredVelocity * deltaTime ; if (Self.SyncCollider.TryGetClosestPointFromCollider(newPosition,out var closestPoint) && closestPoint == newPosition) { Self.SyncPosition = newPosition; currentVelocity = desiredVelocity; } else { foreach (var collider in Physics.OverlapSphere(Self.SyncPosition,0.1f,Self.CharacterActor.stableLayerMask)) { if(collider == Self.SyncCollider)continue; if(collider is not BoxCollider)continue; var distance = Vector3.Distance(collider.ClosestPoint(Self.SyncPosition), Self.SyncPosition); if (distance<0.05f) { Self.CharacterActor.PhysicsComponent.IgnoreCollision(Self.SyncCollider.transform,false); Self.SyncPosition = collider.ClosestPoint(Self.SyncPosition); currentVelocity = desiredVelocity; Self.SyncCollider = collider; Self.CharacterActor.PhysicsComponent.IgnoreCollision(Self.SyncCollider.transform,true); break; } } currentVelocity = default; } if(_freeTurn.AllowUpdateWithoutReset) { var sampleStart =newPosition+ _forward * Vector3.forward * -0.1f + desiredVelocity * deltaTime; var sampleEnd = Self.SyncPosition + _forward * Vector3.forward * 0.1f; RaycastHit hit; if ( Physics.Raycast(Self.ViewPosition,desiredVelocity,out hit,Self.CharacterActor.DefaultBodySize.x,Self.CharacterActor.stableLayerMask) || Physics.Linecast(sampleStart, sampleEnd, out hit, layerMask: Self.CharacterActor.stableLayerMask) ) { var x = Self.Transform.InverseTransformPoint(hit.point).x; switch (x, Self.InputDirection.x) { case(_,0): case (<0,>0): case (>0,<0): break; default: if (Physics.Raycast(hit.point, hit.normal, out _, Self.CharacterActor.DefaultBodySize.x, Self.CharacterActor.stableLayerMask) is false) { if (hit.collider.TryGetClosestPointFromCollider(hit.point + Vector3.up, out closestPoint)) { var newForward = Quaternion.LookRotation( Quaternion.LookRotation(Vector3.ProjectOnPlane(hit.normal, Vector3.up)) * Vector3.back); if (Quaternion.Angle(newForward, _forward) > 30) { DrawText.Write("Rot",hit.point,durationInSec:1); _freeTurn.Reset(); } Self.SyncPosition =closestPoint; Self.CharacterActor.PhysicsComponent.IgnoreCollision(Self.SyncCollider.transform,false); Self.SyncCollider = hit.collider; Self.CharacterActor.PhysicsComponent.IgnoreCollision(Self.SyncCollider.transform,true); _forward = newForward; } } break; } } } } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); Self.Rotation = currentRotation = _forward; } } public sealed class CharacterSeating : CharacterStateBase,ICharacterSeating { private readonly IWorldSeatService _seatService; private readonly IMicroStateMachine _controlMode; private readonly CharacterActor _actor; private readonly IPlayerWeaponInventory _weaponInventory; public UnitySeatNode SeatNode { get; set; } public IEntity SeatEntity { get; set; } private Quaternion _lastRotation; private float2 _additiveVehicleView; private Quaternion _seatCameraView; private Vector3 _localPosition; public CharacterSeating(ICharacterController characterController, IPlayerWeaponInventory weaponInventory, CharacterActor actor, IMicroStateMachine controlMode, IWorldSeatService seatService) : base(characterController) { _weaponInventory = weaponInventory; _actor = actor; _controlMode = controlMode; _seatService = seatService; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); if (_seatService.OccupySeat(SeatEntity.Id, Self.Entity) is false) { Self.TransitionState(); return; } Self.Transform.position = SeatNode.SeatObject.position; Self.Position = SeatNode.SeatObject.position; Self.Rotation = SeatNode.SeatObject.rotation; if (SeatNode.CameraObject) { _localPosition = _actor.transform.InverseTransformPoint(SeatNode.CameraObject.position); } Self.AllowOverride.AddElement(this); Self.CharacterActor.constraintRotation = false; _weaponInventory.AllowWeapon.AddDisableElements(this); Self.Position = SeatNode.SeatObject.position; _lastRotation = SeatNode.SeatObject.rotation; Self.OnInputViewFactor += OnInputView; _seatCameraView= SeatNode.SeatObject.rotation; _additiveVehicleView = default; _controlMode.TransitionState(); _seatService.OnSeatOccupied += OnSeatOccupied; } private void OnSeatOccupied(UnitySeatNode arg1, IEntity arg2, IEntity arg3) { if (arg2.Id == Self.Entity.Id) { Self.TransitionState(); } } private float2 OnInputView(float2 arg) { _seatCameraView *= Quaternion.Euler(arg.y, arg.x,0); return default; } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (!SeatNode.SeatObject) { Self.TransitionState(); } } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { if (!SeatNode.Rigidbody) return; var difference = Quaternion.Inverse(_lastRotation) * SeatNode.Rigidbody.rotation; var eulerAngles = difference.eulerAngles; _lastRotation = SeatNode.Rigidbody.rotation; float2 input = default; input.x += eulerAngles.y; input.y += eulerAngles.x; input = MathV.TransientRotationAxis(input); _additiveVehicleView += input; //Self.Rotation = SeatNode.SeatObject.rotation; } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { localPosition = _localPosition; Self.Transform.position = SeatNode.SeatObject.position; currentRotation = SeatNode.SeatObject.rotation; var additive = math.lerp(0, _additiveVehicleView, 8 * deltaTime); _additiveVehicleView -=additive; //Self.InputView+= additive; _seatCameraView*= Quaternion.Euler(additive.y,additive.x,0); var newCameraView = Quaternion.LookRotation(_seatCameraView * Vector3.forward).eulerAngles; if(SeatNode.SeatObject) newCameraView.z = SeatNode.SeatObject.rotation.eulerAngles.z; _seatCameraView = Quaternion.Euler(newCameraView); viewRotation =_seatCameraView; currentRotation = SeatNode.SeatObject.rotation; if (SeatNode.CameraObject) { SeatNode.CameraObject.rotation = viewRotation; } } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); Self.AllowOverride.RemoveElement(this); Self.CharacterActor.constraintRotation = true; _weaponInventory.AllowWeapon.RemoveDisableElements(this); if (SeatNode.ExitObject) Self.CharacterActor.Position = SeatNode.ExitObject.position; Self.OnInputViewFactor -= OnInputView; var newInputView = MathV.TransientRotationAxis(_seatCameraView.eulerAngles); Self.InputView = new float2(newInputView.y,newInputView.x); _seatService.UnOccupySeat(SeatEntity.Id,out _); _seatService.OnSeatOccupied -= OnSeatOccupied; } } public sealed class CharacterSwimming : CharacterMovementState, ICharacterSwimming { protected override bool UseViewRotation => true; protected override bool UseViewPosition => true; private readonly IPlayerKeyMap _playerKeyMap; public CharacterSwimming(ICharacterController characterController, IPlayerKeyMap playerKeyMap) : base(characterController) { _playerKeyMap = playerKeyMap; Self.InputActionGroup.EnsureCreated(_playerKeyMap.JumpKey); } public override void OnStateEntry(IState old) { base.OnStateEntry(old); Self.CharacterActor.alwaysNotGrounded = true; } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); Self.CharacterActor.alwaysNotGrounded = false; } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { var jumpPressed = Self.InputActionGroup.GetAction(_playerKeyMap.JumpKey.name).ReadValue(); currentVelocity += (float3)Vector3.up * jumpPressed * 2; currentVelocity = (Quaternion)Self.ViewRotation * Self.MoveInput * 3; Vector3 currentPos = Self.Position; var nextPos = currentPos + (Vector3)currentVelocity * deltaTime; var inWaterPos = Self.SyncCollider.ClosestPoint(nextPos); if (inWaterPos != nextPos) { // currentVelocity = inWaterPos - currentPos; } } } public sealed class CharacterInitialize : CharacterStateBase, ICharacterInitialize { private readonly ILogger _logger; public CharacterInitialize(ICharacterController characterController, ILogger logger) : base(characterController) { _logger = logger; } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (Physics.Raycast((Vector3)Self.Position + Vector3.up, Vector3.down, out var hit,512, Self.CharacterActor.stableLayerMask)) { _logger.LogInformation($"玩家已检测到地面:{hit.transform.name},初始化完成"); Self.TransitionState(); } } } public sealed class CharacterLadderState : CharacterMovementState, ICharacterLadder { private readonly IPlayerWeaponInventory _weaponInventory; protected override bool UseViewPosition => true; protected override bool UseViewRotation => true; public float3 UpPoint { get; set; } public float3 DownPoint { get; set; } private Vector3 _rootVelocity; public CharacterLadderState(ICharacterController characterController, IPlayerWeaponInventory weaponInventory) : base(characterController) { _weaponInventory = weaponInventory; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); Vector3 currentPosition = Self.Position; var currentY = currentPosition.y; currentPosition = DownPoint; currentPosition.y = currentY; Self.CharacterActor.alwaysNotGrounded = true; Self.Position = currentPosition + Self.Transform.forward * - Self.CharacterActor.DefaultBodySize.x/2; Self.CharacterActor.ForceNotGrounded(); if (Self.CharacterActor.TryGetComponent(out var animatorLink)) { animatorLink.OnAnimatorMoveEvent += OnAnimatorMove; } Self.LimitedViewAngle.Add(30); _weaponInventory.AllowWeapon.AddDisableElements(this); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); Self.CharacterActor.alwaysNotGrounded = false; if (Self.CharacterActor.TryGetComponent(out var animatorLink)) { animatorLink.OnAnimatorMoveEvent -= OnAnimatorMove; } Self.LimitedViewAngle.Remove(30); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); var currentPosition = Self.Position; if (currentPosition.y > UpPoint.y - 1) { Self.TransitionState(); return; } if (Self.RequestJump) { Self.TransitionState(); Self.Velocity = (-Self.CharacterActor.Forward + Self.CharacterActor.Up) * 6; return; } } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { // base.UpdateVelocity(ref currentVelocity, deltaTime); if (Self.ForceRootMotion.Allow is false) { currentVelocity = Vector3.up * (Self.InputDirection.y * 2); } else { currentVelocity = _rootVelocity; } } public override void UpdateRotation(ref float3 localPosition, ref quaternion currentRotation, ref quaternion viewRotation, float deltaTime) { base.UpdateRotation(ref localPosition, ref currentRotation, ref viewRotation, deltaTime); if (Self.SyncCollider) { currentRotation =Quaternion.LookRotation( Self.SyncCollider.transform.rotation * Vector3.back); } } private void OnAnimatorMove() { _rootVelocity = Self.CharacterActor.Animator.velocity; } } public sealed class CharacterParachute : CharacterMovementState, ICharacterParachute { private readonly IPlayerWeaponInventory _weaponInventory; protected override bool UseViewRotation => true; protected override bool UseViewPosition => true; private Vector3 _targetVelocity; public CharacterParachute(ICharacterController characterController, IPlayerWeaponInventory weaponInventory) : base(characterController) { _weaponInventory = weaponInventory; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); Self.LimitedViewAngle.Add(90); _targetVelocity = Self.Velocity; _weaponInventory.AllowWeapon.AddDisableElements(this); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old,newState); Self.LimitedViewAngle.Remove(90); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { currentVelocity.y = Mathf.Lerp(currentVelocity.y, -5, 3*deltaTime); _targetVelocity = Vector3.ProjectOnPlane((Quaternion)Self.ViewRotation * Self.MoveInput, Vector3.up).normalized; _targetVelocity *= 32; _targetVelocity.y = currentVelocity.y; //currentVelocity = _targetVelocity; currentVelocity = Vector3.MoveTowards(currentVelocity, _targetVelocity,24* deltaTime); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (Self.IsGrounded) { Self.TransitionState(); } } } public sealed class CharacterFreeFall : CharacterMovementState, ICharacterFreeFall { private readonly IPlayerWeaponInventory _weaponInventory; protected override bool UseViewPosition => true; protected override bool UseViewRotation => true; private Vector3 _targetVelocity; public CharacterFreeFall(ICharacterController characterController, IPlayerWeaponInventory weaponInventory) : base(characterController) { _weaponInventory = weaponInventory; } public override void OnStateEntry(IState old) { base.OnStateEntry(old); _weaponInventory.AllowWeapon.AddDisableElements(this); } public override void OnStateExit(IState old, IState newState) { base.OnStateExit(old, newState); _weaponInventory.AllowWeapon.RemoveDisableElements(this); } public override void UpdateVelocity(ref float3 currentVelocity, float deltaTime) { var currentY = currentVelocity.y; _targetVelocity = Vector3.ProjectOnPlane((Quaternion)Self.ViewRotation * Self.MoveInput, Vector3.up).normalized; _targetVelocity *= 64; currentVelocity = Vector3.MoveTowards(currentVelocity, _targetVelocity,64* deltaTime); currentVelocity.y = currentY; // Gravity currentVelocity += (float3)(-Vector3.up * (30 * deltaTime)); // Drag currentVelocity *= (1f / (1f + 0.1f * deltaTime)); } public override void OnStateUpdate(float deltaTime) { base.OnStateUpdate(deltaTime); if (Self.IsGrounded) { Self.TransitionState(); } } } }