1004 lines
28 KiB
C#
1004 lines
28 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using BITFALL.Player.Equip;
|
|
using BITFALL.Player.Movement;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using BITKit.Selection;
|
|
using BITKit.StateMachine;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.AI;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.InputSystem.Interactions;
|
|
using UnityEngine.Splines;
|
|
using UnityEngine.UI;
|
|
|
|
namespace BITFALL.Entities.Player.Movement.States
|
|
{
|
|
[Serializable]
|
|
public class Vault : PlayerCharacterState, IPlayerVaultState
|
|
{
|
|
public float NormalizedTime
|
|
{
|
|
get => _normalizedTime;
|
|
set
|
|
{
|
|
_normalizedTime = value;
|
|
_manualUpdate=true;
|
|
}
|
|
}
|
|
public int Phase { get; set; }
|
|
|
|
[SerializeField] private AnimationCurve entryCurve;
|
|
|
|
private float _elapsedTime;
|
|
private float _normalizedTime;
|
|
private bool _manualUpdate;
|
|
private Vector3 _entryPosition;
|
|
|
|
private Vector3 entryVelocity;
|
|
|
|
private Collider _collider;
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
|
|
Phase = 0;
|
|
_elapsedTime = 0;
|
|
|
|
actor.alwaysNotGrounded = true;
|
|
actor.ColliderComponent.enabled = false;
|
|
actor.IsKinematic = true;
|
|
actor.UseRootMotion = true;
|
|
|
|
_normalizedTime = 0;
|
|
_manualUpdate = false;
|
|
|
|
self.LimitViewAngle = 45;
|
|
|
|
actor.ForceNotGrounded();
|
|
|
|
_entryPosition = actor.Position;
|
|
|
|
entryVelocity = actor.Velocity;
|
|
|
|
_collider = self.vaultPoint.Collider;
|
|
actor.PhysicsComponent.IgnoreCollision(_collider.transform,true);
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
|
|
actor.alwaysNotGrounded = false;
|
|
actor.ColliderComponent.enabled = true;
|
|
actor.IsKinematic = false;
|
|
actor.UseRootMotion = false;
|
|
|
|
if (self.vaultPoint is GetVaultPointFromCollider vaultPoint)
|
|
{
|
|
//actor.Position = vaultPoint.EndPosition-Vector3.up*0.24f;
|
|
}
|
|
|
|
self.LimitViewAngle = 0;
|
|
//actor.Velocity = lastVelocity;
|
|
|
|
//actor.ForceGrounded();
|
|
|
|
self.ExpectJump.Reset();
|
|
self.RequestClimb = false;
|
|
|
|
_normalizedTime = 0;
|
|
_manualUpdate = false;
|
|
Phase = 0;
|
|
|
|
actor.ForceNotGrounded();
|
|
actor.Velocity += actor.Forward * 3 + actor.Up*-2;
|
|
|
|
actor.PhysicsComponent.IgnoreCollision(_collider.transform,false);
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
_elapsedTime += deltaTime;
|
|
base.OnStateUpdate(deltaTime);
|
|
switch (Phase)
|
|
{
|
|
case 0 when _elapsedTime>0.16f:
|
|
// if(Vector3.Distance(
|
|
// characterController.ExpectClimb.shouldBe-Vector3.up*0.64f,
|
|
// actor.Position)
|
|
// <=0.16f)
|
|
// Phase = 1;
|
|
Phase = 1;
|
|
break;
|
|
case 1:
|
|
if(NormalizedTime>=1)
|
|
Exit();
|
|
if (_manualUpdate is false)
|
|
{
|
|
NormalizedTime+=deltaTime;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
deltaTime =deltaTime<0.001f?0.001f:deltaTime;
|
|
base.UpdateVelocity(ref currentVelocity, deltaTime);
|
|
switch (Phase)
|
|
{
|
|
case 0:
|
|
// actor.Position =
|
|
// Vector3.MoveTowards(
|
|
// actor.Position,
|
|
// characterController.ExpectClimb.shouldBe - Vector3.up * 0.64f,
|
|
// 4f
|
|
// );
|
|
var endPos = self.ExpectClimb.shouldBe - Vector3.up * 0.32f;
|
|
var t = entryCurve.Evaluate(_elapsedTime);
|
|
actor.Position = Vector3.Lerp(_entryPosition, endPos, t);
|
|
break;
|
|
case 1 when self.vaultPoint is GetVaultPointFromCollider vaultPoint:
|
|
var newPos =
|
|
Vector3.Lerp(
|
|
vaultPoint.StartPosition,
|
|
vaultPoint.EndPosition,
|
|
NormalizedTime);
|
|
newPos.y = actor.Position.y;
|
|
|
|
actor.Position = newPos;
|
|
|
|
_entryPosition = (newPos - actor.Position)/ deltaTime;;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
public bool ManualCancel()
|
|
{
|
|
if (Enabled is false) return false;
|
|
Exit();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class EdgeClimb : PlayerCharacterState, IPlayerEdgeClimbState
|
|
{
|
|
public int Phase { get; set; }
|
|
|
|
[Inject] private IEquipService _equipService;
|
|
private Collider _collider;
|
|
private Quaternion rotation;
|
|
private readonly List<Collider> _colliders = new List<Collider>();
|
|
private Animator _animator;
|
|
private bool _isStable;
|
|
private Collider[] rangeColliders = new Collider[8];
|
|
private int rangeLength;
|
|
private Vector3 handPoint;
|
|
private Vector3 climbPoint;
|
|
private List<(Collider collider,Vector3 closePoint)> closePoints = new List<(Collider, Vector3)>();
|
|
private Collider[] tempColliders = new Collider[16];
|
|
public float3 NextPoint { get; set; }
|
|
|
|
public bool ManualCancel()
|
|
{
|
|
if (Enabled is false) return false;
|
|
Exit();
|
|
return true;
|
|
}
|
|
public float3[] ClosestPoint => closePointList.ValueArray;
|
|
private CacheList<float3> closePointList = new();
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
|
|
_animator = self.GetComponent<Animator>();
|
|
|
|
_collider = self.edgeClimbPoint.Collider;
|
|
_colliders.Add(_collider);
|
|
actor.PhysicsComponent.IgnoreCollision(_collider.transform,true);
|
|
|
|
var position = actor.Position+ actor.Forward * -1;
|
|
position.y = _collider.bounds.center.y;
|
|
var direction = _collider.bounds.center - position;
|
|
direction = Vector3.ProjectOnPlane(direction, Vector3.up);
|
|
var ray = new Ray(position, direction);
|
|
|
|
Debug.DrawRay(ray.origin,ray.direction * 8,Color.red,1f);
|
|
if (_collider.Raycast(ray, out var hit, 64))
|
|
{
|
|
rotation = Quaternion.LookRotation(hit.normal) * Quaternion.Euler(0, 180, 0);;
|
|
}
|
|
else
|
|
{
|
|
|
|
BIT4Log.Warning<IPlayerEdgeClimbState>(" Edge Climb Raycast Failed");
|
|
}
|
|
|
|
|
|
actor.alwaysNotGrounded = true;
|
|
actor.ColliderComponent.enabled = false;
|
|
actor.UseRootMotion = true;
|
|
|
|
self.LimitViewAngle = 45;
|
|
|
|
Phase = 0;
|
|
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
|
|
self.inputActionGroup.RegisterCallback(self.JumpAction, OnJump);
|
|
self.inputActionGroup.RegisterCallback(self.MovementAction, OnMovement);
|
|
}
|
|
|
|
private void OnMovement(InputAction.CallbackContext obj)
|
|
{
|
|
// if (Phase is not (4 or 5 or 6)) return;
|
|
// var value = obj.ReadValue<Vector2>();
|
|
// if (value is { x: 0, y: 1 })
|
|
// {
|
|
// OnJump();
|
|
// }
|
|
}
|
|
private void OnJump(InputAction.CallbackContext obj)
|
|
{
|
|
if (obj is not {interaction:PressInteraction,performed:true}) return;
|
|
if(Phase is not (4 or 5 or 6))return;
|
|
OnJump();
|
|
}
|
|
private void OnJump()
|
|
{
|
|
|
|
var input = self.InputVector;
|
|
|
|
var startPos = climbPoint - actor.Forward * 0.1f;
|
|
var allowExit = Physics.Linecast(startPos, startPos + actor.Forward * 1f + actor.Up * 0.5f, out _,
|
|
actor.stableLayerMask) is false;
|
|
|
|
if (input.y is not -1)
|
|
{
|
|
if( (allowExit && input.x is 0) || closePoints.Count is 0)
|
|
{
|
|
|
|
var length = Physics.OverlapSphereNonAlloc(climbPoint, 1f, tempColliders,
|
|
actor.stableLayerMask);
|
|
for (var i = 0; i < length; i++)
|
|
{
|
|
var collider = tempColliders[i];
|
|
|
|
_colliders.Add(collider);
|
|
actor.PhysicsComponent.IgnoreCollision(collider.transform, true);
|
|
}
|
|
Phase = 8;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (closePoints.Count is 0) return;
|
|
var direction = actor.Rotation * (Vector2)input;
|
|
var samplePoint = climbPoint + direction;
|
|
var close = closePoints.OrderBy(Close).First();
|
|
|
|
if(input.y is 1 && close.closePoint.y < climbPoint.y) return;
|
|
if(input.y is -1 && close.closePoint.y > climbPoint.y) return;
|
|
|
|
var offset = climbPoint-actor.Position;
|
|
|
|
actor.PhysicsComponent.IgnoreCollision(close.collider.transform,true);
|
|
|
|
_collider = close.collider; _colliders.Add(_collider);
|
|
|
|
NextPoint = close.closePoint - offset;
|
|
|
|
Phase = 1;
|
|
|
|
self.Stamina -= 16;
|
|
return;
|
|
float Close((Collider collider, Vector3 closePoint) arg)
|
|
{
|
|
var distance = Vector3.Distance(climbPoint, arg.closePoint);
|
|
|
|
var panel = new Plane(-actor.Forward,climbPoint);
|
|
var center = panel.ClosestPointOnPlane(climbPoint+direction);
|
|
var localPosition = panel.ClosestPointOnPlane(arg.closePoint)-center;
|
|
|
|
var pos = new Vector2
|
|
{
|
|
y = localPosition.y,
|
|
x = -localPosition.z
|
|
};
|
|
return Vector2.Distance(pos, default);
|
|
}
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
|
|
actor.alwaysNotGrounded = false;
|
|
actor.ColliderComponent.enabled = true;
|
|
actor.UseRootMotion = false;
|
|
|
|
self.LimitViewAngle = 0;
|
|
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
|
|
self.inputActionGroup.UnRegisterCallback(self.JumpAction, OnJump);
|
|
self.inputActionGroup.UnRegisterCallback(self.MovementAction, OnMovement);
|
|
|
|
foreach (var x in _colliders)
|
|
{
|
|
actor.PhysicsComponent.IgnoreCollision(x.transform,false);
|
|
}
|
|
_colliders.Clear();
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
base.OnStateUpdate(deltaTime);
|
|
switch (Phase)
|
|
{
|
|
case 0:
|
|
var targetPos = self.ExpectClimb.shouldBe - Vector3.up * 1.6f;
|
|
targetPos -= self.Rotation * Vector3.forward * 0.35f;
|
|
if (actor.Position.y >= targetPos.y)
|
|
Phase = 5;
|
|
if (Phase is 5)
|
|
actor.Position = targetPos;
|
|
return;
|
|
case 1:
|
|
if (Vector3.Distance(actor.Position, NextPoint) < 0.1f)
|
|
{
|
|
Phase = 5;
|
|
}
|
|
break;
|
|
case 4 or 5 or 6 or 7 or 9:
|
|
self.Stamina -= 5 * deltaTime;
|
|
|
|
if (self.Stamina <= 0)
|
|
{
|
|
Exit();
|
|
return;
|
|
}
|
|
|
|
handPoint = Vector3.Lerp(
|
|
_animator.GetBoneTransform(HumanBodyBones.LeftHand).position,
|
|
_animator.GetBoneTransform(HumanBodyBones.RightHand).position,
|
|
0.5f
|
|
);
|
|
|
|
climbPoint = _collider.ClosestPoint(actor.Position + Vector3.up * 10);
|
|
|
|
rangeLength =
|
|
Physics.OverlapSphereNonAlloc(climbPoint, 1.6f, rangeColliders, actor.stableLayerMask);
|
|
|
|
closePoints.Clear();
|
|
closePointList.Clear();
|
|
for (var i = 0; i < rangeLength; i++)
|
|
{
|
|
var collider = rangeColliders[i];
|
|
|
|
if (collider == _collider)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (collider is MeshCollider { convex: false })
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var closestPoint = collider.ClosestPoint(actor.Position);
|
|
closestPoint.y = collider.bounds.center.y + collider.bounds.extents.y;
|
|
|
|
if (Vector3.Distance(closestPoint, climbPoint) > 2)
|
|
{
|
|
continue;
|
|
}
|
|
var length = Physics.OverlapSphereNonAlloc(closestPoint, 0.1f, tempColliders, actor.stableLayerMask);
|
|
switch (length)
|
|
{
|
|
case <2:
|
|
break;
|
|
case 2:
|
|
if (_collider == tempColliders[0] || _collider==tempColliders[1])
|
|
{
|
|
break;
|
|
}
|
|
continue;
|
|
default:continue;
|
|
}
|
|
var direction = closestPoint - climbPoint;
|
|
direction = actor.transform.InverseTransformVector(direction);
|
|
if (direction.z > 0.1f)
|
|
{
|
|
continue;
|
|
}
|
|
closePoints.Add((collider, closestPoint));
|
|
closePointList.Add(closestPoint);
|
|
}
|
|
|
|
if (_collider.Raycast(new Ray(climbPoint + actor.Forward * -0.1f + actor.Up*-0.1f + actor.Right * (self.InputVector.x * 0.2f), actor.Forward), out _, 1f) is false)
|
|
{
|
|
try
|
|
{
|
|
foreach (var x in closePoints)
|
|
{
|
|
if (Vector3.Distance(x.closePoint, climbPoint) < 0.2f)
|
|
{
|
|
_collider = x.collider;
|
|
throw new InGameException();
|
|
}
|
|
}
|
|
Phase = 5;
|
|
}
|
|
catch (InGameException){}
|
|
|
|
}
|
|
else
|
|
Phase = Phase switch
|
|
{
|
|
5 when self.InputVector.x is not 0 => self.InputVector.x > 0 ? 4 : 6,
|
|
4 or 6 when self.InputVector.x is 0 => 5,
|
|
_ => Phase
|
|
};
|
|
|
|
var point = actor.Position;
|
|
point.y = _animator.GetBoneTransform(HumanBodyBones.RightHand).position.y;
|
|
point.y -= 0.2f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private float upVelocity;
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
base.UpdateVelocity(ref currentVelocity, deltaTime);
|
|
switch (Phase)
|
|
{
|
|
case 0:
|
|
var currentPosition = actor.Position;
|
|
currentPosition = Vector3.Lerp(
|
|
currentPosition,
|
|
self.ExpectClimb.shouldBe - Vector3.up * 1.6f,3.2f*deltaTime);
|
|
currentPosition.y = actor.Position.y;
|
|
currentPosition.y+=(upVelocity+=deltaTime)*deltaTime;
|
|
actor.Position = currentPosition;
|
|
break;
|
|
case 1:
|
|
actor.Position += ((Vector3)NextPoint - actor.Position).normalized * (6 * deltaTime);
|
|
break;
|
|
case 4 or 5 or 6:
|
|
var hand = _animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
|
var closePoint = _collider.ClosestPoint(actor.Position+Vector3.up*8-actor.Forward);
|
|
var offset = closePoint.y - hand.position.y - 0.08f;
|
|
actor.Position+=actor.Up * (offset * 8 * deltaTime);
|
|
|
|
_isStable = false;
|
|
if (_collider.Raycast(new Ray(hand.position - actor.Forward * 0.4f, actor.Forward), out var hit, 1f))
|
|
{
|
|
var targetFootPosition = hit.point - actor.Forward * 0.05f;
|
|
|
|
rotation = Quaternion.LookRotation(hit.normal) * Quaternion.Euler(0, 180, 0);
|
|
|
|
if (Vector3.Distance(targetFootPosition, hand.position) > 0.01f)
|
|
{
|
|
Debug.DrawLine(hand.position, hit.point, Color.red, 1f);
|
|
actor.Position += (targetFootPosition - hand.position) * (deltaTime * 8);
|
|
}
|
|
else
|
|
{
|
|
_isStable = true;
|
|
Debug.DrawLine(hand.position, hit.point, Color.green, 1f);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
if (Phase is 0 or 4 or 5 or 6)
|
|
{
|
|
currentRotation = rotation;
|
|
}
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
|
|
public override void DrawGizmos()
|
|
{
|
|
Gizmos.DrawWireCube(climbPoint,Vector3.one*0.1f);
|
|
Gizmos.DrawCube(handPoint,Vector3.one*0.1f);
|
|
Gizmos.color=Color.green;
|
|
foreach (var x in closePoints)
|
|
{
|
|
Gizmos.DrawSphere(x.closePoint,0.1f);
|
|
}
|
|
}
|
|
}
|
|
[Serializable]
|
|
public class Climb : PlayerCharacterState,IPlayerClimbState
|
|
{
|
|
[SerializeField] protected float lerpDelta = 5;
|
|
private IntervalUpdate cancelInterval = new(0.16f);
|
|
private Transform ignore;
|
|
private bool needInit;
|
|
private float _startDistance;
|
|
private Vector3 _startPos;
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
ignore = self.climbClosePoint.Collider.transform;
|
|
actor.PhysicsComponent.IgnoreCollision(ignore,true);
|
|
base.OnStateEntry(old);
|
|
self.ExpectCrouch.Reset();
|
|
actor.alwaysNotGrounded = true;
|
|
actor.ForceNotGrounded();
|
|
actor.ColliderComponent.enabled = false;
|
|
cancelInterval.Reset();
|
|
needInit = true;
|
|
|
|
self.LimitViewAngle = 80;
|
|
|
|
_startDistance = Vector3.Distance(actor.Position, self.ExpectClimb);
|
|
|
|
_startPos = actor.Position;
|
|
}
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
if (cancelInterval.AllowUpdate && actor.Velocity.sqrMagnitude<=0.16f
|
|
|| Vector3.Distance(self.ExpectClimb,_startPos) > _startDistance
|
|
)
|
|
{
|
|
Exit();
|
|
return;
|
|
}
|
|
|
|
var direction = self.transform.InverseTransformPoint(self.ExpectClimb.shouldBe);
|
|
if (direction.z <= -0.2f)
|
|
{
|
|
Exit();
|
|
return;
|
|
}
|
|
|
|
// var pos = actor.Position;
|
|
// pos.y = self.ExpectClimb.shouldBe.y;
|
|
// if (self.Position.y >= self.ExpectClimb.shouldBe.y && Vector3.Distance(pos,self.ExpectClimb.shouldBe)<0.1f)
|
|
// {
|
|
// Exit();
|
|
// }
|
|
}
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
actor.PhysicsComponent.IgnoreCollision(ignore,false);
|
|
actor.alwaysNotGrounded = false;
|
|
actor.ColliderComponent.enabled = true;
|
|
self.ExpectJump.Reset();
|
|
actor.ForceGrounded();
|
|
|
|
self.LimitViewAngle = 0;
|
|
//
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
if (needInit)
|
|
{
|
|
currentVelocity.y = 0;
|
|
needInit = false;
|
|
}
|
|
var velocity =(self.ExpectClimb.shouldBe - actor.Position)*lerpDelta;
|
|
|
|
velocity += self.Rotation * self.MovementInput.normalized * 1.0f;
|
|
currentVelocity = Vector3.Lerp(currentVelocity,velocity,lerpDelta*deltaTime);
|
|
}
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
public bool ManualCancel()
|
|
{
|
|
if (!Enabled) return false;
|
|
Exit();
|
|
return true;
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Link:PlayerCharacterState,IPlayerLinkState
|
|
{
|
|
public int LinkArea { get; private set; }
|
|
private OffMeshLink _offMeshLink;
|
|
private ISplineContainer _splineContainer;
|
|
private float progress;
|
|
private float increment;
|
|
|
|
[Inject] private IEquipService _equipService;
|
|
[Inject] private InputActionGroup _inputActionGroup;
|
|
|
|
private readonly IntervalUpdate exitInterval = new(0.32f);
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
|
|
self.ExpectCrouch.Reset();
|
|
|
|
self.ExpectJump.Reset();
|
|
|
|
actor.ForceNotGrounded();
|
|
|
|
actor.RigidbodyComponent.IsKinematic = true;
|
|
actor.ColliderComponent.enabled = false;
|
|
actor.UseRootMotion = true;
|
|
|
|
Init(self.OffMeshLink);
|
|
|
|
self.LimitViewAngle = 45;
|
|
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
|
|
exitInterval.Reset();
|
|
|
|
_inputActionGroup.RegisterCallback(self.CrouchAction, OnCrouch);
|
|
_inputActionGroup.RegisterCallback(self.JumpAction, OnJump);
|
|
}
|
|
|
|
private void OnJump(InputAction.CallbackContext obj)
|
|
{
|
|
switch (obj)
|
|
{
|
|
case {interaction:PressInteraction,performed:true}:
|
|
Exit();
|
|
return;
|
|
}
|
|
}
|
|
private void OnCrouch(InputAction.CallbackContext obj)
|
|
{
|
|
switch (obj)
|
|
{
|
|
case { interaction: PressInteraction, performed: true }:
|
|
Exit();
|
|
return;
|
|
}
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
actor.RigidbodyComponent.IsKinematic = false;
|
|
actor.ColliderComponent.enabled = true;
|
|
actor.UseRootMotion = false;
|
|
|
|
self.LimitViewAngle = 0;
|
|
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
|
|
_inputActionGroup.UnRegisterCallback(self.CrouchAction, OnCrouch);
|
|
_inputActionGroup.UnRegisterCallback(self.JumpAction, OnJump);
|
|
}
|
|
|
|
private void Init(OffMeshLink offMeshLink)
|
|
{
|
|
var offsetTransform = offMeshLink.transform;
|
|
_offMeshLink = offMeshLink;
|
|
|
|
offMeshLink.TryGetComponent<ISplineContainer>(out _splineContainer);
|
|
|
|
LinkArea = offMeshLink.area;
|
|
|
|
if (_splineContainer is not null)
|
|
{
|
|
var isStart =
|
|
Vector3.Distance(
|
|
actor.Position,
|
|
offsetTransform.TransformPoint(_splineContainer.Splines[0].Knots.First().Position)
|
|
) <
|
|
Vector3.Distance(
|
|
actor.Position,
|
|
offsetTransform.TransformPoint(_splineContainer.Splines[0].Knots.Last().Position)
|
|
);
|
|
progress = isStart ? 0 : 1;
|
|
increment = isStart ? 1 : -1;
|
|
}
|
|
else
|
|
{
|
|
var offset = Mathf.Lerp(offMeshLink.startTransform.position.y,offMeshLink.endTransform.position.y,0.5f);
|
|
var offsetPos = actor.Position;
|
|
offsetPos.y = offset;
|
|
actor.ForceNotGrounded();
|
|
actor.Position = Vector3.MoveTowards(actor.Position, offsetPos, 0.64f);
|
|
progress = 0.5f;
|
|
}
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
if (_splineContainer is null)
|
|
{
|
|
actor.Rotation = Quaternion.Lerp(
|
|
actor.Rotation,
|
|
_offMeshLink.transform.rotation * Quaternion.Euler(0,-180,0),
|
|
5 * deltaTime
|
|
);
|
|
}
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
actor.ForceNotGrounded();
|
|
|
|
if (_offMeshLink is null) return;
|
|
switch (_splineContainer)
|
|
{
|
|
case null:
|
|
var positionA = _offMeshLink.startTransform.position;
|
|
var positionB = positionA;
|
|
positionB.y = _offMeshLink.endTransform.position.y;
|
|
var positionC = actor.Position + Vector3.up * (0 * deltaTime * 1.6f);
|
|
|
|
Vector3 vectorAC = positionC - positionA;
|
|
Vector3 vectorAB = positionB - positionA;
|
|
|
|
Vector3 closestPoint = positionA + Vector3.Project(vectorAC, vectorAB);
|
|
|
|
actor.Position = closestPoint;
|
|
//currentVelocity = Vector3.Lerp(currentVelocity , (closestPoint - actor.Position) , 5 * deltaTime);
|
|
|
|
self.UnityEntity.SetDirect(BITHash.Player.ActionSpeed,self.MovementInput.z);
|
|
|
|
break;
|
|
case not null:
|
|
var trans = _offMeshLink.transform;
|
|
var pos =trans.position + trans.rotation * _splineContainer.Splines[0].EvaluatePosition(progress +=increment * deltaTime);
|
|
|
|
actor.Position =Vector3.Lerp(actor.Position , pos , 8*deltaTime) ;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
|
|
if (exitInterval.AllowUpdateWithoutReset is false) return;
|
|
switch (_offMeshLink,_splineContainer)
|
|
{
|
|
case (null,null):
|
|
case (not null,_) when !_offMeshLink || _offMeshLink.gameObject.activeInHierarchy is false:
|
|
Exit();
|
|
return;
|
|
case (not null,not null):
|
|
if (progress is > 1.1f or < -0.1f)
|
|
{
|
|
Exit();
|
|
}
|
|
return;
|
|
case (not null,null):
|
|
if (actor.Position.y > _offMeshLink.endTransform.position.y)
|
|
{
|
|
Exit();
|
|
actor.Position = _offMeshLink.endTransform.position;
|
|
return;
|
|
}
|
|
if (actor.Position.y < _offMeshLink.startTransform.position.y)
|
|
{
|
|
Exit();
|
|
actor.Position = _offMeshLink.startTransform.position;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class Dodge : PlayerCharacterState,IPlayerDodgeState
|
|
{
|
|
[SerializeField] private int costStamina = 10;
|
|
[SerializeField] private AnimationCurve curve;
|
|
[SerializeField] private float duration = 0.32f;
|
|
[Inject] private IEquipService _equipService;
|
|
private int direction;
|
|
private float process;
|
|
|
|
[Inject] private IHealth _health;
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
_health.OnDamageFactory += OnDamageFactory;
|
|
|
|
}
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
direction = self.MovementInput.x > 0 ? 1 : -1;
|
|
process = 0;
|
|
self.Stamina-= costStamina;
|
|
|
|
actor.UseRootMotion = true;
|
|
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
actor.UseRootMotion = false;
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
base.OnStateUpdate(deltaTime);
|
|
process += deltaTime / duration;
|
|
}
|
|
|
|
// public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
// {
|
|
// currentVelocity = actor.transform.right * (direction * curve.Evaluate(process+=deltaTime / duration));
|
|
// }
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
if(process>=1)
|
|
Exit();
|
|
if(actor.IsGrounded is false)Exit();
|
|
}
|
|
|
|
private int OnDamageFactory(DamageMessage msg, int currentDamage)
|
|
{
|
|
if (self.CurrentState is not IPlayerDodgeState || msg.Initiator is not Entity initiator)
|
|
return currentDamage;
|
|
var _direction = self.Position - initiator.transform.position;
|
|
var verticalAngle = Vector3.Angle(initiator.transform.forward, _direction) - 90.0f;
|
|
//Debug.Log(verticalAngle);
|
|
return 0;
|
|
|
|
}
|
|
public bool ManualCancel()
|
|
{
|
|
if (!Enabled) return false;
|
|
Exit();
|
|
return true;
|
|
}
|
|
}
|
|
[Serializable]
|
|
public sealed class Fixed:PlayerCharacterState,IPlayerFixedState
|
|
{
|
|
public object FixedObject=>_fixedPlace;
|
|
public float3 FixedPosition=>_fixedPlace.FixedPosition;
|
|
public quaternion FixedRotation=>_fixedPlace.FixedRotation;
|
|
public float3 FixedLocalPosition => throw new NotImplementedException();
|
|
public quaternion FixedLocalRotation => throw new NotImplementedException();
|
|
private IPlayerFixedPlace _fixedPlace;
|
|
|
|
[Inject] private ISelector _selector;
|
|
|
|
[Inject] private IEquipService _equipService;
|
|
|
|
[Inject] private IKnockdown _knockdown;
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
_selector.OnActive+=OnSelectorActive;
|
|
}
|
|
|
|
public override void OnStateEntry(IState old)
|
|
{
|
|
base.OnStateEntry(old);
|
|
//actor.enabled = false;
|
|
//actor.RigidbodyComponent.IsKinematic = true;
|
|
actor.ColliderComponent.enabled = false;
|
|
actor.PhysicsComponent.enabled = false;
|
|
actor.alwaysNotGrounded = true;
|
|
actor.constraintRotation = false;
|
|
self.ExpectCrouch.Reset();
|
|
self.LimitViewAngle = 100;
|
|
|
|
_equipService.AllowEquip.AddDisableElements(this);
|
|
|
|
lastRotation = _fixedPlace.FixedRotation;
|
|
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
{
|
|
base.OnStateExit(old, newState);
|
|
//actor.RigidbodyComponent.IsKinematic = false;
|
|
actor.ColliderComponent.enabled = true;
|
|
actor.alwaysNotGrounded = false;
|
|
actor.PhysicsComponent.enabled = true;
|
|
actor.constraintRotation = true;
|
|
//actor.enabled = true;
|
|
self.LimitViewAngle = 0;
|
|
|
|
_equipService.AllowEquip.RemoveDisableElements(this);
|
|
}
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
{
|
|
currentVelocity = default;
|
|
actor.Position = FixedPosition + _fixedPlace.Velocity * deltaTime;
|
|
;
|
|
}
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
{
|
|
currentRotation = FixedRotation;
|
|
}
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
{
|
|
base.AfterUpdateMovement(deltaTime);
|
|
self.CurrentCameraPosition.shouldBe = self.FpvLocalPosition;
|
|
if (self.ExpectCrouch.shouldBe && _fixedPlace.Exit(self.Entity))
|
|
{
|
|
self.ExpectCrouch.Reset();
|
|
Exit();
|
|
}else if (_fixedPlace is null)
|
|
{
|
|
Exit();
|
|
}
|
|
}
|
|
private void OnSelectorActive(ISelectable obj)
|
|
{
|
|
if (obj is not MonoBehaviour monoBehaviour ||
|
|
monoBehaviour.TryGetComponent<IPlayerFixedPlace>(out var fixedPlace) is false) return;
|
|
if (_knockdown.IsKnockdown) return;
|
|
if (_fixedPlace?.Exit(self.Entity) is false)
|
|
{
|
|
return;
|
|
}
|
|
if (fixedPlace.Entry(self.Entity))
|
|
{
|
|
_fixedPlace = fixedPlace;
|
|
self.TransitionState<Fixed>();
|
|
return;
|
|
}
|
|
_fixedPlace = null;
|
|
}
|
|
|
|
private quaternion lastRotation;
|
|
public override void OnStateUpdate(float deltaTime)
|
|
{
|
|
base.OnStateUpdate(deltaTime);
|
|
var rotation = Quaternion.Inverse(_fixedPlace.FixedRotation) * lastRotation;
|
|
var euler =MathV.TransientRotationAxis(rotation.eulerAngles);
|
|
var add = new float2(euler.x, -euler.y);
|
|
self.AddViewEuler(add);
|
|
lastRotation = _fixedPlace.FixedRotation;
|
|
}
|
|
protected override void Exit()
|
|
{
|
|
base.Exit();
|
|
if (_fixedPlace is not null)
|
|
{
|
|
actor.Position = _fixedPlace.ExitPosition;
|
|
}
|
|
_fixedPlace = null;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class ClimbBar
|
|
{
|
|
|
|
}
|
|
}
|
|
|