using System; using System.Collections; using System.Collections.Generic; using BITFALL.Items.Melee; using BITFALL.Combat; using BITFALL.Player.Movement; using BITKit; using BITKit.Entities; using BITKit.Entities.Melee; using BITKit.StateMachine; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Interactions; namespace BITFALL.Entities.Equipment.Melee { public interface IPlayerMeleeControllerState : IState { } public abstract class PlayerMeleeControllerState : IPlayerMeleeControllerState { [SerializeField] protected MeleeController meleeController; public virtual bool Enabled { get; set; } public virtual void Initialize() { meleeController.Entity.Inject(this); } public virtual void OnStateEntry(IState old) { } public virtual void OnStateUpdate(float deltaTime) { } public virtual void OnStateExit(IState old, IState newState) { } } public sealed class MeleeController : BITEquipBase { [Header(Constant.Header.Input)] [SerializeField] private InputActionReference attackAction; [SerializeField] private InputActionReference blockAction; [Header(Constant.Header.Gameobjects)] [SerializeField] private Transform velocityReference; public override string AddressablePath => item.AddressablePath; public AssetableMelee melee => item as AssetableMelee; protected override Vector3 meleeForce => _velocity; private Vector3 _velocity; private Vector3 _lastPosition; [Inject] private IEntityMovement _movement; [Inject(true)] private IPlayerMovement _playerMovement; [Inject] private IHealth _health; public override void OnAwake() { base.OnAwake(); if (attackAction is not null) { inputActionGroup.RegisterCallback(attackAction, OnAttack); } if (blockAction is not null) { inputActionGroup.RegisterCallback(blockAction, OnBlock); } if (_playerMovement is not null) _health.OnDamageFactory += OnDamageFactory; _movement.OnStateChanged += OnMovementStateChanged; } private void OnMovementStateChanged(IEntityMovementState arg1, IEntityMovementState arg2) { switch (arg2) { case IPlayerDodgeState: TransitionState(); animator.Play(BITConstant.Player.Dodge); break; } } private int OnDamageFactory(DamageMessage arg1, int arg2) { if (Enabled is false || arg1.Initiator is null) return arg2; if (CurrentState is not Blocking blocking) return arg2; var combat = arg1.Initiator.Get(); if (combat is null) return arg2; if (blocking.AllowBlockStun && _playerMovement.Stamina >= melee.BlockStaminaCost) { arg2 =0; combat.HitStun(); animator.Play(BITConstant.Player.BlockStun); _playerMovement.Stamina -= melee.BlockStaminaCost*0.5f; } else { if (_playerMovement.Stamina > melee.BlockStaminaCost) { animator.Play(BITConstant.Player.BlockStun); arg2 /= 3; } else { animator.Play(BITConstant.Player.BlockBreak); arg2 /= 2; } _playerMovement.Stamina -= melee.BlockStaminaCost; } return arg2; } public override void Entry() { base.Entry(); TransitionState(); } public override void Exited() { base.Exited(); _movement.ExecuteCommand(new(this,false)); } public override void OnUpdate(float deltaTime) { base.OnUpdate(deltaTime); var position = velocityReference.position; _velocity = (position - _lastPosition).normalized; _lastPosition = position; UpdateState(deltaTime); var sqr = _movement.LocomotionBasedVelocity.sqrMagnitude; animator.animator.SetFloat(BITConstant.Player.SqrMagnitude,sqr); _movement.ExecuteCommand(new(this,CurrentState is not Idle)); } private void OnBlock(InputAction.CallbackContext obj) { switch (obj) { case {interaction:TapInteraction,started:true} when CurrentState is Idle: TransitionState(); break; case {interaction:TapInteraction,performed:true} when CurrentState is Blocking: case {interaction:HoldInteraction,canceled:true} when CurrentState is Blocking: TransitionState(); break; } } private void OnAttack(InputAction.CallbackContext context) { //如果启用了指针则不开火 if(BITAppForUnity.AllowCursor) { return; } switch (context) { case {interaction: TapInteraction,performed:true} when CurrentState is not (Attack or HeavyAttack or Draw or Blocking): TransitionState(); break; case {interaction: PressInteraction,performed:true} when CurrentState is not (Attack or HeavyAttack or Draw or Blocking): TransitionState(); break; case {interaction: HoldInteraction,canceled:true} when CurrentState is not (Attack or Idle or Draw or Blocking): TransitionState(); break; } } } }