using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; namespace TKS { /// /// 자동 플레이 실측: 아군도 AI 로 조작해 몇 턴을 돌리며 스크린샷·로그를 남긴다. /// 에디터에서 ProjectSetup.AutoPlayCapture 가 SessionState 로 출력 폴더를 넘기면 생성된다. /// public class AutoPlayDriver : MonoBehaviour { public string OutputDir; public int MaxTurns = 3; public int Width = 720; public int Height = 1280; readonly List log = new List(); int shotIndex = 1; #if UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] static void AutoSpawn() { string dir = UnityEditor.SessionState.GetString("TKS_AUTOPLAY_DIR", ""); if (string.IsNullOrEmpty(dir)) return; UnityEditor.SessionState.EraseString("TKS_AUTOPLAY_DIR"); var go = new GameObject("AutoPlayDriver"); var d = go.AddComponent(); d.OutputDir = dir; d.MaxTurns = UnityEditor.SessionState.GetInt("TKS_AUTOPLAY_TURNS", 3); } #endif IEnumerator Start() { Directory.CreateDirectory(OutputDir); float t0 = Time.realtimeSinceStartup; while ((BattleManager.Instance == null || BattleManager.Instance.Phase != BattlePhase.PlayerTurn) && Time.realtimeSinceStartup - t0 < 20f) { yield return null; } var bm = BattleManager.Instance; var cam = Camera.main; if (bm == null || cam == null) { Log("FAIL: BattleManager 또는 카메라 없음"); Finish(1); yield break; } Log("stage=" + bm.Stage.title + " players=" + bm.AliveCount(Faction.Player) + " enemies=" + bm.AliveCount(Faction.Enemy)); yield return Fx.Wait(0.6f); yield return Shot(cam, "start"); var first = FirstActable(bm); if (first != null) { var tgt = EnemyAI.Decide(first, bm.AliveUnits(Faction.Enemy), 1f, bm.Rng, bm.Board); Vector2 pointer = first.Position - (tgt - first.Position) * 0.5f; bm.Sling.ShowPreview(first, tgt, pointer); first.View.SetSelected(true); yield return null; yield return Shot(cam, "aim_" + first.DisplayName); first.View.SetSelected(false); bm.Sling.HidePreview(); } bool firstActionShot = false; for (int turn = 1; turn <= MaxTurns; turn++) { int guard = 0; while (bm.Phase == BattlePhase.PlayerTurn && guard++ < 24) { var u = FirstActable(bm); if (u == null) { bm.OnEmptyTap(); break; } var target = EnemyAI.Decide(u, bm.AliveUnits(Faction.Enemy), 1f, bm.Rng, bm.Board); if (!bm.RequestPlayerAction(u, target)) break; while (bm.Phase == BattlePhase.Resolving) yield return null; Log("turn " + turn + " | " + bm.LastMessage); if (!firstActionShot) { firstActionShot = true; yield return Shot(cam, "after_first_action"); } if (bm.Phase == BattlePhase.StageClear || bm.Phase == BattlePhase.Defeat) break; } while (bm.Phase == BattlePhase.EnemyTurn || bm.Phase == BattlePhase.Resolving) yield return null; Log("turn " + turn + " end | phase=" + bm.Phase + " players=" + bm.AliveCount(Faction.Player) + " enemies=" + bm.AliveCount(Faction.Enemy) + " | " + bm.LastMessage); yield return Shot(cam, "turn" + turn + "_end"); if (bm.Phase == BattlePhase.StageClear || bm.Phase == BattlePhase.Defeat) break; } File.WriteAllLines(Path.Combine(OutputDir, "autoplay_log.txt"), log.ToArray()); Finish(0); } static Unit FirstActable(BattleManager bm) { foreach (var u in bm.AliveUnits(Faction.Player)) { if (!u.ActedThisTurn) return u; } return null; } IEnumerator Shot(Camera cam, string name) { string file = Path.Combine(OutputDir, shotIndex.ToString("00") + "_" + name + ".png"); shotIndex++; yield return CaptureUtil.Capture(cam, Width, Height, file); Log("shot " + file); } void Log(string s) { log.Add(s); Debug.Log("[AutoPlay] " + s); } void Finish(int code) { try { File.WriteAllLines(Path.Combine(OutputDir, "autoplay_log.txt"), log.ToArray()); } catch { } #if UNITY_EDITOR UnityEditor.EditorApplication.Exit(code); #else Application.Quit(code); #endif } } }