103 lines
5.0 KiB
C#
103 lines
5.0 KiB
C#
using TKS.OutGame;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace TKS
|
|
{
|
|
/// <summary>씬에 하나만 두면 카메라·전장·전투 관리자·HUD·입력·월드맵·아웃게임을 코드로 구성하고 본영 로비(없으면 첫 스테이지)로 시작한다.</summary>
|
|
public class GameBootstrap : MonoBehaviour
|
|
{
|
|
public BalanceConfig Config;
|
|
public bool AutoStart = true;
|
|
/// <summary>true = 시작 화면이 본영 로비(출정 → 챕터 월드맵 → 스테이지 팝업 → 전투 · 2026-11-05 #1093). false = 바로 StartStageIndex 전투.</summary>
|
|
[FormerlySerializedAs("StartOnWorldMap")]
|
|
public bool StartOnLobby = true;
|
|
public int StartStageIndex = 0;
|
|
|
|
public BattleManager Battle { get; private set; }
|
|
public CameraController CameraCtrl { get; private set; }
|
|
public WorldMapScreen WorldMap { get; private set; }
|
|
public OutGameRoot OutGame { get; private set; }
|
|
|
|
void Awake()
|
|
{
|
|
if (Config == null) Config = Resources.Load<BalanceConfig>("BalanceConfig");
|
|
if (Config == null)
|
|
{
|
|
Debug.LogError("[TKS] BalanceConfig 자산이 없습니다. 메뉴 TKS/Setup Project 를 실행하세요.");
|
|
return;
|
|
}
|
|
|
|
var cam = Camera.main;
|
|
if (cam == null)
|
|
{
|
|
var cgo = new GameObject("Main Camera");
|
|
cgo.tag = "MainCamera";
|
|
cam = cgo.AddComponent<Camera>();
|
|
}
|
|
cam.orthographic = true;
|
|
cam.clearFlags = CameraClearFlags.SolidColor;
|
|
cam.backgroundColor = new Color(0.07f, 0.09f, 0.11f);
|
|
cam.transform.position = new Vector3(0f, 0f, -10f);
|
|
cam.nearClipPlane = 0.1f;
|
|
cam.farClipPlane = 100f;
|
|
// 탑다운: 같은 정렬 순서의 스프라이트는 y 가 큰(멀리 있는) 유닛이 뒤에 그려진다
|
|
cam.transparencySortMode = TransparencySortMode.CustomAxis;
|
|
cam.transparencySortAxis = Vector3.up;
|
|
// 깊이 텍스처(2026-11-09): WL 에서 옮겨 온 이펙트 셰이더(소프트 파티클 · Hyper Casual 등)가 _CameraDepthTexture 를 읽는다 —
|
|
// 빌트인 카메라는 기본으로 만들지 않아 그 이펙트가 안 보이거나 불투명 덩어리로 그려짐(URP 는 켜져 있음). 전장 = 투명 스프라이트뿐이라 깊이 패스에 그릴 것이 거의 없다.
|
|
cam.depthTextureMode |= DepthTextureMode.Depth;
|
|
|
|
var board = new GameObject("Board").AddComponent<Board>();
|
|
board.Build(Config.boardSize, Config.boardArt);
|
|
|
|
CameraCtrl = cam.GetComponent<CameraController>();
|
|
if (CameraCtrl == null) CameraCtrl = cam.gameObject.AddComponent<CameraController>();
|
|
CameraCtrl.Init(board, Config.cameraViewHeight, Config.cameraMinViewHeight, Config.cameraMaxViewHeight);
|
|
|
|
Battle = new GameObject("BattleManager").AddComponent<BattleManager>();
|
|
Battle.Configure(Config, board);
|
|
|
|
var hud = new GameObject("HUD").AddComponent<BattleHUD>();
|
|
hud.Build(Battle, cam, CameraCtrl);
|
|
Battle.Hud = hud;
|
|
|
|
var input = new GameObject("SlingshotInput").AddComponent<SlingshotInput>();
|
|
input.Init(Battle, cam, hud, CameraCtrl);
|
|
Battle.Sling = input;
|
|
|
|
// 카메라 연동: 행동 중인 유닛 추적 · 아군 턴 시작 시 아군 쪽으로
|
|
var camCtrl = CameraCtrl;
|
|
var battle = Battle;
|
|
battle.UnitActing += u => camCtrl.Follow(u.transform);
|
|
battle.PhaseChanged += phase =>
|
|
{
|
|
if (phase == BattlePhase.PlayerTurn) camCtrl.FocusOn(PlayerFocusPoint(battle));
|
|
else if (phase == BattlePhase.StageClear || phase == BattlePhase.Defeat) camCtrl.StopFollow();
|
|
};
|
|
battle.StageStarted += () => camCtrl.SnapTo(PlayerFocusPoint(battle));
|
|
|
|
WorldMap = new GameObject("WorldMap").AddComponent<WorldMapScreen>();
|
|
WorldMap.Build(Battle, hud, input, cam);
|
|
|
|
// 아웃게임(세이브 · 로비 · 영웅 · 편성 · 거래) — 출전 편성·보상·군량을 전투·월드맵에 연결
|
|
OutGame = new GameObject("OutGame").AddComponent<OutGameRoot>();
|
|
OutGame.Build(Battle, hud, input, WorldMap, cam);
|
|
|
|
if (!AutoStart) return;
|
|
if (StartOnLobby && WorldMap.HasData) OutGame.ShowLobby();
|
|
else Battle.StartStage(StartStageIndex);
|
|
}
|
|
|
|
/// <summary>아군 무게중심에서 적 쪽으로 조금 올린 지점.</summary>
|
|
static Vector2 PlayerFocusPoint(BattleManager battle)
|
|
{
|
|
var players = battle.AliveUnits(Faction.Player);
|
|
if (players.Count == 0) return Vector2.zero;
|
|
Vector2 sum = Vector2.zero;
|
|
foreach (var p in players) sum += p.Position;
|
|
return sum / players.Count + new Vector2(0f, battle.Config.cameraViewHeight * 0.2f);
|
|
}
|
|
}
|
|
}
|