feat: add reusable virtual hud input

This commit is contained in:
ud18010
2026-07-30 11:14:56 +08:00
parent 3546d16632
commit 5853c5bd83
26 changed files with 6403 additions and 31 deletions
@@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Reflection;
using NUnit.Framework;
using UnityEngine;
using XGame.VirtualInput;
public sealed class VirtualActionPadTests
{
private GameObject _root;
[TearDown]
public void TearDown()
{
if (_root != null)
{
Object.DestroyImmediate(_root);
_root = null;
}
}
[Test]
public void Awake_FindsFiveButtonsByNameAndAssignsIds()
{
VirtualActionPad pad = CreatePadWithButtons();
Assert.That(pad.GetButton(ActionButtonId.Primary), Is.Not.Null);
Assert.That(pad.GetButton(ActionButtonId.Skill1), Is.Not.Null);
Assert.That(pad.GetButton(ActionButtonId.Skill2), Is.Not.Null);
Assert.That(pad.GetButton(ActionButtonId.Skill3), Is.Not.Null);
Assert.That(pad.GetButton(ActionButtonId.Skill4), Is.Not.Null);
Assert.That(pad.GetButton(ActionButtonId.Skill4).ButtonId, Is.EqualTo(ActionButtonId.Skill4));
}
[Test]
public void ChildButtonEvent_IsForwardedByPad()
{
VirtualActionPad pad = CreatePadWithButtons();
var events = new List<ActionButtonEvent>();
pad.ButtonEvent += events.Add;
pad.GetButton(ActionButtonId.Primary).HandlePointerDownForTest(new Vector2(100f, 100f), 1, 0f);
Assert.That(events.Count, Is.EqualTo(1));
Assert.That(events[0].ButtonId, Is.EqualTo(ActionButtonId.Primary));
Assert.That(events[0].Phase, Is.EqualTo(ActionButtonPhase.Down));
}
[Test]
public void PadStateApi_ForwardsToChildButton()
{
VirtualActionPad pad = CreatePadWithButtons();
var events = new List<ActionButtonEvent>();
pad.ButtonEvent += events.Add;
pad.SetCharges(ActionButtonId.Skill1, 0);
pad.GetButton(ActionButtonId.Skill1).HandlePointerDownForTest(new Vector2(100f, 100f), 1, 0f);
Assert.That(events.Count, Is.EqualTo(1));
Assert.That(events[0].Phase, Is.EqualTo(ActionButtonPhase.Blocked));
}
[Test]
public void SetCancelAreaVisible_TogglesCancelArea()
{
VirtualActionPad pad = CreatePadWithButtons();
Transform cancel = _root.transform.Find("CancelArea");
Assert.That(cancel, Is.Not.Null);
pad.SetCancelAreaVisible(true);
Assert.That(cancel.gameObject.activeSelf, Is.True);
pad.SetCancelAreaVisible(false);
Assert.That(cancel.gameObject.activeSelf, Is.False);
}
private VirtualActionPad CreatePadWithButtons()
{
_root = new GameObject("UI_VirtualActionPad", typeof(RectTransform));
CreateButtonChild("Btn_Primary", ActionButtonId.Primary);
CreateButtonChild("Btn_Skill1", ActionButtonId.Skill1);
CreateButtonChild("Btn_Skill2", ActionButtonId.Skill2);
CreateButtonChild("Btn_Skill3", ActionButtonId.Skill3);
CreateButtonChild("Btn_Skill4", ActionButtonId.Skill4);
GameObject cancel = new GameObject("CancelArea", typeof(RectTransform));
cancel.transform.SetParent(_root.transform, false);
cancel.SetActive(false);
VirtualActionPad pad = _root.AddComponent<VirtualActionPad>();
InvokePrivate(pad, "Awake");
return pad;
}
private void CreateButtonChild(string name, ActionButtonId id)
{
GameObject child = new GameObject(name, typeof(RectTransform));
child.transform.SetParent(_root.transform, false);
VirtualActionButton button = child.AddComponent<VirtualActionButton>();
button.ButtonId = id;
SetPrivateField(button, "screenCenterOverride", new Vector2(100f, 100f));
SetPrivateField(button, "screenRadiusOverride", 50f);
InvokePrivate(button, "Awake");
}
private static void SetPrivateField(object target, string name, object value)
{
FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
Assert.That(field, Is.Not.Null);
field.SetValue(target, value);
}
private static void InvokePrivate(object target, string name, params object[] args)
{
MethodInfo method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic);
Assert.That(method, Is.Not.Null);
method.Invoke(target, args);
}
}