Danro/Assets/Scripts/Controls/ComInputToInputSystemAdapter.cs

260 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
/// <summary>
/// Адаптер между системой ввода COM и Unity Input System.
/// Создаёт виртуальный Gamepad и транслирует состояние кнопок из:
/// - действий игроков (PlayerAction)
/// - физических пинов (int индексы)
/// </summary>
[DefaultExecutionOrder(-100)]
public class ComInputToInputSystemAdapter : MonoBehaviour
{
private const string VirtualGamepadProduct = "COM Bridge Gamepad";
private const string VirtualGamepadManufacturer = "Robotic Retailers";
[Header("Источник состояния")]
[Tooltip("Если true — использовать In.GetButtonAnyPlayer, иначе — In.GetButtonCurrentPlayer")]
[SerializeField] private bool useAnyPlayer = true;
[Header("Маппинг действий (PlayerAction -> Gamepad)")]
[SerializeField] private List<ActionBinding> actionBindings = new();
[Header("Маппинг пинов (индекс пина -> Gamepad)")]
[SerializeField] private List<PinBinding> pinBindings = new();
[Header("Отладка")]
[SerializeField] private bool logCreateDevice = true;
private static Gamepad _virtualPad;
private static bool _deviceCreated;
private GamepadState _currentState;
#region Структуры маппинга
[Serializable]
public struct ActionBinding
{
public PlayerAction action;
public BindingTarget target;
public GamepadButton button;
public DpadDirection dpadDirection;
}
[Serializable]
public struct PinBinding
{
public int pinIndex;
public BindingTarget target;
public GamepadButton button;
public DpadDirection dpadDirection;
}
public enum BindingTarget { Button, Dpad }
public enum DpadDirection { Up, Down, Left, Right }
#endregion
#region Unity Lifecycle
// Если нет общего инициализатора, можно раскомментировать Awake
// private void Awake()
// {
// Initialize();
// }
private void OnEnable()
{
EnsureVirtualGamepadExists();
}
private void Update()
{
if (_virtualPad == null) return;
UpdateGamepadState();
InputSystem.QueueStateEvent(_virtualPad, _currentState);
}
#endregion
#region Initialization
public void Initialize()
{
EnsureVirtualGamepadExists();
InitializeDefaultBindings();
}
#endregion
#region State Update
private void UpdateGamepadState()
{
_currentState = default;
ProcessActionBindings();
ProcessPinBindings();
}
private void ProcessActionBindings()
{
foreach (ActionBinding binding in actionBindings)
{
bool isPressed = useAnyPlayer
? In.GetButtonAnyPlayer(binding.action)
: In.GetButtonCurrentPlayer(binding.action);
if (isPressed)
{
ApplyBinding(ref _currentState, binding.target, binding.button, binding.dpadDirection);
}
}
}
private void ProcessPinBindings()
{
foreach (PinBinding binding in pinBindings)
{
if (In.GetButton(binding.pinIndex))
{
ApplyBinding(ref _currentState, binding.target, binding.button, binding.dpadDirection);
}
}
}
#endregion
#region Binding Logic
private static void ApplyBinding(
ref GamepadState state,
BindingTarget target,
GamepadButton button,
DpadDirection direction)
{
if (target == BindingTarget.Button)
{
state = state.WithButton(button);
}
else // Dpad
{
GamepadButton dpadButton = direction switch
{
DpadDirection.Up => GamepadButton.DpadUp,
DpadDirection.Down => GamepadButton.DpadDown,
DpadDirection.Left => GamepadButton.DpadLeft,
DpadDirection.Right => GamepadButton.DpadRight,
_ => GamepadButton.DpadUp
};
state = state.WithButton(dpadButton);
}
}
#endregion
#region Virtual Gamepad Management
private void EnsureVirtualGamepadExists()
{
if (_deviceCreated && _virtualPad != null)
return;
// Проверяем, не создан ли уже геймпад
if (TryFindExistingVirtualGamepad(out Gamepad existingGamepad))
{
_virtualPad = existingGamepad;
_deviceCreated = true;
return;
}
CreateVirtualGamepad();
}
private static bool TryFindExistingVirtualGamepad(out Gamepad gamepad)
{
gamepad = null;
foreach (InputDevice device in InputSystem.devices)
{
if (device is not Gamepad { description: { product: VirtualGamepadProduct } } gp) continue;
gamepad = gp;
return true;
}
return false;
}
private void CreateVirtualGamepad()
{
InputDeviceDescription description = new()
{
interfaceName = "Virtual",
deviceClass = "Gamepad",
product = VirtualGamepadProduct,
manufacturer = VirtualGamepadManufacturer
};
_virtualPad = (Gamepad)InputSystem.AddDevice(description);
_deviceCreated = true;
if (logCreateDevice)
{
Debug.Log($"[ComInputAdapter] Виртуальный Gamepad создан: {_virtualPad.name}");
}
}
#endregion
#region Default Bindings
private void InitializeDefaultBindings()
{
if (actionBindings.Count > 0)
return;
AddDefaultActionBindings();
}
private void AddDefaultActionBindings()
{
// Маппинг стрелок на D-Pad
TryAddActionBinding(PlayerAction.up, BindingTarget.Dpad, GamepadButton.North, DpadDirection.Up);
TryAddActionBinding(PlayerAction.down, BindingTarget.Dpad, GamepadButton.South, DpadDirection.Down);
TryAddActionBinding(PlayerAction.left, BindingTarget.Dpad, GamepadButton.West, DpadDirection.Left);
TryAddActionBinding(PlayerAction.right, BindingTarget.Dpad, GamepadButton.East, DpadDirection.Right);
// Кнопки действий
TryAddActionBinding(PlayerAction.action, BindingTarget.Button, GamepadButton.South, DpadDirection.Up);
}
private void TryAddActionBinding(
PlayerAction action,
BindingTarget target,
GamepadButton button,
DpadDirection direction)
{
try
{
actionBindings.Add(new ActionBinding
{
action = action,
target = target,
button = button,
dpadDirection = direction
});
}
catch (Exception e)
{
Debug.LogWarning($"[ComInputAdapter] Не удалось добавить привязку для {action}: {e.Message}");
}
}
#endregion
}