This commit is contained in:
CortexCore
2023-10-20 19:31:12 +08:00
parent 5cd094ed9a
commit a160813262
1878 changed files with 630581 additions and 4485 deletions

View File

@@ -15,7 +15,9 @@
"GUID:bea3628e8b592ae47ade218cb9ec98db",
"GUID:f822dbf6fdfd4a5469cccaa2e4eed3b6",
"GUID:a3de65b07192e7d49bad7b4032d681de",
"GUID:d8b63aba1907145bea998dd612889d6b"
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:f6155d9ae143f3949ac54e8355593d6c",
"GUID:21d1eb854b91ade49bc69a263d12bee2"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -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);
}
}
}

View File

@@ -1,3 +1,4 @@
using BITFALL.Player.Movement;
using BITKit.Entities;
using BITKit.StateMachine;
using Lightbug.CharacterControllerPro.Core;
@@ -9,13 +10,16 @@ namespace BITFALL.Entities.Player.Movement.States
{
[SerializeField] protected PlayerCharacterController characterController;
[SerializeField] protected CharacterActor actor;
private IEntityMovementState entryState;
public bool Enabled { get; set; }
public virtual void Initialize()
{
characterController.entity.Inject(this);
}
public virtual void OnStateEntry(IState old)
{
entryState=old is IPlayerRunState or IPlayerSprintState ? old as IEntityMovementState: null;
}
public virtual void OnStateUpdate(float deltaTime)
@@ -44,5 +48,16 @@ namespace BITFALL.Entities.Player.Movement.States
public virtual void ExecuteCommand<T>(T command)
{
}
protected virtual void Exit()
{
if (entryState is not null && entryState is IEntityMovementState state)
{
characterController.TransitionState(state);
}
else
{
characterController.TransitionState<Walk>();
}
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using BITFALL.Entities.Player.Movement.States;
using BITFALL.Player.Movement;
using BITKit;
using BITKit.StateMachine;
using Lightbug.CharacterControllerPro.Core;
using UnityEngine;
@@ -12,15 +13,25 @@ namespace BITFALL.Entities.Player.Movement.States
{
public abstract class BasicMovement : PlayerCharacterState,IPlayerMovementState
{
[SerializeField] protected Vector3 initialCameraPosition;
[SerializeField] protected float initialSpeed = 3f;
[SerializeField] protected float initialJumpForce = 5f;
[Inject] protected IKnockdown knockdown;
public override void BeforeUpdateMovement(float deltaTime)
{
characterController.CurrentCameraPosition.shouldBe = initialCameraPosition;
}
public override void AfterUpdateMovement(float deltaTime)
{
if (knockdown.IsKnockdown is false && characterController.ExpectParachute.shouldBe)
{
characterController.TransitionState<Parachute>();
characterController.ExpectParachute.Reset();
}
}
public override void UpdateVelocity(ref Vector3 currentVelocity,float deltaTime)
{
var rotation = Quaternion.Euler(0,characterController.LookInput.y,0);
@@ -107,6 +118,7 @@ namespace BITFALL.Entities.Player.Movement.States
public override void AfterUpdateMovement(float deltaTime)
{
base.AfterUpdateMovement(deltaTime);
switch (characterController.ExpectRun.shouldBe,characterController.ExpectCrouch.shouldBe)
{
case (_,true):
@@ -118,6 +130,51 @@ namespace BITFALL.Entities.Player.Movement.States
}
}
}
[Serializable]
public sealed class Parachute : PlayerCharacterState, IPlayerParachuteState
{
[SerializeField] private float moveDamping = 3f;
[SerializeField] private float damping = 1f;
public override void OnStateEntry(IState old)
{
characterController.InvokeOpenParachute();
}
public override void OnStateExit(IState old, IState newState)
{
characterController.InvokeCloseParachute();
}
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{
currentRotation = Quaternion.Euler(0,characterController.LookInput.y,0);
}
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
var rotation = Quaternion.Euler(0,characterController.LookInput.y,0);
var moveVelocity = rotation * characterController.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)
{
characterController.TransitionState<Walk>();
}
characterController.ExpectParachute.Reset();
characterController.CurrentCameraPosition.shouldBe = characterController.FpvLocalPosition;
}
}
[Serializable]
public sealed class Run:BasicMovement,IPlayerRunState
{
@@ -133,6 +190,7 @@ namespace BITFALL.Entities.Player.Movement.States
public override void AfterUpdateMovement(float deltaTime)
{
base.AfterUpdateMovement(deltaTime);
if (characterController.ExpectSprint.shouldBe)
{
characterController.TransitionState<Sprint>();
@@ -157,9 +215,65 @@ namespace BITFALL.Entities.Player.Movement.States
}
}
}
[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)
{
characterController.ExpectCrouch.being = true;
characterController.ExpectCrouch.shouldBe = true;
_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 (characterController.ExpectRun.shouldBe)
{
characterController.TransitionState<Run>();
return;
}
if (characterController.ExpectCrouch.shouldBe is false || (alwaysSlide is false && actor.IsGrounded is false))
{
characterController.TransitionState<Walk>();
return;
}
if (actor.Velocity.sqrMagnitude <= stopSpeed)
{
characterController.TransitionState<Crouch>();
}
characterController.CurrentCameraPosition.shouldBe = characterController.FpvLocalPosition;
}
}
[Serializable]
public sealed class Crouch:BasicMovement,IPlayerCrouchState
{
public override void OnStateEntry(IState old)
{
characterController.ExpectCrouch.being = true;
@@ -171,6 +285,7 @@ namespace BITFALL.Entities.Player.Movement.States
}
public override void AfterUpdateMovement(float deltaTime)
{
base.AfterUpdateMovement(deltaTime);
if (characterController.ExpectRun.shouldBe)
{
characterController.TransitionState<Run>();
@@ -187,19 +302,33 @@ namespace BITFALL.Entities.Player.Movement.States
[Serializable]
public sealed class Sprint:BasicMovement,IPlayerSprintState
{
[SerializeField] private int slideCost = 16;
[SerializeField] private int staminaCost = 1;
public override void OnStateEntry(IState old)
{
characterController.ExpectSprint.being = true;
}
public override void OnStateExit(IState old, IState newState)
{
characterController.ExpectSprint.being = false;
}
public override void OnStateUpdate(float deltaTime)
{
characterController.Stamina -= staminaCost * deltaTime;
}
public override void AfterUpdateMovement(float deltaTime)
{
base.AfterUpdateMovement(deltaTime);
switch (characterController.ExpectRun.shouldBe,characterController.ExpectCrouch.shouldBe)
{
case (_,_) when characterController.Stamina is 0:
characterController.ExpectSprint.Reset();
characterController.TransitionState<Run>();
break;
case (_,true) when characterController.IsGrounded && characterController.Stamina >= slideCost:
characterController.Stamina -= slideCost;
characterController.TransitionState<Slide>();
break;
case (_,true):
characterController.TransitionState<Crouch>();
break;
@@ -215,4 +344,25 @@ namespace BITFALL.Entities.Player.Movement.States
characterController.TransitionState<Walk>();
}
}
[Serializable]
public sealed class Knockdown : BasicMovement, IPlayerKnockdownState
{
public override void Initialize()
{
base.Initialize();
knockdown.OnKnockdown += OnKnockdown;
knockdown.OnRevive += OnRevive;
}
private void OnRevive()
{
if(Enabled)characterController.TransitionState<Walk>();
}
private void OnKnockdown()
{
characterController.TransitionState<Knockdown>();
}
}
}

View File

@@ -1,28 +1,46 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using BITFALL.Player.Movement;
using BITKit;
using BITKit.Entities;
using BITKit.Selection;
using BITKit.StateMachine;
using JetBrains.Annotations;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Splines;
using UnityEngine.UI;
namespace BITFALL.Entities.Player.Movement.States
{
[Serializable]
public class Climb : PlayerCharacterState,IPlayerClimbState
{
[SerializeField] protected float lerpDelta = 5;
private IntervalUpdate cancelInterval = new(0.16f);
public override void OnStateEntry(IState old)
{
base.OnStateEntry(old);
actor.alwaysNotGrounded = true;
actor.ForceNotGrounded();
actor.ColliderComponent.enabled = false;
cancelInterval.Reset();
}
public override void OnStateUpdate(float deltaTime)
{
if (Vector3.Distance(characterController.ExpectClimb.shouldBe, characterController.transform.position) < 0.1f || actor.IsStable)
var distance = Vector3.Distance(characterController.ExpectClimb.shouldBe,
characterController.transform.position);
if (
distance<=0.16f
|| actor.IsStable
|| cancelInterval.AllowUpdate && actor.Velocity.sqrMagnitude<=0.16f
)
{
characterController.TransitionState<Walk>();
Exit();
}
}
public override void OnStateExit(IState old, IState newState)
@@ -37,6 +55,254 @@ namespace BITFALL.Entities.Player.Movement.States
{
currentVelocity =(characterController.ExpectClimb.shouldBe - characterController.transform.position)*lerpDelta;
}
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;
}
}
}

View File

@@ -5,7 +5,9 @@
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:1235ca61e7f433b408ed5a68767e7123",
"GUID:7efac18f239530141802fb139776f333"
"GUID:7efac18f239530141802fb139776f333",
"GUID:f6155d9ae143f3949ac54e8355593d6c",
"GUID:87bea3a21c744b1478660b70494160ba"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using BITFALL.Player.Movement;
using BITKit.Entities;
using BITKit.StateMachine;
using Unity.SharpZipLib.Zip;
using UnityEngine;
// ReSharper disable UnassignedField.Global
@@ -13,6 +15,7 @@ namespace BITFALL.Player.Animation.States
{
[SerializeField] protected PlayerAnimationController animationController;
public virtual bool Enabled { get; set; }
protected IPlayerAnimationState entryState;
public virtual void Initialize()
{
@@ -20,6 +23,7 @@ namespace BITFALL.Player.Animation.States
public virtual void OnStateEntry(IState old)
{
entryState = old as IPlayerAnimationState;
}
public virtual void OnStateUpdate(float deltaTime)
@@ -33,17 +37,38 @@ namespace BITFALL.Player.Animation.States
public virtual void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
}
protected virtual void Exit()
{
if (Enabled is false) return;
switch (entryState)
{
case IPlayerWalkState:
animationController.TransitionState<Walk>();
break;
case IPlayerCrouchState:
animationController.TransitionState<Crouch>();
break;
case IPlayerSprintState:
animationController.TransitionState<Sprint>();
break;
}
}
}
[Serializable]
public class Walk : PlayerAnimateStates
public class Walk : PlayerAnimateStates,IPlayerWalkState
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(old switch
animationController.animator.CrossFade(old switch
{
IPlayerRunState or IPlayerSprintState=> "Walk.Stop",
_=>PlayerAnimationController._Walk
IPlayerLinkState { LinkArea: 5 } => "Walk.ExitClimb",
_=>BITConstant.Player.Walk
},old switch
{
IPlayerRunState or IPlayerSprintState=> 0.08f,
IPlayerSlideState or IPlayerCrouchState => 0.32f,
_=>0.16f
});
}
@@ -65,36 +90,25 @@ namespace BITFALL.Player.Animation.States
}
}
[Serializable]
public class Run : PlayerAnimateStates
public class Run : PlayerAnimateStates,IPlayerRunState
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(PlayerAnimationController._Run);
base.OnStateEntry(old);
animationController.animator.Play(BITConstant.Player.Run);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if (Enabled is false) return;
switch (newState)
{
case IPlayerWalkState:
animationController.TransitionState<Walk>();
break;
case IPlayerCrouchState:
animationController.TransitionState<Crouch>();
break;
case IPlayerSprintState:
animationController.TransitionState<Sprint>();
break;
}
if(Enabled &&newState is not IPlayerRunState)Exit();
}
}
[Serializable]
public class Sprint : PlayerAnimateStates
public class Sprint : PlayerAnimateStates,IPlayerSprintState
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(PlayerAnimationController._Sprint);
animationController.animator.Play(BITConstant.Player.Sprint);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
@@ -112,11 +126,11 @@ namespace BITFALL.Player.Animation.States
}
}
[Serializable]
public class Crouch : PlayerAnimateStates
public class Crouch : PlayerAnimateStates,IPlayerCrouchState
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(PlayerAnimationController._Crouch);
animationController.animator.Play(BITConstant.Player.Crouch);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
@@ -126,4 +140,134 @@ namespace BITFALL.Player.Animation.States
animationController.TransitionState<Walk>();
}
}
[Serializable]
public class Parachute : PlayerAnimateStates
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(BITConstant.Player.Parachute);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if(newState is IPlayerParachuteState)
animationController.TransitionState<Parachute>();
else if(Enabled && newState is not IPlayerKnockdownState)
{
animationController.TransitionState<Walk>();
}
}
}
[Serializable]
public class Slide : PlayerAnimateStates
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(BITConstant.Player.Slide);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if(newState is IPlayerSlideState)
animationController.TransitionState<Slide>();
else if(Enabled && newState is not IPlayerKnockdownState)
{
animationController.TransitionState<Walk>();
}
}
}
[Serializable]
public class Knockdown : PlayerAnimateStates
{
[SerializeField] private AnimatorOverrideController animatorOverrideController;
private RuntimeAnimatorController _initialController;
public override void Initialize()
{
base.Initialize();
_initialController = animationController.animator.animator.runtimeAnimatorController;
}
public override void OnStateEntry(IState old)
{
animationController.animator.animator.runtimeAnimatorController = animatorOverrideController;
animationController.animator.Play(BITConstant.Player.Walk);
}
public override void OnStateExit(IState old, IState newState)
{
animationController.animator.animator.runtimeAnimatorController = _initialController;
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if (newState is IPlayerKnockdownState)
{
animationController.TransitionState<Knockdown>();
}
else if(Enabled)
{
animationController.TransitionState<Walk>();
}
}
}
[Serializable]
public class Link : PlayerAnimateStates,IPlayerLinkState
{
public int LinkArea { get; set; }
public override void OnStateEntry(IState old)
{
switch (LinkArea)
{
case 5:
animationController.animator.Play(BITConstant.Player.ClimbLadder);
break;
}
//animationController.animator.Play(BITConstant.Player._Run);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if (Enabled)
{
switch (newState)
{
case IPlayerWalkState:
animationController.TransitionState<Walk>();
break;
case IPlayerCrouchState:
animationController.TransitionState<Crouch>();
break;
case IPlayerSprintState:
animationController.TransitionState<Sprint>();
break;
}
}
else
{
if (newState is IPlayerLinkState linkState)
{
LinkArea = linkState.LinkArea;
animationController.TransitionState<Link>();
}
}
}
}
[Serializable]
public sealed class Fixed : PlayerAnimateStates
{
public override void OnStateEntry(IState old)
{
animationController.animator.Play(BITConstant.Player.Fixed);
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
base.OnMovementStateChanged(oldState, newState);
if(newState is IPlayerFixedState)
animationController.TransitionState<Fixed>();
else if(Enabled)
Exit();
}
}
}

