BITFALL/Assets/Artists/Scripts/Equip/BITGun.cs

830 lines
30 KiB
C#
Raw Normal View History

2023-10-04 16:50:27 +08:00
using System;
2023-08-23 01:59:40 +08:00
using System.Linq;
2024-03-23 18:07:54 +08:00
using Animancer;
2023-12-15 00:08:02 +08:00
using BITFALL.Guns.Modify;
2023-08-23 01:59:40 +08:00
using BITFALL.Guns.States;
2023-10-31 18:07:15 +08:00
using BITFALL.Player.Equip;
2023-09-01 14:33:54 +08:00
using BITFALL.Player.Movement;
2023-06-08 14:09:50 +08:00
using UnityEngine;
using BITKit;
2024-03-23 18:07:54 +08:00
using BITKit.Animations;
2023-06-08 14:09:50 +08:00
using BITKit.Entities;
2023-08-27 02:58:19 +08:00
using BITKit.Entities.Melee;
2023-06-08 14:09:50 +08:00
using UnityEngine.InputSystem;
using BITKit.StateMachine;
2023-10-20 19:31:12 +08:00
using Cysharp.Threading.Tasks;
2023-09-01 14:33:54 +08:00
using Unity.Mathematics;
2023-08-27 02:58:19 +08:00
using UnityEngine.InputSystem.Interactions;
2023-12-15 00:08:02 +08:00
using Random = UnityEngine.Random;
2023-08-23 01:59:40 +08:00
#if UNITY_EDITOR
#endif
2023-06-08 14:09:50 +08:00
2023-08-27 02:58:19 +08:00
namespace BITFALL.Guns
2023-06-08 14:09:50 +08:00
{
public interface IGunState : IState { }
2023-08-27 02:58:19 +08:00
2023-06-08 14:09:50 +08:00
[System.Serializable]
public abstract class GunState : IGunState
{
public BITGun root;
2023-10-20 19:31:12 +08:00
[Inject]
protected IEntityMovement _entityMovement;
2024-03-23 18:07:54 +08:00
protected AnimancerComponent animancerComponent=>root.AnimancerComponent;
2023-08-23 01:59:40 +08:00
public bool Enabled { get;set; }
2024-03-23 18:07:54 +08:00
protected string[] AnimationKey;
protected bool PlayAnimation(params string[] args)
{
if (root.MotionMatchingService.TryMatch(out var obj,args) is false) return false;
switch (obj)
{
case IMotionMatchingClip clip:
animancerComponent.Play(clip.Clip,0.1f);
return true;
case IMotionMatchingSequence sequence:
//animancerComponent.Play(sequence.Sequence);
return true;
}
return false;
}
protected void PlayAnimation(Action OnEnd = null)
{
if (root.MotionMatchingService.TryMatch(out var obj,AnimationKey) is false) return;
switch (obj)
{
case IMotionMatchingClip clip:
var state = animancerComponent.Play(clip.Clip, 0.1f);
state.Events.OnEnd=OnEnd is null ? null : () =>
{
state.Events.OnEnd = null;
this.OnEnd();
};
break;
}
}
2023-06-08 14:09:50 +08:00
public virtual void Initialize()
{
2023-10-20 19:31:12 +08:00
root.Entity.Inject(this);
2023-08-23 01:59:40 +08:00
_entityMovement.OnStateChanged += OnMovementStateChanged;
2024-03-24 02:05:16 +08:00
// AnimationKey = new []{BITGun.C_Weapon,GetType().Name,root._gun.Name};
AnimationKey = root.SearchKey.Append(GetType().Name).ToArray();
2023-06-08 14:09:50 +08:00
}
2023-08-23 01:59:40 +08:00
public virtual void OnStateEntry(IState old)
2023-06-08 14:09:50 +08:00
{
2024-03-23 18:07:54 +08:00
PlayAnimation(OnEnd);
2023-06-08 14:09:50 +08:00
}
public virtual void OnStateExit(IState old, IState newState)
{
}
2023-08-27 02:58:19 +08:00
public virtual void OnStateUpdate(float deltaTime)
2023-06-08 14:09:50 +08:00
{
}
2023-08-23 01:59:40 +08:00
public virtual void OnMovementStateChanged(IEntityMovementState old, IEntityMovementState newState)
{
}
2023-08-27 02:58:19 +08:00
public virtual void AnimationEvent(string name)
{
}
2024-03-23 18:07:54 +08:00
protected virtual void OnEnd()
{
}
2023-06-08 14:09:50 +08:00
}
[System.Serializable]
public class GunStateMachine : MonoStateMachine<GunState> { }
public class BITGun : BITEquipBase<GunState>
{
2023-12-15 00:08:02 +08:00
[RuntimeInitializeOnLoadMethod]
private static void Reload()
{
_token =(uint)(uint.MaxValue * Random.value);
}
public static uint Token => _token += 1;
private static uint _token;
2023-08-27 02:58:19 +08:00
//简单设置
[Header(Constant.Header.Settings)]
[SerializeField] private Vector3 bulletInitialOffset;
2023-09-01 14:33:54 +08:00
[SerializeField] private SpringEulerAngle recoilSpring=new();
2023-11-15 23:54:54 +08:00
[SerializeField] private float recoilPositionWeight=1;
2023-11-02 20:58:55 +08:00
[Header(Constant.Header.Gameobjects)]
[SerializeField] private Transform initialSight;
[SerializeField] private Optional<Transform> newSight;
[Header(nameof(Optional<GameObject>))]
[SerializeField] private Optional<LocationAdditive> breathingAdditive;
2023-08-27 02:58:19 +08:00
2023-06-08 14:09:50 +08:00
// 输入系统
[Header(Constant.Header.Input)]
2023-11-02 20:58:55 +08:00
[SerializeField] internal InputActionReference fireAction;
[SerializeField] internal InputActionReference aimAction;
[SerializeField] internal InputActionReference reloadAction;
[SerializeField] internal InputActionReference meleeAction;
[SerializeField] internal InputActionReference steadyAimAction;
2023-12-03 17:35:43 +08:00
[SerializeField] internal InputActionReference inspectAction;
2023-10-20 19:31:12 +08:00
[Header(Constant.Header.HotFix)]
[SerializeField] private Transform cameraView;
2023-06-08 14:09:50 +08:00
// 引用组件
[Header(Constant.Header.Components)]
2023-09-01 14:33:54 +08:00
[SerializeField] private LocationAdditive locationAdditive;
2023-11-15 23:54:54 +08:00
[SerializeField] private LocationAdditive selfViewAdditive;
2023-08-27 02:58:19 +08:00
2023-06-08 14:09:50 +08:00
// 引用预制体
[Header(Constant.Header.Prefabs)]
2023-08-23 01:59:40 +08:00
// 内部变量burst
2023-06-08 14:09:50 +08:00
[Header(Constant.Header.InternalVariables)]
2023-08-23 01:59:40 +08:00
public ExpectState<bool> expectFiring;
public ExpectState<bool> expectAiming;
internal readonly IntervalUpdate fireInterval = new(0.32f);
internal readonly IntervalUpdate burstFireInterval = new(0.1f);
2023-06-08 14:09:50 +08:00
internal int burstFireCount;
2023-10-20 19:31:12 +08:00
[Inject]
2023-09-01 14:33:54 +08:00
private IEntityMovement _movement;
2023-10-20 19:31:12 +08:00
[Inject]
2023-09-01 14:33:54 +08:00
private IPlayerMovement _playerMovement;
2023-10-20 19:31:12 +08:00
[Inject]
private IHealth _health;
2023-10-31 18:07:15 +08:00
[Inject] private IEquipService _equipService;
2023-12-03 17:35:43 +08:00
2023-11-30 00:23:23 +08:00
internal AssetableGun _gun=>item as AssetableGun;
2023-11-02 20:58:55 +08:00
private bool isSteadyAim;
2023-12-03 17:35:43 +08:00
private readonly DoubleBuffer<int> cacheRounds = new();
2023-10-20 19:31:12 +08:00
2023-12-15 00:08:02 +08:00
private readonly Optional<Vector3> _fixAimPosition = new();
2023-10-31 18:07:15 +08:00
public bool RequireBolt { get; set; }
2023-06-08 14:09:50 +08:00
#region
2023-10-31 18:07:15 +08:00
public override string AddressablePath => _gun.AddressablePath;
2023-06-08 14:09:50 +08:00
#endregion
2023-11-15 23:54:54 +08:00
2024-03-24 02:05:16 +08:00
private LinearMixerState walkState;
private AnimancerState jumpState;
2023-08-23 01:59:40 +08:00
public override void OnAwake()
{
base.OnAwake();
2024-03-24 02:05:16 +08:00
AnimancerComponent.Layers[3].IsAdditive = true;
AnimancerComponent.Layers[2].IsAdditive = true;
AnimancerComponent.Layers[4].IsAdditive = true;
2024-03-23 18:07:54 +08:00
2023-11-15 23:54:54 +08:00
if (breathingAdditive.Allow)
inputActionGroup.RegisterCallback(steadyAimAction, OnSteadyAim);
2024-03-24 02:05:16 +08:00
2023-12-03 17:35:43 +08:00
2023-11-15 23:54:54 +08:00
BITAppForUnity.AllowCursor.AddListener(OnAllowCursor);
2023-12-03 17:35:43 +08:00
destroyCancellationToken.Register(() => { BITAppForUnity.AllowCursor.RemoveListener(OnAllowCursor); });
}
2023-11-15 23:54:54 +08:00
private void OnAllowCursor(bool allow)
{
if (!allow) return;
expectFiring.Reset();
expectAiming.Reset();
2023-09-01 14:33:54 +08:00
}
2023-11-02 20:58:55 +08:00
private void OnSteadyAim(InputAction.CallbackContext obj)
{
switch (obj)
{
case { interaction: PressInteraction, performed: true } when CurrentState is Aim:
isSteadyAim = true;
break;
case { interaction: PressInteraction, canceled: true }:
isSteadyAim = false;
break;
}
}
2024-03-24 02:05:16 +08:00
private void OnMovementCommand(object obj)
{
switch (obj)
{
case OnPlayerJumpCommand when
MotionMatchingService.TryMatch(out var jump ,SearchKey.Append("Jump").ToArray())
&& jump is IMotionMatchingClip jumpMotion
:
jumpState?.Stop();
jumpState = AnimancerComponent.Layers[4].Play(jumpMotion.Clip);
break;
case OnPlayerLandCommand when
MotionMatchingService.TryMatch(out var land ,SearchKey.Append("Land").ToArray())
&& land is IMotionMatchingClip landMotion
:
jumpState?.Stop();
jumpState = AnimancerComponent.Layers[4].Play(landMotion.Clip,0.1f);
jumpState.Events.OnEnd = () =>
{
jumpState.Events.OnEnd = null;
jumpState.StartFade(0);
};
break;
}
}
2023-08-23 01:59:40 +08:00
2023-08-27 02:58:19 +08:00
private void OnMelee(InputAction.CallbackContext obj)
{
switch (CurrentState)
{
case Equip:
case Melee:
return;
}
TransitionState<Melee>();
}
2023-08-23 01:59:40 +08:00
private void OnReload(InputAction.CallbackContext obj)
{
2023-08-27 02:58:19 +08:00
if (obj.JustPressed() is false) return;
switch (CurrentState)
{
case Equip:
case Melee:
return;
}
2023-12-03 17:35:43 +08:00
if (Item?.TryGetProperty<IClip>(out var clip) is false)
{
_uxPopup?.Popup("<color=yellow>机匣损坏或不存在</color>");
return;
}
if (_inventory.TryGetItem(IsClipReady, out var clipItem) is false)
{
_uxPopup?.Popup("<color=yellow>没有兼容的弹夹</color>");
return;
}
2023-08-23 01:59:40 +08:00
TransitionState<Reload>();
}
2023-06-08 14:09:50 +08:00
2023-11-30 00:23:23 +08:00
public override void Entry()
{
base.Entry();
_movement.ExecuteCommand(new PlayerLimitMoveSpeedCommand()
{
Id = BITHash.Player.Equip,
Limit = true,
Speed = _gun.InitialMovementSpeed
});
inputActionGroup.RegisterCallback(fireAction, OnFire);
inputActionGroup.RegisterCallback(aimAction, OnAim);
inputActionGroup.RegisterCallback(reloadAction, OnReload);
inputActionGroup.RegisterCallback(meleeAction, OnMelee);
2024-03-23 18:07:54 +08:00
TransitionState<Equip>();
2024-03-24 02:05:16 +08:00
if (MotionMatchingService.TryMatch(out var walkMotion, SearchKey.Append(BITConstant.Player.Walk).ToArray())
&&
MotionMatchingService.TryMatch(out var movementMotion, SearchKey.Append(BITConstant.Player.Movement).ToArray()))
{
if (walkMotion is IMotionMatchingClip walkClip && movementMotion is IMotionMatchingClip movementClip)
{
walkState = new LinearMixerState
{
{ movementClip.Clip, 0 },
{ walkClip.Clip, 1 }
};
AnimancerComponent.Layers[2].Play(walkState);
//walkState = AnimancerComponent.Layers[2].Play(walkClip.Clip);
}
}
_movement.OnStateChanged += OnMovementStateChanged;
_movement.OnCommand += OnMovementCommand;
2023-11-30 00:23:23 +08:00
}
2023-12-03 17:35:43 +08:00
private bool IsClipReady(IBasicItem clip)
{
if(Item.TryGetProperty<IClip>(out var _clip) is false) return false;
if(clip.AddressablePath != _clip.AddressablePath) return false;
if(clip.TryGetProperty<IClip>(out var _clipItem) is false) return false;
return _clipItem.Remaining > 0;
}
2023-08-23 01:59:40 +08:00
private void OnMovementStateChanged(IEntityMovementState arg1, IEntityMovementState arg2)
{
2023-11-30 00:23:23 +08:00
if (IsEntered is false) return;
2023-08-23 01:59:40 +08:00
foreach (var x in StateDictionary.Values)
{
x.OnMovementStateChanged(arg1,arg2);
}
}
2023-12-03 17:35:43 +08:00
public override void Exit()
{
base.Exit();
if (Item.TryGetProperty<IClip>(out var clip) && cacheRounds.TryGetRelease(out var rounds))
{
clip.Remaining = rounds;
}
cacheRounds.Clear();
inputActionGroup.UnRegisterCallback(fireAction, OnFire);
inputActionGroup.UnRegisterCallback(aimAction, OnAim);
inputActionGroup.UnRegisterCallback(reloadAction, OnReload);
inputActionGroup.UnRegisterCallback(meleeAction, OnMelee);
2024-03-24 02:05:16 +08:00
_movement.OnStateChanged -= OnMovementStateChanged;
_movement.OnCommand -= OnMovementCommand;
2023-12-03 17:35:43 +08:00
}
2023-10-20 19:31:12 +08:00
public override UniTask EntryAsync()
2023-06-08 14:09:50 +08:00
{
2023-10-20 19:31:12 +08:00
base.EntryAsync();
2023-08-23 01:59:40 +08:00
expectFiring.Reset();
Enabled = true;
2023-06-08 14:09:50 +08:00
2023-10-31 18:07:15 +08:00
fireInterval.Interval = 1f / _gun.FireMode.FireRate;
2023-08-23 01:59:40 +08:00
fireInterval.Reset();
2023-06-08 14:09:50 +08:00
2023-10-31 18:07:15 +08:00
if (_gun.FireMode is BurstFireMode burstFireMode)
2023-06-08 14:09:50 +08:00
{
2023-08-23 01:59:40 +08:00
burstFireInterval.Interval = burstFireMode.BurstFireInterval;
burstFireInterval.Reset();
2023-06-08 14:09:50 +08:00
}
2023-10-20 19:31:12 +08:00
TransitionState<Equip>();
return UniTask.CompletedTask;
2023-06-08 14:09:50 +08:00
}
2023-10-20 19:31:12 +08:00
public override async UniTask ExitAsync()
2023-06-08 14:09:50 +08:00
{
2023-10-20 19:31:12 +08:00
TransitionState<Holster>();
2023-10-31 18:07:15 +08:00
2023-11-30 00:23:23 +08:00
_movement.ExecuteCommand(new PlayerFocusCommand()
{
Focus = false,
Sender = this
});
2023-10-31 18:07:15 +08:00
_equipService.AllowAttack = false;
//inputActionGroup.allowInput.RemoveElement(this);
2023-10-20 19:31:12 +08:00
expectFiring.Reset();
cameraView.localPosition = default;
try
{
2024-03-23 18:07:54 +08:00
while (_health.IsAlive && AnimancerComponent.IsPlaying())
2023-10-20 19:31:12 +08:00
{
destroyCancellationToken.ThrowIfCancellationRequested();
2023-10-31 18:07:15 +08:00
_equipService.Zoom.Value = Mathf.MoveTowards(_equipService.Zoom.Value,0,Time.deltaTime);
2023-10-20 19:31:12 +08:00
await UniTask.NextFrame();
}
2023-10-31 18:07:15 +08:00
_equipService.Zoom.Allow = false;
2023-10-20 19:31:12 +08:00
destroyCancellationToken.ThrowIfCancellationRequested();
2023-10-31 18:07:15 +08:00
_equipService.Stable = 1;
2023-10-20 19:31:12 +08:00
await base.ExitAsync();
}
catch (OperationCanceledException)
2023-06-08 14:09:50 +08:00
{
}
}
2023-11-30 00:23:23 +08:00
public override void Exited()
{
base.Exited();
_movement.ExecuteCommand(new PlayerLimitMoveSpeedCommand()
{
Id = BITHash.Player.Equip,
Limit = false,
Speed = _gun.InitialMovementSpeed
});
}
2023-06-08 14:09:50 +08:00
public override void OnUpdate(float deltaTime)
{
2024-03-12 21:54:29 +08:00
base.OnUpdate(deltaTime);
2023-10-20 19:31:12 +08:00
UpdateState(deltaTime);
2023-10-31 18:07:15 +08:00
switch (_gun.FireMode)
2023-06-08 14:09:50 +08:00
{
2023-08-27 02:58:19 +08:00
case AutoFireMode:
break;
case SemiFireMode:
break;
case BurstFireMode when expectFiring.being:
expectFiring.shouldBe = fireAction.action.WasPressedThisFrame();
if(burstFireInterval.AllowUpdate)
{
2023-10-31 18:07:15 +08:00
switch (AnimationProperties.TryGetValue(BITConstant.Player.AllowFire, out var allowFire))
{
case false:
case true when allowFire >0.9f:
Fire();
break;
}
2023-08-27 02:58:19 +08:00
}
break;
2023-06-08 14:09:50 +08:00
}
2023-11-30 00:23:23 +08:00
_movement.ExecuteCommand(new PlayerFocusCommand()
{
Focus = recoilSpring.value.GetLength() > 0.1f,
Sender = this
});
if(AnimationProperties.TryGetValue(BITConstant.Player.Aim, out var __aim))
{
2024-03-23 18:07:54 +08:00
//animator.animator.SetFloat((int)BITHash.Player.Aim,__aim);
}
2024-03-23 18:07:54 +08:00
2024-01-27 04:09:57 +08:00
var length = _movement.GroundVelocity.GetLength();
2024-03-23 18:07:54 +08:00
// animator.animator.SetFloat(BITConstant.Player.SqrMagnitude,
// Mathf.Clamp(
// length / _movement.ReferenceSpeed,0.1f,1
// )
// );
2024-03-24 02:05:16 +08:00
if (walkState is not null)
{
var value = Mathf.Clamp(
length / _movement.ReferenceSpeed, 0, 1
);
walkState.Parameter = value;
}
2023-10-20 19:31:12 +08:00
2023-09-01 14:33:54 +08:00
recoilSpring.Update(deltaTime,default);
2023-11-30 00:23:23 +08:00
2024-03-24 02:05:16 +08:00
if (_gun.TryGetProperty<IRecoil>(out var recoil) && locationAdditive)
2023-11-30 00:23:23 +08:00
{
2024-02-21 01:40:53 +08:00
//locationAdditive.AddEuler(Vector3.Scale(recoilSpring.value,recoil.ViewRecoilScale) );
locationAdditive.AddRotation(Quaternion.Euler(Vector3.Scale(recoilSpring.value,recoil.ViewRecoilScale)));
2023-11-30 00:23:23 +08:00
}
2023-11-15 23:54:54 +08:00
if (selfViewAdditive)
{
2023-11-21 18:05:18 +08:00
var positionWeight = recoilPositionWeight;
if (AnimationProperties.TryGetValue(BITConstant.Player.Aim, out var aim))
{
positionWeight *= Mathf.Lerp(2, 1, aim);
}
2024-02-21 01:40:53 +08:00
//selfViewAdditive.AddEuler(recoilSpring.value);
selfViewAdditive.AddRotation(Quaternion.Euler(recoilSpring.value));
2023-11-15 23:54:54 +08:00
selfViewAdditive.AddPosition(
new Vector3(
recoilSpring.value.y,
-recoilSpring.value.x,
recoilSpring.value.z
) *
2023-11-21 18:05:18 +08:00
positionWeight
2023-11-15 23:54:54 +08:00
);
}
2023-10-31 18:07:15 +08:00
if(AnimationProperties.TryGetValue(BITConstant.Player.Aim, out var _aim))
{
_equipService.Zoom.Allow = CurrentState is Aim;
2023-11-02 20:58:55 +08:00
_equipService.Zoom.Value =Mathf.Lerp(1,_gun.InitialAimZoom, _aim);
2023-12-15 00:08:02 +08:00
_equipService.AllowScope = _aim > 0.5f && _gun.IsScopeAim;
2023-12-17 02:03:13 +08:00
_equipService.Aim = _aim;
2023-12-15 00:08:02 +08:00
2023-11-02 20:58:55 +08:00
if (breathingAdditive.Allow)
{
var breatheFrequency = 0.5f; // 呼吸的频率,值越大呼吸越快
var breatheAmplitude = 0.005f; // 呼吸的幅度,即准星上下移动的最大距离
if (_playerMovement.Stamina <= 8)
{
breatheFrequency = 8;
breatheAmplitude = 0.1f;
}
var breatheOffset = Mathf.Sin(Time.time * breatheFrequency) * breatheAmplitude;
if (isSteadyAim)
{
if (_playerMovement.Stamina > 0)
{
_playerMovement.Stamina -= 16 * deltaTime;
breatheOffset *= 0.16f;
}
else
{
isSteadyAim = false;
}
}
else
{
breatheOffset *= _aim;
}
_playerMovement.AddViewEuler(new float2(breatheOffset, breatheOffset));
}
if (newSight.Allow)
{
2023-12-15 00:08:02 +08:00
transform.localPosition = Vector3.Lerp(default, _fixAimPosition.Value, _aim);
2023-11-02 20:58:55 +08:00
}
else
{
transform.localPosition = default;
}
2023-10-31 18:07:15 +08:00
}
if (AnimationProperties.TryGetValue(BITConstant.Player.Stable, out var stable))
{
_equipService.Stable = stable;
}
if(AnimationProperties.TryGetValue(BITConstant.Player.AllowFire, out var _allowFire))
{
_equipService.AllowAttack = _allowFire > 0.9f;
}
2023-12-15 00:08:02 +08:00
//AllowRendering.SetDisableElements(64564,_equipService.AllowScope);
2023-11-15 23:54:54 +08:00
expectAiming.shouldBe = inputActionGroup.GetAction(aimAction).IsPressed();
2023-06-08 14:09:50 +08:00
}
2023-12-03 17:35:43 +08:00
2023-08-27 02:58:19 +08:00
public override void AnimationEvent(string eventName)
{
2023-12-03 17:35:43 +08:00
if (IsEntered is false) return;
2023-11-21 18:05:18 +08:00
base.AnimationEvent(eventName);
2023-08-27 02:58:19 +08:00
CurrentState?.AnimationEvent(eventName);
2023-12-03 17:35:43 +08:00
if (Item.TryGetProperty<IClip>(out var clip)
&& _inventory.TryGetItem(IsClipReady, out var clipItem)
&& clipItem.TryGetProperty<IClip>(out var nextClip)
)
switch (eventName)
{
case BITConstant.Player.EjectClip:
if(clip.Remaining <= 0) break;
cacheRounds.Release(clip.Remaining);
clip.Remaining = 0;
break;
case BITConstant.Player.InsertClip:
cacheRounds.TryGetRelease(out var current);
var newRound = nextClip.Remaining;
var swapClipClone = nextClip.Clone().As<IClip>();
var swapClip = clipItem.Clone().As<IBasicItem>();
swapClipClone.Remaining = current;
if (swapClip.TrySetProperty(swapClipClone) is false || _inventory.TrySetItem(swapClip) is false)
{
_uxPopup?.Popup("<color=yellow>弹匣回收失败</color>");
clip.Remaining = current;
break;
}
else
{
clip.Remaining = newRound;
}
// var newRound = Mathf.Clamp(current + nextClip.Remaining, 0,int.MaxValue);
//
// newRound = nextClip.Remaining;
//
// var newClipItem = clipItem.Clone() as IBasicItem;
// nextClip = nextClip.Clone().As<IClip>();
//
// if(newRound>clip.Capacity)
// {
// newRound = clip.Capacity;
// nextClip.Remaining = current + nextClip.Remaining - clip.Capacity;
// }
// else
// {
// nextClip.Remaining = 0;
// }
// if(newRound == 0)
// {
// _uxPopup?.Popup("<color=yellow>空弹匣</color>");
// break;
// }
//
// newClipItem!.TrySetProperty(nextClip);
//
// if (_inventory.TrySetItem(newClipItem))
// {
// clip.Remaining = newRound;
// }
// else
// {
// clip.Remaining = current;
// _uxPopup?.Popup("<color=yellow>弹匣回收失败</color>");
// }
break;
}
2023-08-27 02:58:19 +08:00
}
2023-12-03 17:35:43 +08:00
2023-06-08 14:09:50 +08:00
public void Fire()
{
2023-10-31 18:07:15 +08:00
if (RequireBolt) return;
2024-02-21 01:40:53 +08:00
var infiniteAmmo = Data.Get<int>(BITConstant.Environment.sv_infinite_ammo) is 1;
switch (Item.TryGetProperty<IClip>(out var clip))
2023-12-03 17:35:43 +08:00
{
2024-02-21 01:40:53 +08:00
case false:
case true when infiniteAmmo:
break;
case true when clip.Remaining >0:
2023-12-03 17:35:43 +08:00
clip.Remaining--;
2024-02-21 01:40:53 +08:00
break;
default:
return;
2023-12-03 17:35:43 +08:00
}
2024-02-21 01:40:53 +08:00
2023-06-08 14:09:50 +08:00
//播放射击动画
2024-03-23 18:07:54 +08:00
//UnityEntity.Invoke(Constant.Animation.Play, BITConstant.Player.Fire);
2023-06-08 14:09:50 +08:00
2024-03-24 02:05:16 +08:00
if (MotionMatchingService.TryMatch(out var motion, SearchKey.Append(
CurrentState is Aim ? BITConstant.Player.AimFire : BITConstant.Player.Fire
).ToArray()))
{
if (motion is IMotionMatchingClip fireClip)
{
AnimancerComponent.Layers[3].Stop();
var state =AnimancerComponent.Layers[3].Play(fireClip.Clip);
state.Events.OnEnd = () =>
{
state.Events.OnEnd = null;
};
}
}
2023-11-15 23:54:54 +08:00
if (_gun.BuckShot.Allow)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
InternalAddRecoil();
2024-01-27 04:09:57 +08:00
InternalFire(_gun.BuckShot.Value);
// for (int i = 0; i < _gun.BuckShot.Value; i++)
// {
//
// }
2023-11-15 23:54:54 +08:00
}
else
{
InternalFire();
InternalAddRecoil();
}
2023-06-08 14:09:50 +08:00
//开火模式逻辑判断
2023-10-31 18:07:15 +08:00
switch (_gun.FireMode)
2023-06-08 14:09:50 +08:00
{
case AutoFireMode:
break;
case SemiFireMode:
//如果是半自动开火,则取消射击
2023-08-23 01:59:40 +08:00
expectFiring.Reset();
2023-06-08 14:09:50 +08:00
break;
case BurstFireMode burstFireMode:
burstFireCount++;
2023-08-23 01:59:40 +08:00
expectFiring.being = true;
2023-06-08 14:09:50 +08:00
if(burstFireCount > burstFireMode.BurstRound)
{
burstFireCount = 0;
2023-08-23 01:59:40 +08:00
expectFiring.Reset();
2023-06-08 14:09:50 +08:00
}
break;
}
2023-11-15 23:54:54 +08:00
if (_gun.FireMode is SemiFireMode {RequireBoltAction:true})
{
RequireBolt = true;
}
}
2024-01-27 04:09:57 +08:00
private void InternalFire(int count = 1)
2023-11-15 23:54:54 +08:00
{
//调用BulletManager生成子弹
var _transform = transform;
2023-11-30 00:23:23 +08:00
var rotation =_movement.ViewRotation;
var position = _movement.Position;
position.y = _transform.position.y;
2024-01-27 04:09:57 +08:00
var fireRecoil = Vector2.one;
2023-11-15 23:54:54 +08:00
if (_gun.TryGetProperty<ISpread>(out var spread))
{
2024-01-27 04:09:57 +08:00
fireRecoil *= spread.Spread;
2023-11-15 23:54:54 +08:00
}
2023-11-21 18:05:18 +08:00
if(AnimationProperties.TryGetValue(BITConstant.Player.Aim, out var aim))
{
2024-01-27 04:09:57 +08:00
fireRecoil *= Mathf.Lerp(_gun.InitialHipFireSpread,1,aim);
}
fireRecoil *= recoilSpring.value.GetLength();
var length = fireRecoil.GetLength();
for (var i = 0; i < count; i++)
{
float angle = i * 2 * Mathf.PI / count;
float x = length * Mathf.Cos(angle);
float y = length * Mathf.Sin(angle);
Vector2 point = new Vector2(x, y);
BulletService.Spawn(new SpawnBullet
{
Token = Token,
Initiator = Entity.Id,
//Position = (_transform.position+rotation * bulletInitialOffset),
//Rotation = rotation,
Position = position,
Rotation = rotation,
Forward = rotation * (Vector3.forward + Vector3.up * point.y + Vector3.right * point.x),
InitialDamage = _gun.InitialDamage,
StartSpeed = _gun.InitialBulletSpeed,
InitialForce = _gun.InitialBulletForce,
});
2023-11-21 18:05:18 +08:00
}
2023-11-15 23:54:54 +08:00
}
private void InternalAddRecoil()
{
2023-10-31 18:07:15 +08:00
if (_gun.TryGetProperty<IRecoil>(out var _recoil))
2023-09-01 14:33:54 +08:00
{
var _newRecoil = new Vector3
{
x = _recoil.Recoil.x,
y = _recoil.Recoil.y.Random(),
z = _recoil.Recoil.z.Random()
};
recoilSpring.value = _newRecoil;
_playerMovement.AddViewEuler(new float2(_newRecoil.x,_newRecoil.y));
}
2023-06-08 14:09:50 +08:00
}
2023-08-23 01:59:40 +08:00
private void OnFire(InputAction.CallbackContext context)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
//如果启用了指针则不开火
if(BITAppForUnity.AllowCursor)
{
expectFiring.Reset();
return;
}
2023-10-31 18:07:15 +08:00
switch (_gun.FireMode)
2023-10-24 23:37:59 +08:00
{
case AutoFireMode :
switch (context)
{
2023-11-02 20:58:55 +08:00
case {interaction:PressInteraction , started:true}:
2023-10-24 23:37:59 +08:00
expectFiring.shouldBe = true;
break;
2023-11-02 20:58:55 +08:00
case {interaction:PressInteraction , canceled:true}:
2023-10-24 23:37:59 +08:00
expectFiring.shouldBe = false;
break;
}
break;
case SemiFireMode:
switch (context)
{
2023-11-02 20:58:55 +08:00
case { interaction: PressInteraction, started: true } when fireInterval.AllowUpdateWithoutReset && RequireBolt is false:
2023-10-24 23:37:59 +08:00
expectFiring.shouldBe = true;
break;
}
break;
}
2023-06-08 14:09:50 +08:00
}
2023-08-23 01:59:40 +08:00
private void OnAim(InputAction.CallbackContext context)
2023-06-08 14:09:50 +08:00
{
2023-11-15 23:54:54 +08:00
//如果启用了指针则不开火
if(BITAppForUnity.AllowCursor)
{
expectAiming.Reset();
return;
}
//expectAiming.shouldBe = context.ReadValueAsButton();
2023-06-08 14:09:50 +08:00
}
2023-12-15 00:08:02 +08:00
protected override void OnItemApplied(IBasicItem item)
{
base.OnItemApplied(item);
// var aim = GetComponentInChildren<GunControllerAimComponent>();
// newSight.Allow = aim;
// if (aim)
// {
// newSight.Value = aim.transform;
// var initialSightPos = Transform.InverseTransformVector(initialSight.position);
// var newSightPos = Transform.InverseTransformVector(newSight.Value.position);
// _fixAimPosition.SetValueThenAllow( (newSightPos.y -initialSightPos.y) * Vector3.up);
// }
// else
// {
// _fixAimPosition.Clear();
// }
2023-12-15 00:08:02 +08:00
}
2023-06-08 14:09:50 +08:00
}
2023-11-15 23:54:54 +08:00
// #if UNITY_EDITOR
// [CustomEditor(typeof(BITGun))]
// public class BITGunInspector:BITInspector<BITGun>{}
// #endif
2023-06-08 14:09:50 +08:00
}