Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/CharacterController/CharacterStates.cs

1530 lines
48 KiB
C#
Raw Normal View History

2025-06-24 23:49:13 +08:00
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<Quaternion> _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<IPlayerControlMode> _controlMode;
protected override bool UseViewRotation => false;
protected override bool UseViewPosition => false;
public CharacterWalkState(ICharacterController characterController, IMicroStateMachine<IPlayerControlMode> controlMode) : base(characterController)
{
_controlMode = controlMode;
}
public override void OnStateEntry(IState old)
{
base.OnStateEntry(old);
_controlMode.TransitionState<PlayerWalkMode>();
}
public override void OnStateUpdate(float deltaTime)
{
base.OnStateUpdate(deltaTime);
if(Self.DisableStateTransition.Allow)return;
if (Self.InputDirection is {x:0,y:0})
{
CharacterController.TransitionState<ICharacterStateIdle>();
}
}
}
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<IPlayerControlMode> _controlMode;
protected override bool UseViewRotation => false;
protected override bool UseViewPosition => false;
public CharacterIdleState(ICharacterController characterController, IMicroStateMachine<IPlayerControlMode> controlMode) : base(characterController)
{
_controlMode = controlMode;
}
public override void OnStateEntry(IState old)
{
base.OnStateEntry(old);
_controlMode.TransitionState<PlayerWalkMode>();
}
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<ICharacterStateWalk>();
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<ICharacterStateRun>();
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<MotionWarpingAsset>().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<MotionWarpingAsset>().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<ICharacterStateWalk>();
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<ICharacterStateWalk>();
break;
case { z: > 0, y: < 0 }:
break;
}
if (_ignore && _ignore.TryGetComponent<Collider>(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<PlayerCancelRunCommand>();
_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<ICharacterStateCrouched>();
}
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<IPlayerControlMode> _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<IPlayerControlMode> 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<ICharacterStateIdle>();
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<PlayerCarMode>();
_seatService.OnSeatOccupied += OnSeatOccupied;
}
private void OnSeatOccupied(UnitySeatNode arg1, IEntity arg2, IEntity arg3)
{
if (arg2.Id == Self.Entity.Id)
{
Self.TransitionState<ICharacterStateIdle>();
}
}
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<ICharacterStateWalk>();
}
}
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<InputAction> _playerKeyMap;
public CharacterSwimming(ICharacterController characterController, IPlayerKeyMap<InputAction> 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<float>();
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<CharacterInitialize> _logger;
public CharacterInitialize(ICharacterController characterController, ILogger<CharacterInitialize> 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<ICharacterStateIdle>();
}
}
}
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<AnimatorLink>(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<AnimatorLink>(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<ICharacterStateIdle>();
return;
}
if (Self.RequestJump)
{
Self.TransitionState<ICharacterStateWalk>();
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<ICharacterStateIdle>();
}
}
}
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<ICharacterStateIdle>();
}
}
}
}