236 lines
7.9 KiB
C#
236 lines
7.9 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using DragonLi.Core;
|
||
using Knife.Effects.SimpleController;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// 管理玩家手部武器:
|
||
/// - 拾取后加入可用列表并切换;
|
||
/// - 弹尽后自动移除、切回初始武器;
|
||
/// - 滚轮/摇杆循环切换。
|
||
/// 已去除相机 FOV 同步(与瞄准放大无关),并优化了字典查找与数组长度缓存,减少循环与属性访问开销。
|
||
/// </summary>
|
||
public class PlayerHands : MonoBehaviour
|
||
{
|
||
[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 下标
|
||
|
||
// “当前已拾取并可用”列表里存的是真实数组下标
|
||
private List<int> availableWeaponIndices = new List<int>();
|
||
private int currentAvailableListIndex = -1;
|
||
|
||
void Start()
|
||
{
|
||
int weaponCount = WeaponsObjects.Length;
|
||
weapons = new IWeapon[weaponCount];
|
||
|
||
// 构建 weaponId→数组下标 的字典
|
||
idToIndex = new List<int>(weaponCount);
|
||
for (int i = 0; i < weaponCount; 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);
|
||
}
|
||
|
||
// ——————————————————————————————
|
||
// 把索引 0 号初始武器加入可用列表并激活
|
||
availableWeaponIndices.Clear();
|
||
availableWeaponIndices.Add(0);
|
||
currentAvailableListIndex = 0;
|
||
weapons[0].SetActive(true);
|
||
weapons[0].OnFire += OnFire;
|
||
// ——————————————————————————————
|
||
|
||
// 注册 WeaponSelector 回调(若不需要可留空)
|
||
if (weaponSelector != null)
|
||
weaponSelector.OnSelectedEvent += OnWeaponSelected;
|
||
|
||
// 监听弹尽事件
|
||
Weapon.OnAmmoDepleted += HandleAmmoDepleted;
|
||
}
|
||
|
||
void OnDestroy()
|
||
{
|
||
if (weaponSelector != null)
|
||
weaponSelector.OnSelectedEvent -= OnWeaponSelected;
|
||
|
||
Weapon.OnAmmoDepleted -= HandleAmmoDepleted;
|
||
|
||
// 卸载所有 OnFire 监听
|
||
foreach (var w in weapons)
|
||
{
|
||
if (w != null)
|
||
w.OnFire -= OnFire;
|
||
}
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
// Editor 下用滚轮切换
|
||
#if UNITY_EDITOR
|
||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||
if (scroll > 0f)
|
||
SwitchToNextAvailable();
|
||
else if (scroll < 0f)
|
||
SwitchToPreviousAvailable();
|
||
#endif
|
||
// VR(PICO)摇杆的切换由 Player 脚本里调用
|
||
}
|
||
|
||
/// <summary>
|
||
/// UI 圆环选中时,传入 selectorIndex,映射到 WeaponsObjects 下标后切换
|
||
/// </summary>
|
||
public void OnWeaponSelected(int selectorIndex)
|
||
{
|
||
if (Indices == null || Indices.Length == 0) return;
|
||
|
||
int foundIdx = -1;
|
||
for (int i = 0, len = Indices.Length; i < len; i++)
|
||
{
|
||
if (Indices[i] == selectorIndex)
|
||
{
|
||
foundIdx = i;
|
||
break;
|
||
}
|
||
}
|
||
if (foundIdx < 0) return;
|
||
|
||
int listPos = availableWeaponIndices.IndexOf(foundIdx);
|
||
if (listPos >= 0)
|
||
DeployByAvailableListIndex(listPos);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切到下一个可用武器(循环)
|
||
/// </summary>
|
||
public void SwitchToNextAvailable()
|
||
{
|
||
int count = availableWeaponIndices.Count;
|
||
if (count <= 1) return;
|
||
|
||
int next = (currentAvailableListIndex + 1) % count;
|
||
DeployByAvailableListIndex(next);
|
||
}
|
||
|
||
/// <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>();
|
||
if (w != null)
|
||
w.PickUpWeapon(w.weaponId, ammoCount);
|
||
|
||
// 3. 切换到这一把
|
||
int listPos = availableWeaponIndices.IndexOf(weaponArrayIndex);
|
||
DeployByAvailableListIndex(listPos);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 监听 Weapon.OnAmmoDepleted(weaponId) 事件,移除对应武器并自动切回 0 号
|
||
/// </summary>
|
||
private void HandleAmmoDepleted(int weaponId)
|
||
{
|
||
int weaponArrayIndex = weaponId-1;
|
||
if (!idToIndex.Contains(weaponArrayIndex)) return;
|
||
|
||
int listPos = availableWeaponIndices.IndexOf(weaponArrayIndex);
|
||
if (listPos < 0) return;
|
||
|
||
availableWeaponIndices.RemoveAt(listPos);
|
||
|
||
// 如果移除的正是当前持有的武器,切回 0 号
|
||
if (listPos == currentAvailableListIndex)
|
||
{
|
||
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;
|
||
}
|
||
else if (listPos < currentAvailableListIndex)
|
||
{
|
||
// 若移除的索引小于当前索引要减 1
|
||
currentAvailableListIndex--;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 武器开火时的后坐力回调,将 recoilDelta 传给 Player
|
||
/// </summary>
|
||
private void OnFire(Vector2 recoilDelta)
|
||
{
|
||
if (player != null)
|
||
player.ApplyRecoil(recoilDelta);
|
||
}
|
||
}
|