- Removed deprecated ButtonPinMapping enum and related COM input classes- Updated ComInputToInputSystemAdapter with improved binding logic- Refactored GameManager to use new globals prefab path - Enhanced GameEndUIController with event system focus management - Modified Globals prefab to use pin-based input bindings - Cleaned up obsolete COM system wrapper and native wrapper classes - Adjusted input adapter to support pin bindings over action bindings - Updated manufacturer name in virtual gamepad description
444 lines
20 KiB
C#
444 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using UnityEngine;
|
||
using RR.Game2D.Core.Managers;
|
||
|
||
#if ENABLE_INPUT_SYSTEM
|
||
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.InputSystem.Controls;
|
||
|
||
/// <summary>
|
||
/// Реализация системы ввода с клавиатуры для тестирования и разработки.
|
||
/// Эмулирует работу периферийной платы через стандартные клавиши клавиатуры.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Соответствие клавиш и пинов:
|
||
/// - Игрок 1: WASD + Space
|
||
/// - Игрок 2: Стрелки + RightControl
|
||
/// - Служебные: 1, 2, 3, F5
|
||
/// - Датчики хопера: O, P
|
||
/// </remarks>
|
||
public class KeyboardInput : InputSource
|
||
{
|
||
private int currentPlayer = 1;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
|
||
private GameManager gm;//я получаю кто сейчас ходит через этого менеджера. Если у вас другое, допишите.
|
||
|
||
// Кэш Key -> KeyControl + ссылка на то, для какой клавиатуры он построен
|
||
private static readonly Dictionary<Key, KeyControl> _keyCache = new();
|
||
private static Keyboard _cachedKeyboard;
|
||
|
||
private static void EnsureKeyboardCache()
|
||
{
|
||
var kb = Keyboard.current;
|
||
if (kb == null)
|
||
{
|
||
_keyCache.Clear();
|
||
_cachedKeyboard = null;
|
||
return;
|
||
}
|
||
|
||
// Если клавиатура сменилась (или кэш пуст) — перестроить
|
||
if (_cachedKeyboard == kb && _keyCache.Count != 0) return;
|
||
_cachedKeyboard = kb;
|
||
_keyCache.Clear();
|
||
var keys = kb.allKeys;
|
||
if (keys.Count <= 0) return;
|
||
foreach (var kc in keys.Where(kc => kc != null))
|
||
{
|
||
_keyCache[kc.keyCode] = kc;
|
||
}
|
||
}
|
||
|
||
private static KeyControl GetKeyControl(Key key)
|
||
{
|
||
if (key == Key.None) return null;
|
||
|
||
// Можем спокойно вызываться даже в самом раннем кадре
|
||
EnsureKeyboardCache();
|
||
return _cachedKeyboard == null ? null : _keyCache.GetValueOrDefault(key);
|
||
}
|
||
|
||
|
||
// --- адаптер: из твоего старого KeyCode -> в новый Key ---
|
||
private static Key ToNewKey(UnityEngine.KeyCode old)
|
||
{
|
||
// Пытаемся по имени (у многих совпадают)
|
||
if (Enum.TryParse<Key>(old.ToString(), true, out var k)) return k;
|
||
|
||
// Несовпадающие названия — руками:
|
||
return old switch
|
||
{
|
||
KeyCode.Return => Key.Enter,
|
||
KeyCode.KeypadEnter => Key.NumpadEnter,
|
||
|
||
KeyCode.LeftControl => Key.LeftCtrl,
|
||
KeyCode.RightControl => Key.RightCtrl,
|
||
|
||
KeyCode.LeftShift => Key.LeftShift,
|
||
KeyCode.RightShift => Key.RightShift,
|
||
|
||
KeyCode.LeftAlt => Key.LeftAlt,
|
||
KeyCode.RightAlt => Key.RightAlt,
|
||
|
||
KeyCode.LeftCommand => Key.LeftMeta,
|
||
KeyCode.RightCommand => Key.RightMeta,
|
||
|
||
KeyCode.None => Key.None,
|
||
|
||
_ => Key.None // если нужен редкий кей — добавь сюда
|
||
};
|
||
}
|
||
|
||
// Удобные обёртки
|
||
private static bool IsPressed(Key k)
|
||
{
|
||
if (k == Key.None) return false;
|
||
var c = GetKeyControl(k);
|
||
return c is { isPressed: true };
|
||
}
|
||
|
||
private static bool WasPressedThisFrame(Key k)
|
||
{
|
||
if (k == Key.None) return false;
|
||
var c = GetKeyControl(k);
|
||
return c is { wasPressedThisFrame: true };
|
||
}
|
||
|
||
private static bool WasReleasedThisFrame(Key k)
|
||
{
|
||
if (k == Key.None) return false;
|
||
var c = GetKeyControl(k);
|
||
return c is { wasReleasedThisFrame: true };
|
||
}
|
||
|
||
/// Проверяет состояние кнопки по её физическому пину через клавиатуру (Input System)
|
||
public override bool GetButton(ButtonPinMapping button) => IsPressed(ToNewKey(getKeyCode(button)));
|
||
|
||
/// Проверяет нажатие кнопки по пину в текущем кадре (Input System)
|
||
public override bool GetButtonDown(ButtonPinMapping button) => WasPressedThisFrame(ToNewKey(getKeyCode(button)));
|
||
|
||
/// Проверяет отпускание кнопки по пину в текущем кадре (Input System)
|
||
public override bool GetButtonUp(ButtonPinMapping button) => WasReleasedThisFrame(ToNewKey(getKeyCode(button)));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// По числовому индексу пина
|
||
public override bool GetButton(int pinIndex) => IsPressed(ToNewKey(getKeyCode(pinIndex)));
|
||
|
||
public override bool GetButtonDown(int pinIndex) => WasPressedThisFrame(ToNewKey(getKeyCode(pinIndex)));
|
||
|
||
public override bool GetButtonUp(int pinIndex) => WasReleasedThisFrame(ToNewKey(getKeyCode(pinIndex)));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// Действия текущего игрока (для клавиатуры — это по сути игрок 1)
|
||
public override bool GetButtonCurrentPlayer(PlayerAction button) => GetButton(GetButtonForCurrentPlayer(button));
|
||
|
||
public override bool GetButtonDownCurrentPlayer(PlayerAction button) => GetButtonDown(GetButtonForCurrentPlayer(button));
|
||
|
||
public override bool GetButtonUpCurrentPlayer(PlayerAction button) => GetButtonUp(GetButtonForCurrentPlayer(button));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// Любой игрок (для клавиатуры — эквивалент текущего)
|
||
public override bool GetButtonAnyPlayer(PlayerAction button) => GetButtonCurrentPlayer(button);
|
||
public override bool GetButtonDownAnyPlayer(PlayerAction button) => GetButtonDownCurrentPlayer(button);
|
||
public override bool GetButtonUpAnyPlayer(PlayerAction button) => GetButtonUpCurrentPlayer(button);
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// <summary>
|
||
/// Инициализирует клавиатурный ввод. Всегда возвращает true так как клавиатура всегда доступна.
|
||
/// </summary>
|
||
/// <returns>Всегда true</returns>
|
||
public override bool Initialize()
|
||
{
|
||
gm = GameManager.Instance;
|
||
return true;
|
||
}
|
||
|
||
// ================================================================================
|
||
// ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ
|
||
// ================================================================================
|
||
|
||
/// <summary>
|
||
/// Определяет кнопку текущего игрока для указанного действия.
|
||
/// Для клавиатуры всегда возвращает кнопку первого игрока.
|
||
/// </summary>
|
||
private ButtonPinMapping GetButtonForCurrentPlayer(PlayerAction button)
|
||
{
|
||
var buttons = _buttonByAction(button);
|
||
return currentPlayer == 1 ? buttons.player1button : buttons.player2button;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет действие для обоих игроков используя указанную функцию проверки.
|
||
/// </summary>
|
||
private bool CheckBothPlayers(PlayerAction action, System.Func<ButtonPinMapping, bool> buttonFunc)
|
||
{
|
||
var buttons = _buttonByAction(action);
|
||
return buttonFunc(buttons.player1button) || buttonFunc(buttons.player2button);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возвращает соответствие между игровыми действиями и физическими кнопками игроков.
|
||
/// </summary>
|
||
private (ButtonPinMapping player1button, ButtonPinMapping player2button) _buttonByAction(PlayerAction playerAction) =>
|
||
playerAction switch
|
||
{
|
||
PlayerAction.up => (ButtonPinMapping.up1, ButtonPinMapping.up2),
|
||
PlayerAction.down => (ButtonPinMapping.down1, ButtonPinMapping.down2),
|
||
PlayerAction.left => (ButtonPinMapping.left1, ButtonPinMapping.left2),
|
||
PlayerAction.right => (ButtonPinMapping.right1, ButtonPinMapping.right2),
|
||
PlayerAction.action => (ButtonPinMapping.action1, ButtonPinMapping.action2),
|
||
PlayerAction.extra => (ButtonPinMapping.extra, ButtonPinMapping.extra),
|
||
_ => throw new System.ArgumentException($"Unknown player action: {playerAction}")
|
||
};
|
||
|
||
/// <summary>
|
||
/// Преобразует физический пин в соответствующую клавишу клавиатуры.
|
||
/// </summary>
|
||
private KeyCode getKeyCode(ButtonPinMapping button)
|
||
{
|
||
return button switch
|
||
{
|
||
ButtonPinMapping.up1 => KeyCode.W,
|
||
ButtonPinMapping.right1 => KeyCode.D,
|
||
ButtonPinMapping.down1 => KeyCode.S,
|
||
ButtonPinMapping.left1 => KeyCode.A,
|
||
ButtonPinMapping.action1 => KeyCode.Space,
|
||
|
||
ButtonPinMapping.up2 => KeyCode.UpArrow,
|
||
ButtonPinMapping.right2 => KeyCode.RightArrow,
|
||
ButtonPinMapping.down2 => KeyCode.DownArrow,
|
||
ButtonPinMapping.left2 => KeyCode.LeftArrow,
|
||
ButtonPinMapping.action2 => KeyCode.RightControl,
|
||
|
||
ButtonPinMapping.startOnePlayer => KeyCode.Alpha1,
|
||
ButtonPinMapping.startTwoPlayers => KeyCode.Alpha2,
|
||
|
||
ButtonPinMapping.secret => KeyCode.F5,
|
||
|
||
ButtonPinMapping.extra => KeyCode.Alpha3,
|
||
|
||
ButtonPinMapping.hasPrize => KeyCode.O,
|
||
ButtonPinMapping.prizeGiven => KeyCode.P,
|
||
|
||
_ => KeyCode.None,
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Преобразует числовой индекс пина в соответствующую клавишу клавиатуры.
|
||
/// Используется для методов с прямым доступом по индексу.
|
||
/// </summary>
|
||
private KeyCode getKeyCode(int pinIndex)
|
||
{
|
||
return pinIndex switch
|
||
{
|
||
0 => KeyCode.W, // up1
|
||
1 => KeyCode.D, // right1
|
||
2 => KeyCode.S, // down1
|
||
3 => KeyCode.A, // left1
|
||
4 => KeyCode.Space, // action1
|
||
|
||
5 => KeyCode.UpArrow, // up2
|
||
6 => KeyCode.RightArrow, // right2
|
||
7 => KeyCode.DownArrow, // down2
|
||
8 => KeyCode.LeftArrow, // left2
|
||
9 => KeyCode.RightControl, // action2
|
||
|
||
10 => KeyCode.Alpha1, // startOnePlayer
|
||
11 => KeyCode.Alpha2, // startTwoPlayers
|
||
|
||
12 => KeyCode.F5, // secret
|
||
|
||
13 => KeyCode.Alpha3, // extra
|
||
|
||
14 => KeyCode.O, // hasPrize
|
||
15 => KeyCode.P, // prizeGiven
|
||
|
||
_ => KeyCode.None, // невалидный индекс
|
||
};
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
/// <summary>
|
||
/// Реализация системы ввода с клавиатуры для тестирования и разработки.
|
||
/// Эмулирует работу периферийной платы через стандартные клавиши клавиатуры.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// Соответствие клавиш и пинов:
|
||
/// - Игрок 1: WASD + Space
|
||
/// - Игрок 2: Стрелки + RightControl
|
||
/// - Служебные: 1, 2, 3, F5
|
||
/// - Датчики хопера: O, P
|
||
/// </remarks>
|
||
public class KeyboardInput : InputSource
|
||
{
|
||
private int currentPlayer = 1;//ПЕРЕОПРЕДЕЛИТЕ ОПРЕДЕЛЕНИЕ ТЕКУЩЕГО ИГРОКА ПОД СВОЮ СИСТЕМУ.
|
||
private GameManager gm;//я получаю кто сейчас ходит через этого менеджера. Если у вас другое, допишите.
|
||
|
||
/// <summary>Проверяет состояние кнопки по её физическому пину через клавиатуру</summary>
|
||
public override bool GetButton(ButtonPinMapping button) => Input.GetKey(getKeyCode(button));
|
||
|
||
/// <summary>Проверяет нажатие кнопки по пину в текущем кадре через клавиатуру</summary>
|
||
public override bool GetButtonDown(ButtonPinMapping button) => Input.GetKeyDown(getKeyCode(button));
|
||
|
||
/// <summary>Проверяет отпускание кнопки по пину в текущем кадре через клавиатуру</summary>
|
||
public override bool GetButtonUp(ButtonPinMapping button) => Input.GetKeyUp(getKeyCode(button));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// <summary>Проверяет состояние кнопки по числовому индексу пина через клавиатуру</summary>
|
||
public override bool GetButton(int pinIndex) => Input.GetKey(getKeyCode(pinIndex));
|
||
|
||
/// <summary>Проверяет нажатие кнопки по индексу пина в текущем кадре через клавиатуру</summary>
|
||
public override bool GetButtonDown(int pinIndex) => Input.GetKeyDown(getKeyCode(pinIndex));
|
||
|
||
/// <summary>Проверяет отпускание кнопки по индексу пина в текущем кадре через клавиатуру</summary>
|
||
public override bool GetButtonUp(int pinIndex) => Input.GetKeyUp(getKeyCode(pinIndex));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// <summary>Проверяет состояние действия для текущего игрока (всегда игрок 1 для клавиатуры)</summary>
|
||
public override bool GetButtonCurrentPlayer(PlayerAction button) => GetButton(GetButtonForCurrentPlayer(button));
|
||
|
||
/// <summary>Проверяет начало действия текущим игроком в текущем кадре</summary>
|
||
public override bool GetButtonDownCurrentPlayer(PlayerAction button) => GetButtonDown(GetButtonForCurrentPlayer(button));
|
||
|
||
/// <summary>Проверяет завершение действия текущим игроком в текущем кадре</summary>
|
||
public override bool GetButtonUpCurrentPlayer(PlayerAction button) => GetButtonUp(GetButtonForCurrentPlayer(button));
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// <summary>Проверяет состояние действия для любого из игроков (игрок 1 ИЛИ игрок 2)</summary>
|
||
public override bool GetButtonAnyPlayer(PlayerAction button) => CheckBothPlayers(button, GetButton);
|
||
|
||
/// <summary>Проверяет начало действия любым игроком в текущем кадре</summary>
|
||
public override bool GetButtonDownAnyPlayer(PlayerAction button) => CheckBothPlayers(button, GetButtonDown);
|
||
|
||
/// <summary>Проверяет завершение действия любым игроком в текущем кадре</summary>
|
||
public override bool GetButtonUpAnyPlayer(PlayerAction button) => CheckBothPlayers(button, GetButtonUp);
|
||
|
||
//----------------------------------------------------------------------------------
|
||
|
||
/// <summary>
|
||
/// Инициализирует клавиатурный ввод. Всегда возвращает true так как клавиатура всегда доступна.
|
||
/// </summary>
|
||
/// <returns>Всегда true</returns>
|
||
public override bool Initialize() => gm = GameManager.Instance;
|
||
|
||
// ================================================================================
|
||
// ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ
|
||
// ================================================================================
|
||
|
||
/// <summary>
|
||
/// Определяет кнопку текущего игрока для указанного действия.
|
||
/// Для клавиатуры всегда возвращает кнопку первого игрока.
|
||
/// </summary>
|
||
private ButtonPinMapping GetButtonForCurrentPlayer(PlayerAction button)
|
||
{
|
||
var buttons = _buttonByAction(button);
|
||
return currentPlayer == 1 ? buttons.player1button : buttons.player2button;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет действие для обоих игроков используя указанную функцию проверки.
|
||
/// </summary>
|
||
private bool CheckBothPlayers(PlayerAction action, System.Func<ButtonPinMapping, bool> buttonFunc)
|
||
{
|
||
var buttons = _buttonByAction(action);
|
||
return buttonFunc(buttons.player1button) || buttonFunc(buttons.player2button);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Возвращает соответствие между игровыми действиями и физическими кнопками игроков.
|
||
/// </summary>
|
||
private (ButtonPinMapping player1button, ButtonPinMapping player2button) _buttonByAction(PlayerAction playerAction) =>
|
||
playerAction switch
|
||
{
|
||
PlayerAction.up => (ButtonPinMapping.up1, ButtonPinMapping.up2),
|
||
PlayerAction.down => (ButtonPinMapping.down1, ButtonPinMapping.down2),
|
||
PlayerAction.left => (ButtonPinMapping.left1, ButtonPinMapping.left2),
|
||
PlayerAction.right => (ButtonPinMapping.right1, ButtonPinMapping.right2),
|
||
PlayerAction.action => (ButtonPinMapping.action1, ButtonPinMapping.action2),
|
||
PlayerAction.extra => (ButtonPinMapping.extra, ButtonPinMapping.extra),
|
||
_ => throw new System.ArgumentException($"Unknown player action: {playerAction}")
|
||
};
|
||
|
||
/// <summary>
|
||
/// Преобразует физический пин в соответствующую клавишу клавиатуры.
|
||
/// </summary>
|
||
private KeyCode getKeyCode(ButtonPinMapping button)
|
||
{
|
||
return button switch
|
||
{
|
||
ButtonPinMapping.up1 => KeyCode.W,
|
||
ButtonPinMapping.right1 => KeyCode.D,
|
||
ButtonPinMapping.down1 => KeyCode.S,
|
||
ButtonPinMapping.left1 => KeyCode.A,
|
||
ButtonPinMapping.action1 => KeyCode.Space,
|
||
|
||
ButtonPinMapping.up2 => KeyCode.UpArrow,
|
||
ButtonPinMapping.right2 => KeyCode.RightArrow,
|
||
ButtonPinMapping.down2 => KeyCode.DownArrow,
|
||
ButtonPinMapping.left2 => KeyCode.LeftArrow,
|
||
ButtonPinMapping.action2 => KeyCode.RightControl,
|
||
|
||
ButtonPinMapping.startOnePlayer => KeyCode.Alpha1,
|
||
ButtonPinMapping.startTwoPlayers => KeyCode.Alpha2,
|
||
|
||
ButtonPinMapping.secret => KeyCode.F5,
|
||
|
||
ButtonPinMapping.extra => KeyCode.Alpha3,
|
||
|
||
ButtonPinMapping.hasPrize => KeyCode.O,
|
||
ButtonPinMapping.prizeGiven => KeyCode.P,
|
||
|
||
_ => KeyCode.None,
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// Преобразует числовой индекс пина в соответствующую клавишу клавиатуры.
|
||
/// Используется для методов с прямым доступом по индексу.
|
||
/// </summary>
|
||
private KeyCode getKeyCode(int pinIndex)
|
||
{
|
||
return pinIndex switch
|
||
{
|
||
0 => KeyCode.W, // up1
|
||
1 => KeyCode.D, // right1
|
||
2 => KeyCode.S, // down1
|
||
3 => KeyCode.A, // left1
|
||
4 => KeyCode.Space, // action1
|
||
|
||
5 => KeyCode.UpArrow, // up2
|
||
6 => KeyCode.RightArrow, // right2
|
||
7 => KeyCode.DownArrow, // down2
|
||
8 => KeyCode.LeftArrow, // left2
|
||
9 => KeyCode.RightControl, // action2
|
||
|
||
10 => KeyCode.Alpha1, // startOnePlayer
|
||
11 => KeyCode.Alpha2, // startTwoPlayers
|
||
|
||
12 => KeyCode.F5, // secret
|
||
|
||
13 => KeyCode.Alpha3, // extra
|
||
|
||
14 => KeyCode.O, // hasPrize
|
||
15 => KeyCode.P, // prizeGiven
|
||
|
||
_ => KeyCode.None, // невалидный индекс
|
||
};
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|