810 lines
22 KiB
C#
810 lines
22 KiB
C#
using System;
|
|
using BITFALL.Entities.Player.Movement.States;
|
|
using BITFALL.Player.Equip;
|
|
using BITFALL.Player.Movement;
|
|
using BITFALL.Sensors;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using BITKit.PlayerCamera;
|
|
using BITKit.Sensors;
|
|
using BITKit.StateMachine;
|
|
using Cysharp.Threading.Tasks;
|
|
using Lightbug.CharacterControllerPro.Core;
|
|
using Steamworks.ServerList;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
// ReSharper disable InvertIf
|
|
// ReSharper disable RedundantJumpStatement
|
|
// ReSharper disable ConvertToConstant.Global
|
|
|
|
namespace BITFALL.Entities.Player.Movement.States
|
|
{
|
|
public abstract class BasicMovement : PlayerCharacterState, IPlayerMovementState
|
|
{
|
|
[SerializeField] internal Vector3 initialCameraPosition;
|
|
[SerializeField] internal Vector2 initialSize=new Vector2(0.8f,1.6f);
|
|
[SerializeField] internal float initialSpeed = 3f;
|
|
[SerializeField] internal float initialJumpForce = 5f;
|
|
[Inject] protected IKnockdown knockdown;
|
|
[Inject] protected IPlayerCameraService _cameraService;
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
actor.SetSize(initialSize,CharacterActor.SizeReferenceType.Bottom);
|
|
self.ReferenceSpeed = initialSpeed;
|
|
}
|
|
|
|
public override void BeforeUpdateMovement(float deltaTime)
|
|
{
|
|
self.CurrentCameraPosition.shouldBe = initialCameraPosition;
|
|
}
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
if (knockdown.IsKnockdown)
|
|
{
|
|
self.TransitionState<Knockdown>();
|
|
}
|
|
|
|
if (knockdown.IsKnockdown is false && self.ExpectParachute.shouldBe)
|
|
{
|
|
self.TransitionState<Parachute>();
|
|
self.ExpectParachute.Reset();
|
|
}
|
|
|
|
if (self.RequestClimb is false) return;
|
|
if(self.topBlocked)return;
|
|
|
|
// if (characterController.topBlocked is false && characterController.RequestClimb &&
|
|
// characterController.climbClosePoint.TryGetClosePoint(out var closePoint))
|
|
// {
|
|
// characterController.ExpectClimb.shouldBe = closePoint;
|
|
// characterController.TransitionState<Climb>();
|
|
// return;
|
|
// }
|
|
|
|
if (self.vaultPoint.TryGetClosePoint(out var closePoint))
|
|
{
|
|
self.ExpectClimb.shouldBe = closePoint;
|
|
self.TransitionState<Vault>();
|
|
self.ExpectJump.Reset();
|
|
self.RequestClimb = false;
|
|
return;
|
|
}
|
|
|
|
if (self.climbClosePoint.TryGetClosePoint(out closePoint))
|
|
{
|
|
self.ExpectClimb.shouldBe = closePoint;
|
|
self.TransitionState<Climb>();
|
|
self.ExpectJump.Reset();
|
|
self.RequestClimb = false;
|
|
return;
|
|
}
|
|
|
|
if (self.edgeClimbPoint.TryGetClosePoint(out closePoint))
|
|
{
|
|
self.ExpectClimb.shouldBe = closePoint;
|
|
self.TransitionState<EdgeClimb>();self.ExpectJump.Reset();
|
|
self.RequestClimb = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
var rotation = Quaternion.Euler(0, self.LookInput.y, 0);
|
|
var movementInput = self.MovementInput;
|
|
|
|
if (_cameraService?.IsCameraActivated is false)
|
|
{
|
|
rotation =Quaternion.LookRotation( _cameraService.CameraRotation * Vector3.forward,Vector3.up);
|
|
}
|
|
|
|
var moveVelocity = rotation * new Vector3(
|
|
movementInput.x * Mathf.Min(self.initialSpeed, initialSpeed),
|
|
0,
|
|
movementInput.z * initialSpeed
|
|
);
|
|
if (_cameraService?.IsCameraActivated is false)
|
|
{
|
|
moveVelocity = rotation * movementInput * initialSpeed;
|
|
}
|
|
|
|
if (self.limitSpeed.Allow)
|
|
{
|
|
switch (self.CurrentState)
|
|
{
|
|
case IPlayerWalkState:
|
|
case IPlayerCrouchState:
|
|
moveVelocity = Vector3.ClampMagnitude(moveVelocity, self.limitSpeed.Value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (self.IsGrounded)
|
|
{
|
|
var effectiveGroundNormal = actor.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(-16 * deltaTime));
|
|
currentVelocity = newVelocity;
|
|
|
|
if (self.ExpectJump.shouldBe)
|
|
{
|
|
actor.ForceNotGrounded();
|
|
|
|
// if (characterController.landFreeze.AllowUpdateWithoutReset is false)
|
|
// {
|
|
// currentVelocity = Vector3.Lerp(currentVelocity, default, 0.8f);
|
|
// }
|
|
|
|
currentVelocity.y+= initialJumpForce;
|
|
|
|
|
|
self.ExpectJump.Reset();
|
|
|
|
self.ExecuteCommand<OnPlayerJumpCommand>();
|
|
}
|
|
}
|
|
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 (actor.WallCollision)
|
|
{
|
|
if (Vector3.Dot(currentVelocity + addedVelocity, addedVelocity) > 0f)
|
|
{
|
|
var perpenticularObstructionNormal = Vector3
|
|
.Cross(Vector3.Cross(Vector3.up, actor.GroundContactNormal), Vector3.up).normalized;
|
|
addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
|
|
}
|
|
}
|
|
|
|
// Apply added velocity
|
|
currentVelocity += addedVelocity;
|
|
}
|
|
else
|
|
{
|
|
var tempVelocity = currentVelocity;
|
|
tempVelocity = Vector3.Lerp(tempVelocity, default, 2*deltaTime);
|
|
currentVelocity.x = tempVelocity.x;
|
|
currentVelocity.z = tempVelocity.z;
|
|
}
|
|
// Gravity
|
|
|
|
currentVelocity += -Vector3.up * (30 * deltaTime);
|
|
// Drag
|
|
currentVelocity *= (1f / (1f + 0.1f * deltaTime));
|
|
}
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
var newRotation = Quaternion.Euler(0, self.LookInput.y, 0);
|
|
|
|
|
|
|
|
if (_cameraService.IsCameraActivated is false)
|
|
{
|
|
if (Physics.Raycast(_cameraService.CameraPosition, _cameraService.CameraRotation * Vector3.forward,
|
|
out var hit, 256, LayerMask.GetMask("Default"), QueryTriggerInteraction.Ignore))
|
|
{
|
|
self.ViewForward = (hit.point - (self.Position +
|
|
self.Rotation *
|
|
self.ViewCenter)).normalized;
|
|
|
|
newRotation = Quaternion.LookRotation(self.ViewForward);
|
|
self.ViewRotation = newRotation;
|
|
|
|
self.FocusPoint = hit.point;
|
|
|
|
Debug.DrawLine(_cameraService.CameraPosition, hit.point, Color.green, 0.1f);
|
|
Debug.DrawLine(self.Position + self.ViewCenter,
|
|
self.Position +
|
|
self.ViewCenter + self.ViewRotation * Vector3.forward
|
|
, Color.blue, 0.1f);
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
self.ViewRotation = Quaternion.Euler(self.LookInput);;
|
|
|
|
self.FocusPoint = self.Position +
|
|
self.ViewRotation * Vector3.forward * 256;
|
|
|
|
Debug.DrawLine(_cameraService.CameraPosition, _cameraService.CameraRotation * Vector3.forward,
|
|
Color.red, 0.1f);
|
|
}
|
|
|
|
|
|
var rotationDirection = _cameraService.CameraRotation * self.MovementInput;
|
|
rotationDirection = Vector3.ProjectOnPlane(rotationDirection, Vector3.up);
|
|
if (rotationDirection.sqrMagnitude >= 0.16f)
|
|
{
|
|
var newPlayerRotation =Quaternion.LookRotation(rotationDirection) ;
|
|
currentRotation = Quaternion.Lerp(currentRotation, newPlayerRotation, 1f - Mathf.Exp(-16 * deltaTime));
|
|
}
|
|
|
|
if (self.allowFocus)
|
|
{
|
|
currentRotation =
|
|
Quaternion.LookRotation(_cameraService.CameraRotation * Vector3.forward, Vector3.up);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentRotation = newRotation;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class Walk : BasicMovement, IPlayerWalkState
|
|
{
|
|
[Inject] private InputActionGroup _inputActionGroup;
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
if (self.CurrentState != this) return;
|
|
switch (self.ExpectRun.shouldBe, self.ExpectCrouch.shouldBe)
|
|
{
|
|
case (_,_) when self.topBlocked && self.IsGrounded:
|
|
case (_, true):
|
|
self.TransitionState<Crouch>();
|
|
return;
|
|
case (true, false) when self.pauseRun.Allow is false &&
|
|
self.MovementInput.z > 0:
|
|
self.TransitionState<Run>();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Crawl : BasicMovement,IPlayerCrawlState
|
|
{
|
|
[Inject] private IEquipService _equipService;
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
self.LimitViewAngle = 20;
|
|
base.OnStateEntry(old);
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
if (actor.IsGrounded is false)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
var targetRotation = currentRotation;
|
|
base.UpdateRotation(ref targetRotation,deltaTime);
|
|
currentRotation = Quaternion.RotateTowards(currentRotation,targetRotation,90*deltaTime);
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
self.LimitViewAngle = 0;
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class Parachute : PlayerCharacterState, IPlayerParachuteState
|
|
{
|
|
[SerializeField] private float moveDamping = 3f;
|
|
[SerializeField] private float damping = 1f;
|
|
|
|
[Inject] private IEquipService _equipService;
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
self.InvokeOpenParachute();
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
|
|
var velocity = actor.Velocity;
|
|
velocity.y = Mathf.Clamp(velocity.y, -2, 2);
|
|
actor.Velocity = velocity;
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
self.InvokeCloseParachute();
|
|
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
currentRotation = Quaternion.Euler(0,self.LookInput.y,0);
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
var rotation = Quaternion.Euler(0,self.LookInput.y,0);
|
|
var moveVelocity = rotation * self.MovementInput;
|
|
currentVelocity.y =
|
|
Mathf.MoveTowards(
|
|
currentVelocity.y,
|
|
-8,
|
|
damping * deltaTime
|
|
);
|
|
currentVelocity+= moveVelocity.normalized * (moveDamping * deltaTime);
|
|
currentVelocity.x = Mathf.Clamp(currentVelocity.x, -moveDamping, moveDamping);
|
|
currentVelocity.z = Mathf.Clamp(currentVelocity.z, -moveDamping, moveDamping);
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
if (actor.IsGrounded)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
}
|
|
self.ExpectParachute.Reset();
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Run:BasicMovement,IPlayerRunState
|
|
{
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
self.ExpectRun.being = true;
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
self.ExpectRun.being = false;
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
if (_cameraService.IsCameraActivated is false)
|
|
{
|
|
base.UpdateRotation(ref currentRotation, deltaTime);
|
|
return;
|
|
}
|
|
|
|
var baseRotation = Quaternion.identity;
|
|
|
|
base.UpdateRotation(ref baseRotation, deltaTime);
|
|
var targetRotation = Quaternion.LookRotation(baseRotation * self.MovementInput);
|
|
|
|
float maxAngleDelta = 30; // 你可以根据需要调整最大角度差值
|
|
float maxDeltaMagnitude = Mathf.Sin(Mathf.Deg2Rad * maxAngleDelta / 2);
|
|
|
|
targetRotation = Quaternion.RotateTowards(targetRotation,baseRotation , maxDeltaMagnitude);
|
|
|
|
var max = Quaternion.RotateTowards(targetRotation, currentRotation, maxAngleDelta);
|
|
|
|
var lerp = Quaternion.Lerp(currentRotation, targetRotation, 12 * deltaTime);
|
|
|
|
if (Quaternion.Angle(currentRotation, max) < Quaternion.Angle(currentRotation, lerp))
|
|
{
|
|
currentRotation = lerp;
|
|
}
|
|
else
|
|
{
|
|
currentRotation = max;
|
|
}
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
base.OnStateUpdate(deltaTime);
|
|
AudioSensorService.MakeNoise(actor.Position,self.transform,3,new MovementNoise());
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
|
|
switch (self.CurrentState)
|
|
{
|
|
case Walk:
|
|
case Run:
|
|
case Sprint:
|
|
case Crouch:
|
|
switch (self.ExpectRun.shouldBe, self.ExpectCrouch.shouldBe)
|
|
{
|
|
case (_, true):
|
|
self.TransitionState<Crouch>();
|
|
return;
|
|
case (false, false):
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
|
|
if (_cameraService.IsCameraActivated)
|
|
{
|
|
if (self.MovementInput.z <= 0)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (self.MovementInput == default)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
}
|
|
if (self.pauseRun.Allow)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
if (self.ExpectSprint.shouldBe && self.MovementInput.z > 0)
|
|
{
|
|
self.TransitionState<Sprint>();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void ExecuteCommand<T>(T command)
|
|
{
|
|
if (Enabled is false) return;
|
|
if (command is PlayerCancelRunCommand)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class Slide : BasicMovement, IPlayerSlideState
|
|
{
|
|
[Header(nameof(Slide))]
|
|
[SerializeField] private float additiveSpeed = 1f;
|
|
[SerializeField] private float damping = 1;
|
|
[SerializeField] private float stopSpeed = 0.64f;
|
|
[SerializeField] private bool alwaysSlide;
|
|
private bool _addedVelocity;
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
self.ExpectCrouch.being = true;
|
|
self.ExpectCrouch.shouldBe = true;
|
|
self.ExecuteCommand<PlayerCancelRunCommand>();
|
|
_addedVelocity = false;
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
if (alwaysSlide && actor.IsGrounded is false)
|
|
{
|
|
base.UpdateVelocity(ref currentVelocity, deltaTime);
|
|
}
|
|
else
|
|
{
|
|
if (_addedVelocity is false)
|
|
{
|
|
currentVelocity += currentVelocity.normalized * additiveSpeed;
|
|
_addedVelocity = true;
|
|
}
|
|
else
|
|
{
|
|
currentVelocity = Vector3.Lerp(currentVelocity, Vector3.zero, deltaTime * damping);
|
|
}
|
|
}
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
if (self.ExpectRun.shouldBe)
|
|
{
|
|
self.TransitionState<Run>();
|
|
return;
|
|
}
|
|
if (self.ExpectCrouch.shouldBe is false || (alwaysSlide is false && actor.IsGrounded is false))
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
if (actor.Velocity.sqrMagnitude <= stopSpeed)
|
|
{
|
|
self.TransitionState<Crouch>();
|
|
}
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Crouch:BasicMovement,IPlayerCrouchState
|
|
{
|
|
private readonly IntervalUpdate standInterval = new(0.1f);
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
self.ExpectCrouch.being = true;
|
|
standInterval.Reset();
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
self.ExpectCrouch.being = false;
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
|
|
if(self.topBlocked)standInterval.Reset();
|
|
|
|
if (self.ExpectRun.shouldBe)
|
|
{
|
|
self.TransitionState<Run>();
|
|
return;
|
|
}
|
|
|
|
if (self.ExpectCrouch.shouldBe is false)
|
|
{
|
|
if (self.topBlocked)
|
|
{
|
|
|
|
}
|
|
else if(standInterval.AllowUpdateWithoutReset)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Sprint:BasicMovement,IPlayerSprintState
|
|
{
|
|
[SerializeField] private int slideCost = 16;
|
|
[SerializeField] private int staminaCost = 1;
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
self.ExpectSprint.being = true;
|
|
}
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
self.ExpectSprint.being = false;
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
if (_cameraService.IsCameraActivated is false)
|
|
{
|
|
base.UpdateRotation(ref currentRotation, deltaTime);
|
|
return;
|
|
}
|
|
|
|
var baseRotation = Quaternion.identity;
|
|
base.UpdateRotation(ref baseRotation, deltaTime);
|
|
var targetRotation = Quaternion.LookRotation(baseRotation * self.MovementInput);
|
|
|
|
float maxAngleDelta = 30; // 你可以根据需要调整最大角度差值
|
|
float maxDeltaMagnitude = Mathf.Sin(Mathf.Deg2Rad * maxAngleDelta / 2);
|
|
|
|
targetRotation = Quaternion.RotateTowards(targetRotation,baseRotation , maxDeltaMagnitude);
|
|
|
|
var max = Quaternion.RotateTowards(targetRotation, currentRotation, maxAngleDelta);
|
|
|
|
var lerp = Quaternion.Lerp(currentRotation, targetRotation, 12 * deltaTime);
|
|
|
|
if (Quaternion.Angle(currentRotation, max) < Quaternion.Angle(currentRotation, lerp))
|
|
{
|
|
currentRotation = lerp;
|
|
}
|
|
else
|
|
{
|
|
currentRotation = max;
|
|
}
|
|
}
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
if (actor.IsGrounded && actor.Velocity.GetLength() > self.initialSpeed/2)
|
|
self.Stamina -= staminaCost * deltaTime;
|
|
AudioSensorService.MakeNoise(actor.Position,self.transform);
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
if (Enabled is false) return;
|
|
if (self.pauseRun.Allow)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
switch (self.ExpectRun.shouldBe,self.ExpectCrouch.shouldBe)
|
|
{
|
|
case (_,_) when self.Stamina is 0:
|
|
self.ExpectSprint.Reset();
|
|
self.TransitionState<Run>();
|
|
return;
|
|
case (_,true) when self.IsGrounded && self.Stamina > 0:
|
|
self.Stamina -= slideCost;
|
|
self.TransitionState<Slide>();
|
|
return;
|
|
case (_,true):
|
|
self.TransitionState<Crouch>();
|
|
return;
|
|
case (true,false) when self.MovementInput.z <=0:
|
|
case (false,false):
|
|
self.TransitionState<Walk>();
|
|
return;
|
|
}
|
|
}
|
|
public override void ExecuteCommand<T>(T command)
|
|
{
|
|
if (Enabled is false) return;
|
|
if(command is PlayerCancelRunCommand)
|
|
self.TransitionState<Walk>();
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class Knockdown : BasicMovement, IPlayerKnockdownState
|
|
{
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
knockdown.OnKnockdown += OnKnockdown;
|
|
knockdown.OnRevive += OnRevive;
|
|
}
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
actor.UseRootMotion = true;
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
actor.UseRootMotion = false;
|
|
}
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
base.UpdateVelocity(ref currentVelocity, deltaTime);
|
|
if (knockdown.IsPressured)
|
|
{
|
|
currentVelocity.x = 0;
|
|
currentVelocity.z = 0;
|
|
}
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
private void OnRevive()
|
|
{
|
|
if(Enabled)self.TransitionState<Walk>();
|
|
}
|
|
|
|
private void OnKnockdown()
|
|
{
|
|
self.TransitionState<Knockdown>();
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Clip:PlayerCharacterState
|
|
{
|
|
[BITCommand]
|
|
public static void NoClip()
|
|
{
|
|
_clipAction?.Invoke();
|
|
}
|
|
private static Action _clipAction;
|
|
|
|
[SerializeField] private InputActionReference clipAction;
|
|
[SerializeReference, SubclassSelector] private IReference clipEnv;
|
|
[Inject] private IHealth _health;
|
|
[Inject] private InputActionGroup _inputActionGroup;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
_health.OnSetAlive += OnSetAlive;
|
|
|
|
Data.AddListener<bool>(clipEnv.Value, OnClip);
|
|
|
|
_clipAction = _ClipAction;
|
|
|
|
self.destroyCancellationToken.Register(() =>
|
|
{
|
|
Data.RemoveListender<bool>(clipEnv.Value, OnClip);
|
|
});
|
|
}
|
|
|
|
private void _ClipAction()
|
|
{
|
|
var clip = Data.Get<bool>(clipEnv.Value);
|
|
Data.Set(clipEnv.Value, !clip);
|
|
}
|
|
|
|
private async void OnClip(bool obj)
|
|
{
|
|
await UniTask.SwitchToMainThread();
|
|
if(_health.IsAlive is false) return;
|
|
if (obj && Enabled is false)
|
|
{
|
|
self.TransitionState<Clip>();
|
|
//BIT4Log.Log<Clip>("NoClip Enabled");
|
|
}else if (Enabled && obj is false)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
//BIT4Log.Log<Clip>("NoClip Disabled");
|
|
}
|
|
}
|
|
|
|
private void OnSetAlive(bool obj)
|
|
{
|
|
if (Enabled && obj is false)
|
|
{
|
|
self.TransitionState<Walk>();
|
|
}
|
|
}
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
actor.Velocity = default;
|
|
actor.ColliderComponent.enabled = false;
|
|
actor.alwaysNotGrounded = true;
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
actor.ColliderComponent.enabled = true;
|
|
actor.alwaysNotGrounded = false;
|
|
}
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
actor.Position += self.ViewRotation * self.MovementInput * (
|
|
deltaTime * (_inputActionGroup.GetAction(self.RunAction).IsPressed()
|
|
? 8
|
|
: self.initialSpeed
|
|
));
|
|
actor.Rotation = Quaternion.Euler(0,self.LookInput.y,0);
|
|
}
|
|
}
|
|
}
|