Initial commit: Tiny Tackle Heroes Unity project
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
using System.Collections;
|
||||
using BumpCombat.Combat;
|
||||
using BumpCombat.Core;
|
||||
using BumpCombat.Player;
|
||||
using BumpCombat.Progression;
|
||||
using BumpCombat.Spawning;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace BumpCombat.PlayModeTests
|
||||
{
|
||||
public sealed class GuardVisualTests
|
||||
{
|
||||
[Test]
|
||||
public void GuardMasks_CoverAllSelectedColorAnimationFrames()
|
||||
{
|
||||
string[] sheets = { "Idle", "Walk", "Dash", "Hurt", "Death",
|
||||
"BumpAttack-v1", "BackBumpAttack-v2", "ArtifactUse-v1" };
|
||||
foreach (string sheet in sheets)
|
||||
{
|
||||
Sprite[] masks = Resources.LoadAll<Sprite>("Combat/Guard-v1/Swordsman_" + sheet + "-outline");
|
||||
Assert.That(masks.Length, Is.GreaterThan(0), sheet);
|
||||
foreach (string color in new[] { "Green", "Red", "Blue" })
|
||||
{
|
||||
Sprite[] frames = Resources.LoadAll<Sprite>("Artifacts/ThreeColor-v1/Player/Swordsman_" + sheet + "-" + color + "-v1");
|
||||
Assert.That(masks.Length, Is.EqualTo(frames.Length), sheet + color);
|
||||
foreach (Sprite frame in frames)
|
||||
{
|
||||
Sprite mask = System.Array.Find(masks, item => item.rect == frame.rect);
|
||||
Assert.That(mask, Is.Not.Null, frame.name);
|
||||
Assert.That(mask.pivot, Is.EqualTo(frame.pivot));
|
||||
Assert.That(mask.pixelsPerUnit, Is.EqualTo(frame.pixelsPerUnit));
|
||||
Assert.That(mask.texture.filterMode, Is.EqualTo(FilterMode.Point));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GuardOutline_FollowsFrameFlipPauseAndLifetime()
|
||||
{
|
||||
ArtifactRewardController.GrantCatalogForTests = true;
|
||||
RunManager.ForceProductionModeForTests = false;
|
||||
Time.timeScale = 1f;
|
||||
yield return SceneManager.LoadSceneAsync("CombatPrototype");
|
||||
yield return null;
|
||||
yield return null;
|
||||
Object.FindAnyObjectByType<SpawnDirector>().enabled = false;
|
||||
var health = Object.FindAnyObjectByType<PlayerHealth>();
|
||||
var visual = health.GetComponent<ArtifactChargeVisual>();
|
||||
var body = health.GetComponent<SpriteRenderer>();
|
||||
Assert.That(health.TryActivateGuard(), Is.True);
|
||||
visual.RefreshEquipmentSprite();
|
||||
visual.RefreshGuardOutline();
|
||||
var outline = health.transform.Find("Player Guard Outline").GetComponent<SpriteRenderer>();
|
||||
Assert.That(outline.enabled, Is.True);
|
||||
float guardedHealth = health.CurrentHealth;
|
||||
Assert.That(health.TryTakeDamage(25f, Vector2.right, 1.1f), Is.False);
|
||||
Assert.That(health.CurrentHealth, Is.EqualTo(guardedHealth));
|
||||
Assert.That(health.IsHurtMovementLocked, Is.False);
|
||||
Assert.That(outline.sprite.rect, Is.EqualTo(body.sprite.rect));
|
||||
Assert.That(outline.sprite.pivot, Is.EqualTo(body.sprite.pivot));
|
||||
Assert.That(outline.sprite.pixelsPerUnit, Is.EqualTo(body.sprite.pixelsPerUnit));
|
||||
body.flipX = true;
|
||||
body.sortingOrder = 123;
|
||||
visual.RefreshGuardOutline();
|
||||
Assert.That(outline.flipX, Is.True);
|
||||
Assert.That(outline.sortingOrder, Is.EqualTo(124));
|
||||
Time.timeScale = 0f;
|
||||
yield return new WaitForSecondsRealtime(0.6f);
|
||||
Assert.That(outline.enabled, Is.True);
|
||||
Assert.That(health.IsGuarding, Is.True);
|
||||
body.enabled = false;
|
||||
visual.RefreshGuardOutline();
|
||||
Assert.That(outline.enabled, Is.False);
|
||||
body.enabled = true;
|
||||
visual.RefreshGuardOutline();
|
||||
Assert.That(outline.enabled, Is.True);
|
||||
visual.enabled = false;
|
||||
Assert.That(outline.enabled, Is.False);
|
||||
visual.enabled = true;
|
||||
visual.RefreshGuardOutline();
|
||||
Assert.That(outline.enabled, Is.True);
|
||||
Time.timeScale = 1f;
|
||||
yield return new WaitForSeconds(health.GuardDuration + 0.05f);
|
||||
visual.RefreshGuardOutline();
|
||||
Assert.That(outline.enabled, Is.False);
|
||||
Assert.That(health.IsGuarding, Is.False);
|
||||
Assert.That(health.TryTakeDamage(1f, Vector2.zero, 0f), Is.True);
|
||||
Assert.That(health.CurrentHealth, Is.LessThan(guardedHealth));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GuardBlockImpact_FollowsPlayerPausesAndCleansUp()
|
||||
{
|
||||
ArtifactRewardController.GrantCatalogForTests = true;
|
||||
RunManager.ForceProductionModeForTests = false;
|
||||
Time.timeScale = 1f;
|
||||
yield return SceneManager.LoadSceneAsync("CombatPrototype");
|
||||
yield return null;
|
||||
yield return null;
|
||||
Object.FindAnyObjectByType<SpawnDirector>().enabled = false;
|
||||
PlayerHealth health = Object.FindAnyObjectByType<PlayerHealth>();
|
||||
CombatFeedback feedback = health.GetComponent<CombatFeedback>();
|
||||
SpriteRenderer playerRenderer = health.GetComponent<SpriteRenderer>();
|
||||
Collider2D playerCollider = health.GetComponent<Collider2D>();
|
||||
Assert.That(feedback, Is.Not.Null);
|
||||
Assert.That(playerRenderer, Is.Not.Null);
|
||||
Assert.That(playerCollider, Is.Not.Null);
|
||||
Sprite impactSprite = Resources.Load<Sprite>(
|
||||
CombatFeedback.GetGuardBlockImpactResourcePath());
|
||||
Assert.That(impactSprite, Is.Not.Null);
|
||||
Assert.That(health.TryActivateGuard(), Is.True);
|
||||
|
||||
Vector2 expectedPosition = (Vector2)playerCollider.bounds.center
|
||||
+ Vector2.left * 0.35f;
|
||||
Assert.That(
|
||||
health.TryTakeDamage(5f, Vector2.right * 3f, 0.75f),
|
||||
Is.False);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(1));
|
||||
Transform impact = health.transform.Find("Player Guard Block Impact");
|
||||
Assert.That(impact, Is.Not.Null);
|
||||
Assert.That(impact.parent, Is.EqualTo(health.transform));
|
||||
Assert.That(
|
||||
Vector2.Distance((Vector2)impact.position, expectedPosition),
|
||||
Is.LessThan(0.001f));
|
||||
SpriteRenderer impactRenderer = impact.GetComponent<SpriteRenderer>();
|
||||
Assert.That(impactRenderer.sprite, Is.EqualTo(impactSprite));
|
||||
Assert.That(impactRenderer.color, Is.EqualTo(Color.white));
|
||||
Assert.That(
|
||||
impactRenderer.sortingOrder,
|
||||
Is.EqualTo(playerRenderer.sortingOrder + 20));
|
||||
|
||||
Assert.That(health.TryTakeDamage(5f, Vector2.left, 0.75f), Is.False);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(1),
|
||||
"A second impact inside the 0.08-second interval must be suppressed.");
|
||||
|
||||
yield return new WaitForSeconds(0.09f);
|
||||
Assert.That(health.TryTakeDamage(5f, Vector2.zero, 0.75f), Is.False);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(2));
|
||||
Transform centeredImpact = null;
|
||||
foreach (Transform child in health.GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
if (child.name == "Player Guard Block Impact"
|
||||
&& Vector2.Distance(
|
||||
(Vector2)child.position,
|
||||
(Vector2)playerCollider.bounds.center) < 0.001f)
|
||||
{
|
||||
centeredImpact = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert.That(centeredImpact, Is.Not.Null,
|
||||
"A zero attack direction must place the impact at the body center.");
|
||||
|
||||
Vector3 initialImpactPosition = impact.position;
|
||||
health.transform.position += Vector3.up * 0.25f;
|
||||
Assert.That(impact.position, Is.EqualTo(initialImpactPosition + Vector3.up * 0.25f));
|
||||
|
||||
Time.timeScale = 0f;
|
||||
yield return new WaitForSecondsRealtime(0.22f);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(2),
|
||||
"The impact lifetime must pause with game time.");
|
||||
feedback.enabled = false;
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.Zero);
|
||||
|
||||
feedback.enabled = true;
|
||||
Time.timeScale = 1f;
|
||||
yield return new WaitForSeconds(0.09f);
|
||||
Assert.That(health.TryTakeDamage(5f, Vector2.right, 0.75f), Is.False);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(1));
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.Zero);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GuardBlockImpact_ClearsWhenPlayerDies()
|
||||
{
|
||||
ArtifactRewardController.GrantCatalogForTests = true;
|
||||
RunManager.ForceProductionModeForTests = false;
|
||||
Time.timeScale = 1f;
|
||||
yield return SceneManager.LoadSceneAsync("CombatPrototype");
|
||||
yield return null;
|
||||
yield return null;
|
||||
Object.FindAnyObjectByType<SpawnDirector>().enabled = false;
|
||||
PlayerHealth health = Object.FindAnyObjectByType<PlayerHealth>();
|
||||
CombatFeedback feedback = health.GetComponent<CombatFeedback>();
|
||||
Assert.That(health.TryActivateGuard(), Is.True);
|
||||
Assert.That(health.TryTakeDamage(1f, Vector2.right, 0.75f), Is.False);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.EqualTo(1));
|
||||
|
||||
health.enabled = false;
|
||||
Assert.That(
|
||||
health.TryTakeDamage(health.CurrentHealth, Vector2.right, 0f),
|
||||
Is.True);
|
||||
Assert.That(health.CurrentHealth, Is.Zero);
|
||||
Assert.That(feedback.ActiveGuardBlockImpactVisualCount, Is.Zero);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ArtifactRewardController.GrantCatalogForTests = false;
|
||||
RunManager.ForceProductionModeForTests = false;
|
||||
Time.timeScale = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user