Files
OTG_3/Assets/Editor/Lab3SceneBuilder.cs
2026-06-04 18:31:31 +03:00

821 lines
41 KiB
C#

using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public static class Lab3SceneBuilder
{
private const string ScriptsPath = "Assets/_Scripts";
private const string DataPath = "Assets/_Data";
private const string ItemsPath = "Assets/_Data/Items";
private const string RecipesPath = "Assets/_Data/Recipes";
private const string PrefabsPath = "Assets/_Prefabs";
private const string ScenesPath = "Assets/_Scenes";
private const string MaterialsPath = "Assets/_Materials";
private const string FontsPath = "Assets/_Fonts";
private const string EditorPath = "Assets/Editor";
private const string ScenePath = "Assets/_Scenes/Lab03_CraftingSystem.unity";
private const string RegularFontPath = "Assets/_Fonts/Ubuntu-Regular.ttf";
private const string BoldFontPath = "Assets/_Fonts/Ubuntu-Bold.ttf";
[MenuItem("Tools/Technical Game Design/Lab3/Create Crafting System Scene")]
public static void CreateCraftingSystemScene()
{
CreateFolders();
Font uiFont = InstallUbuntuFont();
Dictionary<string, Material> materials = CreateMaterials();
Dictionary<string, ItemData> items = CreateItems();
List<RecipeData> recipes = CreateRecipes(items);
GameObject recipeButtonPrefab = CreateRecipeButtonPrefab(uiFont);
GameObject slotPrefab = CreateInventorySlotPrefab(uiFont);
GameObject hotbarSlotPrefab = CreateHotbarSlotPrefab(uiFont);
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
scene.name = "Lab03_CraftingSystem";
CreateWorld(materials, items, uiFont);
CreateCameraAndLight();
CreateSystems(items, recipes, materials, uiFont, recipeButtonPrefab, slotPrefab, hotbarSlotPrefab);
EditorSceneManager.SaveScene(scene, ScenePath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
Debug.Log("Lab03 Crafting System scene created: " + ScenePath);
}
private static void CreateFolders()
{
string[] folders =
{
ScriptsPath,
DataPath,
ItemsPath,
RecipesPath,
PrefabsPath,
ScenesPath,
MaterialsPath,
FontsPath,
EditorPath
};
for (int i = 0; i < folders.Length; i++)
{
if (!AssetDatabase.IsValidFolder(folders[i]))
{
Directory.CreateDirectory(folders[i]);
}
}
AssetDatabase.Refresh();
}
private static Font InstallUbuntuFont()
{
string regularSource = FindFontFile(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"
}, "Ubuntu-R*.ttf", "Ubuntu-Regular*.ttf");
string boldSource = FindFontFile(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"
}, "Ubuntu-B*.ttf", "Ubuntu-Bold*.ttf");
if (!string.IsNullOrEmpty(regularSource))
{
File.Copy(regularSource, RegularFontPath, true);
AssetDatabase.ImportAsset(RegularFontPath);
Debug.Log("Ubuntu regular font copied to " + RegularFontPath);
}
else
{
Debug.LogWarning("Ubuntu regular font was not found in system font folders. UI will use built-in Arial fallback.");
}
if (!string.IsNullOrEmpty(boldSource))
{
File.Copy(boldSource, BoldFontPath, true);
AssetDatabase.ImportAsset(BoldFontPath);
Debug.Log("Ubuntu bold font copied to " + BoldFontPath);
}
AssetDatabase.Refresh();
Font font = AssetDatabase.LoadAssetAtPath<Font>(RegularFontPath);
return font != null ? font : Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
}
private static string FindFontFile(string[] preferredPaths, params string[] patterns)
{
for (int i = 0; i < preferredPaths.Length; i++)
{
if (File.Exists(preferredPaths[i]))
{
return preferredPaths[i];
}
}
string[] roots =
{
"/usr/share/fonts/truetype/ubuntu",
"/usr/share/fonts/TTF",
"/usr/share/fonts"
};
for (int i = 0; i < roots.Length; i++)
{
if (!Directory.Exists(roots[i]))
{
continue;
}
for (int p = 0; p < patterns.Length; p++)
{
string[] files = Directory.GetFiles(roots[i], patterns[p], SearchOption.AllDirectories);
if (files.Length > 0)
{
return files[0];
}
}
}
return null;
}
private static Dictionary<string, Material> CreateMaterials()
{
Dictionary<string, Color> materialColors = new Dictionary<string, Color>
{
{ "Mat_Floor", new Color(0.36f, 0.42f, 0.36f) },
{ "Mat_Workbench", new Color(0.42f, 0.25f, 0.12f) },
{ "Mat_Workbench_Dark", new Color(0.22f, 0.13f, 0.07f) },
{ "Mat_Wood", new Color(0.55f, 0.34f, 0.16f) },
{ "Mat_Stone", new Color(0.47f, 0.48f, 0.47f) },
{ "Mat_Iron", new Color(0.55f, 0.58f, 0.62f) },
{ "Mat_Fiber", new Color(0.48f, 0.66f, 0.34f) },
{ "Mat_Coal", new Color(0.05f, 0.05f, 0.05f) },
{ "Mat_Herb", new Color(0.18f, 0.62f, 0.25f) },
{ "Mat_Crystal", new Color(0.35f, 0.78f, 0.95f) },
{ "Mat_Player", new Color(0.20f, 0.44f, 0.82f) },
{ "Mat_Torch_Light", new Color(1.00f, 0.55f, 0.12f) }
};
Dictionary<string, Material> result = new Dictionary<string, Material>();
foreach (KeyValuePair<string, Color> pair in materialColors)
{
string path = MaterialsPath + "/" + pair.Key + ".mat";
Material material = AssetDatabase.LoadAssetAtPath<Material>(path);
if (material == null)
{
material = new Material(Shader.Find("Standard"));
AssetDatabase.CreateAsset(material, path);
}
material.color = pair.Value;
EditorUtility.SetDirty(material);
result[pair.Key] = material;
}
return result;
}
private static Dictionary<string, ItemData> CreateItems()
{
ItemDefinition[] definitions =
{
new ItemDefinition("Wood", "wood", "Древесина", "Базовый строительный ресурс для рукоятей и простых инструментов.", 64, true, new Color(0.58f, 0.36f, 0.16f)),
new ItemDefinition("Stone", "stone", "Камень", "Твердый ресурс для лезвий и ударных частей инструментов.", 64, true, new Color(0.55f, 0.55f, 0.55f)),
new ItemDefinition("Stick", "stick", "Палка", "Готовая рукоять для простых рецептов.", 64, true, new Color(0.64f, 0.42f, 0.20f)),
new ItemDefinition("IronOre", "iron_ore", "Железная руда", "Металлическое сырье для прочных инструментов.", 64, true, new Color(0.56f, 0.58f, 0.64f)),
new ItemDefinition("Fiber", "fiber", "Волокно", "Гибкий материал для перевязки и связки деталей.", 64, true, new Color(0.72f, 0.78f, 0.48f)),
new ItemDefinition("Leather", "leather", "Кожа", "Прочный материал для креплений и украшений.", 32, true, new Color(0.45f, 0.25f, 0.12f)),
new ItemDefinition("Coal", "coal", "Уголь", "Горючий ресурс для факелов.", 64, true, new Color(0.08f, 0.08f, 0.08f)),
new ItemDefinition("Herb", "herb", "Трава", "Лечебное растение для простых расходников.", 64, true, new Color(0.20f, 0.66f, 0.24f)),
new ItemDefinition("Crystal", "crystal", "Кристалл", "Редкий магический ресурс.", 16, true, new Color(0.30f, 0.80f, 1.00f)),
new ItemDefinition("Axe", "axe", "Топор", "Инструмент для рубки древесины.", 1, false, new Color(0.76f, 0.72f, 0.62f)),
new ItemDefinition("Pickaxe", "pickaxe", "Кирка", "Инструмент для добычи камня и руды.", 1, false, new Color(0.65f, 0.68f, 0.72f)),
new ItemDefinition("Torch", "torch", "Факел", "Источник света, создается по две штуки за крафт.", 16, false, new Color(1.00f, 0.62f, 0.18f)),
new ItemDefinition("Bandage", "bandage", "Бинт", "Расходный предмет для восстановления здоровья.", 16, false, new Color(0.92f, 0.90f, 0.82f)),
new ItemDefinition("MagicAmulet", "magic_amulet", "Магический амулет", "Редкий предмет, усиливающий героя.", 1, false, new Color(0.55f, 0.35f, 0.95f))
};
Dictionary<string, ItemData> items = new Dictionary<string, ItemData>();
for (int i = 0; i < definitions.Length; i++)
{
ItemDefinition definition = definitions[i];
string path = ItemsPath + "/" + definition.assetName + ".asset";
ItemData item = AssetDatabase.LoadAssetAtPath<ItemData>(path);
if (item == null)
{
item = ScriptableObject.CreateInstance<ItemData>();
AssetDatabase.CreateAsset(item, path);
}
item.itemId = definition.itemId;
item.itemName = definition.itemName;
item.description = definition.description;
item.maxStack = definition.maxStack;
item.isResource = definition.isResource;
item.itemColor = definition.itemColor;
item.icon = null;
EditorUtility.SetDirty(item);
items[definition.assetName] = item;
}
AssetDatabase.SaveAssets();
return items;
}
private static List<RecipeData> CreateRecipes(Dictionary<string, ItemData> items)
{
RecipeDefinition[] definitions =
{
new RecipeDefinition("Recipe_Axe", "recipe_axe", "Топор", "Простой топор из древесины, палки и камня.", "Axe", 1, new[] { Pair("Wood", 2), Pair("Stick", 1), Pair("Stone", 1) }),
new RecipeDefinition("Recipe_Pickaxe", "recipe_pickaxe", "Кирка", "Прочная кирка для добычи твердых ресурсов.", "Pickaxe", 1, new[] { Pair("Wood", 2), Pair("Stick", 2), Pair("IronOre", 2) }),
new RecipeDefinition("Recipe_Torch", "recipe_torch", "Факел", "Два факела из палки, угля и волокна.", "Torch", 2, new[] { Pair("Stick", 1), Pair("Coal", 1), Pair("Fiber", 1) }),
new RecipeDefinition("Recipe_Bandage", "recipe_bandage", "Бинт", "Простая лечебная повязка из волокна и травы.", "Bandage", 1, new[] { Pair("Fiber", 2), Pair("Herb", 1) }),
new RecipeDefinition("Recipe_MagicAmulet", "recipe_magic_amulet", "Магический амулет", "Редкий амулет из кристаллов, кожи и железной руды.", "MagicAmulet", 1, new[] { Pair("Crystal", 2), Pair("Leather", 1), Pair("IronOre", 1) })
};
List<RecipeData> recipes = new List<RecipeData>();
for (int i = 0; i < definitions.Length; i++)
{
RecipeDefinition definition = definitions[i];
string path = RecipesPath + "/" + definition.assetName + ".asset";
RecipeData recipe = AssetDatabase.LoadAssetAtPath<RecipeData>(path);
if (recipe == null)
{
recipe = ScriptableObject.CreateInstance<RecipeData>();
AssetDatabase.CreateAsset(recipe, path);
}
recipe.recipeId = definition.recipeId;
recipe.recipeName = definition.recipeName;
recipe.description = definition.description;
recipe.result = items[definition.resultKey];
recipe.resultAmount = definition.resultAmount;
recipe.unlockedByDefault = true;
recipe.ingredients = new Ingredient[definition.ingredients.Length];
for (int ingredientIndex = 0; ingredientIndex < definition.ingredients.Length; ingredientIndex++)
{
RecipeIngredientDefinition ingredientDefinition = definition.ingredients[ingredientIndex];
recipe.ingredients[ingredientIndex] = new Ingredient
{
item = items[ingredientDefinition.itemKey],
amount = ingredientDefinition.amount
};
}
EditorUtility.SetDirty(recipe);
recipes.Add(recipe);
}
AssetDatabase.SaveAssets();
return recipes;
}
private static RecipeIngredientDefinition Pair(string itemKey, int amount)
{
return new RecipeIngredientDefinition(itemKey, amount);
}
private static void CreateWorld(Dictionary<string, Material> materials, Dictionary<string, ItemData> items, Font worldFont)
{
GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
floor.name = "Floor";
floor.transform.localScale = new Vector3(2.8f, 1f, 2.2f);
SetMaterial(floor, materials["Mat_Floor"]);
GameObject tableTop = GameObject.CreatePrimitive(PrimitiveType.Cube);
tableTop.name = "Crafting Workbench";
tableTop.transform.position = new Vector3(0f, 0.65f, 3.2f);
tableTop.transform.localScale = new Vector3(3.6f, 0.28f, 1.5f);
SetMaterial(tableTop, materials["Mat_Workbench"]);
CreateCube("Workbench Leg FL", new Vector3(-1.45f, 0.25f, 3.72f), new Vector3(0.22f, 0.55f, 0.22f), materials["Mat_Workbench_Dark"]);
CreateCube("Workbench Leg FR", new Vector3(1.45f, 0.25f, 3.72f), new Vector3(0.22f, 0.55f, 0.22f), materials["Mat_Workbench_Dark"]);
CreateCube("Workbench Leg BL", new Vector3(-1.45f, 0.25f, 2.68f), new Vector3(0.22f, 0.55f, 0.22f), materials["Mat_Workbench_Dark"]);
CreateCube("Workbench Leg BR", new Vector3(1.45f, 0.25f, 2.68f), new Vector3(0.22f, 0.55f, 0.22f), materials["Mat_Workbench_Dark"]);
CreateWorldLabel("Workbench Label", "Верстак: крафт через панель справа", new Vector3(0f, 1.25f, 3.2f), worldFont);
CreatePickup("Wood Pickup A", items["Wood"], 2, PrimitiveType.Cube, new Vector3(-5.5f, 0.35f, -2.8f), new Vector3(0.55f, 0.28f, 0.28f), materials["Mat_Wood"], worldFont);
CreatePickup("Wood Pickup B", items["Wood"], 3, PrimitiveType.Cube, new Vector3(-4.8f, 0.35f, 1.8f), new Vector3(0.55f, 0.28f, 0.28f), materials["Mat_Wood"], worldFont);
CreatePickup("Stone Pickup", items["Stone"], 3, PrimitiveType.Sphere, new Vector3(-2.9f, 0.35f, -4.2f), new Vector3(0.48f, 0.34f, 0.48f), materials["Mat_Stone"], worldFont);
CreatePickup("Stick Pickup", items["Stick"], 2, PrimitiveType.Cube, new Vector3(2.2f, 0.22f, -4.7f), new Vector3(0.75f, 0.14f, 0.14f), materials["Mat_Wood"], worldFont);
CreatePickup("Iron Ore Pickup", items["IronOre"], 2, PrimitiveType.Sphere, new Vector3(5.1f, 0.35f, -2.0f), new Vector3(0.45f, 0.34f, 0.45f), materials["Mat_Iron"], worldFont);
CreatePickup("Fiber Pickup", items["Fiber"], 3, PrimitiveType.Cube, new Vector3(-3.7f, 0.20f, 4.8f), new Vector3(0.6f, 0.12f, 0.3f), materials["Mat_Fiber"], worldFont);
CreatePickup("Leather Pickup", items["Leather"], 1, PrimitiveType.Cube, new Vector3(4.4f, 0.22f, 3.8f), new Vector3(0.55f, 0.12f, 0.42f), materials["Mat_Workbench"], worldFont);
CreatePickup("Coal Pickup", items["Coal"], 2, PrimitiveType.Sphere, new Vector3(5.6f, 0.30f, 1.1f), new Vector3(0.38f, 0.28f, 0.38f), materials["Mat_Coal"], worldFont);
CreatePickup("Herb Pickup", items["Herb"], 2, PrimitiveType.Cube, new Vector3(-0.5f, 0.20f, -5.0f), new Vector3(0.45f, 0.12f, 0.45f), materials["Mat_Herb"], worldFont);
CreatePickup("Crystal Pickup", items["Crystal"], 2, PrimitiveType.Cylinder, new Vector3(2.9f, 0.45f, 5.1f), new Vector3(0.24f, 0.55f, 0.24f), materials["Mat_Crystal"], worldFont);
}
private static void CreateCameraAndLight()
{
GameObject cameraObject = new GameObject("Main Camera");
Camera camera = cameraObject.AddComponent<Camera>();
cameraObject.tag = "MainCamera";
cameraObject.transform.position = new Vector3(0f, 8f, -7f);
cameraObject.transform.rotation = Quaternion.Euler(58f, 0f, 0f);
camera.clearFlags = CameraClearFlags.SolidColor;
camera.backgroundColor = new Color(0.12f, 0.14f, 0.16f);
camera.fieldOfView = 48f;
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, -30f, 0f);
}
private static void CreateSystems(Dictionary<string, ItemData> items, List<RecipeData> recipes, Dictionary<string, Material> materials, Font uiFont, GameObject recipeButtonPrefab, GameObject slotPrefab, GameObject hotbarSlotPrefab)
{
GameObject player = CreatePlayer(materials["Mat_Player"]);
Camera mainCamera = Camera.main;
if (mainCamera != null)
{
CameraFollow follow = mainCamera.gameObject.AddComponent<CameraFollow>();
follow.target = player.transform;
}
GameObject inventoryObject = new GameObject("Player Inventory");
Inventory inventory = inventoryObject.AddComponent<Inventory>();
inventory.maxSlots = 32;
inventory.testResources = new List<InventorySlot>
{
new InventorySlot(items["Wood"], 8),
new InventorySlot(items["Stone"], 6),
new InventorySlot(items["Stick"], 6),
new InventorySlot(items["IronOre"], 4),
new InventorySlot(items["Fiber"], 6),
new InventorySlot(items["Leather"], 2),
new InventorySlot(items["Coal"], 3),
new InventorySlot(items["Herb"], 3),
new InventorySlot(items["Crystal"], 2)
};
GameObject craftingObject = new GameObject("Crafting System");
CraftingSystem craftingSystem = craftingObject.AddComponent<CraftingSystem>();
craftingSystem.playerInventory = inventory;
craftingSystem.availableRecipes = recipes;
craftingSystem.lastMessage = "Собирайте ресурсы на карте, затем создавайте предметы справа.";
GameObject canvasObject = new GameObject("Canvas");
Canvas canvas = canvasObject.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
CanvasScaler scaler = canvasObject.AddComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1280f, 720f);
scaler.matchWidthOrHeight = 0.5f;
canvasObject.AddComponent<GraphicRaycaster>();
GameObject eventSystemObject = new GameObject("EventSystem");
eventSystemObject.AddComponent<EventSystem>();
eventSystemObject.AddComponent<StandaloneInputModule>();
RectTransform root = canvasObject.GetComponent<RectTransform>();
Text title = CreateText("Title", root, "Лабораторная работа №3 - Система крафта", uiFont, 22, FontStyle.Bold, TextAnchor.MiddleCenter, Color.white);
Anchor(title.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -22f), new Vector2(720f, 36f));
Image inventoryPanel = CreatePanel("Inventory Panel", root, new Vector2(150f, -246f), new Vector2(272f, 374f), new Vector2(0f, 1f), new Color(0.055f, 0.070f, 0.085f, 0.97f));
Image recipePanel = CreatePanel("Recipe Panel", root, new Vector2(-196f, -246f), new Vector2(364f, 374f), new Vector2(1f, 1f), new Color(0.055f, 0.070f, 0.085f, 0.97f));
Image detailsPanel = CreatePanel("Recipe Details Panel", root, new Vector2(0f, 158f), new Vector2(500f, 116f), new Vector2(0.5f, 0f), new Color(0.055f, 0.070f, 0.085f, 0.96f));
Image hotbarPanel = CreatePanel("Hotbar Panel", root, new Vector2(0f, 42f), new Vector2(878f, 68f), new Vector2(0.5f, 0f), new Color(0.045f, 0.055f, 0.070f, 0.97f));
Text inventoryTitle = CreateText("Inventory Title", inventoryPanel.rectTransform, "Инвентарь", uiFont, 20, FontStyle.Bold, TextAnchor.MiddleLeft, Color.white);
Anchor(inventoryTitle.rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 160f), new Vector2(240f, 30f));
Transform slotContainer = CreateVerticalContainer("Inventory Slots", inventoryPanel.rectTransform, new Vector2(0f, 4f), new Vector2(248f, 270f), new Vector2(0.5f, 0.5f), 4f, TextAnchor.UpperCenter);
Text inventoryDebug = CreateText("Inventory Debug", inventoryPanel.rectTransform, "Ресурсов: 9", uiFont, 14, FontStyle.Normal, TextAnchor.LowerLeft, new Color(0.78f, 0.84f, 0.88f));
Anchor(inventoryDebug.rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -162f), new Vector2(240f, 24f));
Text recipeTitle = CreateText("Recipe Title", recipePanel.rectTransform, "Рецепты", uiFont, 20, FontStyle.Bold, TextAnchor.MiddleLeft, Color.white);
Anchor(recipeTitle.rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 160f), new Vector2(336f, 30f));
Transform recipeContainer = CreateRectContainer("Recipe Buttons", recipePanel.rectTransform, new Vector2(0f, -8f), new Vector2(336f, 286f), new Vector2(0.5f, 0.5f));
Text recipeDebug = CreateText("Recipe Debug", recipePanel.rectTransform, "Рецептов: 5", uiFont, 14, FontStyle.Normal, TextAnchor.LowerLeft, new Color(0.78f, 0.84f, 0.88f));
Anchor(recipeDebug.rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -162f), new Vector2(336f, 24f));
Text selectedRecipeText = CreateText("Selected Recipe Text", detailsPanel.rectTransform, "", uiFont, 12, FontStyle.Normal, TextAnchor.UpperLeft, new Color(0.88f, 0.92f, 0.95f));
Stretch(selectedRecipeText.rectTransform, 12f, 8f, 12f, 34f);
Text messageText = CreateText("Craft Message", detailsPanel.rectTransform, "Собирайте ресурсы на карте, затем создавайте предметы справа.", uiFont, 13, FontStyle.Bold, TextAnchor.MiddleLeft, new Color(0.74f, 0.95f, 0.70f));
Anchor(messageText.rectTransform, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(12f, 18f), new Vector2(-24f, 28f));
Text interactionText = CreateText("Interaction Text", root, "Подойдите к ресурсу и нажмите E", uiFont, 16, FontStyle.Bold, TextAnchor.MiddleCenter, new Color(1f, 0.92f, 0.62f));
Anchor(interactionText.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -56f), new Vector2(540f, 28f));
Text hintText = CreateText("Hint Text", root, "WASD - движение | E - подобрать | 1-9/0 - слот | F - использовать | R - тестовые ресурсы | C - UI", uiFont, 13, FontStyle.Normal, TextAnchor.MiddleCenter, new Color(0.84f, 0.89f, 0.92f));
Anchor(hintText.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -84f), new Vector2(850f, 24f));
Transform hotbarContainer = CreateHorizontalContainer("Hotbar Slots", hotbarPanel.rectTransform, new Vector2(0f, 0f), new Vector2(854f, 54f), new Vector2(0.5f, 0.5f), 6f, TextAnchor.MiddleCenter);
InventoryUI inventoryUI = inventoryPanel.gameObject.AddComponent<InventoryUI>();
inventoryUI.inventory = inventory;
inventoryUI.slotContainer = slotContainer;
inventoryUI.slotPrefab = slotPrefab;
CraftingUI craftingUI = recipePanel.gameObject.AddComponent<CraftingUI>();
craftingUI.craftingSystem = craftingSystem;
craftingUI.inventory = inventory;
craftingUI.recipeContainer = recipeContainer;
craftingUI.recipeButtonPrefab = recipeButtonPrefab;
craftingUI.messageText = messageText;
craftingUI.selectedRecipeText = selectedRecipeText;
craftingUI.uiFont = uiFont;
PlayerMovement movement = player.GetComponent<PlayerMovement>();
PlayerInteractor interactor = player.AddComponent<PlayerInteractor>();
interactor.inventory = inventory;
interactor.craftingSystem = craftingSystem;
interactor.interactionText = interactionText;
ItemUseSystem itemUseSystem = player.AddComponent<ItemUseSystem>();
itemUseSystem.inventory = inventory;
itemUseSystem.craftingSystem = craftingSystem;
itemUseSystem.playerMovement = movement;
itemUseSystem.playerTransform = player.transform;
itemUseSystem.torchLightMaterial = materials["Mat_Torch_Light"];
itemUseSystem.statusText = messageText;
itemUseSystem.selectableSlotCount = 10;
HotbarUI hotbarUI = hotbarPanel.gameObject.AddComponent<HotbarUI>();
hotbarUI.inventory = inventory;
hotbarUI.itemUseSystem = itemUseSystem;
hotbarUI.slotContainer = hotbarContainer;
hotbarUI.slotPrefab = hotbarSlotPrefab;
hotbarUI.slotCount = 10;
GameObject controllerObject = new GameObject("Crafting Demo Controller");
CraftingDemoController controller = controllerObject.AddComponent<CraftingDemoController>();
controller.inventory = inventory;
controller.craftingSystem = craftingSystem;
controller.craftingPanel = canvasObject;
controller.hintText = hintText;
controller.addStartingResources = false;
ApplyFontToAllText(canvasObject, uiFont);
}
private static GameObject CreateRecipeButtonPrefab(Font font)
{
GameObject root = new GameObject("RecipeButtonPrefab", typeof(RectTransform), typeof(Image), typeof(Button));
RectTransform rect = root.GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(336f, 52f);
Image image = root.GetComponent<Image>();
image.color = new Color(0.13f, 0.18f, 0.20f, 0.98f);
Button button = root.GetComponent<Button>();
ColorBlock colors = button.colors;
colors.normalColor = Color.white;
colors.highlightedColor = new Color(0.90f, 0.96f, 1.00f, 1f);
colors.pressedColor = new Color(0.76f, 0.86f, 0.92f, 1f);
colors.disabledColor = new Color(0.70f, 0.70f, 0.70f, 1f);
button.colors = colors;
Image stateStripe = CreateImage("StateStripe", rect, new Color(0.24f, 0.68f, 0.36f, 1f));
Anchor(stateStripe.rectTransform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(3f, 0f), new Vector2(6f, 44f));
Text title = CreateText("Title", rect, "Recipe", font, 13, FontStyle.Bold, TextAnchor.UpperLeft, Color.white);
Anchor(title.rectTransform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(110f, -10f), new Vector2(190f, 20f));
Text result = CreateText("Result", rect, "Result", font, 12, FontStyle.Bold, TextAnchor.UpperRight, new Color(0.78f, 0.92f, 1f));
Anchor(result.rectTransform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-58f, -10f), new Vector2(100f, 20f));
Text ingredients = CreateText("Ingredients", rect, "Ingredients", font, 10, FontStyle.Normal, TextAnchor.LowerLeft, new Color(0.82f, 0.86f, 0.88f));
Anchor(ingredients.rectTransform, new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(130f, 12f), new Vector2(230f, 20f));
Text status = CreateText("Status", rect, "Status", font, 10, FontStyle.Bold, TextAnchor.LowerRight, new Color(0.76f, 0.95f, 0.72f));
Anchor(status.rectTransform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-46f, 12f), new Vector2(76f, 18f));
string path = PrefabsPath + "/RecipeButtonPrefab.prefab";
ApplyFontToAllText(root, font);
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
Object.DestroyImmediate(root);
return prefab;
}
private static GameObject CreateInventorySlotPrefab(Font font)
{
GameObject root = new GameObject("InventorySlotPrefab", typeof(RectTransform), typeof(Image));
RectTransform rect = root.GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(248f, 26f);
Image image = root.GetComponent<Image>();
image.color = new Color(0.12f, 0.15f, 0.18f, 0.95f);
Image marker = CreateImage("ColorMarker", rect, Color.white);
Anchor(marker.rectTransform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(12f, 0f), new Vector2(12f, 16f));
Text label = CreateText("Label", rect, "Item x0", font, 12, FontStyle.Normal, TextAnchor.MiddleLeft, Color.white);
Anchor(label.rectTransform, new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(30f, 0f), new Vector2(-36f, 0f));
string path = PrefabsPath + "/InventorySlotPrefab.prefab";
ApplyFontToAllText(root, font);
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
Object.DestroyImmediate(root);
return prefab;
}
private static GameObject CreateHotbarSlotPrefab(Font font)
{
GameObject root = new GameObject("HotbarSlotPrefab", typeof(RectTransform), typeof(Image), typeof(Button));
RectTransform rect = root.GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(78f, 50f);
root.GetComponent<Image>().color = new Color(0.10f, 0.12f, 0.15f, 0.92f);
Image marker = CreateImage("ColorMarker", rect, new Color(0.18f, 0.20f, 0.22f, 1f));
Anchor(marker.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -10f), new Vector2(58f, 6f));
Text number = CreateText("Number", rect, "1", font, 12, FontStyle.Bold, TextAnchor.UpperLeft, new Color(0.95f, 0.90f, 0.72f));
Stretch(number.rectTransform, 6f, 4f, 6f, 4f);
Text label = CreateText("Label", rect, "Пусто", font, 10, FontStyle.Normal, TextAnchor.MiddleCenter, Color.white);
Anchor(label.rectTransform, new Vector2(0f, 0f), new Vector2(1f, 1f), new Vector2(0f, -6f), new Vector2(-8f, -16f));
string path = PrefabsPath + "/HotbarSlotPrefab.prefab";
ApplyFontToAllText(root, font);
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
Object.DestroyImmediate(root);
return prefab;
}
private static Image CreatePanel(string name, RectTransform parent, Vector2 anchoredPosition, Vector2 size, Vector2 anchor, Color color)
{
Image panel = CreateImage(name, parent, color);
Anchor(panel.rectTransform, anchor, anchor, anchoredPosition, size);
return panel;
}
private static Transform CreateVerticalContainer(string name, RectTransform parent, Vector2 anchoredPosition, Vector2 size, Vector2 anchor, float spacing, TextAnchor alignment)
{
GameObject container = new GameObject(name, typeof(RectTransform), typeof(VerticalLayoutGroup));
RectTransform rect = container.GetComponent<RectTransform>();
rect.SetParent(parent, false);
Anchor(rect, anchor, anchor, anchoredPosition, size);
VerticalLayoutGroup layout = container.GetComponent<VerticalLayoutGroup>();
layout.spacing = spacing;
layout.childAlignment = alignment;
layout.childControlWidth = true;
layout.childControlHeight = false;
layout.childForceExpandWidth = true;
layout.childForceExpandHeight = false;
return container.transform;
}
private static Transform CreateRectContainer(string name, RectTransform parent, Vector2 anchoredPosition, Vector2 size, Vector2 anchor)
{
GameObject container = new GameObject(name, typeof(RectTransform));
RectTransform rect = container.GetComponent<RectTransform>();
rect.SetParent(parent, false);
Anchor(rect, anchor, anchor, anchoredPosition, size);
return container.transform;
}
private static Transform CreateHorizontalContainer(string name, RectTransform parent, Vector2 anchoredPosition, Vector2 size, Vector2 anchor, float spacing, TextAnchor alignment)
{
GameObject container = new GameObject(name, typeof(RectTransform), typeof(HorizontalLayoutGroup));
RectTransform rect = container.GetComponent<RectTransform>();
rect.SetParent(parent, false);
Anchor(rect, anchor, anchor, anchoredPosition, size);
HorizontalLayoutGroup layout = container.GetComponent<HorizontalLayoutGroup>();
layout.spacing = spacing;
layout.childAlignment = alignment;
layout.childControlWidth = false;
layout.childControlHeight = false;
layout.childForceExpandWidth = false;
layout.childForceExpandHeight = false;
return container.transform;
}
private static Text CreateText(string name, RectTransform parent, string text, Font font, int fontSize, FontStyle style, TextAnchor alignment, Color color)
{
GameObject textObject = new GameObject(name, typeof(RectTransform), typeof(Text));
RectTransform rect = textObject.GetComponent<RectTransform>();
rect.SetParent(parent, false);
Text label = textObject.GetComponent<Text>();
label.text = text;
label.font = font;
label.fontSize = fontSize;
label.fontStyle = style;
label.alignment = alignment;
label.color = color;
label.horizontalOverflow = HorizontalWrapMode.Wrap;
label.verticalOverflow = VerticalWrapMode.Truncate;
return label;
}
private static Image CreateImage(string name, RectTransform parent, Color color)
{
GameObject imageObject = new GameObject(name, typeof(RectTransform), typeof(Image));
RectTransform rect = imageObject.GetComponent<RectTransform>();
rect.SetParent(parent, false);
Image image = imageObject.GetComponent<Image>();
image.color = color;
return image;
}
private static void Anchor(RectTransform rect, Vector2 anchorMin, Vector2 anchorMax, Vector2 anchoredPosition, Vector2 sizeDelta)
{
rect.anchorMin = anchorMin;
rect.anchorMax = anchorMax;
rect.pivot = new Vector2(0.5f, 0.5f);
rect.anchoredPosition = anchoredPosition;
rect.sizeDelta = sizeDelta;
}
private static void Stretch(RectTransform rect, float left, float top, float right, float bottom)
{
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.pivot = new Vector2(0.5f, 0.5f);
rect.offsetMin = new Vector2(left, bottom);
rect.offsetMax = new Vector2(-right, -top);
}
private static void ApplyFontToAllText(GameObject root, Font font)
{
Text[] texts = root.GetComponentsInChildren<Text>(true);
for (int i = 0; i < texts.Length; i++)
{
texts[i].font = font;
EditorUtility.SetDirty(texts[i]);
}
}
private static GameObject CreateCube(string name, Vector3 position, Vector3 scale, Material material)
{
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = name;
cube.transform.position = position;
cube.transform.localScale = scale;
SetMaterial(cube, material);
return cube;
}
private static GameObject CreatePlayer(Material material)
{
GameObject player = GameObject.CreatePrimitive(PrimitiveType.Capsule);
player.name = "Player";
player.transform.position = new Vector3(0f, 0.55f, -2.2f);
player.transform.localScale = new Vector3(0.75f, 1f, 0.75f);
SetMaterial(player, material);
CapsuleCollider capsule = player.GetComponent<CapsuleCollider>();
if (capsule != null)
{
Object.DestroyImmediate(capsule);
}
CharacterController controller = player.AddComponent<CharacterController>();
controller.height = 1.9f;
controller.radius = 0.38f;
controller.center = new Vector3(0f, 0.95f, 0f);
PlayerMovement movement = player.AddComponent<PlayerMovement>();
movement.moveSpeed = 5.2f;
return player;
}
private static void CreatePickup(string name, ItemData item, int amount, PrimitiveType primitiveType, Vector3 position, Vector3 scale, Material material, Font labelFont)
{
GameObject pickup = GameObject.CreatePrimitive(primitiveType);
pickup.name = name;
pickup.transform.position = position;
pickup.transform.localScale = scale;
SetMaterial(pickup, material);
Collider collider = pickup.GetComponent<Collider>();
if (collider != null)
{
collider.isTrigger = true;
}
ResourcePickup resourcePickup = pickup.AddComponent<ResourcePickup>();
resourcePickup.item = item;
resourcePickup.amount = amount;
resourcePickup.respawnSeconds = 10f;
CreateWorldLabel(name + " Label", item.itemName + " x" + amount, position + Vector3.up * 0.85f, labelFont, pickup.transform);
}
private static void CreateWorldLabel(string name, string text, Vector3 position, Font font, Transform parent = null)
{
GameObject labelObject = new GameObject(name);
labelObject.transform.position = position;
if (parent != null)
{
labelObject.transform.SetParent(parent, true);
}
TextMesh textMesh = labelObject.AddComponent<TextMesh>();
textMesh.text = text;
textMesh.font = font;
textMesh.fontSize = 34;
textMesh.characterSize = 0.055f;
textMesh.anchor = TextAnchor.MiddleCenter;
textMesh.alignment = TextAlignment.Center;
textMesh.color = Color.white;
MeshRenderer renderer = labelObject.GetComponent<MeshRenderer>();
if (renderer != null && font != null)
{
renderer.sharedMaterial = font.material;
}
labelObject.transform.rotation = Quaternion.Euler(60f, 0f, 0f);
}
private static void CreateResourceDecoration(string name, PrimitiveType primitiveType, Vector3 position, Vector3 scale, Material material)
{
GameObject resource = GameObject.CreatePrimitive(primitiveType);
resource.name = name;
resource.transform.position = position;
resource.transform.localScale = scale;
SetMaterial(resource, material);
}
private static void SetMaterial(GameObject gameObject, Material material)
{
Renderer renderer = gameObject.GetComponent<Renderer>();
if (renderer != null)
{
renderer.sharedMaterial = material;
}
}
private struct ItemDefinition
{
public readonly string assetName;
public readonly string itemId;
public readonly string itemName;
public readonly string description;
public readonly int maxStack;
public readonly bool isResource;
public readonly Color itemColor;
public ItemDefinition(string assetName, string itemId, string itemName, string description, int maxStack, bool isResource, Color itemColor)
{
this.assetName = assetName;
this.itemId = itemId;
this.itemName = itemName;
this.description = description;
this.maxStack = maxStack;
this.isResource = isResource;
this.itemColor = itemColor;
}
}
private struct RecipeIngredientDefinition
{
public readonly string itemKey;
public readonly int amount;
public RecipeIngredientDefinition(string itemKey, int amount)
{
this.itemKey = itemKey;
this.amount = amount;
}
}
private struct RecipeDefinition
{
public readonly string assetName;
public readonly string recipeId;
public readonly string recipeName;
public readonly string description;
public readonly string resultKey;
public readonly int resultAmount;
public readonly RecipeIngredientDefinition[] ingredients;
public RecipeDefinition(string assetName, string recipeId, string recipeName, string description, string resultKey, int resultAmount, RecipeIngredientDefinition[] ingredients)
{
this.assetName = assetName;
this.recipeId = recipeId;
this.recipeName = recipeName;
this.description = description;
this.resultKey = resultKey;
this.resultAmount = resultAmount;
this.ingredients = ingredients;
}
}
}