using NUnit.Framework; using System.Reflection; using UnityEngine; using XGame; using XGame.ActorBehavior; using XGame.VirtualInput; using XWorld.Framework.ActorBehavior; public sealed class LobbyWorldControllerVirtualJoystickTests { [Test] public void MapMoveInputForTest_UsesJoystickVectorWithCameraAxes() { Vector3 dir = LobbyWorldController.MapMoveInputForTest( new Vector2(1f, 0f), Vector3.forward, Vector3.right, false, false, false, false); Assert.That(dir, Is.EqualTo(Vector3.right)); } [Test] public void MapMoveInputForTest_CombinesKeyboardAndJoystick() { Vector3 dir = LobbyWorldController.MapMoveInputForTest( new Vector2(0f, 1f), Vector3.forward, Vector3.right, true, false, false, false); Assert.That(dir, Is.EqualTo(Vector3.forward * 2f)); } [Test] public void ReleaseJoystickUIForTest_ClearsVirtualJoystickReferences() { GameObject controllerObj = new GameObject("LobbyWorldControllerTest"); GameObject joystickObj = new GameObject("UI_VirtualJoystick", typeof(RectTransform)); try { LobbyWorldController controller = controllerObj.AddComponent(); VirtualJoystick joystick = joystickObj.AddComponent(); SetPrivateField(controller, "joystickRoot", joystickObj.GetComponent()); SetPrivateField(controller, "virtualJoystick", joystick); InvokePrivate(controller, "ReleaseJoystickUI", false); Assert.That(GetPrivateField(controller, "joystickRoot"), Is.Null); Assert.That(GetPrivateField(controller, "virtualJoystick"), Is.Null); } finally { Object.DestroyImmediate(joystickObj); Object.DestroyImmediate(controllerObj); } } [Test] public void GetMoveDirection_IgnoresJoystickWhileSelfBehaviorIsActive() { GameObject controllerObj = new GameObject("LobbyWorldControllerTest"); try { LobbyWorldController controller = controllerObj.AddComponent(); LobbyActorBehaviorRuntime runtime = CreateActiveSkillRuntime(10); SetPrivateField(controller, "selfPlayerId", 10); SetPrivateField(controller, "actorBehaviorRuntime", runtime); SetPrivateField(controller, "joystick", Vector2.up); SetPrivateField(controller, "joystickActive", true); Vector3 dir = (Vector3)InvokePrivate(controller, "GetMoveDirection"); Assert.That(dir, Is.EqualTo(Vector3.zero)); } finally { Object.DestroyImmediate(controllerObj); } } [Test] public void Skill1TapBeforeCatalogReady_StartsAfterCatalogBecomesReady() { GameObject controllerObj = new GameObject("LobbyWorldControllerTest"); try { LobbyWorldController controller = controllerObj.AddComponent(); LobbyActorBehaviorRuntime runtime = CreateReadySkillRuntime(10); SetPrivateField(controller, "selfPlayerId", 10); SetPrivateField(controller, "actorBehaviorRuntime", runtime); SetPrivateField(controller, "actorBehaviorCatalogLoaded", false); InvokePrivate(controller, "OnVirtualActionButtonEvent", new ActionButtonEvent(ActionButtonId.Skill1, ActionButtonPhase.Tap, Vector2.zero, Vector2.zero, Vector2.zero, 0f, 0f, false, 1)); Assert.That(runtime.HasActiveBehavior(10), Is.False); SetPrivateField(controller, "actorBehaviorCatalogLoaded", true); InvokePrivate(controller, "ConsumePendingActionButtonEvent"); Assert.That(runtime.HasActiveBehavior(10), Is.True); } finally { Object.DestroyImmediate(controllerObj); } } 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 object GetPrivateField(object target, string name) { FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic); Assert.That(field, Is.Not.Null); return field.GetValue(target); } private static object InvokePrivate(object target, string name, params object[] args) { MethodInfo method = target.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic); Assert.That(method, Is.Not.Null); return method.Invoke(target, args); } private static LobbyActorBehaviorRuntime CreateActiveSkillRuntime(int actorId) { LobbyActorBehaviorRuntime runtime = CreateReadySkillRuntime(actorId); BehaviorStartResult result = runtime.HandleActionButton( new ActionButtonEvent(ActionButtonId.Skill1, ActionButtonPhase.Tap, Vector2.zero, Vector2.zero, Vector2.zero, 0f, 0f, false, 1), actorId, Vector3.forward); Assert.That(result.Success, Is.True); Assert.That(runtime.HasActiveBehavior(actorId), Is.True); return runtime; } private static LobbyActorBehaviorRuntime CreateReadySkillRuntime(int actorId) { var runtime = new LobbyActorBehaviorRuntime(); runtime.RegisterCatalog(CreateFighterCatalog()); runtime.RegisterOrUpdateActor(actorId, Vector3.zero, Vector3.forward); Assert.That(runtime.SwitchActorCatalog(actorId, LobbyActorBehaviorRuntime.DefaultCatalogType), Is.True); return runtime; } private static BehaviorConfigCatalog CreateFighterCatalog() { return BehaviorConfigCatalog.LoadFromJson( "fighter", @"{ ""type"": ""fighter"", ""version"": 1, ""behaviors"": [ { ""id"": ""quantao01"", ""duration"": 1.0, ""canBeInterrupted"": true, ""input"": ""DirectionOrTarget"", ""timeline"": [], ""logicEffects"": [] } ] }", @"{ ""type"": ""fighter"", ""version"": 1, ""flyObjects"": [] }", @"{ ""type"": ""fighter"", ""version"": 1, ""buffs"": [] }"); } }