using System;
using System.Collections.Generic;
using DragonLi.Core;
using Knife.Effects.SimpleController;
using UnityEngine;
///
/// 管理玩家手部武器:
/// - 拾取后加入可用列表并切换;
/// - 弹尽后自动移除、切回初始武器;
/// - 滚轮/摇杆循环切换。
/// 已去除相机 FOV 同步(与瞄准放大无关),并优化了字典查找与数组长度缓存,减少循环与属性访问开销。
///
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 idToIndex; // weaponId -> WeaponsObjects 下标
// “当前已拾取并可用”列表里存的是真实数组下标
private List availableWeaponIndices = new List();
private int currentAvailableListIndex = -1;
void Start()
{
int weaponCount = WeaponsObjects.Length;
weapons = new IWeapon[weaponCount];
// 构建 weaponId→数组下标 的字典
idToIndex = new List(weaponCount);
for (int i = 0; i < weaponCount; i++)
{
weapons[i] = WeaponsObjects[i].GetComponent();
// 只要实现 IWeapon,就取它的 weaponId(向下转型)
var w = WeaponsObjects[i].GetComponent();
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 脚本里调用
}
///
/// UI 圆环选中时,传入 selectorIndex,映射到 WeaponsObjects 下标后切换
///
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);
}
///
/// 切到下一个可用武器(循环)
///
public void SwitchToNextAvailable()
{
int count = availableWeaponIndices.Count;
if (count <= 1) return;
int next = (currentAvailableListIndex + 1) % count;
DeployByAvailableListIndex(next);
}
///
/// 切到上一个可用武器(循环)
///
public void SwitchToPreviousAvailable()
{
int count = availableWeaponIndices.Count;
if (count <= 1) return;
int prev = (currentAvailableListIndex - 1 + count) % count;
DeployByAvailableListIndex(prev);
}
///
/// 内部:切换到 availableWeaponIndices[listIdx] 对应的武器
///
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();
EventDispatcher.TriggerEvent("ChangeWeaponIcon",(PlayerWeaponType)weaponArrayIndex,curPlayerWeapon.bulletsLeft);
}
///
/// 玩家捡到武器道具时调用:
/// 1. 将 weaponArrayIndex 加入可用列表(若尚未存在);
/// 2. 给它加 ammoCount 子弹;
/// 3. 切到它。
///
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();
if (w != null)
w.PickUpWeapon(w.weaponId, ammoCount);
// 3. 切换到这一把
int listPos = availableWeaponIndices.IndexOf(weaponArrayIndex);
DeployByAvailableListIndex(listPos);
}
///
/// 监听 Weapon.OnAmmoDepleted(weaponId) 事件,移除对应武器并自动切回 0 号
///
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--;
}
}
///
/// 武器开火时的后坐力回调,将 recoilDelta 传给 Player
///
private void OnFire(Vector2 recoilDelta)
{
if (player != null)
player.ApplyRecoil(recoilDelta);
}
}