fix:调整未来战警枪械消失问题

This commit is contained in:
bzx
2026-01-26 12:16:11 +08:00
parent f601114343
commit 8e96f09fb3

View File

@ -1,235 +1,210 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using DragonLi.Core;
using Knife.Effects.SimpleController;
using UnityEngine;
/// <summary>
/// 管理玩家手部武器:
/// - 拾取后加入可用列表并切换;
/// - 弹尽后自动移除、切回初始武器;
/// - 滚轮/摇杆循环切换。
/// 已去除相机 FOV 同步(与瞄准放大无关),并优化了字典查找与数组长度缓存,减少循环与属性访问开销。
/// PlayerHands永远不会空手版
/// </summary>
public class PlayerHands : MonoBehaviour
{
[Header("所有武器预置(含初始武器 + 可捡起武器0号为初始武器")]
[Header("所有武器预制体0 号为初始武器")]
public GameObject[] WeaponsObjects;
public int[] Indices; // 可选UI 圆环选择器索引
public WeaponSelector weaponSelector; // 可选UI 武器选择器事件源
[SerializeField] private Player player; // 用于后坐力回调
private IWeapon[] weapons; // 缓存的 IWeapon 组件
private List<int> idToIndex; // weaponId -> WeaponsObjects 下标
[SerializeField] private Player player;
public WeaponSelector weaponSelector;
public int[] Indices;
// “当前已拾取并可用”列表里存的是真实数组下标
private List<int> availableWeaponIndices = new List<int>();
private int currentAvailableListIndex = -1;
private IWeapon[] weapons;
void Start()
/// <summary>
/// 当前已拥有的武器(存数组下标,永远至少包含 0
/// </summary>
private readonly List<int> available = new List<int>();
/// <summary>
/// available 列表中的当前位置
/// </summary>
private int currentIdx = 0;
#region Unity
private void Start()
{
int weaponCount = WeaponsObjects.Length;
weapons = new IWeapon[weaponCount];
int count = WeaponsObjects.Length;
weapons = new IWeapon[count];
// 构建 weaponId→数组下标 的字典
idToIndex = new List<int>(weaponCount);
for (int i = 0; i < weaponCount; i++)
for (int i = 0; i < count; i++)
{
weapons[i] = WeaponsObjects[i].GetComponent<IWeapon>();
// 只要实现 IWeapon就取它的 weaponId向下转型
var w = WeaponsObjects[i].GetComponent<Weapon>();
w.weaponId = i+1;
if (w != null && !idToIndex.Contains(w.weaponId))
idToIndex.Add(w.weaponId);
// 初始全部隐藏
weapons[i].SetActive(false);
var w = WeaponsObjects[i].GetComponent<Weapon>();
if (w != null)
w.weaponId = i + 1;
WeaponsObjects[i].SetActive(false);
}
// ——————————————————————————————
// 把索引 0 号初始武器加入可用列表并激活
availableWeaponIndices.Clear();
availableWeaponIndices.Add(0);
currentAvailableListIndex = 0;
weapons[0].SetActive(true);
weapons[0].OnFire += OnFire;
// ——————————————————————————————
// 🔒 初始化:永远拥有 0 号武器
available.Clear();
available.Add(0);
currentIdx = 0;
ActivateWeapon(0);
Weapon.OnAmmoDepleted += OnAmmoDepleted;
// 注册 WeaponSelector 回调(若不需要可留空)
if (weaponSelector != null)
weaponSelector.OnSelectedEvent += OnWeaponSelected;
// 监听弹尽事件
Weapon.OnAmmoDepleted += HandleAmmoDepleted;
}
void OnDestroy()
private void OnDestroy()
{
Weapon.OnAmmoDepleted -= OnAmmoDepleted;
if (weaponSelector != null)
weaponSelector.OnSelectedEvent -= OnWeaponSelected;
Weapon.OnAmmoDepleted -= HandleAmmoDepleted;
// 卸载所有 OnFire 监听
foreach (var w in weapons)
{
if (w != null)
w.OnFire -= OnFire;
}
}
void Update()
#endregion
#region / / UI
public void SwitchNext()
{
// Editor 下用滚轮切换
#if UNITY_EDITOR
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll > 0f)
SwitchToNextAvailable();
else if (scroll < 0f)
SwitchToPreviousAvailable();
#endif
// VRPICO摇杆的切换由 Player 脚本里调用
if (available.Count <= 1) return;
int next = (currentIdx + 1) % available.Count;
SwitchByListIndex(next);
}
public void SwitchPrev()
{
if (available.Count <= 1) return;
int prev = (currentIdx - 1 + available.Count) % available.Count;
SwitchByListIndex(prev);
}
/// <summary>
/// UI 圆环选中时,传入 selectorIndex映射到 WeaponsObjects 下标后切换
/// </summary>
public void OnWeaponSelected(int selectorIndex)
{
if (Indices == null || Indices.Length == 0) return;
if (Indices == null) return;
int foundIdx = -1;
for (int i = 0, len = Indices.Length; i < len; i++)
for (int i = 0; i < Indices.Length; i++)
{
if (Indices[i] == selectorIndex)
{
foundIdx = i;
break;
int listPos = available.IndexOf(i);
if (listPos >= 0)
SwitchByListIndex(listPos);
return;
}
}
if (foundIdx < 0) return;
int listPos = availableWeaponIndices.IndexOf(foundIdx);
if (listPos >= 0)
DeployByAvailableListIndex(listPos);
}
/// <summary>
/// 切到下一个可用武器(循环)
/// </summary>
public void SwitchToNextAvailable()
#endregion
#region
public void PickUpAndSwitchTo(int weaponIndex, int ammo)
{
int count = availableWeaponIndices.Count;
if (count <= 1) return;
weaponIndex -= 1;
if (weaponIndex <= 0 || weaponIndex >= WeaponsObjects.Length)
return;
int next = (currentAvailableListIndex + 1) % count;
DeployByAvailableListIndex(next);
}
if (!available.Contains(weaponIndex))
available.Add(weaponIndex);
/// <summary>
/// 切到上一个可用武器(循环)
/// </summary>
public void SwitchToPreviousAvailable()
{
int count = availableWeaponIndices.Count;
if (count <= 1) return;
int prev = (currentAvailableListIndex - 1 + count) % count;
DeployByAvailableListIndex(prev);
}
/// <summary>
/// 内部:切换到 availableWeaponIndices[listIdx] 对应的武器
/// </summary>
private void DeployByAvailableListIndex(int listIdx)
{
int availCount = availableWeaponIndices.Count;
if (listIdx < 0 || listIdx >= availCount) return;
int weaponArrayIndex = availableWeaponIndices[listIdx];
// 如果已经就是这把,直接返回
int oldArrayIndex = availableWeaponIndices[currentAvailableListIndex];
if (weaponArrayIndex == oldArrayIndex) return;
// 停掉旧武器
weapons[oldArrayIndex].OnFire -= OnFire;
weapons[oldArrayIndex].SetActive(false);
// 激活新武器
currentAvailableListIndex = listIdx;
weapons[weaponArrayIndex].OnFire += OnFire;
weapons[weaponArrayIndex].SetActive(true);
Weapon curPlayerWeapon = WeaponsObjects[weaponArrayIndex].GetComponent<Weapon>();
EventDispatcher.TriggerEvent("ChangeWeaponIcon",(PlayerWeaponType)weaponArrayIndex,curPlayerWeapon.bulletsLeft);
}
/// <summary>
/// 玩家捡到武器道具时调用:
/// 1. 将 weaponArrayIndex 加入可用列表(若尚未存在);
/// 2. 给它加 ammoCount 子弹;
/// 3. 切到它。
/// </summary>
public void PickUpAndSwitchTo(int weaponArrayIndex, int ammoCount)
{
weaponArrayIndex -= 1;
int maxIdx = WeaponsObjects.Length - 1;
if (weaponArrayIndex < 0 || weaponArrayIndex > maxIdx) return;
// 1. 加入可用列表(若没在里头)
if (!availableWeaponIndices.Contains(weaponArrayIndex))
availableWeaponIndices.Add(weaponArrayIndex);
// 2. 给这一把上弹
var w = WeaponsObjects[weaponArrayIndex].GetComponent<Weapon>();
var w = WeaponsObjects[weaponIndex].GetComponent<Weapon>();
if (w != null)
w.PickUpWeapon(w.weaponId, ammoCount);
w.PickUpWeapon(w.weaponId, ammo);
// 3. 切换到这一把
int listPos = availableWeaponIndices.IndexOf(weaponArrayIndex);
DeployByAvailableListIndex(listPos);
SwitchByListIndex(available.IndexOf(weaponIndex));
}
/// <summary>
/// 监听 Weapon.OnAmmoDepleted(weaponId) 事件,移除对应武器并自动切回 0 号
/// </summary>
private void HandleAmmoDepleted(int weaponId)
#endregion
#region
private void SwitchByListIndex(int listIdx)
{
int weaponArrayIndex = weaponId-1;
if (!idToIndex.Contains(weaponArrayIndex)) return;
if (listIdx < 0 || listIdx >= available.Count)
return;
int listPos = availableWeaponIndices.IndexOf(weaponArrayIndex);
if (listPos < 0) return;
int newIndex = available[listIdx];
int oldIndex = available[currentIdx];
availableWeaponIndices.RemoveAt(listPos);
if (newIndex == oldIndex)
return;
// 如果移除的正是当前持有的武器,切回 0 号
if (listPos == currentAvailableListIndex)
DeactivateWeapon(oldIndex);
currentIdx = listIdx;
ActivateWeapon(newIndex);
}
private void ActivateWeapon(int index)
{
weapons[index].OnFire += OnFire;
WeaponsObjects[index].SetActive(true);
var w = WeaponsObjects[index].GetComponent<Weapon>();
EventDispatcher.TriggerEvent(
"ChangeWeaponIcon",
(PlayerWeaponType)index,
w != null ? w.bulletsLeft : 0
);
}
private void DeactivateWeapon(int index)
{
weapons[index].OnFire -= OnFire;
WeaponsObjects[index].SetActive(false);
}
#endregion
#region
private void OnAmmoDepleted(int weaponId)
{
int index = weaponId - 1;
// 🔒 初始武器永不移除
if (index <= 0)
return;
int listPos = available.IndexOf(index);
if (listPos < 0)
return;
bool wasCurrent = (listPos == currentIdx);
available.RemoveAt(listPos);
DeactivateWeapon(index);
if (wasCurrent)
{
weapons[weaponArrayIndex].OnFire -= OnFire;
weapons[weaponArrayIndex].SetActive(false);
// 确保 0 号在列表里
if (!availableWeaponIndices.Contains(0))
availableWeaponIndices.Insert(0, 0);
currentAvailableListIndex = availableWeaponIndices.IndexOf(0);
weapons[0].SetActive(true);
weapons[0].OnFire += OnFire;
// 优先切到前一把,否则切 0
int nextListPos = Mathf.Clamp(listPos - 1, 0, available.Count - 1);
currentIdx = nextListPos;
ActivateWeapon(available[currentIdx]);
}
else if (listPos < currentAvailableListIndex)
else if (listPos < currentIdx)
{
// 若移除的索引小于当前索引要减 1
currentAvailableListIndex--;
currentIdx--;
}
}
/// <summary>
/// 武器开火时的后坐力回调,将 recoilDelta 传给 Player
/// </summary>
private void OnFire(Vector2 recoilDelta)
#endregion
#region
private void OnFire(Vector2 recoil)
{
if (player != null)
player.ApplyRecoil(recoilDelta);
player?.ApplyRecoil(recoil);
}
#endregion
}