2023-08-27 02:58:19 +08:00
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
2023-10-20 19:31:12 +08:00
|
|
|
using System.ComponentModel.Composition;
|
|
|
|
using System.Linq;
|
2023-08-27 02:58:19 +08:00
|
|
|
using BITFALL.Player.Movement;
|
2023-10-20 19:31:12 +08:00
|
|
|
using BITKit;
|
|
|
|
using BITKit.Entities;
|
|
|
|
using BITKit.Selection;
|
2023-08-27 02:58:19 +08:00
|
|
|
using BITKit.StateMachine;
|
2023-10-20 19:31:12 +08:00
|
|
|
using JetBrains.Annotations;
|
|
|
|
using Unity.Mathematics;
|
2023-08-27 02:58:19 +08:00
|
|
|
using UnityEngine;
|
2023-10-20 19:31:12 +08:00
|
|
|
using UnityEngine.AI;
|
|
|
|
using UnityEngine.Splines;
|
|
|
|
using UnityEngine.UI;
|
2023-08-27 02:58:19 +08:00
|
|
|
|
|
|
|
namespace BITFALL.Entities.Player.Movement.States
|
|
|
|
{
|
|
|
|
[Serializable]
|
|
|
|
public class Climb : PlayerCharacterState,IPlayerClimbState
|
|
|
|
{
|
|
|
|
[SerializeField] protected float lerpDelta = 5;
|
2023-10-20 19:31:12 +08:00
|
|
|
private IntervalUpdate cancelInterval = new(0.16f);
|
2023-08-27 02:58:19 +08:00
|
|
|
public override void OnStateEntry(IState old)
|
|
|
|
{
|
2023-10-20 19:31:12 +08:00
|
|
|
base.OnStateEntry(old);
|
2023-08-27 02:58:19 +08:00
|
|
|
actor.alwaysNotGrounded = true;
|
|
|
|
actor.ForceNotGrounded();
|
|
|
|
actor.ColliderComponent.enabled = false;
|
2023-10-20 19:31:12 +08:00
|
|
|
cancelInterval.Reset();
|
2023-08-27 02:58:19 +08:00
|
|
|
}
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
|
|
{
|
2023-10-20 19:31:12 +08:00
|
|
|
var distance = Vector3.Distance(characterController.ExpectClimb.shouldBe,
|
|
|
|
characterController.transform.position);
|
|
|
|
if (
|
|
|
|
distance<=0.16f
|
|
|
|
|| actor.IsStable
|
|
|
|
|| cancelInterval.AllowUpdate && actor.Velocity.sqrMagnitude<=0.16f
|
|
|
|
)
|
2023-08-27 02:58:19 +08:00
|
|
|
{
|
2023-10-20 19:31:12 +08:00
|
|
|
Exit();
|
2023-08-27 02:58:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
|
|
{
|
|
|
|
actor.alwaysNotGrounded = false;
|
|
|
|
actor.ColliderComponent.enabled = true;
|
|
|
|
characterController.ExpectJump.Reset();
|
|
|
|
actor.ForceGrounded();
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
|
|
{
|
2023-10-02 23:24:56 +08:00
|
|
|
currentVelocity =(characterController.ExpectClimb.shouldBe - characterController.transform.position)*lerpDelta;
|
2023-08-27 02:58:19 +08:00
|
|
|
}
|
2023-10-20 19:31:12 +08:00
|
|
|
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
|
|
{
|
|
|
|
characterController.CurrentCameraPosition.shouldBe = characterController.FpvLocalPosition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[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;
|
|
|
|
|
|
|
|
public override void OnStateEntry(IState old)
|
|
|
|
{
|
|
|
|
base.OnStateEntry(old);
|
|
|
|
|
|
|
|
characterController.ExpectCrouch.Reset();
|
|
|
|
|
|
|
|
characterController.ExpectJump.Reset();
|
|
|
|
|
|
|
|
actor.ForceNotGrounded();
|
|
|
|
|
|
|
|
actor.RigidbodyComponent.IsKinematic = true;
|
|
|
|
actor.ColliderComponent.enabled = false;
|
|
|
|
|
|
|
|
Init(characterController.OffMeshLink);
|
|
|
|
|
|
|
|
characterController.LimitViewAngle = 45;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void OnStateExit(IState old, IState newState)
|
|
|
|
{
|
|
|
|
base.OnStateExit(old, newState);
|
|
|
|
actor.RigidbodyComponent.IsKinematic = false;
|
|
|
|
actor.ColliderComponent.enabled = true;
|
|
|
|
|
|
|
|
characterController.LimitViewAngle = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
Quaternion.Inverse(_offMeshLink.transform.rotation),
|
|
|
|
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 * (characterController.MovementInput.z * deltaTime * 3);
|
|
|
|
|
|
|
|
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);
|
|
|
|
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 (characterController.ExpectJump.shouldBe|| characterController.ExpectCrouch.shouldBe)
|
|
|
|
{
|
|
|
|
Exit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (_offMeshLink,_splineContainer)
|
|
|
|
{
|
|
|
|
case (null,null):
|
|
|
|
Exit();
|
|
|
|
break;
|
|
|
|
case (not null,not null):
|
|
|
|
if (progress is > 1.1f or < -0.1f)
|
|
|
|
{
|
|
|
|
Exit();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case (not null,null):
|
|
|
|
if (actor.Position.y > _offMeshLink.endTransform.position.y)
|
|
|
|
{
|
|
|
|
Exit();
|
|
|
|
actor.Position = _offMeshLink.endTransform.position;
|
|
|
|
}else if (actor.Position.y < _offMeshLink.startTransform.position.y)
|
|
|
|
{
|
|
|
|
Exit();
|
|
|
|
actor.Position = _offMeshLink.startTransform.position;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
|
|
{
|
|
|
|
characterController.CurrentCameraPosition.shouldBe = characterController.FpvLocalPosition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[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;
|
|
|
|
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;
|
|
|
|
characterController.ExpectCrouch.Reset();
|
|
|
|
characterController.LimitViewAngle = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
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.enabled = true;
|
|
|
|
characterController.LimitViewAngle = 0;
|
|
|
|
}
|
|
|
|
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
|
|
|
{
|
|
|
|
actor.Position = FixedPosition;
|
|
|
|
}
|
|
|
|
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
|
|
|
{
|
|
|
|
currentRotation = FixedRotation;
|
|
|
|
//actor.Rotation = FixedRotation;
|
|
|
|
}
|
|
|
|
public override void AfterUpdateMovement(float deltaTime)
|
|
|
|
{
|
|
|
|
base.AfterUpdateMovement(deltaTime);
|
|
|
|
characterController.CurrentCameraPosition.shouldBe = characterController.FpvLocalPosition;
|
|
|
|
if (characterController.ExpectCrouch.shouldBe && _fixedPlace.Exit(characterController.Entity))
|
|
|
|
{
|
|
|
|
characterController.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 (_fixedPlace?.Exit(characterController.Entity) is false)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (fixedPlace.Entry(characterController.Entity))
|
|
|
|
{
|
|
|
|
_fixedPlace = fixedPlace;
|
|
|
|
characterController.TransitionState<Fixed>();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_fixedPlace = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void OnStateUpdate(float deltaTime)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
protected override void Exit()
|
|
|
|
{
|
|
|
|
base.Exit();
|
|
|
|
if (_fixedPlace is not null)
|
|
|
|
{
|
|
|
|
actor.Position = _fixedPlace.ExitPosition;
|
|
|
|
}
|
|
|
|
_fixedPlace = null;
|
|
|
|
}
|
2023-08-27 02:58:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|