165 lines
6.3 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|