多轮审查和修复
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using BaseGames.Core.Events;
|
||||
@@ -29,6 +30,7 @@ namespace BaseGames.Input
|
||||
public event Action SpiritSkill1CancelledEvent;
|
||||
public event Action SpiritSkill2StartedEvent;
|
||||
public event Action SpiritSkill2CancelledEvent;
|
||||
public event Action SpellCastEvent;
|
||||
public event Action InteractEvent;
|
||||
|
||||
// ── UI Events ─────────────────────────────────────────────────────────
|
||||
@@ -46,12 +48,45 @@ namespace BaseGames.Input
|
||||
private InputActionMap _ui;
|
||||
private bool _isBound;
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
if (_inputActions == null)
|
||||
{
|
||||
Debug.LogError("[InputReaderSO] _inputActions is NULL! Asset not assigned in inspector?");
|
||||
return;
|
||||
}
|
||||
|
||||
// Always disable first so the Input System tears down stale state,
|
||||
// then re-enable to create a fresh state for this Play session.
|
||||
_inputActions.Disable();
|
||||
_inputActions.Enable();
|
||||
|
||||
_gameplay = _inputActions.FindActionMap("Gameplay", throwIfNotFound: false);
|
||||
if (_gameplay == null)
|
||||
Debug.LogError("[InputReaderSO] Could not find 'Gameplay' action map in asset!");
|
||||
|
||||
_ui = _inputActions.FindActionMap("UI", throwIfNotFound: false);
|
||||
if (_ui == null)
|
||||
Debug.LogWarning("[InputReaderSO] Could not find 'UI' action map in asset!");
|
||||
|
||||
if (_gameplay != null && !_isBound)
|
||||
{
|
||||
|
||||
BindActions();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_inputActions == null) return;
|
||||
_gameplay = _inputActions.FindActionMap("Gameplay", throwIfNotFound: false);
|
||||
_ui = _inputActions.FindActionMap("UI", throwIfNotFound: false);
|
||||
BindActions();
|
||||
|
||||
// Reset private state on every OnEnable so stale ScriptableObject
|
||||
// references from a previous Play session don't cause
|
||||
// 'Map must be contained in state' errors.
|
||||
_gameplay = null;
|
||||
_ui = null;
|
||||
_isBound = false;
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
@@ -62,14 +97,60 @@ namespace BaseGames.Input
|
||||
}
|
||||
|
||||
// ── Action Map Switching ──────────────────────────────────────────────
|
||||
public void EnableGameplayInput() { _ui?.Disable(); _gameplay?.Enable(); }
|
||||
public void EnableUIInput() { _gameplay?.Disable(); _ui?.Enable(); }
|
||||
public void EnableGameplayInput()
|
||||
{
|
||||
// Disable UI map if it's active
|
||||
if (_ui != null && _ui.enabled)
|
||||
{
|
||||
|
||||
_ui.Disable();
|
||||
}
|
||||
|
||||
// Ensure gameplay map is enabled
|
||||
if (_gameplay != null && !_gameplay.enabled)
|
||||
{
|
||||
|
||||
_gameplay.Enable();
|
||||
}
|
||||
else if (_gameplay == null)
|
||||
{
|
||||
Debug.LogError("[InputReaderSO.EnableGameplayInput] _gameplay is NULL!");
|
||||
}
|
||||
}
|
||||
|
||||
public void EnableUIInput()
|
||||
{
|
||||
// Disable gameplay map if it's active
|
||||
if (_gameplay != null && _gameplay.enabled)
|
||||
{
|
||||
|
||||
_gameplay.Disable();
|
||||
}
|
||||
|
||||
// Ensure UI map is enabled
|
||||
if (_ui != null && !_ui.enabled)
|
||||
{
|
||||
|
||||
_ui.Enable();
|
||||
}
|
||||
else if (_ui == null)
|
||||
{
|
||||
Debug.LogWarning("[InputReaderSO.EnableUIInput] _ui is NULL!");
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableAllInput() { _gameplay?.Disable(); _ui?.Disable(); }
|
||||
|
||||
// ── Binding ───────────────────────────────────────────────────────────
|
||||
private void BindActions()
|
||||
{
|
||||
if (_gameplay == null || _isBound) return;
|
||||
if (_gameplay == null)
|
||||
{
|
||||
Debug.LogWarning("[InputReaderSO.BindActions] Skipped: _gameplay is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BindPerformed(_gameplay, "Move", ctx =>
|
||||
{
|
||||
@@ -98,7 +179,10 @@ namespace BaseGames.Input
|
||||
BindCanceled(_gameplay, "SpiritSkill1", () => SpiritSkill1CancelledEvent?.Invoke());
|
||||
BindStarted(_gameplay, "SpiritSkill2", () => SpiritSkill2StartedEvent?.Invoke());
|
||||
BindCanceled(_gameplay, "SpiritSkill2", () => SpiritSkill2CancelledEvent?.Invoke());
|
||||
BindStarted(_gameplay, "Spell", () => SpellCastEvent?.Invoke());
|
||||
BindStarted(_gameplay, "Interact", () => InteractEvent?.Invoke());
|
||||
|
||||
|
||||
BindStarted(_gameplay, "Pause", HandlePause);
|
||||
|
||||
if (_ui != null)
|
||||
@@ -116,14 +200,48 @@ namespace BaseGames.Input
|
||||
|
||||
private void HandlePause()
|
||||
{
|
||||
|
||||
|
||||
if (_onPauseRequested == null)
|
||||
{
|
||||
|
||||
_onPauseRequested = FindPauseChannelByName();
|
||||
if (_onPauseRequested == null)
|
||||
Debug.LogError("[InputReaderSO.HandlePause] Could not find EVT_PauseRequested asset!");
|
||||
}
|
||||
|
||||
|
||||
PauseEvent?.Invoke();
|
||||
|
||||
|
||||
_onPauseRequested?.Raise();
|
||||
}
|
||||
|
||||
private static VoidEventChannelSO FindPauseChannelByName()
|
||||
{
|
||||
VoidEventChannelSO[] channels = Resources.FindObjectsOfTypeAll<VoidEventChannelSO>();
|
||||
|
||||
foreach (VoidEventChannelSO channel in channels)
|
||||
{
|
||||
|
||||
if (channel != null && channel.name == "EVT_PauseRequested")
|
||||
return channel;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void BindStarted(InputActionMap map, string name, Action callback)
|
||||
{
|
||||
var action = map.FindAction(name, throwIfNotFound: false);
|
||||
if (action != null) action.started += _ => callback();
|
||||
if (action != null)
|
||||
{
|
||||
action.started += _ => callback();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[BindStarted] Action '{name}' not found in map");
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindPerformed(InputActionMap map, string name,
|
||||
@@ -145,5 +263,59 @@ namespace BaseGames.Input
|
||||
var action = map.FindAction(name, throwIfNotFound: false);
|
||||
if (action != null) action.canceled += _ => callback();
|
||||
}
|
||||
|
||||
// ── Rebinding API (P4-3) ──────────────────────────────────────────────
|
||||
|
||||
private const string PrefKey = "InputBindings";
|
||||
|
||||
/// <summary>查找单个 Action(供 RebindActionRow 显示当前绑定路径)。</summary>
|
||||
public InputAction FindAction(string name)
|
||||
=> _inputActions?.FindAction(name);
|
||||
|
||||
/// <summary>返回 Gameplay Map 所有 Action(供 ConflictDetector 扫描冲突)。</summary>
|
||||
public IEnumerable<InputAction> GetAllActionMap()
|
||||
{
|
||||
var map = _inputActions?.FindActionMap("Gameplay");
|
||||
return map != null ? (IEnumerable<InputAction>)map.actions : Array.Empty<InputAction>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动交互式重绑定(Unity InputSystem RebindingOperation)。
|
||||
/// 调用方无需持有返回值;完成或取消后自动 Dispose。
|
||||
/// </summary>
|
||||
public void StartRebinding(
|
||||
string actionName, int bindingIndex, Action onComplete, Action onCancel)
|
||||
{
|
||||
var action = _inputActions?.FindAction(actionName);
|
||||
if (action == null) { onCancel?.Invoke(); return; }
|
||||
|
||||
action.Disable();
|
||||
action.PerformInteractiveRebinding(bindingIndex)
|
||||
.OnComplete(op => { op.Dispose(); action.Enable(); onComplete?.Invoke(); })
|
||||
.OnCancel(op => { op.Dispose(); action.Enable(); onCancel?.Invoke(); })
|
||||
.Start();
|
||||
}
|
||||
|
||||
/// <summary>将当前绑定覆盖序列化为 JSON,存入 PlayerPrefs(key = "InputBindings")。</summary>
|
||||
public void SaveBindingOverrides()
|
||||
{
|
||||
if (_inputActions == null) return;
|
||||
PlayerPrefs.SetString(PrefKey, _inputActions.SaveBindingOverridesAsJson());
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
/// <summary>从 PlayerPrefs 加载并应用绑定覆盖(首次启动时无操作)。</summary>
|
||||
public void LoadBindingOverrides()
|
||||
{
|
||||
if (_inputActions != null && PlayerPrefs.HasKey(PrefKey))
|
||||
_inputActions.LoadBindingOverridesFromJson(PlayerPrefs.GetString(PrefKey));
|
||||
}
|
||||
|
||||
/// <summary>重置所有绑定为默认值并清除 PlayerPrefs 记录。</summary>
|
||||
public void ResetBindings()
|
||||
{
|
||||
_inputActions?.RemoveAllBindingOverrides();
|
||||
PlayerPrefs.DeleteKey(PrefKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user