1390 lines
70 KiB
C#
1390 lines
70 KiB
C#
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using OTGIntegrated.Abilities;
|
||
|
|
using OTGIntegrated.Combat;
|
||
|
|
using OTGIntegrated.Core;
|
||
|
|
using OTGIntegrated.Crafting;
|
||
|
|
using OTGIntegrated.Dialogue;
|
||
|
|
using OTGIntegrated.Items;
|
||
|
|
using OTGIntegrated.Player;
|
||
|
|
using OTGIntegrated.Quests;
|
||
|
|
using OTGIntegrated.Save;
|
||
|
|
using OTGIntegrated.Stats;
|
||
|
|
using OTGIntegrated.Talents;
|
||
|
|
using OTGIntegrated.UI;
|
||
|
|
using OTGIntegrated.Weapons;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.SceneManagement;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.EventSystems;
|
||
|
|
using UnityEngine.SceneManagement;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
using PlayerInventory = OTGIntegrated.Inventory.Inventory;
|
||
|
|
using InventoryUI = OTGIntegrated.Inventory.InventoryUI;
|
||
|
|
|
||
|
|
public static class Lab8SceneBuilder
|
||
|
|
{
|
||
|
|
private const string ScenePath = "Assets/_Scenes/Lab08_IntegratedRPG.unity";
|
||
|
|
|
||
|
|
private static Font regularFont;
|
||
|
|
private static Font boldFont;
|
||
|
|
private static Dictionary<string, Material> materials;
|
||
|
|
|
||
|
|
[MenuItem("Tools/Technical Game Design/Lab8/Create Integrated RPG Scene")]
|
||
|
|
public static void CreateIntegratedRPGScene()
|
||
|
|
{
|
||
|
|
EnsureProjectFolders();
|
||
|
|
regularFont = InstallUbuntuFont("Ubuntu-Regular.ttf", false);
|
||
|
|
boldFont = InstallUbuntuFont("Ubuntu-Bold.ttf", true);
|
||
|
|
if (boldFont == null)
|
||
|
|
{
|
||
|
|
boldFont = regularFont;
|
||
|
|
}
|
||
|
|
|
||
|
|
materials = CreateMaterials();
|
||
|
|
DataSet data = CreateData();
|
||
|
|
|
||
|
|
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||
|
|
scene.name = "Lab08_IntegratedRPG";
|
||
|
|
|
||
|
|
CreateLighting();
|
||
|
|
CreateGroundAndZones();
|
||
|
|
Camera mainCamera = CreateCamera();
|
||
|
|
PlayerBundle player = CreatePlayer(mainCamera, data);
|
||
|
|
CraftingSystem craftingSystem = CreateVillage(data);
|
||
|
|
QuestManager questManager = CreateQuestManager(data);
|
||
|
|
DialogueManager dialogueManager = CreateDialogueManager();
|
||
|
|
SaveSystem saveSystem = CreateSaveSystem(data);
|
||
|
|
CreateResources(data);
|
||
|
|
CreateGoblinCamp(data);
|
||
|
|
CreateMagicCircle();
|
||
|
|
UIManager uiManager = CreateUI(player, questManager, craftingSystem, dialogueManager, saveSystem);
|
||
|
|
GameManager gameManager = CreateGameManager(player, questManager, dialogueManager, craftingSystem, uiManager, saveSystem);
|
||
|
|
|
||
|
|
EditorUtility.SetDirty(gameManager);
|
||
|
|
EditorUtility.SetDirty(uiManager);
|
||
|
|
EditorSceneManager.SaveScene(scene, ScenePath);
|
||
|
|
AddSceneToBuildSettings(ScenePath);
|
||
|
|
AssetDatabase.SaveAssets();
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
|
||
|
|
Debug.Log($"Lab08 integrated RPG scene created: {ScenePath}");
|
||
|
|
}
|
||
|
|
|
||
|
|
[MenuItem("Tools/Technical Game Design/Lab8/Validate Integrated RPG Scene")]
|
||
|
|
public static void ValidateIntegratedRPGScene()
|
||
|
|
{
|
||
|
|
if (!File.Exists(ToSystemPath(ScenePath)))
|
||
|
|
{
|
||
|
|
throw new System.Exception($"Scene is missing: {ScenePath}");
|
||
|
|
}
|
||
|
|
|
||
|
|
Scene scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
|
||
|
|
int missingScripts = CountMissingScripts(scene);
|
||
|
|
if (missingScripts > 0)
|
||
|
|
{
|
||
|
|
throw new System.Exception($"Missing scripts found: {missingScripts}");
|
||
|
|
}
|
||
|
|
|
||
|
|
Require(Object.FindObjectOfType<GameManager>() != null, "GameManager missing");
|
||
|
|
Require(Object.FindObjectOfType<PlayerController>() != null, "PlayerController missing");
|
||
|
|
Require(Object.FindObjectOfType<PlayerInventory>() != null, "Inventory missing");
|
||
|
|
Require(Object.FindObjectOfType<PlayerStats>() != null, "PlayerStats missing");
|
||
|
|
Require(Object.FindObjectOfType<QuestManager>() != null, "QuestManager missing");
|
||
|
|
Require(Object.FindObjectOfType<DialogueManager>() != null, "DialogueManager missing");
|
||
|
|
Require(Object.FindObjectOfType<UIManager>() != null, "UIManager missing");
|
||
|
|
Require(Object.FindObjectOfType<SaveSystem>() != null, "SaveSystem missing");
|
||
|
|
Require(Object.FindObjectsOfType<Enemy>().Length >= 5, "Goblin enemies missing");
|
||
|
|
Require(Object.FindObjectsOfType<ResourceNode>().Length >= 10, "Resource nodes missing");
|
||
|
|
Require(Object.FindObjectOfType<EventSystem>() != null, "EventSystem missing");
|
||
|
|
|
||
|
|
Font expectedFont = AssetDatabase.LoadAssetAtPath<Font>("Assets/_Fonts/Ubuntu-Regular.ttf");
|
||
|
|
if (expectedFont != null)
|
||
|
|
{
|
||
|
|
foreach (Text text in Resources.FindObjectsOfTypeAll<Text>())
|
||
|
|
{
|
||
|
|
if (text.gameObject.scene == scene)
|
||
|
|
{
|
||
|
|
Require(text.font == expectedFont || text.font == AssetDatabase.LoadAssetAtPath<Font>("Assets/_Fonts/Ubuntu-Bold.ttf"), $"Text does not use Ubuntu font: {text.name}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Debug.Log("Lab08 validation passed: core scene objects, systems, enemies, resources, UI and fonts are present.");
|
||
|
|
}
|
||
|
|
|
||
|
|
private sealed class DataSet
|
||
|
|
{
|
||
|
|
public readonly List<ItemData> allItems = new List<ItemData>();
|
||
|
|
public ItemData wood;
|
||
|
|
public ItemData stone;
|
||
|
|
public ItemData ironOre;
|
||
|
|
public ItemData herb;
|
||
|
|
public ItemData crystal;
|
||
|
|
public ItemData goblinFang;
|
||
|
|
public ItemData basicSwordItem;
|
||
|
|
public ItemData ironAxeItem;
|
||
|
|
public ItemData healthPotion;
|
||
|
|
public ItemData manaPotion;
|
||
|
|
|
||
|
|
public WeaponData basicSwordWeapon;
|
||
|
|
public WeaponData ironAxeWeapon;
|
||
|
|
public RecipeData recipeIronAxe;
|
||
|
|
public RecipeData recipeHealthPotion;
|
||
|
|
public RecipeData recipeManaPotion;
|
||
|
|
public QuestData questGatherWood;
|
||
|
|
public QuestData questKillGoblins;
|
||
|
|
public QuestData questCraftAxe;
|
||
|
|
public DialogueNode elderDialogue;
|
||
|
|
public DialogueNode guardDialogue;
|
||
|
|
public DialogueNode blacksmithDialogue;
|
||
|
|
public DialogueNode mageDialogue;
|
||
|
|
public AbilityData fireball;
|
||
|
|
public AbilityData heal;
|
||
|
|
public AbilityData blink;
|
||
|
|
public TalentData toughness;
|
||
|
|
public TalentData strength;
|
||
|
|
public TalentData agility;
|
||
|
|
public TalentData arcaneFlow;
|
||
|
|
public TalentData advancedStrength;
|
||
|
|
}
|
||
|
|
|
||
|
|
private sealed class PlayerBundle
|
||
|
|
{
|
||
|
|
public GameObject root;
|
||
|
|
public PlayerController controller;
|
||
|
|
public PlayerStats stats;
|
||
|
|
public PlayerInventory inventory;
|
||
|
|
public LevelSystem levelSystem;
|
||
|
|
public WeaponController weaponController;
|
||
|
|
public WeaponManager weaponManager;
|
||
|
|
public AbilityManager abilityManager;
|
||
|
|
public TalentManager talentManager;
|
||
|
|
public PlayerInteraction interaction;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void EnsureProjectFolders()
|
||
|
|
{
|
||
|
|
string[] folders =
|
||
|
|
{
|
||
|
|
"Assets/_Scenes",
|
||
|
|
"Assets/_Scripts",
|
||
|
|
"Assets/_Scripts/Core",
|
||
|
|
"Assets/_Scripts/Player",
|
||
|
|
"Assets/_Scripts/Stats",
|
||
|
|
"Assets/_Scripts/Inventory",
|
||
|
|
"Assets/_Scripts/Items",
|
||
|
|
"Assets/_Scripts/Crafting",
|
||
|
|
"Assets/_Scripts/Dialogue",
|
||
|
|
"Assets/_Scripts/Quests",
|
||
|
|
"Assets/_Scripts/Combat",
|
||
|
|
"Assets/_Scripts/Weapons",
|
||
|
|
"Assets/_Scripts/Abilities",
|
||
|
|
"Assets/_Scripts/Talents",
|
||
|
|
"Assets/_Scripts/UI",
|
||
|
|
"Assets/_Scripts/Save",
|
||
|
|
"Assets/_Data",
|
||
|
|
"Assets/_Data/Items",
|
||
|
|
"Assets/_Data/Recipes",
|
||
|
|
"Assets/_Data/Quests",
|
||
|
|
"Assets/_Data/Dialogue",
|
||
|
|
"Assets/_Data/Abilities",
|
||
|
|
"Assets/_Data/Talents",
|
||
|
|
"Assets/_Data/Weapons",
|
||
|
|
"Assets/_Prefabs",
|
||
|
|
"Assets/_Prefabs/UI",
|
||
|
|
"Assets/_Prefabs/Characters",
|
||
|
|
"Assets/_Prefabs/Items",
|
||
|
|
"Assets/_Prefabs/Effects",
|
||
|
|
"Assets/_Materials",
|
||
|
|
"Assets/_Fonts",
|
||
|
|
"Assets/Editor"
|
||
|
|
};
|
||
|
|
|
||
|
|
for (int i = 0; i < folders.Length; i++)
|
||
|
|
{
|
||
|
|
Directory.CreateDirectory(folders[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Font InstallUbuntuFont(string destinationName, bool bold)
|
||
|
|
{
|
||
|
|
string destination = "Assets/_Fonts/" + destinationName;
|
||
|
|
string[] candidates = bold
|
||
|
|
? new[]
|
||
|
|
{
|
||
|
|
"/usr/share/fonts/truetype/ubuntu/Ubuntu-B.ttf",
|
||
|
|
"/usr/share/fonts/truetype/ubuntu/Ubuntu-Bold.ttf",
|
||
|
|
"/usr/share/fonts/TTF/Ubuntu-B.ttf",
|
||
|
|
"/usr/share/fonts/TTF/Ubuntu-Bold.ttf"
|
||
|
|
}
|
||
|
|
: new[]
|
||
|
|
{
|
||
|
|
"/usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf",
|
||
|
|
"/usr/share/fonts/truetype/ubuntu/Ubuntu-Regular.ttf",
|
||
|
|
"/usr/share/fonts/TTF/Ubuntu-R.ttf",
|
||
|
|
"/usr/share/fonts/TTF/Ubuntu-Regular.ttf"
|
||
|
|
};
|
||
|
|
|
||
|
|
string source = FindExistingFile(candidates);
|
||
|
|
if (string.IsNullOrEmpty(source))
|
||
|
|
{
|
||
|
|
source = FindFontRecursive(bold ? new[] { "Ubuntu-B.ttf", "Ubuntu-Bold.ttf" } : new[] { "Ubuntu-R.ttf", "Ubuntu-Regular.ttf" });
|
||
|
|
}
|
||
|
|
|
||
|
|
if (string.IsNullOrEmpty(source))
|
||
|
|
{
|
||
|
|
Debug.LogWarning("Ubuntu Font was not found. Arial fallback will be used.");
|
||
|
|
return Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||
|
|
}
|
||
|
|
|
||
|
|
File.Copy(source, destination, true);
|
||
|
|
AssetDatabase.ImportAsset(destination, ImportAssetOptions.ForceUpdate);
|
||
|
|
Font font = AssetDatabase.LoadAssetAtPath<Font>(destination);
|
||
|
|
return font != null ? font : Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string FindExistingFile(string[] candidates)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < candidates.Length; i++)
|
||
|
|
{
|
||
|
|
if (File.Exists(candidates[i]))
|
||
|
|
{
|
||
|
|
return candidates[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string FindFontRecursive(string[] fileNames)
|
||
|
|
{
|
||
|
|
string[] roots = { "/usr/share/fonts", "/usr/share/fonts/truetype/ubuntu", "/usr/share/fonts/TTF" };
|
||
|
|
for (int r = 0; r < roots.Length; r++)
|
||
|
|
{
|
||
|
|
if (!Directory.Exists(roots[r]))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int f = 0; f < fileNames.Length; f++)
|
||
|
|
{
|
||
|
|
string[] matches = Directory.GetFiles(roots[r], fileNames[f], SearchOption.AllDirectories);
|
||
|
|
if (matches.Length > 0)
|
||
|
|
{
|
||
|
|
return matches[0];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Dictionary<string, Material> CreateMaterials()
|
||
|
|
{
|
||
|
|
return new Dictionary<string, Material>
|
||
|
|
{
|
||
|
|
["Ground"] = CreateMaterial("Ground", new Color(0.28f, 0.46f, 0.25f, 1f)),
|
||
|
|
["Village"] = CreateMaterial("Village", new Color(0.54f, 0.48f, 0.38f, 1f)),
|
||
|
|
["Wood"] = CreateMaterial("Wood", new Color(0.45f, 0.28f, 0.13f, 1f)),
|
||
|
|
["Leaves"] = CreateMaterial("Leaves", new Color(0.18f, 0.48f, 0.18f, 1f)),
|
||
|
|
["Stone"] = CreateMaterial("Stone", new Color(0.42f, 0.43f, 0.45f, 1f)),
|
||
|
|
["Iron"] = CreateMaterial("Iron", new Color(0.42f, 0.48f, 0.52f, 1f)),
|
||
|
|
["Herb"] = CreateMaterial("Herb", new Color(0.1f, 0.62f, 0.24f, 1f)),
|
||
|
|
["Crystal"] = CreateMaterial("Crystal", new Color(0.18f, 0.84f, 0.95f, 1f), true),
|
||
|
|
["Player"] = CreateMaterial("Player", new Color(0.16f, 0.36f, 0.84f, 1f)),
|
||
|
|
["Elder"] = CreateMaterial("Elder", new Color(0.78f, 0.62f, 0.34f, 1f)),
|
||
|
|
["Guard"] = CreateMaterial("Guard", new Color(0.2f, 0.36f, 0.62f, 1f)),
|
||
|
|
["Blacksmith"] = CreateMaterial("Blacksmith", new Color(0.5f, 0.2f, 0.16f, 1f)),
|
||
|
|
["Mage"] = CreateMaterial("Mage", new Color(0.35f, 0.22f, 0.72f, 1f)),
|
||
|
|
["Goblin"] = CreateMaterial("Goblin", new Color(0.24f, 0.55f, 0.18f, 1f)),
|
||
|
|
["Camp"] = CreateMaterial("Camp", new Color(0.45f, 0.16f, 0.12f, 1f)),
|
||
|
|
["Fire"] = CreateMaterial("Fire", new Color(1f, 0.32f, 0.05f, 1f), true),
|
||
|
|
["Mana"] = CreateMaterial("Mana", new Color(0.36f, 0.25f, 0.95f, 1f), true),
|
||
|
|
["Workbench"] = CreateMaterial("Workbench", new Color(0.35f, 0.22f, 0.12f, 1f))
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Material CreateMaterial(string name, Color color, bool emission = false)
|
||
|
|
{
|
||
|
|
string path = $"Assets/_Materials/M_{name}.mat";
|
||
|
|
Material material = AssetDatabase.LoadAssetAtPath<Material>(path);
|
||
|
|
if (material == null)
|
||
|
|
{
|
||
|
|
material = new Material(Shader.Find("Standard"));
|
||
|
|
AssetDatabase.CreateAsset(material, path);
|
||
|
|
}
|
||
|
|
|
||
|
|
material.color = color;
|
||
|
|
material.SetFloat("_Glossiness", emission ? 0.35f : 0.08f);
|
||
|
|
if (emission)
|
||
|
|
{
|
||
|
|
material.EnableKeyword("_EMISSION");
|
||
|
|
material.SetColor("_EmissionColor", color * 1.5f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
material.DisableKeyword("_EMISSION");
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorUtility.SetDirty(material);
|
||
|
|
return material;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DataSet CreateData()
|
||
|
|
{
|
||
|
|
DataSet data = new DataSet();
|
||
|
|
|
||
|
|
data.wood = CreateItem("Wood", "Wood", "Древесина для строительства и крафта.", 20, ItemType.Resource, new Color(0.55f, 0.33f, 0.16f, 1f));
|
||
|
|
data.stone = CreateItem("Stone", "Stone", "Камень из каменоломни.", 20, ItemType.Resource, new Color(0.52f, 0.53f, 0.55f, 1f));
|
||
|
|
data.ironOre = CreateItem("IronOre", "Iron Ore", "Руда для кузнечных рецептов.", 10, ItemType.Resource, new Color(0.42f, 0.48f, 0.52f, 1f));
|
||
|
|
data.herb = CreateItem("Herb", "Herb", "Лечебная трава.", 20, ItemType.Resource, new Color(0.1f, 0.65f, 0.28f, 1f));
|
||
|
|
data.crystal = CreateItem("Crystal", "Crystal", "Кристалл с магической энергией.", 10, ItemType.Resource, new Color(0.2f, 0.9f, 1f, 1f));
|
||
|
|
data.goblinFang = CreateItem("GoblinFang", "Goblin Fang", "Трофей с гоблина.", 20, ItemType.Quest, new Color(0.75f, 0.72f, 0.54f, 1f));
|
||
|
|
data.basicSwordItem = CreateItem("BasicSword", "Basic Sword", "Простой меч героя.", 1, ItemType.Weapon, new Color(0.72f, 0.78f, 0.84f, 1f));
|
||
|
|
data.ironAxeItem = CreateItem("IronAxe", "Iron Axe", "Тяжёлый железный топор.", 1, ItemType.Weapon, new Color(0.68f, 0.7f, 0.74f, 1f));
|
||
|
|
data.healthPotion = CreateItem("HealthPotion", "Health Potion", "Зелье восстановления здоровья.", 5, ItemType.Consumable, new Color(0.86f, 0.16f, 0.2f, 1f));
|
||
|
|
data.manaPotion = CreateItem("ManaPotion", "Mana Potion", "Зелье восстановления маны.", 5, ItemType.Consumable, new Color(0.16f, 0.32f, 0.9f, 1f));
|
||
|
|
|
||
|
|
data.allItems.AddRange(new[]
|
||
|
|
{
|
||
|
|
data.wood, data.stone, data.ironOre, data.herb, data.crystal, data.goblinFang,
|
||
|
|
data.basicSwordItem, data.ironAxeItem, data.healthPotion, data.manaPotion
|
||
|
|
});
|
||
|
|
|
||
|
|
data.basicSwordWeapon = CreateWeapon("BasicSword", "Basic Sword", 10f, 0.75f, 2.2f, false, 0f, "Базовое оружие ближнего боя.");
|
||
|
|
data.ironAxeWeapon = CreateWeapon("IronAxe", "Iron Axe", 18f, 0.95f, 2.4f, false, 0f, "Скрафченный топор с повышенным уроном.");
|
||
|
|
|
||
|
|
data.recipeIronAxe = CreateRecipe("Recipe_IronAxe", "Iron Axe", "Соберите рукоять и металлическую голову топора.", data.ironAxeItem, 1,
|
||
|
|
IngredientOf(data.wood, 2), IngredientOf(data.stone, 2), IngredientOf(data.ironOre, 1));
|
||
|
|
data.recipeHealthPotion = CreateRecipe("Recipe_HealthPotion", "Health Potion", "Простое лечебное зелье.", data.healthPotion, 1,
|
||
|
|
IngredientOf(data.herb, 2), IngredientOf(data.crystal, 1));
|
||
|
|
data.recipeManaPotion = CreateRecipe("Recipe_ManaPotion", "Mana Potion", "Зелье для восстановления магической энергии.", data.manaPotion, 1,
|
||
|
|
IngredientOf(data.crystal, 2), IngredientOf(data.herb, 1));
|
||
|
|
|
||
|
|
data.questGatherWood = CreateQuest("Quest_GatherWood", "Помощь старосте", "Соберите 5 древесины для укрепления деревни.", "Elder", "Elder", 50, 1,
|
||
|
|
new QuestGoal { goalType = QuestGoalType.CollectItem, targetItem = data.wood, requiredAmount = 5 });
|
||
|
|
data.questKillGoblins = CreateQuest("Quest_KillGoblins", "Очистка лагеря", "Уничтожьте 3 гоблинов возле деревни.", "Guard", "Guard", 100, 0,
|
||
|
|
new QuestGoal { goalType = QuestGoalType.KillEnemy, enemyId = "Goblin", requiredAmount = 3 });
|
||
|
|
data.questKillGoblins.rewardItems = new List<QuestRewardItem> { new QuestRewardItem { item = data.ironOre, amount = 2 } };
|
||
|
|
EditorUtility.SetDirty(data.questKillGoblins);
|
||
|
|
|
||
|
|
data.questCraftAxe = CreateQuest("Quest_CraftAxe", "Работа кузнеца", "Скрафтите железный топор.", "Blacksmith", "Blacksmith", 50, 0,
|
||
|
|
new QuestGoal { goalType = QuestGoalType.CraftItem, targetItem = data.ironAxeItem, requiredAmount = 1 });
|
||
|
|
data.questCraftAxe.rewardItems = new List<QuestRewardItem> { new QuestRewardItem { item = data.healthPotion, amount = 1 } };
|
||
|
|
EditorUtility.SetDirty(data.questCraftAxe);
|
||
|
|
|
||
|
|
data.elderDialogue = CreateDialogue("Dialogue_Elder", "Староста", "Деревня держится, но нам нужна древесина для укрепления стен. Поможешь?");
|
||
|
|
data.guardDialogue = CreateDialogue("Dialogue_Guard", "Стражник", "Гоблины снова заняли лагерь у дороги. Разберись с ними, когда будешь готов.");
|
||
|
|
data.blacksmithDialogue = CreateDialogue("Dialogue_Blacksmith", "Кузнец", "Верстак рядом. Если принесёшь материалы, сможешь сделать железный топор.");
|
||
|
|
data.mageDialogue = CreateDialogue("Dialogue_Mage", "Маг", "Способности привязаны к клавишам 1, 2 и 3. Таланты открываются на K и усиливают твои характеристики.");
|
||
|
|
|
||
|
|
GameObject fireballPrefab = CreateFireballPrefab();
|
||
|
|
GameObject healPrefab = CreateHealPrefab();
|
||
|
|
GameObject blinkPrefab = CreateBlinkPrefab();
|
||
|
|
data.fireball = CreateAbility("Fireball", "Fireball", "Летящий огненный снаряд, наносящий 25 + Damage.", 15f, 2f, 25f, 14f, fireballPrefab, new Color(0.95f, 0.22f, 0.08f, 1f));
|
||
|
|
data.heal = CreateAbility("Heal", "Heal", "Восстанавливает 30 HP.", 20f, 5f, 30f, 0f, healPrefab, new Color(0.22f, 0.9f, 0.36f, 1f));
|
||
|
|
data.blink = CreateAbility("Blink", "Blink", "Телепорт вперёд с проверкой препятствий.", 20f, 6f, 0f, 7f, blinkPrefab, new Color(0.48f, 0.38f, 1f, 1f));
|
||
|
|
|
||
|
|
data.toughness = CreateTalent("Toughness", "Toughness", "MaxHealth +20", new Vector2(-330f, 130f), new[] { new StatModifier(StatType.MaxHealth, ModifierType.FlatAdd, 20f) }, null);
|
||
|
|
data.strength = CreateTalent("Strength", "Strength", "Damage +5", new Vector2(-110f, 130f), new[] { new StatModifier(StatType.Damage, ModifierType.FlatAdd, 5f) }, null);
|
||
|
|
data.agility = CreateTalent("Agility", "Agility", "MoveSpeed +1", new Vector2(110f, 130f), new[] { new StatModifier(StatType.MoveSpeed, ModifierType.FlatAdd, 1f) }, null);
|
||
|
|
data.arcaneFlow = CreateTalent("ArcaneFlow", "Arcane Flow", "MaxMana +25", new Vector2(330f, 130f), new[] { new StatModifier(StatType.MaxMana, ModifierType.FlatAdd, 25f) }, null);
|
||
|
|
data.advancedStrength = CreateTalent("AdvancedStrength", "Advanced Strength", "Damage +10%", new Vector2(-110f, -80f), new[] { new StatModifier(StatType.Damage, ModifierType.PercentAdd, 0.1f) }, new[] { data.strength });
|
||
|
|
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static ItemData CreateItem(string id, string displayName, string description, int maxStack, ItemType type, Color color)
|
||
|
|
{
|
||
|
|
ItemData item = LoadOrCreate<ItemData>($"Assets/_Data/Items/{id}.asset");
|
||
|
|
item.itemId = id;
|
||
|
|
item.displayName = displayName;
|
||
|
|
item.description = description;
|
||
|
|
item.maxStack = maxStack;
|
||
|
|
item.itemType = type;
|
||
|
|
item.itemColor = color;
|
||
|
|
item.icon = CreateIcon("Assets/_Data/Items", id + "_Icon", color);
|
||
|
|
EditorUtility.SetDirty(item);
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static WeaponData CreateWeapon(string id, string displayName, float damage, float rate, float range, bool ranged, float manaCost, string description)
|
||
|
|
{
|
||
|
|
WeaponData weapon = LoadOrCreate<WeaponData>($"Assets/_Data/Weapons/{id}.asset");
|
||
|
|
weapon.weaponId = id;
|
||
|
|
weapon.displayName = displayName;
|
||
|
|
weapon.damage = damage;
|
||
|
|
weapon.attackRate = rate;
|
||
|
|
weapon.range = range;
|
||
|
|
weapon.isRanged = ranged;
|
||
|
|
weapon.manaCost = manaCost;
|
||
|
|
weapon.description = description;
|
||
|
|
EditorUtility.SetDirty(weapon);
|
||
|
|
return weapon;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Ingredient IngredientOf(ItemData item, int amount)
|
||
|
|
{
|
||
|
|
return new Ingredient { item = item, amount = amount };
|
||
|
|
}
|
||
|
|
|
||
|
|
private static RecipeData CreateRecipe(string id, string displayName, string description, ItemData result, int resultAmount, params Ingredient[] ingredients)
|
||
|
|
{
|
||
|
|
RecipeData recipe = LoadOrCreate<RecipeData>($"Assets/_Data/Recipes/{id}.asset");
|
||
|
|
recipe.recipeId = id;
|
||
|
|
recipe.displayName = displayName;
|
||
|
|
recipe.description = description;
|
||
|
|
recipe.resultItem = result;
|
||
|
|
recipe.resultAmount = resultAmount;
|
||
|
|
recipe.ingredients = ingredients;
|
||
|
|
EditorUtility.SetDirty(recipe);
|
||
|
|
return recipe;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static QuestData CreateQuest(string id, string displayName, string description, string giverNpcId, string turnInNpcId, int rewardExp, int rewardTalentPoints, QuestGoal goal)
|
||
|
|
{
|
||
|
|
QuestData quest = LoadOrCreate<QuestData>($"Assets/_Data/Quests/{id}.asset");
|
||
|
|
quest.questId = id;
|
||
|
|
quest.displayName = displayName;
|
||
|
|
quest.description = description;
|
||
|
|
quest.giverNpcId = giverNpcId;
|
||
|
|
quest.turnInNpcId = turnInNpcId;
|
||
|
|
quest.rewardExperience = rewardExp;
|
||
|
|
quest.rewardTalentPoints = rewardTalentPoints;
|
||
|
|
quest.goals = new List<QuestGoal> { goal };
|
||
|
|
quest.rewardItems = quest.rewardItems ?? new List<QuestRewardItem>();
|
||
|
|
EditorUtility.SetDirty(quest);
|
||
|
|
return quest;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DialogueNode CreateDialogue(string id, string speaker, string line)
|
||
|
|
{
|
||
|
|
DialogueNode node = LoadOrCreate<DialogueNode>($"Assets/_Data/Dialogue/{id}.asset");
|
||
|
|
node.nodeId = id;
|
||
|
|
node.speakerName = speaker;
|
||
|
|
node.npcLine = line;
|
||
|
|
node.responses = new[]
|
||
|
|
{
|
||
|
|
new DialogueResponse { responseText = "Расскажи подробнее", endsDialogue = false }
|
||
|
|
};
|
||
|
|
EditorUtility.SetDirty(node);
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static AbilityData CreateAbility(string id, string displayName, string description, float mana, float cooldown, float damage, float range, GameObject effectPrefab, Color color)
|
||
|
|
{
|
||
|
|
AbilityData ability = LoadOrCreate<AbilityData>($"Assets/_Data/Abilities/{id}.asset");
|
||
|
|
ability.abilityId = id;
|
||
|
|
ability.displayName = displayName;
|
||
|
|
ability.description = description;
|
||
|
|
ability.manaCost = mana;
|
||
|
|
ability.cooldown = cooldown;
|
||
|
|
ability.damage = damage;
|
||
|
|
ability.range = range;
|
||
|
|
ability.effectPrefab = effectPrefab;
|
||
|
|
ability.icon = CreateIcon("Assets/_Data/Abilities", id + "_Icon", color);
|
||
|
|
EditorUtility.SetDirty(ability);
|
||
|
|
return ability;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static TalentData CreateTalent(string id, string displayName, string description, Vector2 position, StatModifier[] modifiers, TalentData[] prerequisites)
|
||
|
|
{
|
||
|
|
TalentData talent = LoadOrCreate<TalentData>($"Assets/_Data/Talents/{id}.asset");
|
||
|
|
talent.talentId = id;
|
||
|
|
talent.displayName = displayName;
|
||
|
|
talent.description = description;
|
||
|
|
talent.cost = 1;
|
||
|
|
talent.treePosition = position;
|
||
|
|
talent.modifiers = modifiers;
|
||
|
|
talent.prerequisites = prerequisites;
|
||
|
|
talent.icon = CreateIcon("Assets/_Data/Talents", id + "_Icon", new Color(0.82f, 0.64f, 0.22f, 1f));
|
||
|
|
EditorUtility.SetDirty(talent);
|
||
|
|
return talent;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static T LoadOrCreate<T>(string path) where T : ScriptableObject
|
||
|
|
{
|
||
|
|
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
|
||
|
|
if (asset == null)
|
||
|
|
{
|
||
|
|
asset = ScriptableObject.CreateInstance<T>();
|
||
|
|
AssetDatabase.CreateAsset(asset, path);
|
||
|
|
}
|
||
|
|
|
||
|
|
return asset;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Sprite CreateIcon(string folder, string name, Color color)
|
||
|
|
{
|
||
|
|
Directory.CreateDirectory(folder);
|
||
|
|
string path = $"{folder}/{name}.png";
|
||
|
|
Texture2D texture = new Texture2D(64, 64, TextureFormat.RGBA32, false);
|
||
|
|
Color dark = Color.Lerp(Color.black, color, 0.3f);
|
||
|
|
for (int y = 0; y < 64; y++)
|
||
|
|
{
|
||
|
|
for (int x = 0; x < 64; x++)
|
||
|
|
{
|
||
|
|
Vector2 p = new Vector2(x - 31.5f, y - 31.5f);
|
||
|
|
float t = Mathf.Clamp01(1f - p.magnitude / 38f);
|
||
|
|
Color pixel = Color.Lerp(dark, color, t);
|
||
|
|
if (Mathf.Abs(p.x) < 4f || Mathf.Abs(p.y) < 4f)
|
||
|
|
{
|
||
|
|
pixel = Color.Lerp(pixel, Color.white, 0.3f);
|
||
|
|
}
|
||
|
|
|
||
|
|
texture.SetPixel(x, y, pixel);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
texture.Apply();
|
||
|
|
File.WriteAllBytes(path, texture.EncodeToPNG());
|
||
|
|
Object.DestroyImmediate(texture);
|
||
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
||
|
|
TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
|
||
|
|
if (importer != null)
|
||
|
|
{
|
||
|
|
importer.textureType = TextureImporterType.Sprite;
|
||
|
|
importer.mipmapEnabled = false;
|
||
|
|
importer.spritePixelsPerUnit = 64f;
|
||
|
|
importer.SaveAndReimport();
|
||
|
|
}
|
||
|
|
|
||
|
|
return AssetDatabase.LoadAssetAtPath<Sprite>(path);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateFireballPrefab()
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("PF_FireballEffect");
|
||
|
|
SphereCollider collider = root.AddComponent<SphereCollider>();
|
||
|
|
collider.radius = 0.35f;
|
||
|
|
collider.isTrigger = true;
|
||
|
|
root.AddComponent<FireballEffect>();
|
||
|
|
GameObject visual = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||
|
|
visual.name = "Visual";
|
||
|
|
visual.transform.SetParent(root.transform, false);
|
||
|
|
visual.transform.localScale = Vector3.one * 0.65f;
|
||
|
|
Object.DestroyImmediate(visual.GetComponent<Collider>());
|
||
|
|
visual.GetComponent<Renderer>().sharedMaterial = materials["Fire"];
|
||
|
|
return SavePrefab(root, "Assets/_Prefabs/Effects/PF_FireballEffect.prefab");
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateHealPrefab()
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("PF_HealEffect");
|
||
|
|
root.AddComponent<HealEffect>();
|
||
|
|
return SavePrefab(root, "Assets/_Prefabs/Effects/PF_HealEffect.prefab");
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreateBlinkPrefab()
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("PF_BlinkEffect");
|
||
|
|
root.AddComponent<BlinkEffect>();
|
||
|
|
return SavePrefab(root, "Assets/_Prefabs/Effects/PF_BlinkEffect.prefab");
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject SavePrefab(GameObject root, string path)
|
||
|
|
{
|
||
|
|
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
|
||
|
|
Object.DestroyImmediate(root);
|
||
|
|
return prefab;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateLighting()
|
||
|
|
{
|
||
|
|
RenderSettings.ambientLight = new Color(0.55f, 0.58f, 0.62f, 1f);
|
||
|
|
GameObject lightObject = new GameObject("Directional Light");
|
||
|
|
Light light = lightObject.AddComponent<Light>();
|
||
|
|
light.type = LightType.Directional;
|
||
|
|
light.intensity = 1.05f;
|
||
|
|
lightObject.transform.rotation = Quaternion.Euler(50f, -35f, 0f);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateGroundAndZones()
|
||
|
|
{
|
||
|
|
GameObject ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||
|
|
ground.name = "Integrated RPG Village Ground";
|
||
|
|
ground.transform.localScale = new Vector3(8.5f, 1f, 8.5f);
|
||
|
|
ground.GetComponent<Renderer>().sharedMaterial = materials["Ground"];
|
||
|
|
|
||
|
|
CreateZoneMarker("Central Village", new Vector3(0f, 0.03f, 0f), new Vector3(20f, 0.04f, 20f), materials["Village"]);
|
||
|
|
CreateZoneMarker("Forest", new Vector3(-28f, 0.04f, 18f), new Vector3(24f, 0.04f, 24f), materials["Leaves"]);
|
||
|
|
CreateZoneMarker("Quarry", new Vector3(28f, 0.04f, 18f), new Vector3(24f, 0.04f, 24f), materials["Stone"]);
|
||
|
|
CreateZoneMarker("Goblin Camp", new Vector3(27f, 0.04f, -27f), new Vector3(24f, 0.04f, 24f), materials["Camp"]);
|
||
|
|
CreateZoneMarker("Magic Circle", new Vector3(-28f, 0.04f, -26f), new Vector3(24f, 0.04f, 24f), materials["Mana"]);
|
||
|
|
|
||
|
|
CreateSign("Forest", new Vector3(-11f, 0.1f, 8f));
|
||
|
|
CreateSign("Quarry", new Vector3(11f, 0.1f, 8f));
|
||
|
|
CreateSign("Goblin Camp", new Vector3(14f, 0.1f, -10f));
|
||
|
|
CreateSign("Magic Circle", new Vector3(-14f, 0.1f, -10f));
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateZoneMarker(string name, Vector3 position, Vector3 scale, Material material)
|
||
|
|
{
|
||
|
|
GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||
|
|
marker.name = name + " Zone Tint";
|
||
|
|
marker.transform.position = position;
|
||
|
|
marker.transform.localScale = scale;
|
||
|
|
marker.GetComponent<Renderer>().sharedMaterial = material;
|
||
|
|
Object.DestroyImmediate(marker.GetComponent<Collider>());
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Camera CreateCamera()
|
||
|
|
{
|
||
|
|
GameObject cameraObject = new GameObject("Main Camera");
|
||
|
|
Camera camera = cameraObject.AddComponent<Camera>();
|
||
|
|
camera.tag = "MainCamera";
|
||
|
|
camera.fieldOfView = 48f;
|
||
|
|
camera.transform.position = new Vector3(0f, 14f, -14f);
|
||
|
|
camera.transform.rotation = Quaternion.Euler(55f, 0f, 0f);
|
||
|
|
return camera;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static PlayerBundle CreatePlayer(Camera camera, DataSet data)
|
||
|
|
{
|
||
|
|
PlayerBundle bundle = new PlayerBundle();
|
||
|
|
GameObject player = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
|
|
player.name = "Player";
|
||
|
|
player.tag = "Player";
|
||
|
|
player.transform.position = new Vector3(0f, 1f, -2f);
|
||
|
|
player.GetComponent<Renderer>().sharedMaterial = materials["Player"];
|
||
|
|
|
||
|
|
CharacterController characterController = player.AddComponent<CharacterController>();
|
||
|
|
characterController.height = 2f;
|
||
|
|
characterController.radius = 0.42f;
|
||
|
|
characterController.center = Vector3.zero;
|
||
|
|
Object.DestroyImmediate(player.GetComponent<CapsuleCollider>());
|
||
|
|
|
||
|
|
bundle.root = player;
|
||
|
|
bundle.stats = player.AddComponent<PlayerStats>();
|
||
|
|
bundle.inventory = player.AddComponent<PlayerInventory>();
|
||
|
|
bundle.levelSystem = player.AddComponent<LevelSystem>();
|
||
|
|
bundle.weaponController = null;
|
||
|
|
WeaponController weaponController = player.AddComponent<WeaponController>();
|
||
|
|
bundle.weaponManager = player.AddComponent<WeaponManager>();
|
||
|
|
bundle.abilityManager = player.AddComponent<AbilityManager>();
|
||
|
|
bundle.talentManager = player.AddComponent<TalentManager>();
|
||
|
|
bundle.controller = player.AddComponent<PlayerController>();
|
||
|
|
bundle.interaction = player.AddComponent<PlayerInteraction>();
|
||
|
|
|
||
|
|
GameObject attackOrigin = new GameObject("AttackOrigin");
|
||
|
|
attackOrigin.transform.SetParent(player.transform, false);
|
||
|
|
attackOrigin.transform.localPosition = new Vector3(0f, 0.6f, 0.85f);
|
||
|
|
weaponController.attackOrigin = attackOrigin.transform;
|
||
|
|
bundle.weaponController = weaponController;
|
||
|
|
|
||
|
|
GameObject castOrigin = new GameObject("CastOrigin");
|
||
|
|
castOrigin.transform.SetParent(player.transform, false);
|
||
|
|
castOrigin.transform.localPosition = new Vector3(0f, 1.25f, 0.75f);
|
||
|
|
bundle.abilityManager.castOrigin = castOrigin.transform;
|
||
|
|
bundle.abilityManager.learnedAbilities = new List<AbilityData> { data.fireball, data.heal, data.blink };
|
||
|
|
|
||
|
|
GameObject cameraRoot = new GameObject("PlayerCameraRoot");
|
||
|
|
bundle.controller.cameraRoot = cameraRoot.transform;
|
||
|
|
bundle.controller.playerCamera = camera;
|
||
|
|
|
||
|
|
bundle.weaponManager.weaponController = weaponController;
|
||
|
|
bundle.weaponManager.startingWeapon = data.basicSwordWeapon;
|
||
|
|
bundle.weaponManager.availableWeapons = new List<WeaponData> { data.basicSwordWeapon, data.ironAxeWeapon };
|
||
|
|
bundle.weaponManager.itemUnlocks = new List<WeaponUnlock>
|
||
|
|
{
|
||
|
|
new WeaponUnlock { item = data.ironAxeItem, weapon = data.ironAxeWeapon }
|
||
|
|
};
|
||
|
|
|
||
|
|
bundle.talentManager.allTalents = new List<TalentData>
|
||
|
|
{
|
||
|
|
data.toughness, data.strength, data.agility, data.arcaneFlow, data.advancedStrength
|
||
|
|
};
|
||
|
|
bundle.talentManager.availableTalentPoints = 0;
|
||
|
|
|
||
|
|
return bundle;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static CraftingSystem CreateVillage(DataSet data)
|
||
|
|
{
|
||
|
|
CreateNpc("NPC_Starosta", "Elder", "Староста", data.elderDialogue, data.questGatherWood, data.questGatherWood, false, new Vector3(-3f, 1f, 3f), materials["Elder"]);
|
||
|
|
CreateNpc("NPC_Guard", "Guard", "Стражник", data.guardDialogue, data.questKillGoblins, data.questKillGoblins, false, new Vector3(3f, 1f, 3f), materials["Guard"]);
|
||
|
|
CreateNpc("NPC_Blacksmith", "Blacksmith", "Кузнец", data.blacksmithDialogue, data.questCraftAxe, data.questCraftAxe, true, new Vector3(6f, 1f, -2f), materials["Blacksmith"]);
|
||
|
|
CreateNpc("NPC_Mage", "Mage", "Маг", data.mageDialogue, null, null, false, new Vector3(-6f, 1f, -2f), materials["Mage"]);
|
||
|
|
|
||
|
|
CreateBuilding("Elder House", new Vector3(-6f, 1f, 7f), new Vector3(4f, 2f, 3f));
|
||
|
|
CreateBuilding("Guard Tower", new Vector3(6f, 1.4f, 7f), new Vector3(2.8f, 2.8f, 2.8f));
|
||
|
|
CreateBuilding("Blacksmith Shed", new Vector3(9f, 1f, -5f), new Vector3(4f, 2f, 3f));
|
||
|
|
|
||
|
|
GameObject workbench = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||
|
|
workbench.name = "Workbench";
|
||
|
|
workbench.transform.position = new Vector3(7f, 0.55f, -4f);
|
||
|
|
workbench.transform.localScale = new Vector3(2.2f, 0.7f, 1.1f);
|
||
|
|
workbench.GetComponent<Renderer>().sharedMaterial = materials["Workbench"];
|
||
|
|
CraftingSystem crafting = workbench.AddComponent<CraftingSystem>();
|
||
|
|
crafting.availableRecipes = new List<RecipeData> { data.recipeIronAxe, data.recipeHealthPotion, data.recipeManaPotion };
|
||
|
|
return crafting;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateNpc(string objectName, string npcId, string displayName, DialogueNode dialogue, QuestData offered, QuestData completion, bool crafting, Vector3 position, Material material)
|
||
|
|
{
|
||
|
|
GameObject npc = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
|
|
npc.name = objectName;
|
||
|
|
npc.transform.position = position;
|
||
|
|
npc.GetComponent<Renderer>().sharedMaterial = material;
|
||
|
|
NPCInteract interact = npc.AddComponent<NPCInteract>();
|
||
|
|
interact.npcId = npcId;
|
||
|
|
interact.displayName = displayName;
|
||
|
|
interact.startNode = dialogue;
|
||
|
|
interact.offeredQuest = offered;
|
||
|
|
interact.completionQuest = completion;
|
||
|
|
interact.canOpenCrafting = crafting;
|
||
|
|
CreateNameplate(npc.transform, displayName, new Color(1f, 0.84f, 0.35f, 1f));
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateBuilding(string name, Vector3 position, Vector3 scale)
|
||
|
|
{
|
||
|
|
GameObject building = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||
|
|
building.name = name;
|
||
|
|
building.transform.position = position;
|
||
|
|
building.transform.localScale = scale;
|
||
|
|
building.GetComponent<Renderer>().sharedMaterial = materials["Village"];
|
||
|
|
}
|
||
|
|
|
||
|
|
private static QuestManager CreateQuestManager(DataSet data)
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("QuestManager");
|
||
|
|
QuestManager manager = root.AddComponent<QuestManager>();
|
||
|
|
manager.allQuests = new List<QuestData> { data.questGatherWood, data.questKillGoblins, data.questCraftAxe };
|
||
|
|
return manager;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DialogueManager CreateDialogueManager()
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("DialogueManager");
|
||
|
|
return root.AddComponent<DialogueManager>();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static SaveSystem CreateSaveSystem(DataSet data)
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("SaveSystem");
|
||
|
|
SaveSystem saveSystem = root.AddComponent<SaveSystem>();
|
||
|
|
saveSystem.itemCatalog = data.allItems;
|
||
|
|
return saveSystem;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateResources(DataSet data)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < 7; i++)
|
||
|
|
{
|
||
|
|
Vector3 pos = new Vector3(-34f + i * 2.5f, 0.55f, 15f + (i % 3) * 3f);
|
||
|
|
CreateResource("Wood_Node_" + i, PrimitiveType.Cylinder, pos, new Vector3(0.8f, 0.7f, 0.8f), materials["Wood"], data.wood);
|
||
|
|
CreateTree(new Vector3(pos.x + 1.2f, 0f, pos.z + 1.4f));
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++)
|
||
|
|
{
|
||
|
|
CreateResource("Stone_Node_" + i, PrimitiveType.Sphere, new Vector3(24f + i * 2.4f, 0.55f, 17f + (i % 2) * 3f), Vector3.one * 1.1f, materials["Stone"], data.stone);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 4; i++)
|
||
|
|
{
|
||
|
|
CreateResource("IronOre_Node_" + i, PrimitiveType.Cube, new Vector3(29f + i * 2.2f, 0.55f, 25f), Vector3.one * 1f, materials["Iron"], data.ironOre);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++)
|
||
|
|
{
|
||
|
|
CreateResource("Herb_Node_" + i, PrimitiveType.Capsule, new Vector3(-35f + i * 3f, 0.45f, 28f), new Vector3(0.45f, 0.45f, 0.45f), materials["Herb"], data.herb);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++)
|
||
|
|
{
|
||
|
|
CreateResource("Crystal_Node_" + i, PrimitiveType.Cylinder, new Vector3(-34f + i * 3f, 0.75f, -29f), new Vector3(0.6f, 1.2f, 0.6f), materials["Crystal"], data.crystal);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 9; i++)
|
||
|
|
{
|
||
|
|
CreatePrimitive("Quarry Rock " + i, PrimitiveType.Cube, new Vector3(22f + (i % 3) * 4f, 0.5f, 21f + (i / 3) * 3f), new Vector3(2f, 1f, 1.4f), materials["Stone"]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateResource(string name, PrimitiveType primitive, Vector3 position, Vector3 scale, Material material, ItemData item)
|
||
|
|
{
|
||
|
|
GameObject resource = GameObject.CreatePrimitive(primitive);
|
||
|
|
resource.name = name;
|
||
|
|
resource.transform.position = position;
|
||
|
|
resource.transform.localScale = scale;
|
||
|
|
resource.GetComponent<Renderer>().sharedMaterial = material;
|
||
|
|
ResourceNode node = resource.AddComponent<ResourceNode>();
|
||
|
|
node.itemData = item;
|
||
|
|
node.amount = 1;
|
||
|
|
node.respawnCooldown = 0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateGoblinCamp(DataSet data)
|
||
|
|
{
|
||
|
|
Vector3[] positions =
|
||
|
|
{
|
||
|
|
new Vector3(22f, 1f, -24f),
|
||
|
|
new Vector3(28f, 1f, -23f),
|
||
|
|
new Vector3(33f, 1f, -28f),
|
||
|
|
new Vector3(24f, 1f, -32f),
|
||
|
|
new Vector3(31f, 1f, -34f)
|
||
|
|
};
|
||
|
|
|
||
|
|
for (int i = 0; i < positions.Length; i++)
|
||
|
|
{
|
||
|
|
GameObject goblin = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
|
|
goblin.name = "Goblin_" + (i + 1);
|
||
|
|
goblin.transform.position = positions[i];
|
||
|
|
goblin.GetComponent<Renderer>().sharedMaterial = materials["Goblin"];
|
||
|
|
Enemy enemy = goblin.AddComponent<Enemy>();
|
||
|
|
enemy.enemyId = "Goblin";
|
||
|
|
enemy.displayName = "Goblin";
|
||
|
|
enemy.maxHealth = 50f;
|
||
|
|
enemy.damage = 5f;
|
||
|
|
enemy.expReward = 20;
|
||
|
|
enemy.dropItems = new List<EnemyDrop> { new EnemyDrop { item = data.goblinFang, amount = 1 } };
|
||
|
|
CreateNameplate(goblin.transform, "Goblin", new Color(1f, 0.25f, 0.22f, 1f));
|
||
|
|
}
|
||
|
|
|
||
|
|
CreatePrimitive("Campfire", PrimitiveType.Cylinder, new Vector3(28f, 0.25f, -29f), new Vector3(1.2f, 0.3f, 1.2f), materials["Fire"]);
|
||
|
|
for (int i = 0; i < 6; i++)
|
||
|
|
{
|
||
|
|
CreatePrimitive("Camp Crate " + i, PrimitiveType.Cube, new Vector3(20f + i * 2.4f, 0.45f, -36f), Vector3.one * 0.9f, materials["Wood"]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateMagicCircle()
|
||
|
|
{
|
||
|
|
GameObject circle = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
||
|
|
circle.name = "Magic Circle";
|
||
|
|
circle.transform.position = new Vector3(-28f, 0.08f, -26f);
|
||
|
|
circle.transform.localScale = new Vector3(5.5f, 0.08f, 5.5f);
|
||
|
|
circle.GetComponent<Renderer>().sharedMaterial = materials["Mana"];
|
||
|
|
Object.DestroyImmediate(circle.GetComponent<Collider>());
|
||
|
|
|
||
|
|
for (int i = 0; i < 6; i++)
|
||
|
|
{
|
||
|
|
float angle = i * Mathf.PI * 2f / 6f;
|
||
|
|
Vector3 pos = new Vector3(-28f + Mathf.Cos(angle) * 5f, 0.75f, -26f + Mathf.Sin(angle) * 5f);
|
||
|
|
CreatePrimitive("Mana Crystal " + i, PrimitiveType.Cylinder, pos, new Vector3(0.5f, 1.3f, 0.5f), materials["Crystal"]);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < 3; i++)
|
||
|
|
{
|
||
|
|
GameObject dummy = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
||
|
|
dummy.name = "Training Dummy " + (i + 1);
|
||
|
|
dummy.transform.position = new Vector3(-34f + i * 5f, 1f, -19f);
|
||
|
|
dummy.GetComponent<Renderer>().sharedMaterial = materials["Wood"];
|
||
|
|
Damageable damageable = dummy.AddComponent<Damageable>();
|
||
|
|
damageable.displayName = "Training Dummy";
|
||
|
|
damageable.maxHealth = 100f;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static UIManager CreateUI(PlayerBundle player, QuestManager questManager, CraftingSystem craftingSystem, DialogueManager dialogueManager, SaveSystem saveSystem)
|
||
|
|
{
|
||
|
|
GameObject canvasObject = new GameObject("HUDCanvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
|
||
|
|
Canvas canvas = canvasObject.GetComponent<Canvas>();
|
||
|
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||
|
|
CanvasScaler scaler = canvasObject.GetComponent<CanvasScaler>();
|
||
|
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||
|
|
scaler.referenceResolution = new Vector2(1920f, 1080f);
|
||
|
|
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
|
||
|
|
scaler.matchWidthOrHeight = 0.5f;
|
||
|
|
|
||
|
|
EnsureEventSystem();
|
||
|
|
|
||
|
|
UIManager uiManager = canvasObject.AddComponent<UIManager>();
|
||
|
|
NotificationUI notificationUI = CreateNotificationStack(canvasObject.transform);
|
||
|
|
InteractionPromptUI promptUI = CreateInteractionPrompt(canvasObject.transform);
|
||
|
|
player.interaction.promptUI = promptUI;
|
||
|
|
|
||
|
|
HUDController hud = CreateHud(canvasObject.transform);
|
||
|
|
InventoryUI inventoryUI = CreateInventoryPanel(canvasObject.transform, out GameObject inventoryPanel);
|
||
|
|
CraftingUI craftingUI = CreateCraftingPanel(canvasObject.transform, out GameObject craftingPanel);
|
||
|
|
QuestLogUI questLogUI = CreateQuestLogPanel(canvasObject.transform, out GameObject questPanel);
|
||
|
|
TalentTreeUI talentTreeUI = CreateTalentTreePanel(canvasObject.transform, out GameObject talentPanel);
|
||
|
|
DialogueUI dialogueUI = CreateDialoguePanel(canvasObject.transform, out GameObject dialoguePanel);
|
||
|
|
GameObject pausePanel = CreatePausePanel(canvasObject.transform, out Button resume, out Button saveButton, out Button loadButton, out Button resetButton);
|
||
|
|
|
||
|
|
uiManager.inventoryPanel = inventoryPanel;
|
||
|
|
uiManager.craftingPanel = craftingPanel;
|
||
|
|
uiManager.questLogPanel = questPanel;
|
||
|
|
uiManager.talentTreePanel = talentPanel;
|
||
|
|
uiManager.dialoguePanel = dialoguePanel;
|
||
|
|
uiManager.pausePanel = pausePanel;
|
||
|
|
uiManager.inventoryUI = inventoryUI;
|
||
|
|
uiManager.craftingUI = craftingUI;
|
||
|
|
uiManager.questLogUI = questLogUI;
|
||
|
|
uiManager.talentTreeUI = talentTreeUI;
|
||
|
|
uiManager.hudController = hud;
|
||
|
|
uiManager.resumeButton = resume;
|
||
|
|
uiManager.saveButton = saveButton;
|
||
|
|
uiManager.loadButton = loadButton;
|
||
|
|
uiManager.resetSaveButton = resetButton;
|
||
|
|
|
||
|
|
dialogueManager.dialogueUI = dialogueUI;
|
||
|
|
inventoryPanel.SetActive(false);
|
||
|
|
craftingPanel.SetActive(false);
|
||
|
|
questPanel.SetActive(false);
|
||
|
|
talentPanel.SetActive(false);
|
||
|
|
dialoguePanel.SetActive(false);
|
||
|
|
pausePanel.SetActive(false);
|
||
|
|
return uiManager;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static HUDController CreateHud(Transform canvas)
|
||
|
|
{
|
||
|
|
GameObject hudObject = new GameObject("HUDController");
|
||
|
|
hudObject.transform.SetParent(canvas, false);
|
||
|
|
HUDController hud = hudObject.AddComponent<HUDController>();
|
||
|
|
|
||
|
|
GameObject status = CreatePanel(canvas, "Player Status Panel", new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(24f, 24f), new Vector2(320f, 130f), UITheme.Panel);
|
||
|
|
hud.hpFill = CreateBar(status.transform, "HP", new Vector2(18f, 78f), new Color(0.8f, 0.15f, 0.14f, 1f), out hud.hpText);
|
||
|
|
hud.manaFill = CreateBar(status.transform, "Mana", new Vector2(18f, 44f), new Color(0.15f, 0.35f, 0.88f, 1f), out hud.manaText);
|
||
|
|
hud.expFill = CreateBar(status.transform, "EXP", new Vector2(18f, 10f), new Color(0.86f, 0.58f, 0.24f, 1f), out hud.expText);
|
||
|
|
hud.levelText = CreateText(status.transform, "LevelText", "Level 1", 16, TextAnchor.MiddleLeft, new Vector2(18f, 104f), new Vector2(130f, 22f), boldFont);
|
||
|
|
|
||
|
|
GameObject tracker = CreatePanel(canvas, "Quest Tracker", new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(24f, -24f), new Vector2(420f, 140f), UITheme.Panel);
|
||
|
|
hud.questTitleText = CreateText(tracker.transform, "QuestTitle", "Активная цель", 20, TextAnchor.UpperLeft, new Vector2(18f, -14f), new Vector2(380f, 28f), boldFont);
|
||
|
|
hud.questBodyText = CreateText(tracker.transform, "QuestBody", "Нет активных квестов", 16, TextAnchor.UpperLeft, new Vector2(18f, -48f), new Vector2(380f, 82f), regularFont);
|
||
|
|
|
||
|
|
GameObject abilityBar = CreatePanel(canvas, "Ability Bar", new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 24f), new Vector2(340f, 95f), UITheme.Panel);
|
||
|
|
hud.abilitySlots = new AbilityHudSlot[3];
|
||
|
|
for (int i = 0; i < 3; i++)
|
||
|
|
{
|
||
|
|
hud.abilitySlots[i] = CreateAbilitySlot(abilityBar.transform, i, new Vector2(-108f + i * 108f, 8f));
|
||
|
|
}
|
||
|
|
|
||
|
|
GameObject weaponPanel = CreatePanel(canvas, "Weapon Panel", new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-24f, 24f), new Vector2(260f, 90f), UITheme.Panel);
|
||
|
|
hud.weaponNameText = CreateText(weaponPanel.transform, "WeaponName", "Weapon: -", 16, TextAnchor.UpperLeft, new Vector2(16f, -12f), new Vector2(230f, 24f), boldFont);
|
||
|
|
hud.weaponDamageText = CreateText(weaponPanel.transform, "WeaponDamage", "Damage: -", 16, TextAnchor.UpperLeft, new Vector2(16f, -38f), new Vector2(230f, 22f), regularFont);
|
||
|
|
hud.weaponHintText = CreateText(weaponPanel.transform, "WeaponHint", "LMB — Attack", 14, TextAnchor.UpperLeft, new Vector2(16f, -62f), new Vector2(230f, 20f), regularFont);
|
||
|
|
|
||
|
|
return hud;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Image CreateBar(Transform parent, string name, Vector2 anchored, Color fillColor, out Text valueText)
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject(name + "Bar", typeof(RectTransform), typeof(Image));
|
||
|
|
root.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = root.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = new Vector2(0f, 0f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 0f);
|
||
|
|
rect.pivot = new Vector2(0f, 0f);
|
||
|
|
rect.anchoredPosition = anchored;
|
||
|
|
rect.sizeDelta = new Vector2(284f, 22f);
|
||
|
|
root.GetComponent<Image>().color = new Color(0.03f, 0.035f, 0.045f, 0.9f);
|
||
|
|
|
||
|
|
GameObject fillObject = new GameObject("Fill", typeof(RectTransform), typeof(Image));
|
||
|
|
fillObject.transform.SetParent(root.transform, false);
|
||
|
|
RectTransform fillRect = fillObject.GetComponent<RectTransform>();
|
||
|
|
fillRect.anchorMin = Vector2.zero;
|
||
|
|
fillRect.anchorMax = Vector2.one;
|
||
|
|
fillRect.offsetMin = Vector2.zero;
|
||
|
|
fillRect.offsetMax = Vector2.zero;
|
||
|
|
Image fill = fillObject.GetComponent<Image>();
|
||
|
|
fill.color = fillColor;
|
||
|
|
fill.type = Image.Type.Filled;
|
||
|
|
fill.fillMethod = Image.FillMethod.Horizontal;
|
||
|
|
fill.fillOrigin = 0;
|
||
|
|
fill.fillAmount = 1f;
|
||
|
|
|
||
|
|
valueText = CreateText(root.transform, name + "Text", name, 14, TextAnchor.MiddleCenter, Vector2.zero, new Vector2(284f, 22f), regularFont);
|
||
|
|
valueText.rectTransform.anchorMin = Vector2.zero;
|
||
|
|
valueText.rectTransform.anchorMax = Vector2.one;
|
||
|
|
valueText.rectTransform.offsetMin = Vector2.zero;
|
||
|
|
valueText.rectTransform.offsetMax = Vector2.zero;
|
||
|
|
return fill;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static AbilityHudSlot CreateAbilitySlot(Transform parent, int index, Vector2 anchored)
|
||
|
|
{
|
||
|
|
GameObject root = CreatePanel(parent, "AbilitySlot_" + (index + 1), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), anchored, new Vector2(82f, 78f), new Color(0.08f, 0.09f, 0.12f, 0.92f));
|
||
|
|
AbilityHudSlot slot = new AbilityHudSlot();
|
||
|
|
slot.iconImage = root.GetComponent<Image>();
|
||
|
|
slot.keyText = CreateText(root.transform, "Key", (index + 1).ToString(), 14, TextAnchor.UpperLeft, new Vector2(7f, -4f), new Vector2(24f, 22f), boldFont);
|
||
|
|
slot.nameText = CreateText(root.transform, "Name", "-", 13, TextAnchor.LowerCenter, new Vector2(0f, 2f), new Vector2(78f, 22f), regularFont);
|
||
|
|
slot.manaText = CreateText(root.transform, "Mana", "-", 13, TextAnchor.UpperRight, new Vector2(-7f, -4f), new Vector2(34f, 22f), regularFont);
|
||
|
|
GameObject overlayObject = new GameObject("CooldownOverlay", typeof(RectTransform), typeof(Image));
|
||
|
|
overlayObject.transform.SetParent(root.transform, false);
|
||
|
|
RectTransform overlayRect = overlayObject.GetComponent<RectTransform>();
|
||
|
|
overlayRect.anchorMin = Vector2.zero;
|
||
|
|
overlayRect.anchorMax = Vector2.one;
|
||
|
|
overlayRect.offsetMin = Vector2.zero;
|
||
|
|
overlayRect.offsetMax = Vector2.zero;
|
||
|
|
slot.cooldownOverlay = overlayObject.GetComponent<Image>();
|
||
|
|
slot.cooldownOverlay.color = new Color(0f, 0f, 0f, 0.58f);
|
||
|
|
slot.cooldownOverlay.type = Image.Type.Filled;
|
||
|
|
slot.cooldownOverlay.fillMethod = Image.FillMethod.Radial360;
|
||
|
|
slot.cooldownOverlay.fillAmount = 0f;
|
||
|
|
slot.cooldownText = CreateText(root.transform, "CooldownText", string.Empty, 18, TextAnchor.MiddleCenter, Vector2.zero, new Vector2(82f, 78f), boldFont);
|
||
|
|
slot.cooldownText.rectTransform.anchorMin = Vector2.zero;
|
||
|
|
slot.cooldownText.rectTransform.anchorMax = Vector2.one;
|
||
|
|
slot.cooldownText.rectTransform.offsetMin = Vector2.zero;
|
||
|
|
slot.cooldownText.rectTransform.offsetMax = Vector2.zero;
|
||
|
|
return slot;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static NotificationUI CreateNotificationStack(Transform canvas)
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("Notification Stack", typeof(RectTransform), typeof(VerticalLayoutGroup));
|
||
|
|
root.transform.SetParent(canvas, false);
|
||
|
|
RectTransform rect = root.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = new Vector2(0.5f, 1f);
|
||
|
|
rect.anchorMax = new Vector2(0.5f, 1f);
|
||
|
|
rect.pivot = new Vector2(0.5f, 1f);
|
||
|
|
rect.anchoredPosition = new Vector2(0f, -28f);
|
||
|
|
rect.sizeDelta = new Vector2(540f, 260f);
|
||
|
|
VerticalLayoutGroup layout = root.GetComponent<VerticalLayoutGroup>();
|
||
|
|
layout.spacing = 8f;
|
||
|
|
layout.childAlignment = TextAnchor.UpperCenter;
|
||
|
|
layout.childControlWidth = false;
|
||
|
|
layout.childControlHeight = false;
|
||
|
|
NotificationUI notificationUI = root.AddComponent<NotificationUI>();
|
||
|
|
notificationUI.stackRoot = rect;
|
||
|
|
notificationUI.uiFont = regularFont;
|
||
|
|
return notificationUI;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static InteractionPromptUI CreateInteractionPrompt(Transform canvas)
|
||
|
|
{
|
||
|
|
GameObject root = CreatePanel(canvas, "Interaction Prompt", new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 136f), new Vector2(520f, 42f), new Color(0.03f, 0.04f, 0.06f, 0.86f));
|
||
|
|
Text text = CreateText(root.transform, "PromptText", "E — взаимодействие", 17, TextAnchor.MiddleCenter, Vector2.zero, new Vector2(520f, 42f), boldFont);
|
||
|
|
text.rectTransform.anchorMin = Vector2.zero;
|
||
|
|
text.rectTransform.anchorMax = Vector2.one;
|
||
|
|
text.rectTransform.offsetMin = Vector2.zero;
|
||
|
|
text.rectTransform.offsetMax = Vector2.zero;
|
||
|
|
InteractionPromptUI prompt = root.AddComponent<InteractionPromptUI>();
|
||
|
|
prompt.root = root;
|
||
|
|
prompt.promptText = text;
|
||
|
|
root.SetActive(false);
|
||
|
|
return prompt;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static InventoryUI CreateInventoryPanel(Transform canvas, out GameObject panel)
|
||
|
|
{
|
||
|
|
panel = CreatePanel(canvas, "InventoryPanel", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(900f, 620f), UITheme.Panel);
|
||
|
|
InventoryUI ui = panel.AddComponent<InventoryUI>();
|
||
|
|
ui.panelRoot = panel;
|
||
|
|
ui.uiFont = regularFont;
|
||
|
|
ui.titleText = CreateText(panel.transform, "Title", "Инвентарь", 30, TextAnchor.UpperLeft, new Vector2(28f, -22f), new Vector2(280f, 42f), boldFont);
|
||
|
|
GameObject grid = new GameObject("SlotGrid", typeof(RectTransform), typeof(GridLayoutGroup));
|
||
|
|
grid.transform.SetParent(panel.transform, false);
|
||
|
|
RectTransform gridRect = grid.GetComponent<RectTransform>();
|
||
|
|
gridRect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
gridRect.anchorMax = new Vector2(0f, 1f);
|
||
|
|
gridRect.pivot = new Vector2(0f, 1f);
|
||
|
|
gridRect.anchoredPosition = new Vector2(30f, -92f);
|
||
|
|
gridRect.sizeDelta = new Vector2(500f, 390f);
|
||
|
|
GridLayoutGroup layout = grid.GetComponent<GridLayoutGroup>();
|
||
|
|
layout.cellSize = new Vector2(90f, 90f);
|
||
|
|
layout.spacing = new Vector2(10f, 10f);
|
||
|
|
layout.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
||
|
|
layout.constraintCount = 5;
|
||
|
|
ui.slotGrid = grid.transform;
|
||
|
|
ui.descriptionText = CreateText(panel.transform, "Description", "Выберите предмет.", 17, TextAnchor.UpperLeft, new Vector2(560f, -96f), new Vector2(300f, 360f), regularFont);
|
||
|
|
ui.hintText = CreateText(panel.transform, "Hint", "I — закрыть", 15, TextAnchor.LowerLeft, new Vector2(30f, 22f), new Vector2(500f, 28f), regularFont);
|
||
|
|
ui.closeButton = CreateButton(panel.transform, "CloseButton", "Закрыть", new Vector2(760f, -560f), new Vector2(110f, 38f));
|
||
|
|
return ui;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static CraftingUI CreateCraftingPanel(Transform canvas, out GameObject panel)
|
||
|
|
{
|
||
|
|
panel = CreatePanel(canvas, "CraftingPanel", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(1050f, 650f), UITheme.Panel);
|
||
|
|
CraftingUI ui = panel.AddComponent<CraftingUI>();
|
||
|
|
ui.panelRoot = panel;
|
||
|
|
ui.uiFont = regularFont;
|
||
|
|
CreateText(panel.transform, "Title", "Крафт", 30, TextAnchor.UpperLeft, new Vector2(28f, -22f), new Vector2(280f, 42f), boldFont);
|
||
|
|
ui.recipeListRoot = CreateVerticalList(panel.transform, "RecipeList", new Vector2(30f, -88f), new Vector2(320f, 470f));
|
||
|
|
ui.ingredientsText = CreateText(panel.transform, "Ingredients", "Ингредиенты", 18, TextAnchor.UpperLeft, new Vector2(390f, -90f), new Vector2(280f, 300f), regularFont);
|
||
|
|
ui.resultText = CreateText(panel.transform, "Result", "Результат", 20, TextAnchor.UpperLeft, new Vector2(720f, -90f), new Vector2(280f, 120f), boldFont);
|
||
|
|
ui.descriptionText = CreateText(panel.transform, "Description", string.Empty, 17, TextAnchor.UpperLeft, new Vector2(720f, -230f), new Vector2(280f, 180f), regularFont);
|
||
|
|
ui.messageText = CreateText(panel.transform, "Message", string.Empty, 16, TextAnchor.LowerLeft, new Vector2(390f, 42f), new Vector2(360f, 42f), regularFont);
|
||
|
|
ui.craftButton = CreateButton(panel.transform, "CraftButton", "Создать", new Vector2(822f, -555f), new Vector2(150f, 42f));
|
||
|
|
ui.closeButton = CreateButton(panel.transform, "CloseButton", "Закрыть", new Vector2(32f, -585f), new Vector2(120f, 38f));
|
||
|
|
return ui;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static QuestLogUI CreateQuestLogPanel(Transform canvas, out GameObject panel)
|
||
|
|
{
|
||
|
|
panel = CreatePanel(canvas, "QuestLogPanel", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(1050f, 650f), UITheme.Panel);
|
||
|
|
QuestLogUI ui = panel.AddComponent<QuestLogUI>();
|
||
|
|
ui.panelRoot = panel;
|
||
|
|
ui.uiFont = regularFont;
|
||
|
|
ui.titleText = CreateText(panel.transform, "Title", "Журнал квестов", 30, TextAnchor.UpperLeft, new Vector2(28f, -22f), new Vector2(360f, 42f), boldFont);
|
||
|
|
CreateText(panel.transform, "ActiveHeader", "Активные", 20, TextAnchor.UpperLeft, new Vector2(32f, -78f), new Vector2(180f, 30f), boldFont);
|
||
|
|
ui.activeListRoot = CreateVerticalList(panel.transform, "ActiveList", new Vector2(30f, -115f), new Vector2(340f, 230f));
|
||
|
|
CreateText(panel.transform, "CompletedHeader", "Завершённые", 20, TextAnchor.UpperLeft, new Vector2(32f, -365f), new Vector2(220f, 30f), boldFont);
|
||
|
|
ui.completedListRoot = CreateVerticalList(panel.transform, "CompletedList", new Vector2(30f, -402f), new Vector2(340f, 160f));
|
||
|
|
ui.detailText = CreateText(panel.transform, "Details", "Нет выбранного квеста.", 17, TextAnchor.UpperLeft, new Vector2(420f, -92f), new Vector2(570f, 480f), regularFont);
|
||
|
|
ui.closeButton = CreateButton(panel.transform, "CloseButton", "Закрыть", new Vector2(32f, -585f), new Vector2(120f, 38f));
|
||
|
|
return ui;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static TalentTreeUI CreateTalentTreePanel(Transform canvas, out GameObject panel)
|
||
|
|
{
|
||
|
|
panel = CreatePanel(canvas, "TalentTreePanel", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(1150f, 720f), UITheme.Panel);
|
||
|
|
TalentTreeUI ui = panel.AddComponent<TalentTreeUI>();
|
||
|
|
ui.panelRoot = panel;
|
||
|
|
ui.uiFont = regularFont;
|
||
|
|
ui.titleText = CreateText(panel.transform, "Title", "Дерево талантов", 30, TextAnchor.UpperLeft, new Vector2(28f, -22f), new Vector2(360f, 42f), boldFont);
|
||
|
|
ui.pointsText = CreateText(panel.transform, "Points", "Очки талантов: 0", 20, TextAnchor.UpperRight, new Vector2(760f, -24f), new Vector2(340f, 36f), boldFont);
|
||
|
|
GameObject lineRoot = new GameObject("LineRoot", typeof(RectTransform));
|
||
|
|
lineRoot.transform.SetParent(panel.transform, false);
|
||
|
|
ui.lineRoot = lineRoot.GetComponent<RectTransform>();
|
||
|
|
StretchRect(ui.lineRoot, new Vector2(40f, 80f), new Vector2(-340f, -110f));
|
||
|
|
GameObject nodesRoot = new GameObject("NodesRoot", typeof(RectTransform));
|
||
|
|
nodesRoot.transform.SetParent(panel.transform, false);
|
||
|
|
ui.nodesRoot = nodesRoot.GetComponent<RectTransform>();
|
||
|
|
StretchRect(ui.nodesRoot, new Vector2(40f, 80f), new Vector2(-340f, -110f));
|
||
|
|
ui.statsText = CreateText(panel.transform, "Stats", "Характеристики", 17, TextAnchor.UpperLeft, new Vector2(840f, -100f), new Vector2(270f, 360f), regularFont);
|
||
|
|
ui.saveButton = CreateButton(panel.transform, "SaveButton", "Save", new Vector2(50f, -660f), new Vector2(110f, 38f));
|
||
|
|
ui.loadButton = CreateButton(panel.transform, "LoadButton", "Load", new Vector2(180f, -660f), new Vector2(110f, 38f));
|
||
|
|
ui.resetButton = CreateButton(panel.transform, "ResetButton", "Reset", new Vector2(310f, -660f), new Vector2(110f, 38f));
|
||
|
|
ui.closeButton = CreateButton(panel.transform, "CloseButton", "Закрыть", new Vector2(980f, -660f), new Vector2(120f, 38f));
|
||
|
|
|
||
|
|
GameObject tooltipRoot = CreatePanel(panel.transform, "TalentTooltip", new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-28f, 34f), new Vector2(310f, 160f), new Color(0.03f, 0.04f, 0.055f, 0.96f));
|
||
|
|
Text tooltipText = CreateText(tooltipRoot.transform, "Text", string.Empty, 15, TextAnchor.UpperLeft, new Vector2(14f, -12f), new Vector2(282f, 136f), regularFont);
|
||
|
|
TalentTooltipUI tooltip = tooltipRoot.AddComponent<TalentTooltipUI>();
|
||
|
|
tooltip.panelRoot = tooltipRoot;
|
||
|
|
tooltip.contentText = tooltipText;
|
||
|
|
ui.tooltip = tooltip;
|
||
|
|
tooltipRoot.SetActive(false);
|
||
|
|
return ui;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DialogueUI CreateDialoguePanel(Transform canvas, out GameObject panel)
|
||
|
|
{
|
||
|
|
panel = CreatePanel(canvas, "DialoguePanel", new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 170f), new Vector2(1100f, 300f), new Color(0.04f, 0.05f, 0.07f, 0.94f));
|
||
|
|
DialogueUI ui = panel.AddComponent<DialogueUI>();
|
||
|
|
ui.panelRoot = panel;
|
||
|
|
ui.uiFont = regularFont;
|
||
|
|
ui.speakerText = CreateText(panel.transform, "Speaker", "NPC", 24, TextAnchor.UpperLeft, new Vector2(28f, -22f), new Vector2(360f, 36f), boldFont);
|
||
|
|
ui.lineText = CreateText(panel.transform, "Line", string.Empty, 20, TextAnchor.UpperLeft, new Vector2(28f, -68f), new Vector2(680f, 150f), regularFont);
|
||
|
|
ui.responseRoot = CreateVerticalList(panel.transform, "Responses", new Vector2(720f, -48f), new Vector2(340f, 210f));
|
||
|
|
ui.closeButton = CreateButton(panel.transform, "CloseButton", "Закрыть", new Vector2(962f, -250f), new Vector2(110f, 36f));
|
||
|
|
return ui;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreatePausePanel(Transform canvas, out Button resume, out Button save, out Button load, out Button reset)
|
||
|
|
{
|
||
|
|
GameObject panel = CreatePanel(canvas, "PausePanel", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(420f, 340f), UITheme.Panel);
|
||
|
|
CreateText(panel.transform, "Title", "Пауза", 30, TextAnchor.UpperCenter, new Vector2(0f, -24f), new Vector2(420f, 44f), boldFont).rectTransform.anchorMin = new Vector2(0f, 1f);
|
||
|
|
resume = CreateButton(panel.transform, "Resume", "Продолжить", new Vector2(100f, -92f), new Vector2(220f, 42f));
|
||
|
|
save = CreateButton(panel.transform, "Save", "Сохранить", new Vector2(100f, -146f), new Vector2(220f, 42f));
|
||
|
|
load = CreateButton(panel.transform, "Load", "Загрузить", new Vector2(100f, -200f), new Vector2(220f, 42f));
|
||
|
|
reset = CreateButton(panel.transform, "Reset", "Сбросить сохранение", new Vector2(100f, -254f), new Vector2(220f, 42f));
|
||
|
|
return panel;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameManager CreateGameManager(PlayerBundle player, QuestManager questManager, DialogueManager dialogueManager, CraftingSystem craftingSystem, UIManager uiManager, SaveSystem saveSystem)
|
||
|
|
{
|
||
|
|
GameObject root = new GameObject("GameManager");
|
||
|
|
GameManager manager = root.AddComponent<GameManager>();
|
||
|
|
manager.playerController = player.controller;
|
||
|
|
manager.playerStats = player.stats;
|
||
|
|
manager.inventory = player.inventory;
|
||
|
|
manager.levelSystem = player.levelSystem;
|
||
|
|
manager.weaponManager = player.weaponManager;
|
||
|
|
manager.abilityManager = player.abilityManager;
|
||
|
|
manager.talentManager = player.talentManager;
|
||
|
|
manager.questManager = questManager;
|
||
|
|
manager.dialogueManager = dialogueManager;
|
||
|
|
manager.craftingSystem = craftingSystem;
|
||
|
|
manager.uiManager = uiManager;
|
||
|
|
manager.saveSystem = saveSystem;
|
||
|
|
return manager;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateTree(Vector3 position)
|
||
|
|
{
|
||
|
|
GameObject trunk = CreatePrimitive("Tree Trunk", PrimitiveType.Cylinder, position + Vector3.up * 0.8f, new Vector3(0.55f, 1.6f, 0.55f), materials["Wood"]);
|
||
|
|
GameObject leaves = CreatePrimitive("Tree Leaves", PrimitiveType.Sphere, position + Vector3.up * 2.45f, new Vector3(2.1f, 1.7f, 2.1f), materials["Leaves"]);
|
||
|
|
leaves.transform.SetParent(trunk.transform, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreatePrimitive(string name, PrimitiveType primitive, Vector3 position, Vector3 scale, Material material)
|
||
|
|
{
|
||
|
|
GameObject obj = GameObject.CreatePrimitive(primitive);
|
||
|
|
obj.name = name;
|
||
|
|
obj.transform.position = position;
|
||
|
|
obj.transform.localScale = scale;
|
||
|
|
Renderer renderer = obj.GetComponent<Renderer>();
|
||
|
|
if (renderer != null)
|
||
|
|
{
|
||
|
|
renderer.sharedMaterial = material;
|
||
|
|
}
|
||
|
|
|
||
|
|
return obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateNameplate(Transform parent, string text, Color color)
|
||
|
|
{
|
||
|
|
GameObject nameObject = new GameObject("Nameplate");
|
||
|
|
nameObject.transform.SetParent(parent, false);
|
||
|
|
nameObject.transform.localPosition = new Vector3(0f, 1.55f, 0f);
|
||
|
|
TextMesh mesh = nameObject.AddComponent<TextMesh>();
|
||
|
|
mesh.text = text;
|
||
|
|
mesh.anchor = TextAnchor.MiddleCenter;
|
||
|
|
mesh.alignment = TextAlignment.Center;
|
||
|
|
mesh.characterSize = 0.22f;
|
||
|
|
mesh.fontSize = 42;
|
||
|
|
mesh.color = color;
|
||
|
|
if (regularFont != null)
|
||
|
|
{
|
||
|
|
mesh.font = regularFont;
|
||
|
|
mesh.GetComponent<MeshRenderer>().sharedMaterial = regularFont.material;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateSign(string text, Vector3 position)
|
||
|
|
{
|
||
|
|
GameObject sign = CreatePrimitive("Sign " + text, PrimitiveType.Cube, position + Vector3.up * 0.8f, new Vector3(1.8f, 0.9f, 0.12f), materials["Wood"]);
|
||
|
|
CreateNameplate(sign.transform, text, Color.white);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static GameObject CreatePanel(Transform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPosition, Vector2 size, Color color)
|
||
|
|
{
|
||
|
|
GameObject panel = new GameObject(name, typeof(RectTransform), typeof(Image));
|
||
|
|
panel.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = panel.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = anchorMin;
|
||
|
|
rect.anchorMax = anchorMax;
|
||
|
|
rect.pivot = pivot;
|
||
|
|
rect.anchoredPosition = anchoredPosition;
|
||
|
|
rect.sizeDelta = size;
|
||
|
|
panel.GetComponent<Image>().color = color;
|
||
|
|
return panel;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Text CreateText(Transform parent, string name, string value, int fontSize, TextAnchor anchor, Vector2 anchoredPosition, Vector2 size, Font font)
|
||
|
|
{
|
||
|
|
GameObject textObject = new GameObject(name, typeof(RectTransform), typeof(Text));
|
||
|
|
textObject.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = textObject.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 1f);
|
||
|
|
rect.pivot = new Vector2(0f, 1f);
|
||
|
|
rect.anchoredPosition = anchoredPosition;
|
||
|
|
rect.sizeDelta = size;
|
||
|
|
Text text = textObject.GetComponent<Text>();
|
||
|
|
text.text = value;
|
||
|
|
text.font = font != null ? font : regularFont != null ? regularFont : Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||
|
|
text.fontSize = fontSize;
|
||
|
|
text.alignment = anchor;
|
||
|
|
text.color = UITheme.Text;
|
||
|
|
text.supportRichText = true;
|
||
|
|
return text;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Button CreateButton(Transform parent, string name, string label, Vector2 anchoredPosition, Vector2 size)
|
||
|
|
{
|
||
|
|
GameObject buttonObject = new GameObject(name, typeof(RectTransform), typeof(Image), typeof(Button));
|
||
|
|
buttonObject.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = buttonObject.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 1f);
|
||
|
|
rect.pivot = new Vector2(0f, 1f);
|
||
|
|
rect.anchoredPosition = anchoredPosition;
|
||
|
|
rect.sizeDelta = size;
|
||
|
|
buttonObject.GetComponent<Image>().color = new Color(0.13f, 0.18f, 0.24f, 0.96f);
|
||
|
|
Text text = CreateText(buttonObject.transform, "Text", label, 16, TextAnchor.MiddleCenter, Vector2.zero, size, regularFont);
|
||
|
|
text.rectTransform.anchorMin = Vector2.zero;
|
||
|
|
text.rectTransform.anchorMax = Vector2.one;
|
||
|
|
text.rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||
|
|
text.rectTransform.anchoredPosition = Vector2.zero;
|
||
|
|
text.rectTransform.offsetMin = Vector2.zero;
|
||
|
|
text.rectTransform.offsetMax = Vector2.zero;
|
||
|
|
return buttonObject.GetComponent<Button>();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static RectTransform CreateVerticalList(Transform parent, string name, Vector2 anchoredPosition, Vector2 size)
|
||
|
|
{
|
||
|
|
GameObject list = new GameObject(name, typeof(RectTransform), typeof(VerticalLayoutGroup));
|
||
|
|
list.transform.SetParent(parent, false);
|
||
|
|
RectTransform rect = list.GetComponent<RectTransform>();
|
||
|
|
rect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 1f);
|
||
|
|
rect.pivot = new Vector2(0f, 1f);
|
||
|
|
rect.anchoredPosition = anchoredPosition;
|
||
|
|
rect.sizeDelta = size;
|
||
|
|
VerticalLayoutGroup layout = list.GetComponent<VerticalLayoutGroup>();
|
||
|
|
layout.spacing = 8f;
|
||
|
|
layout.childAlignment = TextAnchor.UpperLeft;
|
||
|
|
layout.childControlWidth = false;
|
||
|
|
layout.childControlHeight = false;
|
||
|
|
return rect;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void StretchRect(RectTransform rect, Vector2 offsetMin, Vector2 offsetMax)
|
||
|
|
{
|
||
|
|
rect.anchorMin = Vector2.zero;
|
||
|
|
rect.anchorMax = Vector2.one;
|
||
|
|
rect.offsetMin = offsetMin;
|
||
|
|
rect.offsetMax = offsetMax;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void EnsureEventSystem()
|
||
|
|
{
|
||
|
|
if (Object.FindObjectOfType<EventSystem>() != null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
GameObject eventSystem = new GameObject("EventSystem", typeof(EventSystem), typeof(StandaloneInputModule));
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AddSceneToBuildSettings(string path)
|
||
|
|
{
|
||
|
|
List<EditorBuildSettingsScene> scenes = new List<EditorBuildSettingsScene>(EditorBuildSettings.scenes);
|
||
|
|
for (int i = 0; i < scenes.Count; i++)
|
||
|
|
{
|
||
|
|
if (scenes[i].path == path)
|
||
|
|
{
|
||
|
|
scenes[i] = new EditorBuildSettingsScene(path, true);
|
||
|
|
EditorBuildSettings.scenes = scenes.ToArray();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
scenes.Add(new EditorBuildSettingsScene(path, true));
|
||
|
|
EditorBuildSettings.scenes = scenes.ToArray();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int CountMissingScripts(Scene scene)
|
||
|
|
{
|
||
|
|
int total = 0;
|
||
|
|
GameObject[] roots = scene.GetRootGameObjects();
|
||
|
|
for (int i = 0; i < roots.Length; i++)
|
||
|
|
{
|
||
|
|
total += CountMissingScriptsRecursive(roots[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return total;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int CountMissingScriptsRecursive(GameObject obj)
|
||
|
|
{
|
||
|
|
int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(obj);
|
||
|
|
foreach (Transform child in obj.transform)
|
||
|
|
{
|
||
|
|
count += CountMissingScriptsRecursive(child.gameObject);
|
||
|
|
}
|
||
|
|
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string ToSystemPath(string assetPath)
|
||
|
|
{
|
||
|
|
return Path.GetFullPath(assetPath);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void Require(bool condition, string message)
|
||
|
|
{
|
||
|
|
if (!condition)
|
||
|
|
{
|
||
|
|
throw new System.Exception(message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|