Add fixed-camera tower effect preview scene
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
using System.Collections.Generic;
|
||||
namespace BumpCombat.Defense
|
||||
{
|
||||
internal static class DefenseTowerArtDurations
|
||||
{
|
||||
private static readonly Dictionary<string, int[]> Values = new()
|
||||
{
|
||||
["Bodies/Fire/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T1-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T2-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T3-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/Base-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T4-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T1-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T2-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T3-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/Base-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Fire/T4-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T1-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T2-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T3-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/Base-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T4-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T1-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T2-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T3-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/Base-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Lightning/T4-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T1-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T2-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T3-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/Base-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T4-Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T1-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T2-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T3-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/Base-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Ice/T4-Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T1-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T2-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T3-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/Base-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T4-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T1-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T2-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T3-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/Base-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Control/T4-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T1-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T2-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T3-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/Base-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T4-Attack"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T1-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T2-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T3-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/Base-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Support/T4-Heal"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Summon/T1-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Summon/T2-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Summon/T3-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Summon/Base-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Bodies/Summon/T4-Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Effects/Fire/T1-Fireball"] = new[] { 90, 90, 90, 90 },
|
||||
["Effects/Fire/T2-Fireball"] = new[] { 90, 90, 90, 90 },
|
||||
["Effects/Fire/T3-Fireball"] = new[] { 90, 90, 90, 90 },
|
||||
["Effects/Fire/Impact"] = new[] { 45, 55, 60, 50 },
|
||||
["Effects/Fire/Meteor-Flight"] = new[] { 80, 80, 80, 80 },
|
||||
["Effects/Fire/Meteor-Impact"] = new[] { 40, 50, 60, 70, 60, 60, 60, 80 },
|
||||
["Sources/BlackKnight-NoSkull"] = new[] { 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Effects/Fire/Flamethrower"] = new[] { 80, 80, 80, 70, 65, 65, 70 },
|
||||
["Effects/Lightning/T1-Bolt"] = new[] { 30, 40, 30, 30, 40, 40, 40, 50 },
|
||||
["Effects/Lightning/T2-Bolt"] = new[] { 30, 40, 30, 30, 40, 40, 40, 50 },
|
||||
["Effects/Lightning/T3-Bolt"] = new[] { 30, 40, 30, 30, 40, 40, 40, 50 },
|
||||
["Effects/Lightning/Arc"] = new[] { 30, 40, 30, 30, 40, 40, 40, 50 },
|
||||
["Effects/Lightning/ImpactWave"] = new[] { 40, 40, 50, 50, 60, 60 },
|
||||
["Effects/Lightning/LightningStorm"] = new[] { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 },
|
||||
["Effects/Ice/T1-Volley"] = new[] { 125 },
|
||||
["Effects/Ice/T2-Volley"] = new[] { 125 },
|
||||
["Effects/Ice/T3-Volley"] = new[] { 125 },
|
||||
["Effects/Ice/Shard"] = new[] { 125 },
|
||||
["Effects/Ice/Freezebolt"] = new[] { 85, 85, 85, 85 },
|
||||
["Effects/Ice/Impact"] = new[] { 40, 50, 60, 70 },
|
||||
["Effects/Ice/GlacialCage-Front"] = new[] { 65, 65, 90, 140, 140, 140, 70, 70 },
|
||||
["Effects/Ice/GlacialCage-Back"] = new[] { 65, 65, 90, 140, 140, 140, 70, 70 },
|
||||
["Effects/Control/T1-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Control/T2-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Control/T3-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Support/T1-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Support/T2-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Support/T3-Aura"] = new[] { 140, 140, 140, 140, 140, 140 },
|
||||
["Effects/Control/StoneGaze"] = new[] { 90, 90, 90, 90, 90, 90, 90, 90 },
|
||||
["Effects/Control/Temporal"] = new[] { 170, 170, 170, 170, 170, 170, 170, 170 },
|
||||
["Effects/Support/Imbuing"] = new[] { 130, 130, 130, 130, 130, 130, 130, 130 },
|
||||
["Effects/Support/Smothering"] = new[] { 150, 150, 150, 150, 150, 150, 150, 150 },
|
||||
["Summons/Slime/Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/Slime/Walk"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Walk"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/Slime/Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/Slime/Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/Slime/Hurt"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Hurt"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/Slime/Death"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/GiantSlime/Death"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Idle"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Walk"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Attack01"] = new[] { 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Attack02"] = new[] { 125, 125, 125, 125, 125, 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Hurt"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/Death"] = new[] { 125, 125, 125, 125 },
|
||||
["Summons/LavaSlime/GroundSpike-Segment"] = new[] { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
|
||||
["Summons/LavaSlime/GroundSpike-Wave"] = new[] { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
|
||||
};
|
||||
|
||||
public static ICollection<string> Keys => Values.Keys;
|
||||
|
||||
public static int FrameCount(string key)
|
||||
{
|
||||
return Values.TryGetValue(key, out int[] values) ? values.Length : 0;
|
||||
}
|
||||
|
||||
public static float Seconds(string key, int frame)
|
||||
{
|
||||
if (!Values.TryGetValue(key, out int[] values) || values.Length == 0)
|
||||
{
|
||||
return 0.125f;
|
||||
}
|
||||
int safeFrame = frame < 0 ? 0 : frame >= values.Length ? values.Length - 1 : frame;
|
||||
return values[safeFrame] / 1000f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe0c687a555c4bc291e278b2e7dabc04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BumpCombat.Defense
|
||||
{
|
||||
public sealed class Defense25DPreview : MonoBehaviour
|
||||
{
|
||||
private const string BodyKey = "Bodies/Fire/T3-Idle";
|
||||
private const string FlightKey = "Effects/Fire/Meteor-Flight";
|
||||
private const string ImpactKey = "Effects/Fire/Meteor-Impact";
|
||||
private const float AuraFrameSeconds = 0.14f;
|
||||
|
||||
[SerializeField] private SpriteRenderer body, auraBack, auraFront, meteor;
|
||||
[SerializeField] private Sprite[] auraBackFrames, auraFrontFrames, meteorFlightFrames, meteorImpactFrames, bodyFrames;
|
||||
[SerializeField] private Transform groundAnchor, bodyVisual;
|
||||
[SerializeField] private float flightHeight = 1.7f;
|
||||
|
||||
public SpriteRenderer Body => body;
|
||||
public SpriteRenderer AuraBack => auraBack;
|
||||
public SpriteRenderer AuraFront => auraFront;
|
||||
public SpriteRenderer Meteor => meteor;
|
||||
public Sprite[] AuraBackFrames => auraBackFrames;
|
||||
public Sprite[] AuraFrontFrames => auraFrontFrames;
|
||||
public Sprite[] MeteorFlightFrames => meteorFlightFrames;
|
||||
public Sprite[] MeteorImpactFrames => meteorImpactFrames;
|
||||
public Sprite[] BodyFrames => bodyFrames;
|
||||
public Transform GroundAnchor => groundAnchor;
|
||||
public Transform BodyVisual => bodyVisual;
|
||||
public float CurrentMeteorHeight { get; private set; }
|
||||
public Vector2 CurrentMeteorGround { get; private set; }
|
||||
|
||||
public void Configure(Sprite[] back, Sprite[] front, Sprite[] flight, Sprite[] impact, Sprite[] character)
|
||||
{
|
||||
auraBackFrames = back; auraFrontFrames = front; meteorFlightFrames = flight;
|
||||
meteorImpactFrames = impact; bodyFrames = character;
|
||||
}
|
||||
|
||||
public static Vector3 ProjectGroundAndHeight(Vector2 groundPosition, float height) =>
|
||||
new Vector3(groundPosition.x - height, groundPosition.y + height, 0f);
|
||||
|
||||
private IEnumerator Start()
|
||||
{
|
||||
StartCoroutine(AnimateAura());
|
||||
StartCoroutine(AnimateBody());
|
||||
StartCoroutine(MoveTarget());
|
||||
while (true)
|
||||
{
|
||||
yield return new WaitForSeconds(0.25f);
|
||||
yield return PlayMeteor();
|
||||
yield return new WaitForSeconds(0.55f);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator MoveTarget()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Vector3 p = groundAnchor.position;
|
||||
p.x = Mathf.Sin(Time.time * 0.7f) * 0.65f;
|
||||
groundAnchor.position = p;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateAura()
|
||||
{
|
||||
int frame = 0;
|
||||
while (true)
|
||||
{
|
||||
auraBack.sprite = auraBackFrames[frame];
|
||||
auraFront.sprite = auraFrontFrames[frame];
|
||||
frame = (frame + 1) % auraBackFrames.Length;
|
||||
yield return new WaitForSeconds(AuraFrameSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator AnimateBody()
|
||||
{
|
||||
int frame = 0;
|
||||
while (true)
|
||||
{
|
||||
body.sprite = bodyFrames[frame];
|
||||
frame = (frame + 1) % bodyFrames.Length;
|
||||
yield return new WaitForSeconds(DefenseTowerArt.FrameSeconds(BodyKey, frame == 0 ? bodyFrames.Length - 1 : frame - 1));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator PlayMeteor()
|
||||
{
|
||||
CurrentMeteorGround = groundAnchor.position;
|
||||
meteor.enabled = true;
|
||||
CurrentMeteorHeight = flightHeight;
|
||||
float flightDuration = 0f;
|
||||
for (int i = 0; i < meteorFlightFrames.Length; i++) flightDuration += DefenseTowerArt.FrameSeconds(FlightKey, i);
|
||||
|
||||
float elapsed = 0f;
|
||||
for (int i = 0; i < meteorFlightFrames.Length; i++)
|
||||
{
|
||||
meteor.sprite = meteorFlightFrames[i];
|
||||
float frameSeconds = DefenseTowerArt.FrameSeconds(FlightKey, i);
|
||||
float frameElapsed = 0f;
|
||||
while (frameElapsed < frameSeconds)
|
||||
{
|
||||
CurrentMeteorHeight = flightHeight * (1f - elapsed / flightDuration);
|
||||
meteor.transform.position = ProjectGroundAndHeight(CurrentMeteorGround, CurrentMeteorHeight);
|
||||
float dt = Mathf.Min(Time.deltaTime, frameSeconds - frameElapsed);
|
||||
frameElapsed += dt;
|
||||
elapsed += dt;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentMeteorHeight = 0f;
|
||||
meteor.transform.position = ProjectGroundAndHeight(CurrentMeteorGround, 0f);
|
||||
for (int i = 0; i < meteorImpactFrames.Length; i++)
|
||||
{
|
||||
meteor.sprite = meteorImpactFrames[i];
|
||||
yield return new WaitForSeconds(DefenseTowerArt.FrameSeconds(ImpactKey, i));
|
||||
}
|
||||
meteor.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c00de25d48634556853f7a2df8445f18
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BumpCombat.Defense
|
||||
{
|
||||
public static class DefenseTowerArt
|
||||
{
|
||||
private const string ResourceRoot = "DefenseTowers-v1/";
|
||||
private static readonly Dictionary<string, Sprite[]> Frames = new();
|
||||
|
||||
public static ICollection<string> Keys => DefenseTowerArtDurations.Keys;
|
||||
|
||||
public static int ExpectedFrameCount(string key)
|
||||
{
|
||||
return DefenseTowerArtDurations.FrameCount(key);
|
||||
}
|
||||
|
||||
public static Sprite[] Load(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
return Array.Empty<Sprite>();
|
||||
}
|
||||
|
||||
if (!Frames.TryGetValue(key, out Sprite[] sprites))
|
||||
{
|
||||
sprites = Resources.LoadAll<Sprite>(ResourceRoot + key);
|
||||
Array.Sort(sprites, CompareFrameNames);
|
||||
Frames.Add(key, sprites);
|
||||
}
|
||||
return sprites;
|
||||
}
|
||||
|
||||
public static float FrameSeconds(string key, int frame)
|
||||
{
|
||||
return DefenseTowerArtDurations.Seconds(key, frame);
|
||||
}
|
||||
|
||||
public static string BodyKey(DefenseTowerKind kind, int tier, string motion)
|
||||
{
|
||||
string family = kind switch
|
||||
{
|
||||
DefenseTowerKind.Direct => "Fire",
|
||||
DefenseTowerKind.Summon => "Summon",
|
||||
DefenseTowerKind.Lightning => "Lightning",
|
||||
DefenseTowerKind.Cold => "Ice",
|
||||
DefenseTowerKind.Seismic => "Control",
|
||||
_ => "Support",
|
||||
};
|
||||
return $"Bodies/{family}/T{tier}-{motion}";
|
||||
}
|
||||
|
||||
private static int CompareFrameNames(Sprite left, Sprite right)
|
||||
{
|
||||
return FrameIndex(left.name).CompareTo(FrameIndex(right.name));
|
||||
}
|
||||
|
||||
private static int FrameIndex(string name)
|
||||
{
|
||||
int separator = name.LastIndexOf('_');
|
||||
return separator >= 0 && int.TryParse(name.Substring(separator + 1), out int index)
|
||||
? index : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3608a711d7f74976b57e54ef7981c28a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using BumpCombat.Defense;
|
||||
|
||||
namespace BumpCombat.Editor
|
||||
{
|
||||
public static class Defense25DPreviewSetup
|
||||
{
|
||||
private const string ScenePath = "Assets/_Project/Scenes/Defense25DPreview.unity";
|
||||
private const string PreviewArt = "Assets/_Project/Art/Defense25DPreview";
|
||||
private const string BackName = "Support-T3-Aura-Back";
|
||||
private const string FrontName = "Support-T3-Aura-Front";
|
||||
|
||||
[MenuItem("BumpCombat/Defense 2.5D/Build and Open Preview Scene")]
|
||||
public static void BuildAndOpen() {
|
||||
if (!Application.isBatchMode && !EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) return;
|
||||
ImportParentAuraArt();
|
||||
AssetDatabase.Refresh();
|
||||
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
var cameraObject = new GameObject("Fixed Orthographic Camera");
|
||||
var camera = cameraObject.AddComponent<Camera>();
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = 2.8125f;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.backgroundColor = new Color(0.08f, 0.1f, 0.14f);
|
||||
camera.transform.position = new Vector3(0f, 0.3f, -10f);
|
||||
camera.tag = "MainCamera";
|
||||
|
||||
var anchor = new GameObject("Target Ground Anchor").transform;
|
||||
var back = CreateSprite("Aura Back", anchor, 10);
|
||||
back.transform.localScale = Vector3.one * 0.8f;
|
||||
var bodyVisual = new GameObject("Character Visual (cell center above foot anchor)").transform;
|
||||
bodyVisual.SetParent(anchor, false);
|
||||
bodyVisual.localPosition = new Vector3(0f, 9f / 32f, 0f);
|
||||
var body = CreateSprite("Fire T3 Character (effect target)", bodyVisual, 30);
|
||||
Sprite[] bodyFrames = DefenseTowerArt.Load("Bodies/Fire/T3-Idle");
|
||||
body.sprite = bodyFrames.FirstOrDefault();
|
||||
var front = CreateSprite("Aura Front", anchor, 40);
|
||||
front.transform.localScale = back.transform.localScale;
|
||||
|
||||
var meteor = CreateSprite("Meteor (ground position + height projection)", null, 50);
|
||||
meteor.enabled = false;
|
||||
var root = new GameObject("Defense 2.5D Preview");
|
||||
var preview = root.AddComponent<Defense25DPreview>();
|
||||
var so = new SerializedObject(preview);
|
||||
so.FindProperty("flightHeight").floatValue = 1.7f;
|
||||
so.FindProperty("body").objectReferenceValue = body;
|
||||
so.FindProperty("auraBack").objectReferenceValue = back;
|
||||
so.FindProperty("auraFront").objectReferenceValue = front;
|
||||
so.FindProperty("meteor").objectReferenceValue = meteor;
|
||||
so.FindProperty("groundAnchor").objectReferenceValue = anchor;
|
||||
so.FindProperty("bodyVisual").objectReferenceValue = bodyVisual;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
preview.Configure(LoadPreviewFrames(BackName), LoadPreviewFrames(FrontName),
|
||||
DefenseTowerArt.Load("Effects/Fire/Meteor-Flight"), DefenseTowerArt.Load("Effects/Fire/Meteor-Impact"), bodyFrames);
|
||||
EditorUtility.SetDirty(preview);
|
||||
EditorSceneManager.SaveScene(scene, ScenePath);
|
||||
Selection.activeGameObject = root;
|
||||
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<SceneAsset>(ScenePath));
|
||||
Debug.Log($"Defense 2.5D preview saved: {ScenePath}; aura={preview.AuraBackFrames.Length}/{preview.AuraFrontFrames.Length}; body=Fire T3 Idle.");
|
||||
}
|
||||
|
||||
private static void ImportParentAuraArt()
|
||||
{
|
||||
string directory = Path.GetFullPath(Path.Combine(Application.dataPath, "_Project/Art/Defense25DPreview"));
|
||||
Directory.CreateDirectory(directory);
|
||||
string backTarget = Path.Combine(directory, BackName + ".png");
|
||||
string frontTarget = Path.Combine(directory, FrontName + ".png");
|
||||
string sourceRoot = File.Exists(backTarget) && File.Exists(frontTarget) ? null : FindParentOutputRoot();
|
||||
ImportAura(sourceRoot == null ? null : Path.Combine(sourceRoot, BackName + ".png"), backTarget, $"{PreviewArt}/{BackName}.png");
|
||||
ImportAura(sourceRoot == null ? null : Path.Combine(sourceRoot, FrontName + ".png"), frontTarget, $"{PreviewArt}/{FrontName}.png");
|
||||
}
|
||||
|
||||
private static string FindParentOutputRoot()
|
||||
{
|
||||
for (DirectoryInfo folder = new DirectoryInfo(Application.dataPath); folder != null; folder = folder.Parent)
|
||||
{
|
||||
string candidate = Path.Combine(folder.FullName, "output/tower-25d-v1/assets");
|
||||
if (File.Exists(Path.Combine(candidate, BackName + ".png")) && File.Exists(Path.Combine(candidate, FrontName + ".png"))) return candidate;
|
||||
}
|
||||
throw new FileNotFoundException("Could not find output/tower-25d-v1/assets with both parent aura sheets.");
|
||||
}
|
||||
|
||||
private static void ImportAura(string source, string target, string assetPath)
|
||||
{
|
||||
if (!File.Exists(target)) File.Copy(source, target);
|
||||
AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
|
||||
var importer = (TextureImporter)AssetImporter.GetAtPath(assetPath);
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Multiple;
|
||||
importer.spritePixelsPerUnit = 32;
|
||||
importer.filterMode = FilterMode.Point;
|
||||
importer.mipmapEnabled = false;
|
||||
importer.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
foreach (string platform in new[] { "DefaultTexturePlatform", "Standalone", "WebGL", "Android", "iPhone" })
|
||||
{
|
||||
TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings(platform);
|
||||
settings.name = platform;
|
||||
settings.overridden = true;
|
||||
settings.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
importer.SetPlatformTextureSettings(settings);
|
||||
}
|
||||
var metas = new SpriteMetaData[6];
|
||||
for (int i = 0; i < metas.Length; i++)
|
||||
metas[i] = new SpriteMetaData { name = Path.GetFileNameWithoutExtension(target) + "_" + i,
|
||||
rect = new Rect(i * 100, 0, 100, 100), alignment = (int)SpriteAlignment.Custom, pivot = new Vector2(0.5f, 0.4f) };
|
||||
importer.spritesheet = metas;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
private static Sprite[] LoadPreviewFrames(string name) =>
|
||||
AssetDatabase.LoadAllAssetsAtPath($"{PreviewArt}/{name}.png").OfType<Sprite>().OrderBy(s => s.name).ToArray();
|
||||
|
||||
private static SpriteRenderer CreateSprite(string name, Transform parent, int order)
|
||||
{
|
||||
var go = new GameObject(name);
|
||||
if (parent != null) go.transform.SetParent(parent, false);
|
||||
var renderer = go.AddComponent<SpriteRenderer>();
|
||||
renderer.sortingOrder = order;
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3d92f18b0aa45df9a6f1d2a9fd12ac7
|
||||
Reference in New Issue
Block a user