122 lines
6.3 KiB
C#
122 lines
6.3 KiB
C#
using System.Collections;
|
|
using System.IO;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.TestTools;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor.SceneManagement;
|
|
#endif
|
|
using BumpCombat.Defense;
|
|
|
|
namespace BumpCombat.PlayModeTests
|
|
{
|
|
public sealed class Defense25DPreviewTests
|
|
{
|
|
private float previousTimeScale;
|
|
|
|
[UnitySetUp]
|
|
public IEnumerator SetNormalTimeScale()
|
|
{
|
|
previousTimeScale = Time.timeScale;
|
|
Time.timeScale = 1f;
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTearDown]
|
|
public IEnumerator RestoreTimeScale()
|
|
{
|
|
Time.timeScale = previousTimeScale;
|
|
yield return null;
|
|
}
|
|
|
|
[UnityTest]
|
|
public IEnumerator FireTargetAuraAndMeteor_KeepGroundHeightLayersAndCaptureRuntimeFrames()
|
|
{
|
|
#if UNITY_EDITOR
|
|
EditorSceneManager.LoadSceneInPlayMode("Assets/_Project/Scenes/Defense25DPreview.unity", new LoadSceneParameters(LoadSceneMode.Single));
|
|
#else
|
|
SceneManager.LoadScene("Defense25DPreview");
|
|
#endif
|
|
yield return null;
|
|
var preview = Object.FindFirstObjectByType<Defense25DPreview>();
|
|
Assert.That(preview, Is.Not.Null);
|
|
Assert.That(preview.AuraBackFrames.Length, Is.EqualTo(6));
|
|
Assert.That(preview.AuraFrontFrames.Length, Is.EqualTo(6));
|
|
Assert.That(preview.BodyFrames.Length, Is.EqualTo(6));
|
|
Assert.That(preview.MeteorFlightFrames.Length, Is.EqualTo(4));
|
|
Assert.That(preview.MeteorImpactFrames.Length, Is.EqualTo(8));
|
|
Assert.That(preview.Body.sprite.name, Does.StartWith("T3-Idle_"));
|
|
Assert.That(preview.Body.transform.parent.GetComponentsInChildren<SpriteRenderer>().Length, Is.EqualTo(1));
|
|
Assert.That(preview.AuraBack.sortingOrder, Is.LessThan(preview.Body.sortingOrder));
|
|
Assert.That(preview.Body.sortingOrder, Is.LessThan(preview.AuraFront.sortingOrder));
|
|
Assert.That(preview.AuraBack.transform.position, Is.EqualTo(preview.AuraFront.transform.position));
|
|
Assert.That(preview.AuraBackFrames[0].pivot / preview.AuraBackFrames[0].rect.size, Is.EqualTo(new Vector2(0.5f, 0.4f)));
|
|
Assert.That(Camera.main.orthographicSize, Is.EqualTo(2.8125f));
|
|
Assert.That(preview.AuraBack.transform.localScale, Is.EqualTo(preview.AuraFront.transform.localScale));
|
|
Assert.That(preview.BodyVisual.localPosition.y, Is.EqualTo(9f / 32f).Within(0.0001f));
|
|
Assert.That(Defense25DPreview.ProjectGroundAndHeight(new Vector2(3f, 4f), 2f), Is.EqualTo(new Vector3(1f, 6f, 0f)));
|
|
|
|
string output = FindOutputDirectory();
|
|
float deadline = Time.realtimeSinceStartup + 5f;
|
|
while (!preview.Meteor.enabled && Time.realtimeSinceStartup < deadline) yield return null;
|
|
Assert.That(preview.Meteor.enabled, Is.True, "Meteor did not start within five realtime seconds.");
|
|
Capture(Camera.main, Path.Combine(output, "runtime-01-meteor-early.png"));
|
|
Vector3 earlyViewport = Camera.main.WorldToViewportPoint(preview.Meteor.transform.position);
|
|
Assert.That(earlyViewport.y, Is.InRange(0f, 1f), "Early meteor must stay within the camera frame.");
|
|
|
|
float initialHeight = preview.CurrentMeteorHeight;
|
|
deadline = Time.realtimeSinceStartup + 5f;
|
|
while (!(preview.CurrentMeteorHeight > 0f && preview.CurrentMeteorHeight <= initialHeight * 0.6f) &&
|
|
Time.realtimeSinceStartup < deadline) yield return null;
|
|
Assert.That(preview.CurrentMeteorHeight, Is.GreaterThan(0f).And.LessThanOrEqualTo(initialHeight * 0.6f),
|
|
"Midflight capture did not reach the height threshold within five realtime seconds.");
|
|
Capture(Camera.main, Path.Combine(output, "runtime-02-meteor-midflight.png"));
|
|
Assert.That(preview.Meteor.transform.position, Is.Not.EqualTo(preview.GroundAnchor.position));
|
|
Assert.That(preview.CurrentMeteorGround, Is.Not.EqualTo((Vector2)preview.GroundAnchor.position));
|
|
|
|
deadline = Time.realtimeSinceStartup + 5f;
|
|
while (!(preview.Meteor.enabled && preview.CurrentMeteorHeight <= 0f) &&
|
|
Time.realtimeSinceStartup < deadline) yield return null;
|
|
Assert.That(preview.Meteor.enabled && preview.CurrentMeteorHeight <= 0f, Is.True,
|
|
"Meteor did not reach ground height within five realtime seconds.");
|
|
Capture(Camera.main, Path.Combine(output, "runtime-03-meteor-impact.png"));
|
|
deadline = Time.realtimeSinceStartup + 5f;
|
|
while (preview.Meteor.enabled && Time.realtimeSinceStartup < deadline) yield return null;
|
|
Assert.That(preview.Meteor.enabled, Is.False, "Meteor impact sequence did not finish within five realtime seconds.");
|
|
Assert.That(preview.AuraBack.transform.position.x, Is.EqualTo(preview.GroundAnchor.position.x).Within(0.0001f));
|
|
}
|
|
|
|
private static void Capture(Camera camera, string path)
|
|
{
|
|
const int width = 1280, height = 720;
|
|
var texture = new RenderTexture(width, height, 24, RenderTextureFormat.ARGB32);
|
|
var image = new Texture2D(width, height, TextureFormat.RGB24, false);
|
|
camera.targetTexture = texture;
|
|
camera.Render();
|
|
RenderTexture previous = RenderTexture.active;
|
|
RenderTexture.active = texture;
|
|
image.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
|
image.Apply();
|
|
File.WriteAllBytes(path, image.EncodeToPNG());
|
|
camera.targetTexture = null;
|
|
RenderTexture.active = previous;
|
|
Object.Destroy(texture);
|
|
Object.Destroy(image);
|
|
}
|
|
|
|
private static string FindOutputDirectory()
|
|
{
|
|
for (DirectoryInfo folder = new DirectoryInfo(Application.dataPath); folder != null; folder = folder.Parent)
|
|
{
|
|
string output = Path.Combine(folder.FullName, "output/tower-25d-v1");
|
|
if (Directory.Exists(output)) return output;
|
|
}
|
|
|
|
string projectOutput = Path.GetFullPath(Path.Combine(Application.dataPath, "../output/tower-25d-v1"));
|
|
Directory.CreateDirectory(projectOutput);
|
|
return projectOutput;
|
|
}
|
|
}
|
|
}
|