- Added DownDash ability with cooldown and speed configuration. - Introduced DownDashState to handle down dashing mechanics, including gravity manipulation and animation playback. - Updated PlayerMovement to support DownDash functionality. - Enhanced PlayerStats to manage spring charge consumption and healing. - Modified PlayerCombat and WeaponHitBoxInstance to support new hit confirmation events. - Updated AbilityType to include new form types for character abilities. - Improved Gizmos for better visualization of enemy detection and attack ranges. - Added feedback systems for form switching in PlayerFeedback and IFeedbackPlayer. - Refactored combat and movement states to accommodate new abilities and ensure smooth transitions.
140 lines
5.4 KiB
C#
140 lines
5.4 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.Player
|
||
{
|
||
/// <summary>
|
||
/// 武器管理器。
|
||
/// 监听 FormController.OnFormChanged,依据当前形态切换 ActiveWeapon。
|
||
/// 支持护符 Override:护符调用 SetOverride() 临时替换特定形态的武器。
|
||
/// 架构 05_PlayerModule §7。
|
||
/// </summary>
|
||
public class WeaponManager : MonoBehaviour
|
||
{
|
||
[SerializeField] private FormController _formController;
|
||
[SerializeField] private WeaponSO _startingWeapon; // 无 FormController 时的回退武器
|
||
|
||
[Header("HitBox 挂载点")]
|
||
[Tooltip("武器 HitBox Prefab 实例化的父节点,应为 Player 层级下的 [WeaponSocket] 子节点。")]
|
||
[SerializeField] private Transform _weaponSocket;
|
||
|
||
public WeaponSO ActiveWeapon { get; private set; }
|
||
public WeaponHitBoxInstance ActiveHitBoxInstance { get; private set; }
|
||
|
||
public event Action<WeaponSO> OnWeaponChanged;
|
||
|
||
// 护符注入的武器覆盖:Key = FormSO.formId,Value = 替换武器(架构 05 §7)
|
||
private readonly Dictionary<string, WeaponSO> _overrides = new();
|
||
|
||
// 对象池:避免每次切换形态时 Instantiate/Destroy(Key = WeaponSO,Value = 已创建实例)
|
||
private readonly Dictionary<WeaponSO, WeaponHitBoxInstance> _hitBoxPool = new();
|
||
|
||
private void Awake()
|
||
{
|
||
if (_formController != null && _formController.CurrentForm != null)
|
||
ApplyWeapon(_formController.CurrentForm);
|
||
else if (_startingWeapon != null)
|
||
SetDirectWeapon(_startingWeapon);
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (_formController != null)
|
||
_formController.OnFormChanged += HandleFormChanged;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (_formController != null)
|
||
_formController.OnFormChanged -= HandleFormChanged;
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
// 若 FormController 在 Awake 时 CurrentForm 尚未初始化,在 Start 重试
|
||
if (ActiveWeapon == null && _formController != null && _formController.CurrentForm != null)
|
||
ApplyWeapon(_formController.CurrentForm);
|
||
else if (ActiveWeapon == null && _startingWeapon != null)
|
||
SetDirectWeapon(_startingWeapon);
|
||
}
|
||
|
||
// ── 内部切换 ───────────────────────────────────────────────────────────
|
||
|
||
private void HandleFormChanged() => ApplyWeapon(_formController.CurrentForm);
|
||
|
||
private void ApplyWeapon(FormSO form)
|
||
{
|
||
if (form == null) return;
|
||
WeaponSO next = _overrides.TryGetValue(form.formId, out var ov) ? ov : form.defaultWeapon;
|
||
if (next == ActiveWeapon) return;
|
||
SetDirectWeapon(next);
|
||
}
|
||
|
||
private void SetDirectWeapon(WeaponSO weapon)
|
||
{
|
||
// 归还旧实例到池(SetActive(false) 会触发 HitBox.OnDisable → Deactivate,自动关闭 Collider2D)
|
||
ActiveHitBoxInstance?.gameObject.SetActive(false);
|
||
|
||
ActiveWeapon = weapon;
|
||
ActiveHitBoxInstance = null;
|
||
|
||
if (weapon?.hitBoxPrefab != null && _weaponSocket != null)
|
||
{
|
||
if (!_hitBoxPool.TryGetValue(weapon, out var pooled) || pooled == null)
|
||
{
|
||
var go = Instantiate(weapon.hitBoxPrefab, _weaponSocket);
|
||
pooled = go.GetComponent<WeaponHitBoxInstance>();
|
||
_hitBoxPool[weapon] = pooled;
|
||
}
|
||
pooled.gameObject.SetActive(true);
|
||
ActiveHitBoxInstance = pooled;
|
||
}
|
||
|
||
// 通知订阅者(PlayerCombat 取消旧实例事件订阅,订阅新实例)
|
||
OnWeaponChanged?.Invoke(weapon);
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
foreach (var inst in _hitBoxPool.Values)
|
||
if (inst != null) Destroy(inst.gameObject);
|
||
_hitBoxPool.Clear();
|
||
}
|
||
|
||
// ── 护符 Override API(由 WeaponOverrideEffect 调用,架构 05 §7)──────
|
||
|
||
/// <summary>为指定形态设置武器覆盖。formId 为空 = 覆盖所有形态。</summary>
|
||
public void SetOverride(string formId, WeaponSO weapon)
|
||
{
|
||
if (string.IsNullOrEmpty(formId))
|
||
{
|
||
if (_formController != null)
|
||
foreach (var f in _formController.AllForms)
|
||
_overrides[f.formId] = weapon;
|
||
}
|
||
else
|
||
{
|
||
_overrides[formId] = weapon;
|
||
}
|
||
if (_formController?.CurrentForm != null)
|
||
ApplyWeapon(_formController.CurrentForm);
|
||
}
|
||
|
||
/// <summary>移除覆盖,恢复默认武器。formId 为空 = 移除所有形态覆盖。</summary>
|
||
public void ClearOverride(string formId)
|
||
{
|
||
if (string.IsNullOrEmpty(formId))
|
||
{
|
||
_overrides.Clear();
|
||
}
|
||
else
|
||
{
|
||
_overrides.Remove(formId);
|
||
}
|
||
if (_formController?.CurrentForm != null)
|
||
ApplyWeapon(_formController.CurrentForm);
|
||
}
|
||
}
|
||
}
|