using System.Collections; using System.Linq; using BumpCombat.Constants; using BumpCombat.Defense.Comparison; using BumpCombat.Player; using NUnit.Framework; using UnityEditor; using UnityEngine; using UnityEngine.TestTools; using Object = UnityEngine.Object; namespace BumpCombat.Tests { public sealed class Defense25DPlayerArtPlayModeTests { private const string SettingsPath = "Assets/_Project/Constants/Defense25DComparison/ComparisonSettings.asset"; private Defense25DComparison world; private Defense25DComparisonSettings settings; private Defense25DPlayerArt playerArt; [UnitySetUp] public IEnumerator SetUp() { settings = Object.Instantiate( AssetDatabase.LoadAssetAtPath(SettingsPath)); Assert.That(settings, Is.Not.Null); settings.Enemy = AssetDatabase.LoadAssetAtPath( "Assets/_Project/Constants/Enemies/Slime.asset"); settings.PlayerArt = ReadCharacter("Swordsman", "Swordsman", "BumpAttack-v1"); settings.EnemyArt = ReadCharacter("Slime", "Slime", "Attack"); world = new GameObject("2.5D player art test world") .AddComponent(); world.Initialize(settings); world.AutoSpawn = false; world.ReadInput = false; playerArt = world.Player.gameObject.AddComponent(); playerArt.Bind(world); yield return null; } [UnityTearDown] public IEnumerator TearDown() { if (world != null) Object.Destroy(world.gameObject); if (settings != null) Object.Destroy(settings); yield return null; } [UnityTest] public IEnumerator EquipmentSprite_UsesMatchingExistingFramesForEachPaletteAndRestores() { ActiveArtifactEffect[] effects = { ActiveArtifactEffect.Dash, ActiveArtifactEffect.Pulse, ActiveArtifactEffect.ChainLightning, }; SpriteRenderer body = world.Player.Visual.Renderer; for (int i = 0; i < effects.Length; i++) { ActiveArtifactDefinition definition = world.Loadout.FindArtifact(effects[i]); Assert.That(definition, Is.Not.Null, effects[i].ToString()); Assert.That(world.Loadout.TryAddArtifact(definition), Is.True); Assert.That(world.Loadout.Select(i), Is.True); yield return null; Sprite tinted = body.sprite; Assert.That(tinted, Is.Not.Null); Assert.That(tinted.texture.name, Is.EqualTo("Swordsman_Idle-" + definition.ArtifactColor + "-v1")); Sprite original = settings.PlayerArt.Idle.FirstOrDefault( frame => frame.rect == tinted.rect); Assert.That(original, Is.Not.Null); Assert.That(tinted.rect, Is.EqualTo(original.rect)); Assert.That(tinted.pivot, Is.EqualTo(original.pivot)); Assert.That(tinted.pixelsPerUnit, Is.EqualTo(original.pixelsPerUnit)); playerArt.ResetVisuals(); Assert.That(body.sprite.texture.name, Is.EqualTo("Swordsman_Idle")); } } [UnityTest] public IEnumerator PrecoloredSequenceFrame_IsResolvedToBaseForSelectedPalette() { Sprite[] blueFrames = Resources.LoadAll( "Artifacts/ThreeColor-v1/Player/Swordsman_Idle-Blue-v1"); Sprite blueFrame = blueFrames.FirstOrDefault(frame => settings.PlayerArt.Idle.Any(original => original.rect == frame.rect)); Assert.That(blueFrame, Is.Not.Null); ActiveArtifactDefinition red = world.Loadout.FindArtifact(ActiveArtifactEffect.Pulse); Assert.That(red, Is.Not.Null); Assert.That(world.Loadout.TryAddArtifact(red), Is.True); Assert.That(world.Loadout.Select(0), Is.True); world.Player.Visual.Renderer.sprite = blueFrame; yield return null; Sprite recolored = world.Player.Visual.Renderer.sprite; Assert.That(recolored.texture.name, Is.EqualTo("Swordsman_Idle-Red-v1")); Assert.That(recolored.rect, Is.EqualTo(blueFrame.rect)); Assert.That(recolored.rect, Is.EqualTo(settings.PlayerArt.Idle .First(original => original.rect == blueFrame.rect).rect)); playerArt.ResetVisuals(); Assert.That(world.Player.Visual.Renderer.sprite.texture.name, Is.EqualTo("Swordsman_Idle")); } [UnityTest] public IEnumerator PrecoloredArtifactUseFrame_UsesBasePaletteAndGuardMaskKeys() { ActiveArtifactDefinition red = world.Loadout.FindArtifact(ActiveArtifactEffect.Pulse); Assert.That(red, Is.Not.Null); Assert.That(world.Loadout.TryAddArtifact(red), Is.True); Assert.That(world.Loadout.Select(0), Is.True); Sprite sequenceFrame = Resources.LoadAll( "Artifacts/ThreeColor-v1/Player/Swordsman_ArtifactUse-v1-Blue-v1").First(); SpriteRenderer body = world.Player.Visual.Renderer; body.sprite = sequenceFrame; world.Player.Visual.enabled = false; Assert.That(world.Player.TryActivateGuard(), Is.True); yield return null; SpriteRenderer outline = body.transform.Find("Player Guard Outline") .GetComponent(); Assert.That(outline.enabled, Is.True); Assert.That(outline.sprite.texture.name, Is.EqualTo("Swordsman_ArtifactUse-v1-outline")); Assert.That(outline.sprite.rect, Is.EqualTo(sequenceFrame.rect)); Assert.That(body.sprite.texture.name, Is.EqualTo("Swordsman_ArtifactUse-v1-Red-v1")); Assert.That(body.sprite.rect, Is.EqualTo(sequenceFrame.rect)); } [UnityTest] public IEnumerator DisabledWorld_DoesNotReapplyPaletteVisuals() { ActiveArtifactDefinition red = world.Loadout.FindArtifact(ActiveArtifactEffect.Pulse); Assert.That(world.Loadout.TryAddArtifact(red), Is.True); Assert.That(world.Loadout.Select(0), Is.True); SpriteRenderer body = world.Player.Visual.Renderer; Sprite original = settings.PlayerArt.Idle[0]; body.sprite = original; world.enabled = false; yield return null; Assert.That(body.sprite, Is.SameAs(original)); world.enabled = true; } [UnityTest] public IEnumerator UnguardedPlayer_HasNoOutlineAndResetRestoresSourceSprite() { SpriteRenderer body = world.Player.Visual.Renderer; Assert.That(body.transform.Find("Player Guard Outline"), Is.Null, "The art component has no local guard-state substitute; it follows the actor state."); yield return null; playerArt.ResetVisuals(); Assert.That(body.sprite.texture.name, Is.EqualTo("Swordsman_Idle")); playerArt.enabled = false; Assert.That(body.sprite.texture.name, Is.EqualTo("Swordsman_Idle")); } private static ComparisonSpriteFrames ReadCharacter(string folder, string prefix, string attack) { Sprite[] Read(string suffix) => AssetDatabase.LoadAllAssetsAtPath( $"Assets/_Project/Art/Characters/{folder}/{prefix}_{suffix}.png") .OfType() .OrderBy(sprite => int.TryParse( sprite.name[(sprite.name.LastIndexOf('_') + 1)..], out int frame) ? frame : 0) .ToArray(); return new ComparisonSpriteFrames { Idle = Read("Idle"), Walk = Read("Walk"), Attack = Read(attack), Hurt = Read("Hurt"), Death = Read("Death"), }; } } }