fix чать инвенторя
This commit is contained in:
@@ -1,29 +1,51 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Централизованный ввод на основе New Input System.
|
||||
/// Singleton, DontDestroyOnLoad.
|
||||
/// Биндинги сохраняются в PlayerPrefs автоматически при изменении.
|
||||
/// </summary>
|
||||
public class PlayerInput : MonoBehaviour
|
||||
{
|
||||
public static PlayerInput Instance { get; private set; }
|
||||
|
||||
// Continuous axes
|
||||
public float MouseX { get; private set; }
|
||||
public float MouseY { get; private set; }
|
||||
public float Horizontal { get; private set; }
|
||||
public float Vertical { get; private set; }
|
||||
// ── Ссылка на InputActionAsset ────────────────────────────────────────────
|
||||
[Tooltip("Назначьте Assets/Input/PlayerControls.inputactions")]
|
||||
public InputActionAsset actions;
|
||||
|
||||
// Continuous states
|
||||
public bool Crouch { get; private set; }
|
||||
public bool Run { get; private set; }
|
||||
// ── Непрерывные значения ──────────────────────────────────────────────────
|
||||
public Vector2 MoveInput { get; private set; }
|
||||
public Vector2 LookInput { get; private set; }
|
||||
public bool Crouch { get; private set; }
|
||||
public bool Run { get; private set; }
|
||||
|
||||
// Events for discrete actions
|
||||
public event Action OnToggleInventory;
|
||||
public event Action OnDropPressed;
|
||||
public event Action OnPickupPressed;
|
||||
public event Action OnJumpPressed;
|
||||
public event Action<int> OnHotbarSelect;
|
||||
// ── Дискретные события ────────────────────────────────────────────────────
|
||||
public event Action OnToggleInventory;
|
||||
public event Action OnDropPressed;
|
||||
public event Action OnPickupPressed;
|
||||
public event Action OnJumpPressed;
|
||||
public event Action<int> OnHotbarSelect;
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
// ── Включение/выключение gameplay-ввода (инвентарь открыт) ───────────────
|
||||
public bool Enabled
|
||||
{
|
||||
get => _gameplayMap != null && _gameplayMap.enabled;
|
||||
set
|
||||
{
|
||||
if (_gameplayMap == null) return;
|
||||
if (value) _gameplayMap.Enable();
|
||||
else _gameplayMap.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Приватные поля ────────────────────────────────────────────────────────
|
||||
private InputActionMap _gameplayMap;
|
||||
private InputActionMap _uiMap;
|
||||
private const string BINDINGS_PREF_KEY = "PlayerBindings_v1";
|
||||
|
||||
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
@@ -34,46 +56,116 @@ public class PlayerInput : MonoBehaviour
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (actions == null)
|
||||
{
|
||||
actions = Resources.Load<InputActionAsset>("PlayerControls");
|
||||
if (actions == null)
|
||||
{
|
||||
Debug.LogError("[PlayerInput] PlayerControls.inputactions не назначен и не найден в Resources!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Создаём рабочую копию чтобы не менять оригинальный asset
|
||||
actions = Instantiate(actions);
|
||||
|
||||
// Загрузить сохранённые биндинги
|
||||
var saved = PlayerPrefs.GetString(BINDINGS_PREF_KEY, "");
|
||||
if (!string.IsNullOrEmpty(saved))
|
||||
actions.LoadBindingOverridesFromJson(saved);
|
||||
|
||||
_gameplayMap = actions.FindActionMap("Gameplay", throwIfNotFound: true);
|
||||
_uiMap = actions.FindActionMap("UI", throwIfNotFound: true);
|
||||
|
||||
// Подписка: дискретные кнопки
|
||||
_gameplayMap["Jump"].performed += _ => OnJumpPressed?.Invoke();
|
||||
_gameplayMap["Pickup"].performed += _ => OnPickupPressed?.Invoke();
|
||||
_gameplayMap["Drop"].performed += _ => OnDropPressed?.Invoke();
|
||||
|
||||
// UI map всегда активна — нет double-fire бага
|
||||
_uiMap["ToggleInventory"].performed += _ => OnToggleInventory?.Invoke();
|
||||
_uiMap["CloseInventory"].performed += _ => OnToggleInventory?.Invoke();
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
int idx = i;
|
||||
_gameplayMap[$"Hotbar{idx}"].performed += _ => OnHotbarSelect?.Invoke(idx);
|
||||
}
|
||||
|
||||
_gameplayMap.Enable();
|
||||
_uiMap.Enable();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
_gameplayMap?.Disable();
|
||||
_uiMap?.Disable();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Always allow toggle inventory (Tab/Escape) even when input is disabled
|
||||
if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.Escape))
|
||||
OnToggleInventory?.Invoke();
|
||||
if (_gameplayMap == null || !_gameplayMap.enabled) return;
|
||||
|
||||
if (!Enabled) return;
|
||||
|
||||
// Axes
|
||||
MouseX = Input.GetAxis("Mouse X");
|
||||
MouseY = Input.GetAxis("Mouse Y");
|
||||
Horizontal = Input.GetAxisRaw("Horizontal");
|
||||
Vertical = Input.GetAxisRaw("Vertical");
|
||||
|
||||
// Continuous keys
|
||||
Crouch = Input.GetKey(KeyCode.C);
|
||||
Run = Input.GetKey(KeyCode.LeftShift);
|
||||
|
||||
// Discrete actions
|
||||
if (Input.GetButtonDown("Jump"))
|
||||
OnJumpPressed?.Invoke();
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Tab))
|
||||
OnToggleInventory?.Invoke();
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Q))
|
||||
OnDropPressed?.Invoke();
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.E))
|
||||
OnPickupPressed?.Invoke();
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Alpha1 + i))
|
||||
{
|
||||
OnHotbarSelect?.Invoke(i);
|
||||
}
|
||||
}
|
||||
MoveInput = _gameplayMap["Move"].ReadValue<Vector2>();
|
||||
LookInput = _gameplayMap["Look"].ReadValue<Vector2>();
|
||||
Crouch = _gameplayMap["Crouch"].IsPressed();
|
||||
Run = _gameplayMap["Run"].IsPressed();
|
||||
}
|
||||
|
||||
// ── Сохранение/загрузка биндингов ────────────────────────────────────────
|
||||
|
||||
[ContextMenu("Save Bindings")]
|
||||
public void SaveBindings()
|
||||
{
|
||||
if (actions == null) return;
|
||||
PlayerPrefs.SetString(BINDINGS_PREF_KEY, actions.SaveBindingOverridesAsJson());
|
||||
PlayerPrefs.Save();
|
||||
Debug.Log("[PlayerInput] Биндинги сохранены");
|
||||
}
|
||||
|
||||
[ContextMenu("Reset Bindings to Defaults")]
|
||||
public void ResetBindings()
|
||||
{
|
||||
if (actions == null) return;
|
||||
foreach (var action in actions)
|
||||
action.RemoveAllBindingOverrides();
|
||||
PlayerPrefs.DeleteKey(BINDINGS_PREF_KEY);
|
||||
Debug.Log("[PlayerInput] Биндинги сброшены к умолчаниям");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Интерактивный ремаппинг. Передайте имя action, имя map и callback для UI.
|
||||
/// Пример: StartRebind("Jump", "Gameplay", () => UpdateUI());
|
||||
/// </summary>
|
||||
public void StartRebind(string actionName, string mapName, Action onComplete)
|
||||
{
|
||||
var map = actions?.FindActionMap(mapName);
|
||||
var action = map?.FindAction(actionName);
|
||||
if (action == null)
|
||||
{
|
||||
Debug.LogWarning($"[PlayerInput] Действие '{actionName}' в map '{mapName}' не найдено");
|
||||
return;
|
||||
}
|
||||
|
||||
action.Disable();
|
||||
action.PerformInteractiveRebinding()
|
||||
.WithControlsExcluding("<Mouse>/position")
|
||||
.WithControlsExcluding("<Mouse>/delta")
|
||||
.OnComplete(op =>
|
||||
{
|
||||
op.Dispose();
|
||||
action.Enable();
|
||||
SaveBindings();
|
||||
onComplete?.Invoke();
|
||||
})
|
||||
.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Доступ к InputActionAsset для UI-ремаппинга и отображения текущих биндингов.
|
||||
/// </summary>
|
||||
public InputActionAsset GetActions() => actions;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user