211 lines
4.9 KiB
C#
211 lines
4.9 KiB
C#
using System.Collections.Generic;
|
||
using DragonLi.Core;
|
||
using Knife.Effects.SimpleController;
|
||
using UnityEngine;
|
||
|
||
/// <summary>
|
||
/// PlayerHands(永远不会空手版)
|
||
/// </summary>
|
||
public class PlayerHands : MonoBehaviour
|
||
{
|
||
[Header("所有武器预制体(0 号为初始武器)")]
|
||
public GameObject[] WeaponsObjects;
|
||
|
||
[SerializeField] private Player player;
|
||
public WeaponSelector weaponSelector;
|
||
public int[] Indices;
|
||
|
||
private IWeapon[] weapons;
|
||
|
||
/// <summary>
|
||
/// 当前已拥有的武器(存数组下标,永远至少包含 0)
|
||
/// </summary>
|
||
private readonly List<int> available = new List<int>();
|
||
|
||
/// <summary>
|
||
/// available 列表中的当前位置
|
||
/// </summary>
|
||
private int currentIdx = 0;
|
||
|
||
#region Unity
|
||
|
||
private void Start()
|
||
{
|
||
int count = WeaponsObjects.Length;
|
||
weapons = new IWeapon[count];
|
||
|
||
for (int i = 0; i < count; i++)
|
||
{
|
||
weapons[i] = WeaponsObjects[i].GetComponent<IWeapon>();
|
||
|
||
var w = WeaponsObjects[i].GetComponent<Weapon>();
|
||
if (w != null)
|
||
w.weaponId = i + 1;
|
||
|
||
WeaponsObjects[i].SetActive(false);
|
||
}
|
||
|
||
// 🔒 初始化:永远拥有 0 号武器
|
||
available.Clear();
|
||
available.Add(0);
|
||
currentIdx = 0;
|
||
ActivateWeapon(0);
|
||
|
||
Weapon.OnAmmoDepleted += OnAmmoDepleted;
|
||
|
||
if (weaponSelector != null)
|
||
weaponSelector.OnSelectedEvent += OnWeaponSelected;
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
Weapon.OnAmmoDepleted -= OnAmmoDepleted;
|
||
|
||
if (weaponSelector != null)
|
||
weaponSelector.OnSelectedEvent -= OnWeaponSelected;
|
||
|
||
foreach (var w in weapons)
|
||
if (w != null)
|
||
w.OnFire -= OnFire;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 切换接口(滚轮 / 摇杆 / UI)
|
||
|
||
public void SwitchNext()
|
||
{
|
||
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);
|
||
}
|
||
|
||
public void OnWeaponSelected(int selectorIndex)
|
||
{
|
||
if (Indices == null) return;
|
||
|
||
for (int i = 0; i < Indices.Length; i++)
|
||
{
|
||
if (Indices[i] == selectorIndex)
|
||
{
|
||
int listPos = available.IndexOf(i);
|
||
if (listPos >= 0)
|
||
SwitchByListIndex(listPos);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 拾取
|
||
|
||
public void PickUpAndSwitchTo(int weaponIndex, int ammo)
|
||
{
|
||
weaponIndex -= 1;
|
||
if (weaponIndex <= 0 || weaponIndex >= WeaponsObjects.Length)
|
||
return;
|
||
|
||
if (!available.Contains(weaponIndex))
|
||
available.Add(weaponIndex);
|
||
|
||
var w = WeaponsObjects[weaponIndex].GetComponent<Weapon>();
|
||
if (w != null)
|
||
w.PickUpWeapon(w.weaponId, ammo);
|
||
|
||
SwitchByListIndex(available.IndexOf(weaponIndex));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 核心切换逻辑
|
||
|
||
private void SwitchByListIndex(int listIdx)
|
||
{
|
||
if (listIdx < 0 || listIdx >= available.Count)
|
||
return;
|
||
|
||
int newIndex = available[listIdx];
|
||
int oldIndex = available[currentIdx];
|
||
|
||
if (newIndex == oldIndex)
|
||
return;
|
||
|
||
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)
|
||
{
|
||
// 优先切到前一把,否则切 0
|
||
int nextListPos = Mathf.Clamp(listPos - 1, 0, available.Count - 1);
|
||
currentIdx = nextListPos;
|
||
ActivateWeapon(available[currentIdx]);
|
||
}
|
||
else if (listPos < currentIdx)
|
||
{
|
||
currentIdx--;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 后坐力
|
||
|
||
private void OnFire(Vector2 recoil)
|
||
{
|
||
player?.ApplyRecoil(recoil);
|
||
}
|
||
|
||
#endregion
|
||
}
|