feat: editor script para crear escenas Chapter2 y Chapter3

Menu: Ajedrez Purgatorio > Create Chapter Scenes
- Duplica Chapter1 como base para Chapter2 (El Hospital) y Chapter3 (La Corte del Juicio)
- Configura titulos, resetea stats de campana
- Crea DeadKingInputUI y DeadKingRevealUI si no existen
- Actualiza Build Settings con las 4 escenas
This commit is contained in:
2026-08-17 04:41:08 -03:00
parent f7df1befca
commit e4fee2bd80
+388
View File
@@ -0,0 +1,388 @@
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;
using System.IO;
/// <summary>
/// Creates Chapter2 and Chapter3 scenes by duplicating Chapter1
/// and configuring chapter-specific settings.
/// Run via menu: Ajedrez Purgatorio > Create Chapter Scenes
/// </summary>
public static class CreateChapterScenes
{
private const string CHAPTER1_PATH = "Assets/Scenes/Chapter1.unity";
private const string CHAPTER2_PATH = "Assets/Scenes/Chapter2.unity";
private const string CHAPTER3_PATH = "Assets/Scenes/Chapter3.unity";
[MenuItem("Ajedrez Purgatorio/Create Chapter Scenes")]
public static void Execute()
{
Debug.Log("═══════════════════════════════════════════════");
Debug.Log(" CREANDO ESCENAS Chapter2 y Chapter3 ");
Debug.Log("═══════════════════════════════════════════════");
if (!File.Exists(CHAPTER1_PATH))
{
Debug.LogError($"Chapter1 no encontrado en {CHAPTER1_PATH}. Ejecuta ProjectSetup primero.");
return;
}
CreateChapter2();
CreateChapter3();
UpdateBuildSettings();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("═══════════════════════════════════════════════");
Debug.Log(" ✅ Escenas Chapter2 y Chapter3 creadas ");
Debug.Log("═══════════════════════════════════════════════");
}
static void CreateChapter2()
{
Debug.Log("── Creando Chapter2 (El Hospital)...");
if (File.Exists(CHAPTER2_PATH))
{
Debug.Log(" ⏭ Chapter2 ya existe. Sobrescribiendo...");
AssetDatabase.DeleteAsset(CHAPTER2_PATH);
}
// Open Chapter1 and save as Chapter2
var chapter1 = EditorSceneManager.OpenScene(CHAPTER1_PATH, OpenSceneMode.Single);
var chapter2 = EditorSceneManager.SaveScene(chapter1, CHAPTER2_PATH);
// Re-open Chapter2 to modify it
EditorSceneManager.OpenScene(CHAPTER2_PATH, OpenSceneMode.Single);
// Configure chapter-specific settings
ConfigureChapterScene("El Hospital", "Capítulo 2", "ch2_intro", "ch2_outro");
// Save
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
Debug.Log(" ✅ Chapter2 creado y configurado.");
}
static void CreateChapter3()
{
Debug.Log("── Creando Chapter3 (La Corte del Juicio)...");
if (File.Exists(CHAPTER3_PATH))
{
Debug.Log(" ⏭ Chapter3 ya existe. Sobrescribiendo...");
AssetDatabase.DeleteAsset(CHAPTER3_PATH);
}
// Open Chapter1 and save as Chapter3
var chapter1 = EditorSceneManager.OpenScene(CHAPTER1_PATH, OpenSceneMode.Single);
var chapter3 = EditorSceneManager.SaveScene(chapter1, CHAPTER3_PATH);
// Re-open Chapter3 to modify it
EditorSceneManager.OpenScene(CHAPTER3_PATH, OpenSceneMode.Single);
// Configure chapter-specific settings
ConfigureChapterScene("La Corte del Juicio", "Capítulo 3", "ch3_intro", "ch3_outro");
// Save
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
Debug.Log(" ✅ Chapter3 creado y configurado.");
}
static void ConfigureChapterScene(string chapterName, string chapterTitle, string introDialogue, string outroDialogue)
{
// Update any title/label text in the scene
var titleTexts = Object.FindObjectsByType<TextMeshProUGUI>(FindObjectsSortMode.None);
foreach (var tmp in titleTexts)
{
// Update chapter title if found
if (tmp.name == "Title" && tmp.text.Contains("Capítulo"))
{
tmp.text = chapterTitle;
}
}
// Find GameManager and reset board state
var gm = Object.FindFirstObjectByType<GameManager>();
if (gm != null)
{
// Reset campaign stats for new chapter
gm.ResetCampaignStats();
}
// Ensure GameStateManager exists and is reset
if (Object.FindFirstObjectByType<GameStateManager>() == null)
{
new GameObject("GameStateManager").AddComponent<GameStateManager>();
}
// Ensure AIController exists
if (Object.FindFirstObjectByType<AIController>() == null)
{
new GameObject("AIController").AddComponent<AIController>();
}
// Ensure DeadKingPool asset exists (it's a ScriptableObject, not MonoBehaviour)
var dkpAsset = AssetDatabase.LoadAssetAtPath<DeadKingPool>("Assets/Game/Data/DeadKingPool.asset");
if (dkpAsset == null)
{
Debug.LogWarning(" ⚠ DeadKingPool.asset not found. Create it via Ajedrez Purgatorio menu if needed.");
}
else
{
Debug.Log(" ✅ DeadKingPool asset found.");
}
// Ensure DeadKingInputUI and DeadKingRevealUI exist in scene
if (Object.FindFirstObjectByType<AjedrezPurgatorio.UI.DeadKingInputUI>() == null)
{
CreateDeadKingInputUI();
}
if (Object.FindFirstObjectByType<DeadKingRevealUI>() == null)
{
CreateDeadKingRevealUI();
}
Debug.Log($" ✅ Escena configurada: {chapterName} ({chapterTitle})");
}
static void CreateDeadKingInputUI()
{
Debug.Log(" ── Creando DeadKingInputUI...");
// Find or create PurgatoryCanvas
var cv = GameObject.Find("PurgatoryCanvas");
if (cv == null)
{
cv = new GameObject("PurgatoryCanvas");
var canvas = cv.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 120;
var scaler = cv.AddComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920, 1080);
cv.AddComponent<GraphicRaycaster>();
}
// Create the panel
var panel = CreatePanel("DeadKingInputPanel", cv.transform, new Vector2(700, 500), new Color(.05f, .02f, .08f, .97f));
var titleTMP = CreateTMP("TitleText", panel.transform, "INSCRIBE TU NOMBRE", 36f);
titleTMP.color = new Color(.9f, .1f, .1f);
titleTMP.fontStyle = FontStyles.Bold;
titleTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(titleTMP.rectTransform, .05f, .84f, .95f, .97f);
var nameLabel = CreateTMP("NameLabel", panel.transform, "Tu nombre:", 18f);
nameLabel.color = new Color(.8f, .8f, .8f);
AnchorNorm(nameLabel.rectTransform, .08f, .72f, .92f, .80f);
// Name input field placeholder
var nameInputGO = new GameObject("NameInputField");
nameInputGO.transform.SetParent(panel.transform, false);
var nameInputRT = nameInputGO.AddComponent<RectTransform>();
AnchorNorm(nameInputRT, .08f, .62f, .92f, .72f);
var nameInputImg = nameInputGO.AddComponent<Image>();
nameInputImg.color = new Color(.15f, .1f, .15f);
var nameInput = nameInputGO.AddComponent<TMP_InputField>();
nameInput.characterLimit = 20;
var msgLabel = CreateTMP("MessageLabel", panel.transform, "Tu mensaje:", 18f);
msgLabel.color = new Color(.8f, .8f, .8f);
AnchorNorm(msgLabel.rectTransform, .08f, .48f, .92f, .56f);
// Message input field placeholder
var msgInputGO = new GameObject("MessageInputField");
msgInputGO.transform.SetParent(panel.transform, false);
var msgInputRT = msgInputGO.AddComponent<RectTransform>();
AnchorNorm(msgInputRT, .08f, .28f, .92f, .48f);
var msgInputImg = msgInputGO.AddComponent<Image>();
msgInputImg.color = new Color(.15f, .1f, .15f);
var msgInput = msgInputGO.AddComponent<TMP_InputField>();
msgInput.characterLimit = 100;
// Submit button
var submitGO = CreateButton("SubmitButton", panel.transform, "INSCRIBIR");
submitGO.GetComponent<Image>().color = new Color(.35f, .08f, .08f);
AnchorNorm(submitGO.GetComponent<RectTransform>(), .25f, .06f, .75f, .18f);
// Feedback text
var feedbackTMP = CreateTMP("FeedbackText", panel.transform, "", 20f);
feedbackTMP.color = new Color(.3f, .9f, .3f);
feedbackTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(feedbackTMP.rectTransform, .08f, .20f, .92f, .28f);
panel.SetActive(false);
// Add the component
var deadKingUI = panel.AddComponent<AjedrezPurgatorio.UI.DeadKingInputUI>();
var so = new SerializedObject(deadKingUI);
SetProp(so, "_panel", panel);
SetProp(so, "_nameInputField", nameInput);
SetProp(so, "_messageInputField", msgInput);
SetProp(so, "_submitButton", submitGO.GetComponent<Button>());
SetProp(so, "_feedbackText", feedbackTMP);
so.ApplyModifiedPropertiesWithoutUndo();
Debug.Log(" ✅ DeadKingInputUI creado.");
}
static void CreateDeadKingRevealUI()
{
Debug.Log(" ── Creando DeadKingRevealUI...");
var cv = GameObject.Find("PurgatoryCanvas");
if (cv == null)
{
cv = new GameObject("PurgatoryCanvas");
var canvas = cv.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 125;
var scaler = cv.AddComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920, 1080);
cv.AddComponent<GraphicRaycaster>();
}
var panel = CreatePanel("DeadKingRevealPanel", cv.transform, new Vector2(700, 500), new Color(.08f, .02f, .02f, .97f));
var titleTMP = CreateTMP("RevealTitle", panel.transform, "UN CAÍDTO REGRESA", 36f);
titleTMP.color = new Color(.9f, .1f, .1f);
titleTMP.fontStyle = FontStyles.Bold;
titleTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(titleTMP.rectTransform, .05f, .84f, .95f, .97f);
var nameTMP = CreateTMP("DeadKingName", panel.transform, "Nombre del Rey Caído", 28f);
nameTMP.color = new Color(1f, .85f, .2f);
nameTMP.fontStyle = FontStyles.Bold;
nameTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(nameTMP.rectTransform, .05f, .68f, .95f, .82f);
var quoteTMP = CreateTMP("DeadKingQuote", panel.transform, "\"...\"", 22f);
quoteTMP.color = new Color(.7f, .7f, .85f);
quoteTMP.fontStyle = FontStyles.Italic;
quoteTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(quoteTMP.rectTransform, .08f, .48f, .92f, .66f);
var statsTMP = CreateTMP("DeadKingStats", panel.transform, "Capítulo alcanzado: ?\nPiezas perdidas: ?", 18f);
statsTMP.color = new Color(.75f, .75f, .75f);
statsTMP.alignment = TextAlignmentOptions.Center;
AnchorNorm(statsTMP.rectTransform, .05f, .30f, .95f, .46f);
var continueGO = CreateButton("ContinueButton", panel.transform, "CONTINUAR");
continueGO.GetComponent<Image>().color = new Color(.18f, .36f, .18f);
AnchorNorm(continueGO.GetComponent<RectTransform>(), .3f, .06f, .7f, .18f);
panel.SetActive(false);
var revealUI = panel.AddComponent<DeadKingRevealUI>();
var so = new SerializedObject(revealUI);
SetProp(so, "_panel", panel);
SetProp(so, "_playerNameText", nameTMP);
SetProp(so, "_messageText", quoteTMP);
SetProp(so, "_statsText", statsTMP);
SetProp(so, "_continueButton", continueGO.GetComponent<Button>());
so.ApplyModifiedPropertiesWithoutUndo();
Debug.Log(" ✅ DeadKingRevealUI creado.");
}
static void UpdateBuildSettings()
{
Debug.Log("── Actualizando Build Settings...");
string[] scenes = {
"Assets/Scenes/MainMenu.unity",
"Assets/Scenes/Chapter1.unity",
"Assets/Scenes/Chapter2.unity",
"Assets/Scenes/Chapter3.unity",
};
var list = new System.Collections.Generic.List<EditorBuildSettingsScene>();
foreach (var s in scenes)
{
if (File.Exists(s))
{
list.Add(new EditorBuildSettingsScene(s, true));
Debug.Log($" ✅ {s} en Build Settings");
}
else
{
Debug.LogWarning($" ⚠ No existe: {s}");
}
}
EditorBuildSettings.scenes = list.ToArray();
}
// ══════════════════════════════════════════════════════
// HELPERS
// ══════════════════════════════════════════════════════
static GameObject CreatePanel(string name, Transform parent, Vector2 size, Color color)
{
var go = new GameObject(name);
go.transform.SetParent(parent, false);
var img = go.AddComponent<Image>();
img.color = color;
var rt = go.GetComponent<RectTransform>();
rt.anchorMin = rt.anchorMax = rt.pivot = new Vector2(.5f, .5f);
rt.sizeDelta = size;
rt.anchoredPosition = Vector2.zero;
return go;
}
static TextMeshProUGUI CreateTMP(string name, Transform parent, string text, float size)
{
var go = new GameObject(name);
go.transform.SetParent(parent, false);
var tmp = go.AddComponent<TextMeshProUGUI>();
tmp.text = text;
tmp.fontSize = size;
tmp.color = Color.white;
tmp.enableWordWrapping = true;
return tmp;
}
static GameObject CreateButton(string name, Transform parent, string label)
{
var go = new GameObject(name);
go.transform.SetParent(parent, false);
var img = go.AddComponent<Image>();
img.color = new Color(.22f, .12f, .08f);
var btn = go.AddComponent<Button>();
var col = btn.colors;
col.highlightedColor = new Color(.45f, .3f, .18f);
col.pressedColor = new Color(.12f, .06f, .03f);
btn.colors = col;
var tGO = new GameObject("Text (TMP)");
tGO.transform.SetParent(go.transform, false);
var tmp = tGO.AddComponent<TextMeshProUGUI>();
tmp.text = label;
tmp.fontSize = 26f;
tmp.fontStyle = FontStyles.Bold;
tmp.color = Color.white;
tmp.alignment = TextAlignmentOptions.Center;
var tRT = tGO.GetComponent<RectTransform>();
tRT.anchorMin = Vector2.zero;
tRT.anchorMax = Vector2.one;
tRT.offsetMin = tRT.offsetMax = Vector2.zero;
return go;
}
static void AnchorNorm(RectTransform rt, float xMin, float yMin, float xMax, float yMax)
{
rt.anchorMin = new Vector2(xMin, yMin);
rt.anchorMax = new Vector2(xMax, yMax);
rt.offsetMin = rt.offsetMax = Vector2.zero;
}
static void SetProp(SerializedObject so, string field, Object val)
{
var p = so.FindProperty(field);
if (p != null)
p.objectReferenceValue = val;
else
Debug.LogWarning($" ⚠ campo '{field}' no encontrado en {so.targetObject?.GetType().Name}");
}
}