Files
tiny_tackle_heroes/Assets/_Project/Tests/PlayMode/ZoneArrivalPlayModeTests.cs
T
2026-09-23 12:53:52 +09:00

165 lines
6.3 KiB
C#

using System.Collections;
using BumpCombat.Core;
using BumpCombat.Player;
using BumpCombat.Stage;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace BumpCombat.PlayModeTests
{
public sealed class ZoneArrivalPlayModeTests
{
private GameObject arenaObject;
private GameObject playerObject;
private GameObject stageObject;
private RunManager existingRunManager;
private bool existingRunManagerWasEnabled;
private float previousTimeScale;
[SetUp]
public void SetUp()
{
previousTimeScale = Time.timeScale;
existingRunManager = Object.FindAnyObjectByType<RunManager>();
if (existingRunManager != null)
{
existingRunManagerWasEnabled = existingRunManager.enabled;
existingRunManager.enabled = false;
}
Time.timeScale = 1f;
}
[TearDown]
public void TearDown()
{
if (stageObject != null)
{
Object.Destroy(stageObject);
}
if (playerObject != null)
{
Object.Destroy(playerObject);
}
if (arenaObject != null)
{
Object.Destroy(arenaObject);
}
if (existingRunManager != null)
{
existingRunManager.enabled = existingRunManagerWasEnabled;
}
Time.timeScale = previousTimeScale;
}
[Timeout(60000)]
[UnityTest]
public IEnumerator ArrivalDoor_RejectsImmediateReverseAndRetriesOnStayAfterCooldown()
{
arenaObject = new GameObject("ArrivalPlayMode_ArenaBounds");
arenaObject.AddComponent<ArenaBounds>();
playerObject = new GameObject("ArrivalPlayMode_Player");
PlayerController player = playerObject.AddComponent<PlayerController>();
CircleCollider2D playerBody = playerObject.AddComponent<CircleCollider2D>();
playerBody.radius = 0.22f;
playerBody.offset = new Vector2(0.11f, -0.07f);
Rigidbody2D rigidbody = playerObject.GetComponent<Rigidbody2D>();
rigidbody.bodyType = RigidbodyType2D.Kinematic;
rigidbody.gravityScale = 0f;
rigidbody.constraints = RigidbodyConstraints2D.FreezeRotation;
playerObject.GetComponent<Animator>().enabled = false;
player.enabled = false;
stageObject = new GameObject("ArrivalPlayMode_StageManager");
StageManager stageManager = stageObject.AddComponent<StageManager>();
stageManager.StartRun(4242);
// StageManager.Start also builds its autonomous test stage. Let
// that lifecycle pass before taking connector references.
yield return null;
ZoneInstance startZone = stageManager.CurrentZone;
Assert.That(startZone, Is.Not.Null);
ZoneConnector sourceConnector = FindOutgoingConnector(stageManager);
Assert.That(sourceConnector, Is.Not.Null);
yield return new WaitForSecondsRealtime(0.4f);
MoveBodyCenter(player, playerBody, sourceConnector.GetComponent<BoxCollider2D>().bounds.center);
yield return new WaitForFixedUpdate();
int targetNodeId = sourceConnector.TargetNodeId;
float transitionDeadline = Time.realtimeSinceStartup + 2f;
while ((stageManager.IsTransitioning
|| stageManager.CurrentZone == null
|| stageManager.CurrentZone.NodeId != targetNodeId)
&& Time.realtimeSinceStartup < transitionDeadline)
{
yield return null;
}
Assert.That(stageManager.CurrentZone.NodeId, Is.EqualTo(targetNodeId));
Assert.That(stageManager.IsTransitioning, Is.False);
ZoneConnector arrivalConnector = stageManager.CurrentZone.GetConnector(sourceConnector.TargetSocketId);
Assert.That(arrivalConnector, Is.Not.Null);
arrivalConnector.SetLocked(false);
BoxCollider2D arrivalTrigger = arrivalConnector.GetComponent<BoxCollider2D>();
Assert.That(arrivalTrigger.bounds.Intersects(playerBody.bounds), Is.False);
// Enter the destination trigger immediately after transition. The
// trigger stay must be ignored until the manager cooldown expires.
MoveBodyCenter(player, playerBody, arrivalTrigger.bounds.center);
yield return new WaitForFixedUpdate();
yield return new WaitForSecondsRealtime(0.1f);
Assert.That(stageManager.CurrentZone.NodeId, Is.EqualTo(targetNodeId));
float returnDeadline = Time.realtimeSinceStartup + 2f;
while ((stageManager.IsTransitioning
|| stageManager.CurrentZone == null
|| stageManager.CurrentZone.NodeId != startZone.NodeId)
&& Time.realtimeSinceStartup < returnDeadline)
{
yield return null;
}
Assert.That(stageManager.CurrentZone.NodeId, Is.EqualTo(startZone.NodeId));
// The return arrival is also outside its doorway. Leaving the
// player there must not produce an automatic pingpong transition.
yield return new WaitForSecondsRealtime(0.45f);
Assert.That(stageManager.CurrentZone.NodeId, Is.EqualTo(startZone.NodeId));
}
private static ZoneConnector FindOutgoingConnector(StageManager stageManager)
{
for (int direction = 0; direction < 4; direction++)
{
ZoneConnector connector = stageManager.CurrentZone.GetConnector((StageDirection)direction);
if (connector != null && connector.TargetNodeId >= 0)
{
return connector;
}
}
return null;
}
private static void MoveBodyCenter(
PlayerController player,
Collider2D playerBody,
Vector2 bodyCenter)
{
Vector2 bodyOffset = (Vector2)playerBody.bounds.center
- (Vector2)player.transform.position;
player.transform.position = bodyCenter - bodyOffset;
Physics2D.SyncTransforms();
}
}
}