Danro/Assets/Scripts/Controls/ComInputToInputSystemAdapter.cs

176 lines
7.0 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>
/// Мост из твоего фасада In (COM/клава и т.д.) в новый Input System.
/// Создаёт виртуальный Gamepad и обновляет его состояние на основе:
/// - действий игроков (PlayerAction), или
/// - физических пинов (int / ButtonPinMapping)
/// Выбирай способ через списки маппинга в инспекторе.
/// </summary>
[DefaultExecutionOrder(-100)] // пораньше, чтобы UI увидел ввод
public class ComInputToInputSystemAdapter : MonoBehaviour
{
[Header("Источник состояния")]
[Tooltip("Если true — брать состояние из In.GetButton* AnyPlayer; если false — из CurrentPlayer.")]
public bool useAnyPlayer = true;
[Header("Маппинг по действиям (PlayerAction -> Gamepad)")]
public List<ActionBinding> actionBindings = new();
[Header("Маппинг по пинам (индекс пина -> Gamepad)")]
public List<PinBinding> pinBindings = new();
[Header("Отладка")]
public bool logCreateDevice = true;
private static Gamepad _virtualPad;
private GamepadState _state;
// Защита от дублей при отключённом Domain Reload
private static bool _deviceCreated;
[Serializable]
public struct ActionBinding
{
public PlayerAction action; // твой enum
public TargetTarget target;
public GamepadButton button; // если target == Button
public DpadDir dpadDirection; // если target == Dpad
}
[Serializable]
public struct PinBinding
{
public int pinIndex; // твой физический индекс пина
public TargetTarget target;
public GamepadButton button; // если target == Button
public DpadDir dpadDirection; // если target == Dpad
}
public enum TargetTarget { Button, Dpad }
public enum DpadDir { Up, Down, Left, Right }
private void Awake()
{
EnsureVirtualGamepad();
TryAddDefaultBindingsIfEmpty();
}
private void OnEnable() => EnsureVirtualGamepad();
private void OnDisable()
{
// Обычно устройство не удаляем, чтобы не ломать PlayerInput при живых сценах.
// Если нужно строго чистить — раскомментируй:
// if (_virtualPad != null) { InputSystem.RemoveDevice(_virtualPad); _virtualPad = null; _deviceCreated = false; }
}
private void Update()
{
if (_virtualPad == null) return;
_state = default;
// 1) По действиям
for (int i = 0; i < actionBindings.Count; i++)
{
var b = actionBindings[i];
bool pressed = useAnyPlayer
? In.GetButtonAnyPlayer(b.action)
: In.GetButtonCurrentPlayer(b.action);
ApplyBinding(ref _state, b.target, b.button, b.dpadDirection, pressed);
}
// 2) По пинам
for (int i = 0; i < pinBindings.Count; i++)
{
var b = pinBindings[i];
bool pressed = In.GetButton(b.pinIndex);
ApplyBinding(ref _state, b.target, b.button, b.dpadDirection, pressed);
}
InputSystem.QueueStateEvent(_virtualPad, _state);
// Обновлять InputSystem вручную не нужно (обновится в цикле Unity)
}
private static void ApplyBinding(ref GamepadState st, TargetTarget target, GamepadButton btn, DpadDir dir, bool pressed)
{
if (!pressed) return;
if (target == TargetTarget.Button)
{
st = st.WithButton(btn, true);
}
else
{
switch (dir)
{
case DpadDir.Up: st = st.WithButton(GamepadButton.DpadUp, true); break;
case DpadDir.Down: st = st.WithButton(GamepadButton.DpadDown, true); break;
case DpadDir.Left: st = st.WithButton(GamepadButton.DpadLeft, true); break;
case DpadDir.Right: st = st.WithButton(GamepadButton.DpadRight, true); break;
}
}
}
private void EnsureVirtualGamepad()
{
if (_deviceCreated && _virtualPad != null) return;
// ищем уже созданный «COM Bridge», чтобы не дублировать
foreach (var dev in InputSystem.devices)
{
if (dev is Gamepad gp && gp.description.product == "COM Bridge Gamepad")
{
_virtualPad = gp;
_deviceCreated = true;
return;
}
}
var desc = new InputDeviceDescription
{
interfaceName = "Virtual",
deviceClass = "Gamepad",
product = "COM Bridge Gamepad",
manufacturer = "YourCompany"
};
_virtualPad = (Gamepad)InputSystem.AddDevice(desc);
_deviceCreated = true;
if (logCreateDevice) Debug.Log("[InputBridge] Виртуальный Gamepad создан: " + _virtualPad);
}
private void TryAddDefaultBindingsIfEmpty()
{
// Если пусто — добавим базовый маппинг стрелок на D-Pad.
if (actionBindings.Count == 0)
{
// Переименуй ниже на свои реальные имена в enum PlayerAction, если отличаются.
TryAddActionBinding(PlayerAction.up, TargetTarget.Dpad, GamepadButton.North, DpadDir.Up);
TryAddActionBinding(PlayerAction.down, TargetTarget.Dpad, GamepadButton.South, DpadDir.Down);
TryAddActionBinding(PlayerAction.left, TargetTarget.Dpad, GamepadButton.West, DpadDir.Left);
TryAddActionBinding(PlayerAction.right, TargetTarget.Dpad, GamepadButton.East, DpadDir.Right);
// Часто удобно:
// Confirm -> South (A), Back/Cancel -> East (B)
SafeTry(() => actionBindings.Add(new ActionBinding { action = PlayerAction.action, target = TargetTarget.Button, button = GamepadButton.South, dpadDirection = DpadDir.Up }));
SafeTry(() => actionBindings.Add(new ActionBinding { action = PlayerAction.extra, target = TargetTarget.Button, button = GamepadButton.East, dpadDirection = DpadDir.Up }));
}
}
private void TryAddActionBinding(PlayerAction action, TargetTarget target, GamepadButton btn, DpadDir dir)
{
SafeTry(() => actionBindings.Add(new ActionBinding { action = action, target = target, button = btn, dpadDirection = dir }));
}
private static void SafeTry(Action a)
{
try { a(); } catch { /* если в твоём enum нет таких значений — просто пропустим */ }
}
}