Add fixed-camera tower effect preview scene

This commit is contained in:
2026-09-24 22:02:14 +09:00
parent 926b3f6c5d
commit 0aba40db2b
31 changed files with 2923 additions and 0 deletions
@@ -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