using System.Collections; using System.Collections.Generic; using UnityEngine; using BITKit; using BITKit.Entities; using UnityEngine.UIElements; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Interactions; using BITKit.Animations; using BITKit.StateMachine; using Net.Client; using Unity.Mathematics; using UnityEngine.VFX; using System.Diagnostics; using BITFALL.Guns; namespace BITFALL { public interface IGunState : IState { } [System.Serializable] public abstract class GunState : IGunState { public BITGun root; public virtual void Initialize() { } public virtual void OnStateEnter(IState old) { } public virtual void OnStateExit(IState old, IState newState) { } public virtual void OnStateUpdate() { } public virtual void OnMovementCallback(IMovementCallback callback) { } } [System.Serializable] public class GunStateMachine : MonoStateMachine { } public class BITGun : BITEquipBase { // 常数引用 public const string _Movement = "Movement"; public const string _Run = "Run"; public const string _Aim = "Aim"; public const string _Interactive = "Interactive"; public const string _Equip = "Equip"; public const string _Fire = "Fire"; // 输入系统 [Header(Constant.Header.Input)] public InputActionReference fireAction; public InputActionReference aimAction; public InputActionGroup actionGroup = new(); // 状态机 [Header(Constant.Header.State)] public GunStateMachine stateMachine; // 引用组件 [Header(Constant.Header.Components)] public Renderer[] rendererComponents; public VFXPlayer vfxPlayer; // 引用预制体 [Header(Constant.Header.Prefabs)] public AssetableGun assetable; [Header(Constant.Header.Reference)] // 内部变量 [Header(Constant.Header.InternalVariables)] public ExpectState isFiring; public ExpectState isAiming; internal IntervalUpdate fireUpdater = new(0.32f); internal IntervalUpdate brustFireUpdater = new(0.1f); internal int burstFireCount; #region 接口实现 public override string AddressablePath => assetable.AdressablePath; #endregion public override void Entry() { animator.animator.enabled = true; actionGroup.allowInput.SetElements(this, true); foreach (var x in rendererComponents) { x.enabled = true; } isFiring.Reset(); stateMachine.StateMachine.TransitionState(stateMachine.states[0]); entity.AddListener(OnMovementCallback); fireUpdater.updateInterval = 1f / assetable.FireMode.FireRate; fireUpdater.Reset(); if(assetable.FireMode is BurstFireMode burstFireMode) { brustFireUpdater.updateInterval = burstFireMode.BurstFireInterval; brustFireUpdater.Reset(); } } public override void Exit() { actionGroup.allowInput.SetElements(this, false); foreach (var x in rendererComponents) { x.enabled = false; } isFiring.Reset(); animator.animator.enabled = false; entity.RemoveListener(OnMovementCallback); } public override void OnAwake() { actionGroup.RegisterCallback(fireAction, OnFire); actionGroup.RegisterCallback(aimAction, OnAim); stateMachine.OnStart(); } public override void OnStart() { base.OnStart(); foreach (var x in rendererComponents) { x.enabled = false; } } public override void OnUpdate(float deltaTime) { stateMachine?.CurrentState?.OnStateUpdate(); if(assetable.FireMode is BurstFireMode && isFiring.being) { if(brustFireUpdater) { Fire(); } } } public void Fire() { //如果启用了指针则不开火 if(BITAppForUnity.AllowCursor) { return; } //播放射击动画 animator.Play(BITGun._Fire); //调用IMovementCancenAction接口,取消奔跑或冲刺 Entity.Invoke(new CancelRunOrSprint()); //调用BulletManager生成子弹 BulletService.Spawn(new() { initiator = entity.Id, pos = transform.position.Fix(), rot = transform.rotation, forward = transform.forward.Fix(), //pos=transform.position, //rot=transform.rotation, }); //播放枪口MuzzleFlash vfxPlayer.Excute(); //开火模式逻辑判断 switch (assetable.FireMode) { case AutoFireMode: break; case SemiFireMode: //如果是半自动开火,则取消射击 isFiring.Reset(); break; case BurstFireMode burstFireMode: burstFireCount++; isFiring.being = true; if(burstFireCount > burstFireMode.BurstRound) { burstFireCount = 0; isFiring.Reset(); } break; } } void OnFire(InputAction.CallbackContext context) { switch (assetable.FireMode) { case AutoFireMode: case SemiFireMode: isFiring.shouldBe = context.ReadValueAsButton(); break; case BurstFireMode: if(isFiring.being is false) isFiring.shouldBe = context.ReadValueAsButton();//|| context.action.triggered; break; } } void OnAim(InputAction.CallbackContext context) { isAiming.shouldBe = context.ReadValueAsButton(); } void OnMovementCallback(IMovementCallback callback) { stateMachine?.CurrentState?.OnMovementCallback(callback); } } }