936 lines
45 KiB
C#
936 lines
45 KiB
C#
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using TMPro;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.AI;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
using WarGame.Data;
|
||
|
|
using WarGame.Deployment;
|
||
|
|
using WarGame.Managers;
|
||
|
|
using WarGame.UI;
|
||
|
|
using WarGame.Units;
|
||
|
|
|
||
|
|
namespace WarGame.EditorTools
|
||
|
|
{
|
||
|
|
[InitializeOnLoad]
|
||
|
|
public static class AutoBattlerSetupHelper
|
||
|
|
{
|
||
|
|
private const string DataPath = "Assets/Data/Units";
|
||
|
|
private const string PrefabPath = "Assets/Prefabs/Units";
|
||
|
|
private const string UIPath = "Assets/Prefabs/UI";
|
||
|
|
|
||
|
|
static AutoBattlerSetupHelper()
|
||
|
|
{
|
||
|
|
EditorApplication.delayCall += CheckInitialSetup;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CheckInitialSetup()
|
||
|
|
{
|
||
|
|
if (!File.Exists("Assets/Prefabs/Units/PF_BaseUnit.prefab"))
|
||
|
|
{
|
||
|
|
SetupBatch();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[MenuItem("Tools/WarGame/Setup Complete AutoBattler (Assets + Scene)", false, 1)]
|
||
|
|
public static void SetupCompleteAutoBattler()
|
||
|
|
{
|
||
|
|
ExecuteSetup(isInteractive: true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static void SetupBatch()
|
||
|
|
{
|
||
|
|
ExecuteSetup(isInteractive: false);
|
||
|
|
}
|
||
|
|
|
||
|
|
public static void ExecuteSetup(bool isInteractive)
|
||
|
|
{
|
||
|
|
EnsureDirectories();
|
||
|
|
|
||
|
|
// 1. Create Unit Prefabs
|
||
|
|
GameObject unitBasePrefab = CreateOrUpdateUnitPrefab();
|
||
|
|
GameObject cardPrefab = CreateOrUpdateShopCardPrefab();
|
||
|
|
|
||
|
|
// 2. Create UnitData ScriptableObjects
|
||
|
|
List<UnitDataSO> playerUnits = CreatePlayerUnitData(unitBasePrefab);
|
||
|
|
List<UnitDataSO> enemyUnits = CreateEnemyUnitData(unitBasePrefab);
|
||
|
|
|
||
|
|
// 3. Setup Scene Hierarchy
|
||
|
|
SetupSceneHierarchy(playerUnits, enemyUnits, cardPrefab, unitBasePrefab);
|
||
|
|
|
||
|
|
AssetDatabase.SaveAssets();
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
|
||
|
|
if (isInteractive)
|
||
|
|
{
|
||
|
|
EditorUtility.DisplayDialog(
|
||
|
|
"WarGame Setup Complete",
|
||
|
|
"Successfully generated all ScriptableObjects, Prefabs, UI, and Scene Managers!\n\n" +
|
||
|
|
"• Player Units: Swordsman, Archer, Knight\n" +
|
||
|
|
"• Enemy Types: Bandit Warrior, Bandit Archer\n" +
|
||
|
|
"• Advanced Tactics: Flanking (Lv.2), Feint Retreat (Lv.3)\n" +
|
||
|
|
"• HUD & Shop: Live Unit Counts, Economy, Battle Results\n\n" +
|
||
|
|
"You can now press Play to test recruitment, leveling, and auto-battles!",
|
||
|
|
"Awesome!"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Debug.Log("[WarGame] AutoBattler setup completed successfully.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void EnsureDirectories()
|
||
|
|
{
|
||
|
|
if (!Directory.Exists(DataPath)) Directory.CreateDirectory(DataPath);
|
||
|
|
if (!Directory.Exists(PrefabPath)) Directory.CreateDirectory(PrefabPath);
|
||
|
|
if (!Directory.Exists(UIPath)) Directory.CreateDirectory(UIPath);
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateOrUpdateUnitPrefab()
|
||
|
|
{
|
||
|
|
string prefabFilePath = $"{PrefabPath}/PF_BaseUnit.prefab";
|
||
|
|
GameObject existing = AssetDatabase.LoadAssetAtPath<GameObject>(prefabFilePath);
|
||
|
|
if (existing != null) return existing;
|
||
|
|
|
||
|
|
// Create temporary instance
|
||
|
|
GameObject root = new GameObject("PF_BaseUnit");
|
||
|
|
|
||
|
|
// Add Collider & NavMeshAgent
|
||
|
|
CapsuleCollider collider = root.AddComponent<CapsuleCollider>();
|
||
|
|
collider.center = new Vector3(0, 1f, 0);
|
||
|
|
collider.radius = 0.5f;
|
||
|
|
collider.height = 2f;
|
||
|
|
|
||
|
|
NavMeshAgent agent = root.AddComponent<NavMeshAgent>();
|
||
|
|
agent.speed = 3.5f;
|
||
|
|
agent.angularSpeed = 360f;
|
||
|
|
agent.acceleration = 12f;
|
||
|
|
agent.stoppingDistance = 1.2f;
|
||
|
|
agent.radius = 0.5f;
|
||
|
|
agent.height = 2f;
|
||
|
|
|
||
|
|
// Visual mesh (Capsule)
|
||
|
|
GameObject visual = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
|
|
visual.name = "Visual";
|
||
|
|
visual.transform.SetParent(root.transform);
|
||
|
|
visual.transform.localPosition = new Vector3(0, 1f, 0);
|
||
|
|
visual.transform.localScale = new Vector3(0.9f, 0.9f, 0.9f);
|
||
|
|
Object.DestroyImmediate(visual.GetComponent<Collider>()); // remove inner collider
|
||
|
|
|
||
|
|
Renderer renderer = visual.GetComponent<Renderer>();
|
||
|
|
|
||
|
|
// Forward direction indicator (Nose / visor)
|
||
|
|
GameObject visor = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||
|
|
visor.name = "Visor";
|
||
|
|
visor.transform.SetParent(visual.transform);
|
||
|
|
visor.transform.localPosition = new Vector3(0, 0.4f, 0.45f);
|
||
|
|
visor.transform.localScale = new Vector3(0.5f, 0.2f, 0.3f);
|
||
|
|
Object.DestroyImmediate(visor.GetComponent<Collider>());
|
||
|
|
|
||
|
|
// Health Bar World Canvas
|
||
|
|
GameObject healthBarObj = new GameObject("HealthBar_Canvas");
|
||
|
|
healthBarObj.transform.SetParent(root.transform);
|
||
|
|
healthBarObj.transform.localPosition = new Vector3(0, 2.3f, 0);
|
||
|
|
|
||
|
|
Canvas canvas = healthBarObj.AddComponent<Canvas>();
|
||
|
|
canvas.renderMode = RenderMode.WorldSpace;
|
||
|
|
RectTransform canvasRect = canvas.GetComponent<RectTransform>();
|
||
|
|
canvasRect.sizeDelta = new Vector2(1.5f, 0.6f);
|
||
|
|
healthBarObj.transform.localScale = new Vector3(0.015f, 0.015f, 0.015f);
|
||
|
|
|
||
|
|
// Slider Background
|
||
|
|
GameObject sliderObj = new GameObject("HealthSlider");
|
||
|
|
sliderObj.transform.SetParent(healthBarObj.transform);
|
||
|
|
RectTransform sliderRect = sliderObj.AddComponent<RectTransform>();
|
||
|
|
sliderRect.sizeDelta = new Vector2(100f, 15f);
|
||
|
|
sliderRect.anchoredPosition = new Vector2(0, 5f);
|
||
|
|
Slider slider = sliderObj.AddComponent<Slider>();
|
||
|
|
|
||
|
|
// Slider Background Image
|
||
|
|
GameObject bgObj = new GameObject("Background");
|
||
|
|
bgObj.transform.SetParent(sliderObj.transform);
|
||
|
|
RectTransform bgRect = bgObj.AddComponent<RectTransform>();
|
||
|
|
bgRect.anchorMin = Vector2.zero;
|
||
|
|
bgRect.anchorMax = Vector2.one;
|
||
|
|
bgRect.sizeDelta = Vector2.zero;
|
||
|
|
Image bgImg = bgObj.AddComponent<Image>();
|
||
|
|
bgImg.color = new Color(0.15f, 0.15f, 0.15f, 0.85f);
|
||
|
|
|
||
|
|
// Fill Area & Fill
|
||
|
|
GameObject fillArea = new GameObject("Fill Area");
|
||
|
|
fillArea.transform.SetParent(sliderObj.transform);
|
||
|
|
RectTransform fillAreaRect = fillArea.AddComponent<RectTransform>();
|
||
|
|
fillAreaRect.anchorMin = Vector2.zero;
|
||
|
|
fillAreaRect.anchorMax = Vector2.one;
|
||
|
|
fillAreaRect.sizeDelta = Vector2.zero;
|
||
|
|
|
||
|
|
GameObject fillObj = new GameObject("Fill");
|
||
|
|
fillObj.transform.SetParent(fillArea.transform);
|
||
|
|
RectTransform fillRect = fillObj.AddComponent<RectTransform>();
|
||
|
|
fillRect.anchorMin = Vector2.zero;
|
||
|
|
fillRect.anchorMax = Vector2.one;
|
||
|
|
fillRect.sizeDelta = Vector2.zero;
|
||
|
|
Image fillImg = fillObj.AddComponent<Image>();
|
||
|
|
fillImg.color = new Color(0.2f, 0.8f, 0.2f);
|
||
|
|
|
||
|
|
slider.targetGraphic = fillImg;
|
||
|
|
slider.fillRect = fillRect;
|
||
|
|
slider.value = 1f;
|
||
|
|
|
||
|
|
// Level Text
|
||
|
|
GameObject levelTextObj = new GameObject("LevelText");
|
||
|
|
levelTextObj.transform.SetParent(healthBarObj.transform);
|
||
|
|
RectTransform levelRect = levelTextObj.AddComponent<RectTransform>();
|
||
|
|
levelRect.anchoredPosition = new Vector2(-60f, 5f);
|
||
|
|
levelRect.sizeDelta = new Vector2(50f, 20f);
|
||
|
|
TextMeshProUGUI levelText = levelTextObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
levelText.text = "Lv.1";
|
||
|
|
levelText.fontSize = 18;
|
||
|
|
levelText.alignment = TextAlignmentOptions.Center;
|
||
|
|
levelText.color = Color.yellow;
|
||
|
|
|
||
|
|
// Unit Name Text
|
||
|
|
GameObject nameTextObj = new GameObject("NameText");
|
||
|
|
nameTextObj.transform.SetParent(healthBarObj.transform);
|
||
|
|
RectTransform nameRect = nameTextObj.AddComponent<RectTransform>();
|
||
|
|
nameRect.anchoredPosition = new Vector2(0, 25f);
|
||
|
|
nameRect.sizeDelta = new Vector2(150f, 20f);
|
||
|
|
TextMeshProUGUI nameText = nameTextObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
nameText.text = "Unit";
|
||
|
|
nameText.fontSize = 16;
|
||
|
|
nameText.alignment = TextAlignmentOptions.Center;
|
||
|
|
nameText.color = Color.white;
|
||
|
|
|
||
|
|
// Tactic Status Text
|
||
|
|
GameObject tacticTextObj = new GameObject("TacticText");
|
||
|
|
tacticTextObj.transform.SetParent(healthBarObj.transform);
|
||
|
|
RectTransform tacticRect = tacticTextObj.AddComponent<RectTransform>();
|
||
|
|
tacticRect.anchoredPosition = new Vector2(0, 48f);
|
||
|
|
tacticRect.sizeDelta = new Vector2(180f, 22f);
|
||
|
|
TextMeshProUGUI tacticText = tacticTextObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
tacticText.text = "FLANKING!";
|
||
|
|
tacticText.fontSize = 18;
|
||
|
|
tacticText.fontStyle = FontStyles.Bold;
|
||
|
|
tacticText.alignment = TextAlignmentOptions.Center;
|
||
|
|
tacticText.color = Color.yellow;
|
||
|
|
tacticTextObj.SetActive(false);
|
||
|
|
|
||
|
|
// Setup UnitHealthBar component
|
||
|
|
UnitHealthBar healthBarComp = healthBarObj.AddComponent<UnitHealthBar>();
|
||
|
|
SerializedObject hbSo = new SerializedObject(healthBarComp);
|
||
|
|
hbSo.FindProperty("healthSlider").objectReferenceValue = slider;
|
||
|
|
hbSo.FindProperty("fillImage").objectReferenceValue = fillImg;
|
||
|
|
hbSo.FindProperty("levelText").objectReferenceValue = levelText;
|
||
|
|
hbSo.FindProperty("tacticStatusText").objectReferenceValue = tacticText;
|
||
|
|
hbSo.FindProperty("unitNameText").objectReferenceValue = nameText;
|
||
|
|
hbSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
// Setup Unit component
|
||
|
|
Unit unitComp = root.AddComponent<Unit>();
|
||
|
|
SerializedObject unitSo = new SerializedObject(unitComp);
|
||
|
|
unitSo.FindProperty("agent").objectReferenceValue = agent;
|
||
|
|
unitSo.FindProperty("healthBar").objectReferenceValue = healthBarComp;
|
||
|
|
unitSo.FindProperty("mainRenderer").objectReferenceValue = renderer;
|
||
|
|
unitSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
// Save as Prefab
|
||
|
|
GameObject prefabAsset = PrefabUtility.SaveAsPrefabAsset(root, prefabFilePath);
|
||
|
|
Object.DestroyImmediate(root);
|
||
|
|
return prefabAsset;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateOrUpdateShopCardPrefab()
|
||
|
|
{
|
||
|
|
string prefabFilePath = $"{UIPath}/PF_ShopCard.prefab";
|
||
|
|
GameObject existing = AssetDatabase.LoadAssetAtPath<GameObject>(prefabFilePath);
|
||
|
|
if (existing != null) return existing;
|
||
|
|
|
||
|
|
GameObject cardRoot = new GameObject("PF_ShopCard");
|
||
|
|
RectTransform rootRect = cardRoot.AddComponent<RectTransform>();
|
||
|
|
rootRect.sizeDelta = new Vector2(230f, 130f);
|
||
|
|
|
||
|
|
Image bg = cardRoot.AddComponent<Image>();
|
||
|
|
bg.color = new Color(0.12f, 0.15f, 0.2f, 0.95f);
|
||
|
|
|
||
|
|
// Unit Name
|
||
|
|
GameObject nameObj = new GameObject("UnitName");
|
||
|
|
nameObj.transform.SetParent(cardRoot.transform);
|
||
|
|
RectTransform nameRect = nameObj.AddComponent<RectTransform>();
|
||
|
|
nameRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
nameRect.anchorMax = new Vector2(1f, 1f);
|
||
|
|
nameRect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
nameRect.anchoredPosition = new Vector2(10f, -8f);
|
||
|
|
nameRect.sizeDelta = new Vector2(-20f, 24f);
|
||
|
|
TextMeshProUGUI nameText = nameObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
nameText.text = "Swordsman";
|
||
|
|
nameText.fontSize = 18;
|
||
|
|
nameText.fontStyle = FontStyles.Bold;
|
||
|
|
nameText.color = Color.white;
|
||
|
|
|
||
|
|
// Class Type
|
||
|
|
GameObject classObj = new GameObject("ClassType");
|
||
|
|
classObj.transform.SetParent(cardRoot.transform);
|
||
|
|
RectTransform classRect = classObj.AddComponent<RectTransform>();
|
||
|
|
classRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
classRect.anchorMax = new Vector2(1f, 1f);
|
||
|
|
classRect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
classRect.anchoredPosition = new Vector2(10f, -32f);
|
||
|
|
classRect.sizeDelta = new Vector2(-20f, 18f);
|
||
|
|
TextMeshProUGUI classText = classObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
classText.text = "Melee Infantry";
|
||
|
|
classText.fontSize = 13;
|
||
|
|
classText.color = new Color(0.6f, 0.8f, 1f);
|
||
|
|
|
||
|
|
// Stats Text
|
||
|
|
GameObject statsObj = new GameObject("StatsText");
|
||
|
|
statsObj.transform.SetParent(cardRoot.transform);
|
||
|
|
RectTransform statsRect = statsObj.AddComponent<RectTransform>();
|
||
|
|
statsRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
statsRect.anchorMax = new Vector2(1f, 1f);
|
||
|
|
statsRect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
statsRect.anchoredPosition = new Vector2(10f, -52f);
|
||
|
|
statsRect.sizeDelta = new Vector2(-20f, 18f);
|
||
|
|
TextMeshProUGUI statsText = statsObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
statsText.text = "HP: 120 | ATK: 18 | DEF: 3";
|
||
|
|
statsText.fontSize = 12;
|
||
|
|
statsText.color = new Color(0.85f, 0.85f, 0.85f);
|
||
|
|
|
||
|
|
// Tactics Text
|
||
|
|
GameObject tacticsObj = new GameObject("TacticsText");
|
||
|
|
tacticsObj.transform.SetParent(cardRoot.transform);
|
||
|
|
RectTransform tacticsRect = tacticsObj.AddComponent<RectTransform>();
|
||
|
|
tacticsRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
tacticsRect.anchorMax = new Vector2(1f, 1f);
|
||
|
|
tacticsRect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
tacticsRect.anchoredPosition = new Vector2(10f, -72f);
|
||
|
|
tacticsRect.sizeDelta = new Vector2(-20f, 18f);
|
||
|
|
TextMeshProUGUI tacticsText = tacticsObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
tacticsText.text = "Tactics: [Lv.2: Flanking] [Lv.3: Feint]";
|
||
|
|
tacticsText.fontSize = 11;
|
||
|
|
tacticsText.color = new Color(1f, 0.85f, 0.3f);
|
||
|
|
|
||
|
|
// Buy Button
|
||
|
|
GameObject btnObj = new GameObject("BuyButton");
|
||
|
|
btnObj.transform.SetParent(cardRoot.transform);
|
||
|
|
RectTransform btnRect = btnObj.AddComponent<RectTransform>();
|
||
|
|
btnRect.anchorMin = new Vector2(0f, 0f);
|
||
|
|
btnRect.anchorMax = new Vector2(1f, 0f);
|
||
|
|
btnRect.pivot = new Vector2(0.5f, 0f);
|
||
|
|
btnRect.anchoredPosition = new Vector2(0f, 8f);
|
||
|
|
btnRect.sizeDelta = new Vector2(-20f, 28f);
|
||
|
|
|
||
|
|
Image btnImg = btnObj.AddComponent<Image>();
|
||
|
|
btnImg.color = new Color(0.2f, 0.6f, 0.25f);
|
||
|
|
Button btn = btnObj.AddComponent<Button>();
|
||
|
|
|
||
|
|
GameObject btnTextObj = new GameObject("BtnText");
|
||
|
|
btnTextObj.transform.SetParent(btnObj.transform);
|
||
|
|
RectTransform btnTextRect = btnTextObj.AddComponent<RectTransform>();
|
||
|
|
btnTextRect.anchorMin = Vector2.zero;
|
||
|
|
btnTextRect.anchorMax = Vector2.one;
|
||
|
|
btnTextRect.sizeDelta = Vector2.zero;
|
||
|
|
TextMeshProUGUI btnText = btnTextObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
btnText.text = "Buy (50 Gold)";
|
||
|
|
btnText.fontSize = 14;
|
||
|
|
btnText.fontStyle = FontStyles.Bold;
|
||
|
|
btnText.alignment = TextAlignmentOptions.Center;
|
||
|
|
btnText.color = Color.white;
|
||
|
|
|
||
|
|
// Setup ShopCardUI
|
||
|
|
ShopCardUI cardUI = cardRoot.AddComponent<ShopCardUI>();
|
||
|
|
SerializedObject so = new SerializedObject(cardUI);
|
||
|
|
so.FindProperty("unitNameText").objectReferenceValue = nameText;
|
||
|
|
so.FindProperty("classTypeText").objectReferenceValue = classText;
|
||
|
|
so.FindProperty("costText").objectReferenceValue = btnText;
|
||
|
|
so.FindProperty("statsSummaryText").objectReferenceValue = statsText;
|
||
|
|
so.FindProperty("tacticsInfoText").objectReferenceValue = tacticsText;
|
||
|
|
so.FindProperty("buyButton").objectReferenceValue = btn;
|
||
|
|
so.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(cardRoot, prefabFilePath);
|
||
|
|
Object.DestroyImmediate(cardRoot);
|
||
|
|
return prefab;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<UnitDataSO> CreatePlayerUnitData(GameObject unitPrefab)
|
||
|
|
{
|
||
|
|
List<UnitDataSO> list = new List<UnitDataSO>();
|
||
|
|
|
||
|
|
// 1. Swordsman
|
||
|
|
UnitDataSO swordsman = ScriptableObject.CreateInstance<UnitDataSO>();
|
||
|
|
swordsman.unitName = "Swordsman";
|
||
|
|
swordsman.unitClass = UnitClassType.MeleeInfantry;
|
||
|
|
swordsman.description = "Frontline fighter that unlocks flanking and feint retreat.";
|
||
|
|
swordsman.goldCost = 50;
|
||
|
|
swordsman.unitPrefab = unitPrefab;
|
||
|
|
swordsman.maxHealth = 120f;
|
||
|
|
swordsman.attackDamage = 18f;
|
||
|
|
swordsman.attackRange = 1.8f;
|
||
|
|
swordsman.attackInterval = 1.2f;
|
||
|
|
swordsman.moveSpeed = 3.6f;
|
||
|
|
swordsman.defenseArmor = 3f;
|
||
|
|
swordsman.criticalChance = 0.12f;
|
||
|
|
swordsman.healthGrowth = 25f;
|
||
|
|
swordsman.damageGrowth = 4f;
|
||
|
|
swordsman.defenseGrowth = 1.2f;
|
||
|
|
swordsman.baseExpRequirement = 40;
|
||
|
|
|
||
|
|
swordsman.unlockedTactics = new List<UnlockedTactic>
|
||
|
|
{
|
||
|
|
new UnlockedTactic
|
||
|
|
{
|
||
|
|
tacticType = UnitTacticType.Flanking,
|
||
|
|
requiredLevel = 2,
|
||
|
|
description = "Maneuvers around enemy flanks or rear to deal +50% bonus flank damage.",
|
||
|
|
valueMultiplier = 1.5f,
|
||
|
|
cooldown = 4f
|
||
|
|
},
|
||
|
|
new UnlockedTactic
|
||
|
|
{
|
||
|
|
tacticType = UnitTacticType.FeintRetreat,
|
||
|
|
requiredLevel = 3,
|
||
|
|
description = "When HP drops below 35%, feigns retreat toward friendly lines to disrupt enemies, then rallies!",
|
||
|
|
triggerThreshold = 0.35f,
|
||
|
|
duration = 3.0f,
|
||
|
|
cooldown = 20f
|
||
|
|
}
|
||
|
|
};
|
||
|
|
SaveOrUpdateSO(swordsman, $"{DataPath}/SO_Swordsman.asset");
|
||
|
|
list.Add(swordsman);
|
||
|
|
|
||
|
|
// 2. Archer
|
||
|
|
UnitDataSO archer = ScriptableObject.CreateInstance<UnitDataSO>();
|
||
|
|
archer.unitName = "Archer";
|
||
|
|
archer.unitClass = UnitClassType.Archer;
|
||
|
|
archer.description = "Ranged specialist providing steady high damage from afar.";
|
||
|
|
archer.goldCost = 65;
|
||
|
|
archer.unitPrefab = unitPrefab;
|
||
|
|
archer.maxHealth = 80f;
|
||
|
|
archer.attackDamage = 24f;
|
||
|
|
archer.attackRange = 8.5f;
|
||
|
|
archer.attackInterval = 1.5f;
|
||
|
|
archer.moveSpeed = 3.2f;
|
||
|
|
archer.defenseArmor = 1f;
|
||
|
|
archer.criticalChance = 0.18f;
|
||
|
|
archer.healthGrowth = 16f;
|
||
|
|
archer.damageGrowth = 5.5f;
|
||
|
|
archer.defenseGrowth = 0.6f;
|
||
|
|
archer.baseExpRequirement = 45;
|
||
|
|
|
||
|
|
archer.unlockedTactics = new List<UnlockedTactic>
|
||
|
|
{
|
||
|
|
new UnlockedTactic
|
||
|
|
{
|
||
|
|
tacticType = UnitTacticType.Flanking,
|
||
|
|
requiredLevel = 2,
|
||
|
|
description = "Reposition to open angles to fire at vulnerable targets.",
|
||
|
|
valueMultiplier = 1.4f,
|
||
|
|
cooldown = 5f
|
||
|
|
}
|
||
|
|
};
|
||
|
|
SaveOrUpdateSO(archer, $"{DataPath}/SO_Archer.asset");
|
||
|
|
list.Add(archer);
|
||
|
|
|
||
|
|
// 3. Knight / Cavalry
|
||
|
|
UnitDataSO knight = ScriptableObject.CreateInstance<UnitDataSO>();
|
||
|
|
knight.unitName = "Knight";
|
||
|
|
knight.unitClass = UnitClassType.Cavalry;
|
||
|
|
knight.description = "Fast, durable shock warrior suited for aggressive flanking charges.";
|
||
|
|
knight.goldCost = 90;
|
||
|
|
knight.unitPrefab = unitPrefab;
|
||
|
|
knight.maxHealth = 180f;
|
||
|
|
knight.attackDamage = 22f;
|
||
|
|
knight.attackRange = 2.0f;
|
||
|
|
knight.attackInterval = 1.3f;
|
||
|
|
knight.moveSpeed = 4.8f;
|
||
|
|
knight.defenseArmor = 6f;
|
||
|
|
knight.criticalChance = 0.15f;
|
||
|
|
knight.healthGrowth = 35f;
|
||
|
|
knight.damageGrowth = 4.5f;
|
||
|
|
knight.defenseGrowth = 2f;
|
||
|
|
knight.baseExpRequirement = 55;
|
||
|
|
|
||
|
|
knight.unlockedTactics = new List<UnlockedTactic>
|
||
|
|
{
|
||
|
|
new UnlockedTactic
|
||
|
|
{
|
||
|
|
tacticType = UnitTacticType.Flanking,
|
||
|
|
requiredLevel = 2,
|
||
|
|
description = "Cavalry flank charge dealing +75% massive flank damage!",
|
||
|
|
valueMultiplier = 1.75f,
|
||
|
|
cooldown = 4f
|
||
|
|
},
|
||
|
|
new UnlockedTactic
|
||
|
|
{
|
||
|
|
tacticType = UnitTacticType.FeintRetreat,
|
||
|
|
requiredLevel = 3,
|
||
|
|
description = "Feigns a tactical retreat pulling enemies out of formation before charging back.",
|
||
|
|
triggerThreshold = 0.30f,
|
||
|
|
duration = 3.5f,
|
||
|
|
cooldown = 15f
|
||
|
|
}
|
||
|
|
};
|
||
|
|
SaveOrUpdateSO(knight, $"{DataPath}/SO_Knight.asset");
|
||
|
|
list.Add(knight);
|
||
|
|
|
||
|
|
return list;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<UnitDataSO> CreateEnemyUnitData(GameObject unitPrefab)
|
||
|
|
{
|
||
|
|
List<UnitDataSO> list = new List<UnitDataSO>();
|
||
|
|
|
||
|
|
// Bandit Warrior
|
||
|
|
UnitDataSO bandit = ScriptableObject.CreateInstance<UnitDataSO>();
|
||
|
|
bandit.unitName = "Bandit Raider";
|
||
|
|
bandit.unitClass = UnitClassType.MeleeInfantry;
|
||
|
|
bandit.goldCost = 40;
|
||
|
|
bandit.unitPrefab = unitPrefab;
|
||
|
|
bandit.maxHealth = 95f;
|
||
|
|
bandit.attackDamage = 14f;
|
||
|
|
bandit.attackRange = 1.6f;
|
||
|
|
bandit.attackInterval = 1.25f;
|
||
|
|
bandit.moveSpeed = 3.4f;
|
||
|
|
bandit.defenseArmor = 2f;
|
||
|
|
bandit.healthGrowth = 20f;
|
||
|
|
bandit.damageGrowth = 3f;
|
||
|
|
bandit.baseExpRequirement = 35;
|
||
|
|
SaveOrUpdateSO(bandit, $"{DataPath}/SO_Bandit_Raider.asset");
|
||
|
|
list.Add(bandit);
|
||
|
|
|
||
|
|
// Bandit Archer
|
||
|
|
UnitDataSO banditArcher = ScriptableObject.CreateInstance<UnitDataSO>();
|
||
|
|
banditArcher.unitName = "Bandit Archer";
|
||
|
|
banditArcher.unitClass = UnitClassType.Archer;
|
||
|
|
banditArcher.goldCost = 50;
|
||
|
|
banditArcher.unitPrefab = unitPrefab;
|
||
|
|
banditArcher.maxHealth = 70f;
|
||
|
|
banditArcher.attackDamage = 18f;
|
||
|
|
banditArcher.attackRange = 7.5f;
|
||
|
|
banditArcher.attackInterval = 1.6f;
|
||
|
|
banditArcher.moveSpeed = 3.0f;
|
||
|
|
banditArcher.defenseArmor = 1f;
|
||
|
|
banditArcher.healthGrowth = 14f;
|
||
|
|
banditArcher.damageGrowth = 4f;
|
||
|
|
banditArcher.baseExpRequirement = 35;
|
||
|
|
SaveOrUpdateSO(banditArcher, $"{DataPath}/SO_Bandit_Archer.asset");
|
||
|
|
list.Add(banditArcher);
|
||
|
|
|
||
|
|
return list;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void SaveOrUpdateSO(ScriptableObject so, string path)
|
||
|
|
{
|
||
|
|
UnitDataSO existing = AssetDatabase.LoadAssetAtPath<UnitDataSO>(path);
|
||
|
|
if (existing != null)
|
||
|
|
{
|
||
|
|
EditorUtility.CopySerialized(so, existing);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
AssetDatabase.CreateAsset(so, path);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void SetupSceneHierarchy(
|
||
|
|
List<UnitDataSO> playerUnits,
|
||
|
|
List<UnitDataSO> enemyUnits,
|
||
|
|
GameObject cardPrefab,
|
||
|
|
GameObject unitPrefab)
|
||
|
|
{
|
||
|
|
// 1. Create Ground / Arena if not present
|
||
|
|
GameObject ground = GameObject.Find("ArenaGround");
|
||
|
|
if (ground == null)
|
||
|
|
{
|
||
|
|
ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||
|
|
ground.name = "ArenaGround";
|
||
|
|
ground.transform.position = Vector3.zero;
|
||
|
|
ground.transform.localScale = new Vector3(5f, 1f, 5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Deployment Zones
|
||
|
|
GameObject playerZoneObj = GameObject.Find("PlayerDeploymentZone");
|
||
|
|
if (playerZoneObj == null)
|
||
|
|
{
|
||
|
|
playerZoneObj = new GameObject("PlayerDeploymentZone");
|
||
|
|
playerZoneObj.transform.position = new Vector3(0, 0, -8f);
|
||
|
|
}
|
||
|
|
DeploymentZone playerZone = playerZoneObj.GetComponent<DeploymentZone>();
|
||
|
|
if (playerZone == null) playerZone = playerZoneObj.AddComponent<DeploymentZone>();
|
||
|
|
|
||
|
|
GameObject enemyZoneObj = GameObject.Find("EnemyDeploymentZone");
|
||
|
|
if (enemyZoneObj == null)
|
||
|
|
{
|
||
|
|
enemyZoneObj = new GameObject("EnemyDeploymentZone");
|
||
|
|
enemyZoneObj.transform.position = new Vector3(0, 0, 8f);
|
||
|
|
}
|
||
|
|
DeploymentZone enemyZone = enemyZoneObj.GetComponent<DeploymentZone>();
|
||
|
|
if (enemyZone == null) enemyZone = enemyZoneObj.AddComponent<DeploymentZone>();
|
||
|
|
|
||
|
|
// 3. Battle Manager & Game Manager
|
||
|
|
GameObject mgrObj = GameObject.Find("GameManagers");
|
||
|
|
if (mgrObj == null)
|
||
|
|
{
|
||
|
|
mgrObj = new GameObject("GameManagers");
|
||
|
|
}
|
||
|
|
GameManager gm = mgrObj.GetComponent<GameManager>();
|
||
|
|
if (gm == null) gm = mgrObj.AddComponent<GameManager>();
|
||
|
|
|
||
|
|
BattleManager bm = mgrObj.GetComponent<BattleManager>();
|
||
|
|
if (bm == null) bm = mgrObj.AddComponent<BattleManager>();
|
||
|
|
|
||
|
|
SerializedObject bmSo = new SerializedObject(bm);
|
||
|
|
bmSo.FindProperty("playerDeploymentZone").objectReferenceValue = playerZone;
|
||
|
|
bmSo.FindProperty("enemyDeploymentZone").objectReferenceValue = enemyZone;
|
||
|
|
bmSo.FindProperty("defaultUnitPrefab").objectReferenceValue = unitPrefab;
|
||
|
|
bmSo.FindProperty("startingGold").intValue = 150;
|
||
|
|
|
||
|
|
// Configure predefined waves
|
||
|
|
SerializedProperty wavesProp = bmSo.FindProperty("predefinedWaves");
|
||
|
|
wavesProp.ClearArray();
|
||
|
|
|
||
|
|
// Wave 1: 2 Bandit Raiders
|
||
|
|
wavesProp.InsertArrayElementAtIndex(0);
|
||
|
|
SerializedProperty w1 = wavesProp.GetArrayElementAtIndex(0);
|
||
|
|
w1.FindPropertyRelative("waveName").stringValue = "Wave 1 - Scouts";
|
||
|
|
w1.FindPropertyRelative("rewardGold").intValue = 60;
|
||
|
|
w1.FindPropertyRelative("waveBonusExp").intValue = 30;
|
||
|
|
SerializedProperty w1Enemies = w1.FindPropertyRelative("enemies");
|
||
|
|
w1Enemies.InsertArrayElementAtIndex(0);
|
||
|
|
w1Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("unitData").objectReferenceValue = enemyUnits[0];
|
||
|
|
w1Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("count").intValue = 2;
|
||
|
|
w1Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("level").intValue = 1;
|
||
|
|
|
||
|
|
// Wave 2: 3 Raiders + 1 Archer
|
||
|
|
wavesProp.InsertArrayElementAtIndex(1);
|
||
|
|
SerializedProperty w2 = wavesProp.GetArrayElementAtIndex(1);
|
||
|
|
w2.FindPropertyRelative("waveName").stringValue = "Wave 2 - Raiding Party";
|
||
|
|
w2.FindPropertyRelative("rewardGold").intValue = 90;
|
||
|
|
w2.FindPropertyRelative("waveBonusExp").intValue = 45;
|
||
|
|
SerializedProperty w2Enemies = w2.FindPropertyRelative("enemies");
|
||
|
|
w2Enemies.InsertArrayElementAtIndex(0);
|
||
|
|
w2Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("unitData").objectReferenceValue = enemyUnits[0];
|
||
|
|
w2Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("count").intValue = 3;
|
||
|
|
w2Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("level").intValue = 1;
|
||
|
|
|
||
|
|
w2Enemies.InsertArrayElementAtIndex(1);
|
||
|
|
w2Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("unitData").objectReferenceValue = enemyUnits[1];
|
||
|
|
w2Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("count").intValue = 1;
|
||
|
|
w2Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("level").intValue = 2;
|
||
|
|
|
||
|
|
// Wave 3: 4 Raiders + 2 Archers (Lv 2-3)
|
||
|
|
wavesProp.InsertArrayElementAtIndex(2);
|
||
|
|
SerializedProperty w3 = wavesProp.GetArrayElementAtIndex(2);
|
||
|
|
w3.FindPropertyRelative("waveName").stringValue = "Wave 3 - Veteran Warband";
|
||
|
|
w3.FindPropertyRelative("rewardGold").intValue = 130;
|
||
|
|
w3.FindPropertyRelative("waveBonusExp").intValue = 60;
|
||
|
|
SerializedProperty w3Enemies = w3.FindPropertyRelative("enemies");
|
||
|
|
w3Enemies.InsertArrayElementAtIndex(0);
|
||
|
|
w3Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("unitData").objectReferenceValue = enemyUnits[0];
|
||
|
|
w3Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("count").intValue = 4;
|
||
|
|
w3Enemies.GetArrayElementAtIndex(0).FindPropertyRelative("level").intValue = 2;
|
||
|
|
|
||
|
|
w3Enemies.InsertArrayElementAtIndex(1);
|
||
|
|
w3Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("unitData").objectReferenceValue = enemyUnits[1];
|
||
|
|
w3Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("count").intValue = 2;
|
||
|
|
w3Enemies.GetArrayElementAtIndex(1).FindPropertyRelative("level").intValue = 3;
|
||
|
|
|
||
|
|
bmSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
// 4. Setup Canvas and UI
|
||
|
|
CreateOrUpdateCanvasUI(playerUnits, cardPrefab);
|
||
|
|
|
||
|
|
// 5. Position Camera
|
||
|
|
Camera cam = Camera.main;
|
||
|
|
if (cam != null)
|
||
|
|
{
|
||
|
|
cam.transform.position = new Vector3(0, 16f, -16f);
|
||
|
|
cam.transform.rotation = Quaternion.Euler(48f, 0, 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateOrUpdateCanvasUI(List<UnitDataSO> playerUnits, GameObject cardPrefab)
|
||
|
|
{
|
||
|
|
GameObject canvasObj = GameObject.Find("BattleCanvas");
|
||
|
|
if (canvasObj == null)
|
||
|
|
{
|
||
|
|
canvasObj = new GameObject("BattleCanvas");
|
||
|
|
Canvas canvas = canvasObj.AddComponent<Canvas>();
|
||
|
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||
|
|
CanvasScaler scaler = canvasObj.AddComponent<CanvasScaler>();
|
||
|
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||
|
|
scaler.referenceResolution = new Vector2(1920, 1080);
|
||
|
|
canvasObj.AddComponent<GraphicRaycaster>();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ensure EventSystem
|
||
|
|
if (Object.FindFirstObjectByType<UnityEngine.EventSystems.EventSystem>() == null)
|
||
|
|
{
|
||
|
|
GameObject esObj = new GameObject("EventSystem");
|
||
|
|
esObj.AddComponent<UnityEngine.EventSystems.EventSystem>();
|
||
|
|
esObj.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
|
||
|
|
}
|
||
|
|
|
||
|
|
// TOP HUD PANEL
|
||
|
|
GameObject hudPanel = new GameObject("TopHUD");
|
||
|
|
hudPanel.transform.SetParent(canvasObj.transform, false);
|
||
|
|
RectTransform hudRect = hudPanel.AddComponent<RectTransform>();
|
||
|
|
hudRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
hudRect.anchorMax = new Vector2(1f, 1f);
|
||
|
|
hudRect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
hudRect.sizeDelta = new Vector2(0, 90f);
|
||
|
|
Image hudBg = hudPanel.AddComponent<Image>();
|
||
|
|
hudBg.color = new Color(0.08f, 0.1f, 0.14f, 0.85f);
|
||
|
|
|
||
|
|
// Ongoing Unit Count: Player Alive
|
||
|
|
GameObject pAliveObj = new GameObject("PlayerAliveText");
|
||
|
|
pAliveObj.transform.SetParent(hudPanel.transform, false);
|
||
|
|
RectTransform pAliveRect = pAliveObj.AddComponent<RectTransform>();
|
||
|
|
pAliveRect.anchorMin = new Vector2(0f, 0.5f);
|
||
|
|
pAliveRect.anchorMax = new Vector2(0f, 0.5f);
|
||
|
|
pAliveRect.anchoredPosition = new Vector2(180f, 0);
|
||
|
|
pAliveRect.sizeDelta = new Vector2(300f, 40f);
|
||
|
|
TextMeshProUGUI pAliveText = pAliveObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
pAliveText.text = "Player Army: 0 / 0";
|
||
|
|
pAliveText.fontSize = 22;
|
||
|
|
pAliveText.fontStyle = FontStyles.Bold;
|
||
|
|
pAliveText.color = new Color(0.3f, 0.8f, 1f);
|
||
|
|
|
||
|
|
// Ongoing Unit Count: Enemy Alive
|
||
|
|
GameObject eAliveObj = new GameObject("EnemyAliveText");
|
||
|
|
eAliveObj.transform.SetParent(hudPanel.transform, false);
|
||
|
|
RectTransform eAliveRect = eAliveObj.AddComponent<RectTransform>();
|
||
|
|
eAliveRect.anchorMin = new Vector2(1f, 0.5f);
|
||
|
|
eAliveMaxAnchor(eAliveRect);
|
||
|
|
eAliveRect.anchoredPosition = new Vector2(-180f, 0);
|
||
|
|
eAliveRect.sizeDelta = new Vector2(300f, 40f);
|
||
|
|
TextMeshProUGUI eAliveText = eAliveObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
eAliveText.text = "Enemy Force: 0 / 0";
|
||
|
|
eAliveText.fontSize = 22;
|
||
|
|
eAliveText.fontStyle = FontStyles.Bold;
|
||
|
|
eAliveText.alignment = TextAlignmentOptions.Right;
|
||
|
|
eAliveText.color = new Color(1f, 0.35f, 0.35f);
|
||
|
|
|
||
|
|
// Round & Phase Text (Center)
|
||
|
|
GameObject waveObj = new GameObject("WaveText");
|
||
|
|
waveObj.transform.SetParent(hudPanel.transform, false);
|
||
|
|
RectTransform waveRect = waveObj.AddComponent<RectTransform>();
|
||
|
|
waveRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||
|
|
waveRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||
|
|
waveRect.anchoredPosition = new Vector2(0, 15f);
|
||
|
|
waveRect.sizeDelta = new Vector2(400f, 30f);
|
||
|
|
TextMeshProUGUI waveText = waveObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
waveText.text = "Battle Round: 1";
|
||
|
|
waveText.fontSize = 24;
|
||
|
|
waveText.fontStyle = FontStyles.Bold;
|
||
|
|
waveText.alignment = TextAlignmentOptions.Center;
|
||
|
|
waveText.color = Color.white;
|
||
|
|
|
||
|
|
GameObject statusObj = new GameObject("PhaseStatusText");
|
||
|
|
statusObj.transform.SetParent(hudPanel.transform, false);
|
||
|
|
RectTransform statusRect = statusObj.AddComponent<RectTransform>();
|
||
|
|
statusRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||
|
|
statusRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||
|
|
statusRect.anchoredPosition = new Vector2(0, -18f);
|
||
|
|
statusRect.sizeDelta = new Vector2(500f, 25f);
|
||
|
|
TextMeshProUGUI statusText = statusObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
statusText.text = "PHASE: RECRUITMENT & PREPARATION";
|
||
|
|
statusText.fontSize = 16;
|
||
|
|
statusText.alignment = TextAlignmentOptions.Center;
|
||
|
|
statusText.color = new Color(0.3f, 0.8f, 1f);
|
||
|
|
|
||
|
|
// Game Speed Controls (HUD Left)
|
||
|
|
GameObject speed1x = CreateButton(hudPanel.transform, "Speed1x", "1x", new Vector2(380f, 0), new Vector2(50f, 35f));
|
||
|
|
GameObject speed2x = CreateButton(hudPanel.transform, "Speed2x", "2x", new Vector2(440f, 0), new Vector2(50f, 35f));
|
||
|
|
GameObject speed4x = CreateButton(hudPanel.transform, "Speed4x", "4x", new Vector2(500f, 0), new Vector2(50f, 35f));
|
||
|
|
|
||
|
|
// Start Battle Button (HUD Right-ish or Bottom)
|
||
|
|
GameObject startBtnObj = CreateButton(canvasObj.transform, "StartBattleBtn", "START BATTLE", new Vector2(0, 190f), new Vector2(260f, 55f));
|
||
|
|
RectTransform startBtnRect = startBtnObj.GetComponent<RectTransform>();
|
||
|
|
startBtnRect.anchorMin = new Vector2(0.5f, 0f);
|
||
|
|
startBtnRect.anchorMax = new Vector2(0.5f, 0f);
|
||
|
|
startBtnObj.GetComponent<Image>().color = new Color(0.85f, 0.4f, 0.1f);
|
||
|
|
startBtnObj.GetComponentInChildren<TextMeshProUGUI>().fontSize = 22;
|
||
|
|
|
||
|
|
// Wire BattleHUD
|
||
|
|
BattleHUD battleHUD = canvasObj.AddComponent<BattleHUD>();
|
||
|
|
SerializedObject hudSo = new SerializedObject(battleHUD);
|
||
|
|
hudSo.FindProperty("playerUnitsCountText").objectReferenceValue = pAliveText;
|
||
|
|
hudSo.FindProperty("enemyUnitsCountText").objectReferenceValue = eAliveText;
|
||
|
|
hudSo.FindProperty("waveTitleText").objectReferenceValue = waveText;
|
||
|
|
hudSo.FindProperty("battleStatusText").objectReferenceValue = statusText;
|
||
|
|
hudSo.FindProperty("startBattleButton").objectReferenceValue = startBtnObj.GetComponent<Button>();
|
||
|
|
hudSo.FindProperty("speed1xButton").objectReferenceValue = speed1x.GetComponent<Button>();
|
||
|
|
hudSo.FindProperty("speed2xButton").objectReferenceValue = speed2x.GetComponent<Button>();
|
||
|
|
hudSo.FindProperty("speed4xButton").objectReferenceValue = speed4x.GetComponent<Button>();
|
||
|
|
hudSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
// RECRUITMENT SHOP PANEL (BOTTOM)
|
||
|
|
GameObject shopPanel = new GameObject("ShopPanel");
|
||
|
|
shopPanel.transform.SetParent(canvasObj.transform, false);
|
||
|
|
RectTransform shopRect = shopPanel.AddComponent<RectTransform>();
|
||
|
|
shopRect.anchorMin = new Vector2(0f, 0f);
|
||
|
|
shopRect.anchorMax = new Vector2(1f, 0f);
|
||
|
|
shopRect.pivot = new Vector2(0.5f, 0f);
|
||
|
|
shopRect.sizeDelta = new Vector2(0, 160f);
|
||
|
|
Image shopBg = shopPanel.AddComponent<Image>();
|
||
|
|
shopBg.color = new Color(0.06f, 0.08f, 0.12f, 0.92f);
|
||
|
|
|
||
|
|
// Gold Display
|
||
|
|
GameObject goldObj = new GameObject("GoldText");
|
||
|
|
goldObj.transform.SetParent(shopPanel.transform, false);
|
||
|
|
RectTransform goldRect = goldObj.AddComponent<RectTransform>();
|
||
|
|
goldRect.anchorMin = new Vector2(0f, 0.5f);
|
||
|
|
goldRect.anchorMax = new Vector2(0f, 0.5f);
|
||
|
|
goldRect.anchoredPosition = new Vector2(120f, 0);
|
||
|
|
goldRect.sizeDelta = new Vector2(200f, 40f);
|
||
|
|
TextMeshProUGUI goldText = goldObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
goldText.text = "Gold: 150";
|
||
|
|
goldText.fontSize = 24;
|
||
|
|
goldText.fontStyle = FontStyles.Bold;
|
||
|
|
goldText.color = new Color(1f, 0.85f, 0.2f);
|
||
|
|
|
||
|
|
// Shop Cards Container
|
||
|
|
GameObject cardsContainer = new GameObject("CardsContainer");
|
||
|
|
cardsContainer.transform.SetParent(shopPanel.transform, false);
|
||
|
|
RectTransform containerRect = cardsContainer.AddComponent<RectTransform>();
|
||
|
|
containerRect.anchorMin = new Vector2(0.2f, 0f);
|
||
|
|
containerRect.anchorMax = new Vector2(0.95f, 1f);
|
||
|
|
containerRect.sizeDelta = Vector2.zero;
|
||
|
|
HorizontalLayoutGroup hlg = cardsContainer.AddComponent<HorizontalLayoutGroup>();
|
||
|
|
hlg.spacing = 15f;
|
||
|
|
hlg.childAlignment = TextAnchor.MiddleCenter;
|
||
|
|
hlg.childControlWidth = false;
|
||
|
|
hlg.childControlHeight = false;
|
||
|
|
|
||
|
|
ShopUI shopUI = shopPanel.AddComponent<ShopUI>();
|
||
|
|
SerializedObject shopSo = new SerializedObject(shopUI);
|
||
|
|
shopSo.FindProperty("goldDisplayText").objectReferenceValue = goldText;
|
||
|
|
shopSo.FindProperty("cardsContainer").objectReferenceValue = cardsContainer.transform;
|
||
|
|
shopSo.FindProperty("cardPrefab").objectReferenceValue = cardPrefab;
|
||
|
|
shopSo.FindProperty("shopPanel").objectReferenceValue = shopPanel;
|
||
|
|
|
||
|
|
SerializedProperty catalogProp = shopSo.FindProperty("purchasableUnits");
|
||
|
|
catalogProp.ClearArray();
|
||
|
|
for (int i = 0; i < playerUnits.Count; i++)
|
||
|
|
{
|
||
|
|
catalogProp.InsertArrayElementAtIndex(i);
|
||
|
|
catalogProp.GetArrayElementAtIndex(i).objectReferenceValue = playerUnits[i];
|
||
|
|
}
|
||
|
|
shopSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
// POST-BATTLE RESULTS MODAL
|
||
|
|
GameObject resultsModal = new GameObject("ResultsModal");
|
||
|
|
resultsModal.transform.SetParent(canvasObj.transform, false);
|
||
|
|
RectTransform modalRect = resultsModal.AddComponent<RectTransform>();
|
||
|
|
modalRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||
|
|
modalRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||
|
|
modalRect.sizeDelta = new Vector2(500f, 360f);
|
||
|
|
Image modalBg = resultsModal.AddComponent<Image>();
|
||
|
|
modalBg.color = new Color(0.08f, 0.1f, 0.15f, 0.97f);
|
||
|
|
|
||
|
|
// Victory Title
|
||
|
|
GameObject resTitle = new GameObject("ResultTitle");
|
||
|
|
resTitle.transform.SetParent(resultsModal.transform, false);
|
||
|
|
RectTransform resTitleRect = resTitle.AddComponent<RectTransform>();
|
||
|
|
resTitleRect.anchoredPosition = new Vector2(0, 130f);
|
||
|
|
resTitleRect.sizeDelta = new Vector2(460f, 50f);
|
||
|
|
TextMeshProUGUI resTitleText = resTitle.AddComponent<TextMeshProUGUI>();
|
||
|
|
resTitleText.text = "VICTORY!";
|
||
|
|
resTitleText.fontSize = 32;
|
||
|
|
resTitleText.fontStyle = FontStyles.Bold;
|
||
|
|
resTitleText.alignment = TextAlignmentOptions.Center;
|
||
|
|
resTitleText.color = new Color(0.2f, 1f, 0.4f);
|
||
|
|
|
||
|
|
// Gold Reward
|
||
|
|
GameObject goldRew = new GameObject("GoldReward");
|
||
|
|
goldRew.transform.SetParent(resultsModal.transform, false);
|
||
|
|
RectTransform goldRewRect = goldRew.AddComponent<RectTransform>();
|
||
|
|
goldRewRect.anchoredPosition = new Vector2(0, 80f);
|
||
|
|
goldRewRect.sizeDelta = new Vector2(460f, 30f);
|
||
|
|
TextMeshProUGUI goldRewText = goldRew.AddComponent<TextMeshProUGUI>();
|
||
|
|
goldRewText.text = "Gold Earned: +95";
|
||
|
|
goldRewText.fontSize = 20;
|
||
|
|
goldRewText.alignment = TextAlignmentOptions.Center;
|
||
|
|
goldRewText.color = new Color(1f, 0.85f, 0.2f);
|
||
|
|
|
||
|
|
// Casualties Text
|
||
|
|
GameObject casObj = new GameObject("CasualtiesText");
|
||
|
|
casObj.transform.SetParent(resultsModal.transform, false);
|
||
|
|
RectTransform casRect = casObj.AddComponent<RectTransform>();
|
||
|
|
casRect.anchoredPosition = new Vector2(0, 35f);
|
||
|
|
casRect.sizeDelta = new Vector2(460f, 40f);
|
||
|
|
TextMeshProUGUI casText = casObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
casText.text = "Surviving Units: 3 / 3\nEnemies Defeated: 2";
|
||
|
|
casText.fontSize = 17;
|
||
|
|
casText.alignment = TextAlignmentOptions.Center;
|
||
|
|
casText.color = Color.white;
|
||
|
|
|
||
|
|
// Level Up Report Text
|
||
|
|
GameObject lvlObj = new GameObject("LevelReportText");
|
||
|
|
lvlObj.transform.SetParent(resultsModal.transform, false);
|
||
|
|
RectTransform lvlRect = lvlObj.AddComponent<RectTransform>();
|
||
|
|
lvlRect.anchoredPosition = new Vector2(0, -35f);
|
||
|
|
lvlRect.sizeDelta = new Vector2(440f, 75f);
|
||
|
|
TextMeshProUGUI lvlText = lvlObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
lvlText.text = "• Swordsman reached Level 2! Unlocked [Flanking]!";
|
||
|
|
lvlText.fontSize = 15;
|
||
|
|
lvlText.alignment = TextAlignmentOptions.Center;
|
||
|
|
lvlText.color = new Color(0.4f, 0.9f, 1f);
|
||
|
|
|
||
|
|
// Continue Button
|
||
|
|
GameObject contBtn = CreateButton(resultsModal.transform, "ContinueBtn", "CONTINUE", new Vector2(0, -135f), new Vector2(220f, 45f));
|
||
|
|
contBtn.GetComponent<Image>().color = new Color(0.2f, 0.65f, 0.35f);
|
||
|
|
contBtn.GetComponentInChildren<TextMeshProUGUI>().fontSize = 20;
|
||
|
|
|
||
|
|
BattleResultUI resultUI = resultsModal.AddComponent<BattleResultUI>();
|
||
|
|
SerializedObject resSo = new SerializedObject(resultUI);
|
||
|
|
resSo.FindProperty("resultPanel").objectReferenceValue = resultsModal;
|
||
|
|
resSo.FindProperty("resultTitleText").objectReferenceValue = resTitleText;
|
||
|
|
resSo.FindProperty("goldRewardText").objectReferenceValue = goldRewText;
|
||
|
|
resSo.FindProperty("casualtiesText").objectReferenceValue = casText;
|
||
|
|
resSo.FindProperty("levelUpReportText").objectReferenceValue = lvlText;
|
||
|
|
resSo.FindProperty("continueButton").objectReferenceValue = contBtn.GetComponent<Button>();
|
||
|
|
resSo.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
resultsModal.SetActive(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void eAliveMaxAnchor(RectTransform rect)
|
||
|
|
{
|
||
|
|
rect.anchorMax = new Vector2(1f, 0.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateButton(Transform parent, string name, string label, Vector2 pos, Vector2 size)
|
||
|
|
{
|
||
|
|
GameObject btnObj = new GameObject(name);
|
||
|
|
btnObj.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = btnObj.AddComponent<RectTransform>();
|
||
|
|
rect.anchoredPosition = pos;
|
||
|
|
rect.sizeDelta = size;
|
||
|
|
|
||
|
|
Image img = btnObj.AddComponent<Image>();
|
||
|
|
img.color = new Color(0.25f, 0.3f, 0.4f);
|
||
|
|
btnObj.AddComponent<Button>();
|
||
|
|
|
||
|
|
GameObject textObj = new GameObject("Text");
|
||
|
|
textObj.transform.SetParent(btnObj.transform, false);
|
||
|
|
RectTransform tRect = textObj.AddComponent<RectTransform>();
|
||
|
|
tRect.anchorMin = Vector2.zero;
|
||
|
|
tRect.anchorMax = Vector2.one;
|
||
|
|
tRect.sizeDelta = Vector2.zero;
|
||
|
|
TextMeshProUGUI tmp = textObj.AddComponent<TextMeshProUGUI>();
|
||
|
|
tmp.text = label;
|
||
|
|
tmp.fontSize = 15;
|
||
|
|
tmp.fontStyle = FontStyles.Bold;
|
||
|
|
tmp.alignment = TextAlignmentOptions.Center;
|
||
|
|
tmp.color = Color.white;
|
||
|
|
|
||
|
|
return btnObj;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|