fix:调整未来战警枪械消失问题
This commit is contained in:
@ -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
|
||||
// VR(PICO)摇杆的切换由 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user