fix чать инвенторя

This commit is contained in:
jze9
2026-04-16 01:51:46 +05:00
parent 057f5d3d1e
commit 6c3f72385e
35 changed files with 18160 additions and 14313 deletions

View File

@@ -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;
}