using System; using BITFALL.Entities.Player.Movement.States; using BITFALL.Player.Movement; using BITKit; using BITKit.Entities; using BITKit.Entities.Physics; using BITKit.Entities.Player; using Lightbug.CharacterControllerPro.Core; using Unity.Mathematics; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Interactions; using UnityEngine.UIElements; namespace BITFALL.Entities.Player.Movement { [CustomType(typeof(IEntityMovement))] [CustomType(typeof(IPlayerMovement))] public class PlayerCharacterController : StateBasedPlayerComponent,IEntityMovement,IServiceRegister,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; [SerializeReference,SubclassSelector] private IClosePoint climbClosePoint; [SerializeReference, SubclassSelector] private IProvider adsProvider; [SerializeField] private LocationAdditive locationAdditive; public Vector3 ViewCenter { get; set; } public Quaternion ViewRotation { get; set; } public Vector3 LocomotionBasedVelocity { get;private set; } public Vector3 Velocity => actor.Velocity; public Vector3 GroundVelocity=>actor.GroundVelocity; public Vector3 AngularVelocity { get;private set; } 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 ExpectState CurrentCameraPosition; private readonly ValidHandle allowMovement = new(); private readonly ValidHandle allowRun = new(); private IEntityPhysics physics; private IHealth _health; private bool isDead; private Vector3 keepVelocity; public override void OnAwake() { _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); allowRun.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=default) { foreach (var x in StateDictionary.Values) { x.ExecuteCommand(command); } switch (command) { case PlayerEnableRunCommand enableRunCommand: allowRun.RemoveDisableElements(enableRunCommand.Lock); ExpectRun.Reset(); ExpectSprint.Reset(); break; case PlayerDisableRunCommand disableRunCommand: allowRun.AddDisableElements(disableRunCommand.Lock); break; } OnCommand?.Invoke(command); } public event Action OnCommand; 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; AngularVelocity = new Vector3 ( raw.y, -raw.x ); } 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) { if (allowRun.Allow is false) return; 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); CurrentState?.AfterUpdateMovement(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 additiveTransform = locationAdditive.transform; var rotation = Quaternion.Euler(LookInput); locationAdditive.SetGlobalRotation(rotation); CurrentCameraPosition.being = Vector3.Lerp(CurrentCameraPosition.being,CurrentCameraPosition.shouldBe,5 * deltaTime); locationAdditive.AddPosition(CurrentCameraPosition); ViewRotation = rotation; ViewCenter = additiveTransform.position + additiveTransform.forward; } public void AddViewEuler(float2 euler) { LookInput = new Vector3 { x = LookInput.x + euler.x, y = LookInput.y + euler.y }; } } }