1
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
using System.Timers;
|
||||
using BITFALL.Entities.Player.Movement.States;
|
||||
using BITFALL.Player.Movement;
|
||||
using BITKit;
|
||||
using BITKit.Entities;
|
||||
using BITKit.Entities.Movement;
|
||||
using BITKit.Entities.Physics;
|
||||
using BITKit.Entities.Player;
|
||||
using Lightbug.CharacterControllerPro.Core;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Interactions;
|
||||
using UnityEngine.UIElements;
|
||||
@@ -16,9 +20,8 @@ namespace BITFALL.Entities.Player.Movement
|
||||
{
|
||||
[CustomType(typeof(IEntityMovement))]
|
||||
[CustomType(typeof(IPlayerMovement))]
|
||||
public class PlayerCharacterController : StateBasedPlayerComponent<IEntityMovementState>,IEntityMovement,IServiceRegister,IPlayerMovement
|
||||
public class PlayerCharacterController : StateBasedPlayerComponent<IEntityMovementState>,IEntityMovement,IPlayerMovement
|
||||
{
|
||||
public override Type BaseType => typeof(IEntityMovement);
|
||||
[SerializeField] private CharacterActor actor;
|
||||
[SerializeField] private Vector3 initialCameraPosition = new(0,0.11f,0.27f);
|
||||
[SerializeField] private float initialSpeed;
|
||||
@@ -29,6 +32,8 @@ namespace BITFALL.Entities.Player.Movement
|
||||
private IProvider adsProvider;
|
||||
|
||||
[SerializeField] private LocationAdditive locationAdditive;
|
||||
|
||||
[SerializeField] private Transform fpvPoint;
|
||||
|
||||
public Vector3 ViewCenter { get; set; }
|
||||
public Quaternion ViewRotation { get; set; }
|
||||
@@ -42,32 +47,48 @@ namespace BITFALL.Entities.Player.Movement
|
||||
public Vector2 LookInput{ get; private set; }
|
||||
public ExpectState<bool> ExpectRun;
|
||||
public ExpectState<bool> ExpectJump;
|
||||
public ExpectState<bool> ExpectParachute;
|
||||
public ExpectState<bool> ExpectCrouch;
|
||||
public ExpectState<bool> ExpectSprint;
|
||||
public ExpectState<Vector3> ExpectClimb;
|
||||
public ExpectState<Vector3> CurrentCameraPosition;
|
||||
public OffMeshLink OffMeshLink { get; private set; }
|
||||
|
||||
[Header(Constant.Header.Gameobjects)]
|
||||
[SerializeField] private Transform parachuteModel;
|
||||
|
||||
private readonly ValidHandle allowMovement = new();
|
||||
private readonly ValidHandle allowRun = new();
|
||||
[Inject]
|
||||
private IEntityPhysics physics;
|
||||
[Inject]
|
||||
private IHealth _health;
|
||||
|
||||
private bool isDead;
|
||||
private Vector3 keepVelocity;
|
||||
private readonly DoubleBuffer<Vector3> gravityDamage = new();
|
||||
private readonly DoubleBuffer<float> gravityDamping = new();
|
||||
private Vector3 cacheGravity;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
_health = entity.Get<IHealth>();
|
||||
base.OnAwake();
|
||||
_health.OnSetAlive += OnSetAlive;
|
||||
physics = entity.Get<IEntityPhysics>();
|
||||
physics.OnSetPhysics += OnSetPhysics;
|
||||
LookInput = MathV.TransientRotationAxis(transform.rotation.eulerAngles);
|
||||
|
||||
parachuteModel.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
foreach (var x in GetComponentsInChildren<Collider>(true))
|
||||
{
|
||||
actor.PhysicsComponent.IgnoreCollision(x.transform,true);
|
||||
}
|
||||
}
|
||||
TransitionState<Walk>();
|
||||
}
|
||||
|
||||
private void OnSetPhysics(bool obj)
|
||||
{
|
||||
if (obj is false) return;
|
||||
@@ -89,6 +110,8 @@ namespace BITFALL.Entities.Player.Movement
|
||||
{
|
||||
isDead = true;
|
||||
}
|
||||
Enabled = true;
|
||||
TransitionState<Walk>();
|
||||
}
|
||||
public void SyncMovement(Vector3 velocity, Vector3 position, Quaternion rotation, bool isGrounded)
|
||||
{
|
||||
@@ -123,6 +146,12 @@ namespace BITFALL.Entities.Player.Movement
|
||||
case PlayerDisableRunCommand disableRunCommand:
|
||||
allowRun.AddDisableElements(disableRunCommand.Lock);
|
||||
break;
|
||||
case PlayerChangeVelocityCommand changeVelocityCommand:
|
||||
actor.Velocity = Vector3.Lerp(actor.Velocity, changeVelocityCommand.Velocity, 5 * Time.deltaTime);
|
||||
break;
|
||||
case PlayerAddGravityDampingCommand addGravityDampingCommand:
|
||||
gravityDamping.Release(addGravityDampingCommand.Damping);
|
||||
break;
|
||||
}
|
||||
OnCommand?.Invoke(command);
|
||||
}
|
||||
@@ -140,6 +169,26 @@ namespace BITFALL.Entities.Player.Movement
|
||||
lookInput.y += raw.x;
|
||||
lookInput.x = Mathf.Clamp(lookInput.x, -80, 80);
|
||||
LookInput = lookInput;
|
||||
|
||||
var rotation = Quaternion.Euler(LookInput);
|
||||
if (LimitViewAngle is not 0)
|
||||
{
|
||||
float angleDifference = Quaternion.Angle(rotation, FpvRotation);
|
||||
|
||||
// 如果角度差大于最大允许角度差,进行限制
|
||||
if (angleDifference > LimitViewAngle)
|
||||
{
|
||||
//将当前旋转限制在最大允许角度差的范围内
|
||||
rotation = Quaternion.Lerp(
|
||||
rotation,
|
||||
Quaternion.RotateTowards(FpvRotation,rotation , LimitViewAngle),
|
||||
5 * Time.deltaTime
|
||||
);
|
||||
//rotation = Quaternion.RotateTowards(FpvRotation, rotation, LimitViewAngle);
|
||||
|
||||
LookInput = MathV.TransientRotationAxis(rotation.eulerAngles);
|
||||
}
|
||||
}
|
||||
|
||||
AngularVelocity = new Vector3
|
||||
(
|
||||
@@ -150,29 +199,70 @@ namespace BITFALL.Entities.Player.Movement
|
||||
public void Jump(InputAction.CallbackContext context)
|
||||
{
|
||||
if (ExpectJump.shouldBe) return;
|
||||
if (context.interaction is not null && context.started is false) return;
|
||||
if (actor.IsGrounded)
|
||||
ExpectJump.shouldBe = true;
|
||||
ExpectCrouch.Reset();
|
||||
if (climbClosePoint.TryGetClosePoint(out var closePoint))
|
||||
if (context is not {interaction:PressInteraction , performed:true}) return;
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
ExpectClimb.shouldBe = closePoint;
|
||||
TransitionState<Climb>();
|
||||
case IPlayerLinkState:
|
||||
ExpectJump.shouldBe = true;
|
||||
break;
|
||||
case IPlayerWalkState:
|
||||
case IPlayerRunState:
|
||||
case IPlayerSprintState:
|
||||
case IPlayerCrouchState:
|
||||
case IPlayerSlideState:
|
||||
foreach (var x in Physics.OverlapSphere(actor.Position, 1, LayerMask.GetMask("Dynamic")))
|
||||
{
|
||||
if (!x.TryGetComponent<OffMeshLink>(out var offMeshLink)) continue;
|
||||
var toTarget = x.transform.position - transform.position;
|
||||
toTarget = Vector3.ProjectOnPlane(toTarget, Vector3.up);
|
||||
|
||||
// 获取正前方的向量
|
||||
var forward = actor.Forward;
|
||||
|
||||
// 计算点积
|
||||
var dotProduct = Vector3.Dot(toTarget.normalized, forward);
|
||||
|
||||
if (dotProduct < 0.8f) continue;
|
||||
|
||||
OffMeshLink = offMeshLink;
|
||||
TransitionState<Link>();
|
||||
return;
|
||||
}
|
||||
|
||||
if (climbClosePoint.TryGetClosePoint(out var closePoint))
|
||||
{
|
||||
ExpectClimb.shouldBe = closePoint;
|
||||
TransitionState<Climb>();
|
||||
return;
|
||||
}
|
||||
switch (actor.IsGrounded)
|
||||
{
|
||||
case true:
|
||||
ExpectJump.shouldBe = true;
|
||||
break;
|
||||
case false when actor.VerticalVelocity.y<=-16f:
|
||||
ExpectParachute.shouldBe = true;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ExpectCrouch.Reset();
|
||||
}
|
||||
public void Run(InputAction.CallbackContext context)
|
||||
{
|
||||
if (allowRun.Allow is false) return;
|
||||
switch (context)
|
||||
{
|
||||
case { interaction: PressInteraction, started: true }:
|
||||
//case { interaction: PressInteraction, started: true }:
|
||||
case { interaction: PressInteraction, performed:true }:
|
||||
if (ExpectRun.shouldBe)
|
||||
ExpectSprint.shouldBe = true;
|
||||
ExpectRun.shouldBe = true;
|
||||
ExpectCrouch.Reset();
|
||||
break;
|
||||
case {interaction:MultiTapInteraction,performed:true}:
|
||||
ExpectSprint.shouldBe = true;
|
||||
ExpectSprint.shouldBe = ExpectRun.shouldBe = true;
|
||||
ExpectCrouch.Reset();
|
||||
break;
|
||||
}
|
||||
@@ -197,6 +287,8 @@ namespace BITFALL.Entities.Player.Movement
|
||||
{
|
||||
CurrentState?.BeforeUpdateMovement(deltaTime);
|
||||
|
||||
UpdateState(deltaTime);
|
||||
|
||||
CurrentState?.AfterUpdateMovement(deltaTime);
|
||||
}
|
||||
|
||||
@@ -204,12 +296,21 @@ namespace BITFALL.Entities.Player.Movement
|
||||
{
|
||||
var currentVelocity = actor.Velocity;
|
||||
var currentRotation = actor.Rotation;
|
||||
CurrentState.OnStateUpdate(deltaTime);
|
||||
|
||||
if (Stamina is not 100 && staminaRecoveryInterval.AllowUpdateWithoutReset)
|
||||
{
|
||||
Stamina+=10 * deltaTime;
|
||||
}
|
||||
|
||||
CurrentState?.UpdateVelocity(ref currentVelocity, deltaTime);
|
||||
CurrentState?.UpdateRotation(ref currentRotation, deltaTime);
|
||||
|
||||
if (gravityDamping.TryGetRelease(out var damping) && currentVelocity.y < 0)
|
||||
{
|
||||
currentVelocity.y = Mathf.Clamp(currentVelocity.y + damping, float.MinValue, 0);
|
||||
}
|
||||
|
||||
if (allowMovement && _health.IsAlive)
|
||||
if (allowMovement && _health.IsAlive && actor.RigidbodyComponent.IsKinematic is false)
|
||||
{
|
||||
actor.Velocity = currentVelocity;
|
||||
actor.Rotation = currentRotation;
|
||||
@@ -220,14 +321,69 @@ namespace BITFALL.Entities.Player.Movement
|
||||
var localVelocity = transform.InverseTransformDirection(Velocity);
|
||||
localVelocity.y = 0;
|
||||
LocomotionBasedVelocity = localVelocity;
|
||||
}
|
||||
|
||||
|
||||
if(actor.IsStable is false && actor.IsGrounded is false)
|
||||
{
|
||||
if (cacheGravity != default && (actor.VerticalVelocity - cacheGravity).sqrMagnitude < 4)
|
||||
{
|
||||
gravityDamage.Release(actor.VerticalVelocity);
|
||||
}
|
||||
cacheGravity = actor.VerticalVelocity;
|
||||
//Debug.Log($"IsGround:{actor.IsGrounded}\tIsStable:{actor.IsStable}\tVelocity:{actor.VerticalVelocity}");
|
||||
}
|
||||
else if (actor.IsStable && gravityDamage.TryGetRelease(out var currentGravity))
|
||||
{
|
||||
cacheGravity = default;
|
||||
var value = currentGravity.y;
|
||||
//Debug.Log($"Vector:{currentVelocity}\tMagnitude:{value}\tGravity:{currentGravity}");
|
||||
//Debug.Log(value);
|
||||
switch (value)
|
||||
{
|
||||
case > 0:
|
||||
break;
|
||||
case < -16:
|
||||
entity.Invoke<DamageMessage>(new DamageMessage()
|
||||
{
|
||||
damage = value < -30 ? int.MaxValue : (int)math.abs(value) * 2 ,
|
||||
damageType = new GravityDamage(),
|
||||
location = new Location()
|
||||
{
|
||||
position = actor.Position,
|
||||
rotation = actor.Rotation
|
||||
},
|
||||
initiator = entity,
|
||||
target = entity,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public override void OnLateUpdate(float deltaTime)
|
||||
{
|
||||
if (allowMovement.Allow is false) return;
|
||||
var additiveTransform = locationAdditive.transform;
|
||||
|
||||
var rotation = Quaternion.Euler(LookInput);
|
||||
|
||||
if (LimitViewAngle is not 0)
|
||||
{
|
||||
float angleDifference = Quaternion.Angle(rotation, FpvRotation);
|
||||
|
||||
// 如果角度差大于最大允许角度差,进行限制
|
||||
if (angleDifference > LimitViewAngle)
|
||||
{
|
||||
// 将当前旋转限制在最大允许角度差的范围内
|
||||
rotation = Quaternion.Lerp(
|
||||
rotation,
|
||||
Quaternion.RotateTowards(FpvRotation,rotation , LimitViewAngle),
|
||||
5 * deltaTime
|
||||
);
|
||||
|
||||
LookInput = MathV.TransientRotationAxis(rotation.eulerAngles);
|
||||
}
|
||||
}
|
||||
|
||||
locationAdditive.SetGlobalRotation(rotation);
|
||||
|
||||
@@ -239,6 +395,27 @@ namespace BITFALL.Entities.Player.Movement
|
||||
|
||||
ViewCenter = additiveTransform.position + additiveTransform.forward;
|
||||
}
|
||||
private float _stamina = 100;
|
||||
public float Stamina
|
||||
{
|
||||
get=>_stamina;
|
||||
set
|
||||
{
|
||||
if (value < _stamina)
|
||||
{
|
||||
staminaRecoveryInterval.Reset();
|
||||
}
|
||||
_stamina = Mathf.Clamp(value, 0, 100);
|
||||
OnStaminaChanged?.Invoke(_stamina);
|
||||
}
|
||||
}
|
||||
private readonly IntervalUpdate staminaRecoveryInterval = new(1);
|
||||
public int LimitViewAngle { get; set; }
|
||||
public event Action<float> OnStaminaChanged;
|
||||
public float3 FpvPosition => fpvPoint.position;
|
||||
public quaternion FpvRotation => fpvPoint.rotation;
|
||||
public float3 FpvLocalPosition =>fpvPoint.localPosition;
|
||||
public quaternion FpvLocalRotation => fpvPoint.localRotation;
|
||||
|
||||
public void AddViewEuler(float2 euler)
|
||||
{
|
||||
@@ -248,6 +425,20 @@ namespace BITFALL.Entities.Player.Movement
|
||||
y = LookInput.y + euler.y
|
||||
};
|
||||
}
|
||||
public event Func<bool> TryOpenParachute;
|
||||
public event Action OnParachuteOpened;
|
||||
public event Action OnParachuteClosed;
|
||||
|
||||
internal void InvokeOpenParachute()
|
||||
{
|
||||
OnParachuteOpened?.Invoke();
|
||||
parachuteModel.gameObject.SetActive(true);
|
||||
}
|
||||
internal void InvokeCloseParachute()
|
||||
{
|
||||
OnParachuteClosed?.Invoke();
|
||||
parachuteModel.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user