using System; using BITFALL.Entities.Player.Movement.States; using BITKit; using BITKit.Entities; using BITKit.Entities.Physics; using BITKit.Entities.Player; using Lightbug.CharacterControllerPro.Core; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Interactions; using UnityEngine.UIElements; namespace BITFALL.Entities.Player.Movement { public class PlayerCharacterController : StateBasedPlayerComponent,IEntityMovement,IServiceRegister { public override Type BaseType => typeof(IEntityMovement); [SerializeField] private CharacterActor actor; [SerializeField] private Vector3 initialCameraPosition = new Vector3(0,0.11f,0.27f); [SerializeField] private float initialSpeed; [SerializeReference,SubclassSelector] private IClosePoint climbClosePoint; [SerializeReference, SubclassSelector] private IProvider adsProvider; [SerializeField] private Transform cameraTransform; public Vector3 LocomotionBasedVelocity { get;private set; } public Vector3 Velocity => actor.Velocity; public Vector3 GroundVelocity=>actor.GroundVelocity; public bool IsGrounded => actor.IsGrounded; public Vector3 MovementInput { get; private set; } public Vector2 LookInput{ get; private set; } public ExpectState ExpectRun; public ExpectState ExpectJump; public ExpectState ExpectCrouch; public ExpectState ExpectSprint; public ExpectState expectClimb; public Vector3 CurrentCameraPosition; private readonly ValidHandle allowMovement = new(); private IEntityPhysics physics; private IHealth _health; private bool isDead; private Vector3 keepVelocity; public override void OnAwake() { CurrentCameraPosition = initialCameraPosition; _health = entity.Get(); _health.OnSetAlive += OnSetAlive; physics = entity.Get(); physics.OnSetPhysics += OnSetPhysics; } private void OnSetPhysics(bool obj) { if (obj is false) return; physics.Velocity = keepVelocity; actor.Velocity = Vector3.zero; } private void OnSetAlive(bool obj) { allowMovement.SetElements(this,obj); if (obj) { if (!isDead) return; actor.Position = physics.Center; isDead = false; } else { isDead = true; } } public void SyncMovement(Vector3 velocity, Vector3 position, Quaternion rotation, bool isGrounded) { throw new NotImplementedException(); } public void Movement(Vector3 relativeVector) { MovementInput = relativeVector; } public void Movement(InputAction.CallbackContext context) { MovementInput = context.ReadValue(); MovementInput = new Vector3(MovementInput.x,0,MovementInput.y); if (!(MovementInput.z <= 0.16f)) return; ExpectRun.Reset(); ExpectSprint.Reset(); } public void ExecuteCommand(T command) { foreach (var x in StateDictionary.Values) { x.ExecuteCommand(command); } } public void View(InputAction.CallbackContext context) { if (BITAppForUnity.AllowCursor) return; var playerConfig = Data.Get() ?? new PlayerConfig(); var ads = adsProvider.Get(); if (ads is 0) ads = 1; var raw = context.ReadValue() * playerConfig.sensitivity * playerConfig.m_yaw * ads; var lookInput = LookInput; lookInput.x -= raw.y; lookInput.y += raw.x; lookInput.x = Mathf.Clamp(lookInput.x, -80, 80); LookInput = lookInput; } 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)) { expectClimb.shouldBe = closePoint; TransitionState(); } } public void Run(InputAction.CallbackContext context) { switch (context) { case { interaction: PressInteraction, started: true }: if (ExpectRun.shouldBe) ExpectSprint.shouldBe = true; ExpectRun.shouldBe = true; ExpectCrouch.Reset(); break; case {interaction:MultiTapInteraction,performed:true}: ExpectSprint.shouldBe = true; ExpectCrouch.Reset(); break; } } public void Crouch(InputAction.CallbackContext context) { if (context.interaction is not null && context.started is false) return; if (CurrentState is Climb) { TransitionState(); } else { ExpectCrouch.shouldBe = !ExpectCrouch.shouldBe; ExpectRun.Reset(); } } public override void OnUpdate(float deltaTime) { CurrentState?.BeforeUpdateMovement(deltaTime); } public override void OnFixedUpdate(float deltaTime) { var currentVelocity = actor.Velocity; var currentRotation = actor.Rotation; CurrentState.OnStateUpdate(deltaTime); CurrentState?.UpdateVelocity(ref currentVelocity, deltaTime); CurrentState?.UpdateRotation(ref currentRotation, deltaTime); if (allowMovement && _health.IsAlive) { actor.Velocity = currentVelocity; actor.Rotation = currentRotation; if (currentVelocity.sqrMagnitude > 0.01f) keepVelocity = currentVelocity; } var localVelocity = transform.InverseTransformDirection(Velocity); localVelocity.y = 0; LocomotionBasedVelocity = localVelocity; } public override void OnLateUpdate(float deltaTime) { if (allowMovement.Allow is false) return; var rotation = Quaternion.Euler(LookInput); cameraTransform.rotation = rotation; CurrentState?.AfterUpdateMovement(deltaTime); cameraTransform.localPosition = Vector3.Lerp(cameraTransform.localPosition,CurrentCameraPosition,5 * deltaTime); } } }