View File

@@ -14,10 +14,7 @@ namespace BITFALL.Player.Animation
}
public class PlayerAnimationController : StateBasedComponent<IPlayerAnimationState>
{
public const string _Walk = "Walk";
public const string _Run = "Run";
public const string _Sprint = "Sprint";
public const string _Crouch = "Crouch";
[SerializeField] internal UnityAnimator animator;
private IEntityMovement _movement;

View File

@@ -17,7 +17,7 @@ namespace BITFALL.Player.Animation.States
}
public override void OnMovementStateChanged(IEntityMovementState oldState, IEntityMovementState newState)
{
if (newState is IPlayerClimbState)
if (newState is IPlayerClimbState or IPlayerLinkState { LinkArea: 4 })
{
animationController.TransitionState<Climb>();
}

View File

@@ -10,7 +10,8 @@
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:ef0bb553b58b90b488bdbe8672e3be0b",
"GUID:677cd05ca06c46b4395470200b1acdad",
"GUID:30cdc242b1ac6a944a460f4ab0b77b88"
"GUID:30cdc242b1ac6a944a460f4ab0b77b88",
"GUID:7efac18f239530141802fb139776f333"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -22,14 +22,22 @@ namespace BITFALL.Player.Survival
private bool OnUseItem(IBasicItem arg)
{
switch (arg)
var used = false;
{
case var _ when arg.GetAssetable().TryGetProperty<PlayerEatAddHunger>(out var addHunger) &&
_survival.Elements.TryGetAny(x => x is PlayerSurvivalHunger, out var hunger):
hunger.Value += addHunger.Value;
return true;
if (arg.GetAssetable().TryGetProperty<PlayerEatAddHunger>(out var addHunger) &&
_survival.Elements.TryGetAny(x => x is PlayerSurvivalHunger, out var element))
{
element.Value += addHunger.Value;
used = true;
}
if (arg.GetAssetable().TryGetProperty<PlayerEatAddThirst>(out var addThirst) &&
_survival.Elements.TryGetAny(x => x is PlayerSurvivalThirst, out element))
{
element.Value += addThirst.Value;
used = true;
}
}
return false;
return used;
}
}

View File

@@ -8,13 +8,21 @@ using UnityEngine;
namespace BITFALL.Player.Survival
{
[Serializable]
public struct SurvivalDamage : IDamageType
{
public IPlayerSurvivalElement element;
public string Message;
}
[CustomType(typeof(IPlayerSurvivalService))]
public class PlayerSurvivalService : EntityComponent, IPlayerSurvivalService
{
public IPlayerSurvivalElement[] Elements { get; set; } = Array.Empty<IPlayerSurvivalElement>();
[SerializeReference, SubclassSelector] private IPlayerSurvivalElement[] initialElements = Array.Empty<IPlayerSurvivalElement>();
private IntervalUpdate _interval = new(1);
private readonly IntervalUpdate _interval = new(1);
[SerializeReference,SubclassSelector,Inject] private IDamageService _damageService;
[Inject]
private IHealth _health;
public override void OnAwake()
{
Elements = initialElements;
@@ -26,6 +34,18 @@ namespace BITFALL.Player.Survival
foreach (var x in Elements)
{
x.Value -= 1;
if (x.Value <= 0)
{
_damageService.Execute(new DamageMessage()
{
damageType = new SurvivalDamage()
{
element = x,
},
target = entity,
damage = 1,
});
}
}
}
}