98 lines
4.1 KiB
C#
98 lines
4.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
// 전투 유닛 도트 그림 — Resources/Art/Units/px_<그림 id>.png(PD 원화 시트 80종 도트화 · 2026-10-28 · 드래곤 501 = Krea 2 생성 2026-10-30)
|
|
// 유닛 → 그림 = Data/unit_art.json(표에 없거나 그림이 없으면 null → 코드 그림 그대로)
|
|
// 애니 프레임(2026-10-30 · Wan 2.2 I2V + 원화 고정 합성 · scripts/pixel/vs_anim.py) = Art/Units/anim/px_<art>_<walk|attack>_<k>.png · 표 = Data/unit_anim.json(fps · 공격 타격 프레임)
|
|
namespace VS.View
|
|
{
|
|
public static class UnitArt
|
|
{
|
|
[Serializable] class Row { public int id; public int art; }
|
|
[Serializable] class Table { public Row[] units; }
|
|
[Serializable] public class Clip { public int art; public string act; public int frames; public int hit = -1; public string seed; }
|
|
[Serializable] class AnimTable { public float fps = 10f; public Clip[] clips; }
|
|
|
|
static Dictionary<int, int> map;
|
|
static readonly Dictionary<int, Sprite> cache = new Dictionary<int, Sprite>();
|
|
static readonly Dictionary<string, Sprite[]> frames = new Dictionary<string, Sprite[]>();
|
|
static AnimTable anim;
|
|
|
|
static void Load()
|
|
{
|
|
if (map != null) return;
|
|
map = new Dictionary<int, int>();
|
|
var txt = GameApp.ReadData("unit_art");
|
|
if (txt != null) foreach (var r in JsonUtility.FromJson<Table>(txt).units) map[r.id] = r.art;
|
|
}
|
|
|
|
public static Sprite ForUnit(int unitId)
|
|
{
|
|
Load();
|
|
return map.TryGetValue(unitId, out var art) ? Get(art) : null;
|
|
}
|
|
|
|
/// 유닛 → 그림 번호(없으면 0) — 유닛 목록에서 보유 유닛이 쓰는 그림을 미보유 칸에서 뺄 때
|
|
public static int ArtOf(int unitId)
|
|
{
|
|
Load();
|
|
return map.TryGetValue(unitId, out var art) ? art : 0;
|
|
}
|
|
|
|
public static Sprite Get(int art)
|
|
{
|
|
if (cache.TryGetValue(art, out var s)) return s;
|
|
s = Load("Art/Units/px_" + art);
|
|
cache[art] = s; return s;
|
|
}
|
|
|
|
static Sprite Load(string path)
|
|
{
|
|
var s = Resources.Load<Sprite>(path);
|
|
if (s == null)
|
|
{
|
|
// .meta 가 Sprite 로 안 들어간 경우 — 텍스처로 읽어 점 필터 스프라이트로
|
|
var tex = Resources.Load<Texture2D>(path);
|
|
if (tex != null) { tex.filterMode = FilterMode.Point; s = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0f), 32); }
|
|
}
|
|
return s;
|
|
}
|
|
|
|
public static float Fps { get { LoadAnim(); return anim.fps; } }
|
|
|
|
static void LoadAnim()
|
|
{
|
|
if (anim != null) return;
|
|
var txt = GameApp.ReadData("unit_anim");
|
|
anim = txt != null ? JsonUtility.FromJson<AnimTable>(txt) : new AnimTable { clips = new Clip[0] };
|
|
if (anim.clips == null) anim.clips = new Clip[0];
|
|
if (anim.fps <= 0f) anim.fps = 10f;
|
|
}
|
|
|
|
/// 그 그림의 동작 프레임(없으면 null) — act = walk · attack
|
|
public static Sprite[] Frames(int art, string act)
|
|
{
|
|
string key = art + "_" + act;
|
|
if (frames.TryGetValue(key, out var f)) return f;
|
|
var list = new List<Sprite>();
|
|
for (int k = 0; k < 64; k++)
|
|
{
|
|
var s = Load($"Art/Units/anim/px_{art}_{act}_{k}");
|
|
if (s == null) break;
|
|
list.Add(s);
|
|
}
|
|
f = list.Count > 0 ? list.ToArray() : null;
|
|
frames[key] = f; return f;
|
|
}
|
|
|
|
/// 공격 타격 프레임 번호(unit_anim.json hit · 없으면 가운데) — 이 프레임이 시뮬의 타격 순간에 오도록 앞 프레임을 예비 동작으로 재생
|
|
public static int HitFrame(int art, int count)
|
|
{
|
|
LoadAnim();
|
|
foreach (var c in anim.clips) if (c.art == art && c.act == "attack" && c.hit >= 0) return Mathf.Clamp(c.hit, 0, count - 1);
|
|
return count / 2;
|
|
}
|
|
}
|
|
}
|