313 lines
16 KiB
C#
313 lines
16 KiB
C#
|
|
using System.IO;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.Events;
|
||
|
|
using UnityEditor.SceneManagement;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.Events;
|
||
|
|
using UnityEngine.SceneManagement;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
public static class Lab6SceneBuilder
|
||
|
|
{
|
||
|
|
private const string ScriptsPath = "Assets/_Scripts";
|
||
|
|
private const string ScenesPath = "Assets/_Scenes";
|
||
|
|
private const string MaterialsPath = "Assets/_Materials";
|
||
|
|
private const string PrefabsPath = "Assets/_Prefabs";
|
||
|
|
private const string EditorPath = "Assets/Editor";
|
||
|
|
private const string ScenePath = "Assets/_Scenes/PuzzleScene.unity";
|
||
|
|
|
||
|
|
[MenuItem("Tools/Lab6/Create Full Puzzle Scene")]
|
||
|
|
public static void CreateFullPuzzleScene()
|
||
|
|
{
|
||
|
|
CreateProjectFolders();
|
||
|
|
|
||
|
|
// Builder создаёт сцену с нуля, чтобы после пункта меню не требовалась настройка инспектора.
|
||
|
|
Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||
|
|
scene.name = "PuzzleScene";
|
||
|
|
|
||
|
|
Material floorMaterial = CreateMaterial("M_Floor", new Color(0.45f, 0.50f, 0.46f));
|
||
|
|
Material wallMaterial = CreateMaterial("M_Wall", new Color(0.64f, 0.66f, 0.67f));
|
||
|
|
Material doorMaterial = CreateMaterial("M_Door", new Color(0.36f, 0.21f, 0.12f));
|
||
|
|
Material exitDoorMaterial = CreateMaterial("M_ExitDoor", new Color(0.12f, 0.28f, 0.42f));
|
||
|
|
Material keyMaterial = CreateMaterial("M_Key", new Color(1.00f, 0.78f, 0.16f));
|
||
|
|
Material gemMaterial = CreateMaterial("M_Gem", new Color(0.12f, 0.76f, 0.90f));
|
||
|
|
Material cogMaterial = CreateMaterial("M_Cog", new Color(0.62f, 0.62f, 0.62f));
|
||
|
|
Material highlightMaterial = CreateMaterial("M_Item_Highlight", new Color(1.00f, 1.00f, 0.35f));
|
||
|
|
Material dragMaterial = CreateMaterial("M_Item_Drag", new Color(1.00f, 0.50f, 0.18f));
|
||
|
|
Material inactiveMaterial = CreateMaterial("M_Item_Inactive", new Color(0.26f, 0.30f, 0.32f));
|
||
|
|
Material slotNormalMaterial = CreateMaterial("M_Slot_Normal", new Color(0.18f, 0.18f, 0.20f));
|
||
|
|
Material slotValidMaterial = CreateMaterial("M_Slot_Valid", new Color(0.12f, 0.75f, 0.25f));
|
||
|
|
Material slotInvalidMaterial = CreateMaterial("M_Slot_Invalid", new Color(0.85f, 0.12f, 0.10f));
|
||
|
|
Material slotSuccessMaterial = CreateMaterial("M_Slot_Success", new Color(0.10f, 0.45f, 1.00f));
|
||
|
|
|
||
|
|
CreateRoom(floorMaterial, wallMaterial);
|
||
|
|
Camera camera = CreateCameraAndLight();
|
||
|
|
CreateEventSystem();
|
||
|
|
|
||
|
|
Door keyDoor = CreateDoor("Door_Key", new Vector3(0f, 1.25f, -0.45f), new Vector3(2.25f, 2.5f, 0.28f), doorMaterial, Vector3.up * 3.2f);
|
||
|
|
Door exitDoor = CreateDoor("Door_Exit", new Vector3(0f, 1.25f, 5.85f), new Vector3(2.25f, 2.5f, 0.28f), exitDoorMaterial, Vector3.right * 2.8f);
|
||
|
|
|
||
|
|
PuzzleUI puzzleUI = CreateCanvasAndUI();
|
||
|
|
|
||
|
|
DraggableObject key = CreateItem("Key", PrimitiveType.Cube, ItemType.Key, new Vector3(-4.6f, 0.35f, -4.25f), new Vector3(0.9f, 0.45f, 0.45f), keyMaterial, highlightMaterial, dragMaterial);
|
||
|
|
DraggableObject gem = CreateItem("Gem", PrimitiveType.Sphere, ItemType.Gem, new Vector3(-3.7f, 0.42f, 1.9f), new Vector3(0.75f, 0.75f, 0.75f), gemMaterial, highlightMaterial, dragMaterial);
|
||
|
|
DraggableObject cog = CreateItem("Cog_False", PrimitiveType.Cylinder, ItemType.Cog, new Vector3(4.4f, 0.35f, -4.15f), new Vector3(0.72f, 0.24f, 0.72f), cogMaterial, highlightMaterial, dragMaterial);
|
||
|
|
|
||
|
|
gem.inactiveMaterial = inactiveMaterial;
|
||
|
|
|
||
|
|
Slot keySlot = CreateSlot("KeySlot", ItemType.Key, new Vector3(-1.4f, 0.08f, -4.25f), slotNormalMaterial, slotValidMaterial, slotInvalidMaterial, slotSuccessMaterial);
|
||
|
|
Slot gemSlot = CreateSlot("GemSlot", ItemType.Gem, new Vector3(3.15f, 0.08f, 2.15f), slotNormalMaterial, slotValidMaterial, slotInvalidMaterial, slotSuccessMaterial);
|
||
|
|
|
||
|
|
PuzzleManager manager = new GameObject("PuzzleManager").AddComponent<PuzzleManager>();
|
||
|
|
manager.puzzleUI = puzzleUI;
|
||
|
|
manager.gemItem = gem;
|
||
|
|
|
||
|
|
// Связываем слоты с менеджером и дверями через persistent UnityEvent.
|
||
|
|
AddPersistentListener(keySlot.onItemPlaced, manager.OnKeyPlaced);
|
||
|
|
AddPersistentListener(keySlot.onItemPlaced, keyDoor.Open);
|
||
|
|
AddPersistentListener(gemSlot.onItemPlaced, manager.OnGemPlaced);
|
||
|
|
AddPersistentListener(gemSlot.onItemPlaced, exitDoor.Open);
|
||
|
|
|
||
|
|
CreateWorldLabel("KEY", key.transform.position + new Vector3(0f, 0.75f, 0f), Color.black);
|
||
|
|
CreateWorldLabel("KEY SLOT", keySlot.transform.position + new Vector3(0f, 0.35f, 0f), Color.white);
|
||
|
|
CreateWorldLabel("GEM", gem.transform.position + new Vector3(0f, 0.85f, 0f), Color.black);
|
||
|
|
CreateWorldLabel("GEM SLOT", gemSlot.transform.position + new Vector3(0f, 0.35f, 0f), Color.white);
|
||
|
|
CreateWorldLabel("FALSE ITEM", cog.transform.position + new Vector3(0f, 0.75f, 0f), Color.black);
|
||
|
|
CreateWorldLabel("Door_Key", keyDoor.transform.position + new Vector3(0f, 1.7f, -0.25f), Color.white);
|
||
|
|
CreateWorldLabel("Door_Exit", exitDoor.transform.position + new Vector3(0f, 1.7f, -0.25f), Color.white);
|
||
|
|
|
||
|
|
Selection.activeObject = camera.gameObject;
|
||
|
|
EditorSceneManager.SaveScene(scene, ScenePath);
|
||
|
|
AssetDatabase.SaveAssets();
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
|
||
|
|
Debug.Log("Lab 6 puzzle scene created and saved: " + ScenePath);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateProjectFolders()
|
||
|
|
{
|
||
|
|
Directory.CreateDirectory(ScriptsPath);
|
||
|
|
Directory.CreateDirectory(ScenesPath);
|
||
|
|
Directory.CreateDirectory(MaterialsPath);
|
||
|
|
Directory.CreateDirectory(PrefabsPath);
|
||
|
|
Directory.CreateDirectory(EditorPath);
|
||
|
|
AssetDatabase.Refresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Material CreateMaterial(string materialName, Color color)
|
||
|
|
{
|
||
|
|
string path = MaterialsPath + "/" + materialName + ".mat";
|
||
|
|
Material material = AssetDatabase.LoadAssetAtPath<Material>(path);
|
||
|
|
|
||
|
|
if (material == null)
|
||
|
|
{
|
||
|
|
material = new Material(Shader.Find("Standard"));
|
||
|
|
AssetDatabase.CreateAsset(material, path);
|
||
|
|
}
|
||
|
|
|
||
|
|
material.color = color;
|
||
|
|
material.SetColor("_Color", color);
|
||
|
|
EditorUtility.SetDirty(material);
|
||
|
|
return material;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateRoom(Material floorMaterial, Material wallMaterial)
|
||
|
|
{
|
||
|
|
GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
||
|
|
floor.name = "Floor";
|
||
|
|
floor.transform.localScale = new Vector3(0.8f, 1f, 0.6f);
|
||
|
|
floor.GetComponent<Renderer>().sharedMaterial = floorMaterial;
|
||
|
|
|
||
|
|
CreateCube("Wall_Back", new Vector3(0f, 1.25f, 6.1f), new Vector3(16f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
CreateCube("Wall_Front", new Vector3(0f, 1.25f, -6.1f), new Vector3(16f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
CreateCube("Wall_Left", new Vector3(-8.1f, 1.25f, 0f), new Vector3(0.25f, 2.5f, 12.2f), wallMaterial);
|
||
|
|
CreateCube("Wall_Right", new Vector3(8.1f, 1.25f, 0f), new Vector3(0.25f, 2.5f, 12.2f), wallMaterial);
|
||
|
|
|
||
|
|
CreateCube("Partition_Left", new Vector3(-5.05f, 1.25f, -0.45f), new Vector3(5.9f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
CreateCube("Partition_Right", new Vector3(5.05f, 1.25f, -0.45f), new Vector3(5.9f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
CreateCube("ExitWall_Left", new Vector3(-5.05f, 1.25f, 5.85f), new Vector3(5.9f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
CreateCube("ExitWall_Right", new Vector3(5.05f, 1.25f, 5.85f), new Vector3(5.9f, 2.5f, 0.25f), wallMaterial);
|
||
|
|
|
||
|
|
CreateCube("WorkZone_Start", new Vector3(-3.2f, 0.025f, -4.2f), new Vector3(6.5f, 0.05f, 2.2f), floorMaterial);
|
||
|
|
CreateCube("WorkZone_Gem", new Vector3(0f, 0.025f, 2.1f), new Vector3(7.2f, 0.05f, 2.3f), floorMaterial);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Camera CreateCameraAndLight()
|
||
|
|
{
|
||
|
|
GameObject cameraObject = new GameObject("Main Camera");
|
||
|
|
Camera camera = cameraObject.AddComponent<Camera>();
|
||
|
|
cameraObject.tag = "MainCamera";
|
||
|
|
cameraObject.transform.position = new Vector3(0f, 9.5f, -7.5f);
|
||
|
|
cameraObject.transform.rotation = Quaternion.Euler(56f, 0f, 0f);
|
||
|
|
camera.orthographic = true;
|
||
|
|
camera.orthographicSize = 7.2f;
|
||
|
|
camera.clearFlags = CameraClearFlags.Skybox;
|
||
|
|
|
||
|
|
GameObject lightObject = new GameObject("Directional Light");
|
||
|
|
Light light = lightObject.AddComponent<Light>();
|
||
|
|
light.type = LightType.Directional;
|
||
|
|
light.intensity = 1.1f;
|
||
|
|
lightObject.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
|
||
|
|
|
||
|
|
return camera;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateEventSystem()
|
||
|
|
{
|
||
|
|
GameObject eventSystem = new GameObject("EventSystem");
|
||
|
|
eventSystem.AddComponent<UnityEngine.EventSystems.EventSystem>();
|
||
|
|
eventSystem.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static PuzzleUI CreateCanvasAndUI()
|
||
|
|
{
|
||
|
|
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);
|
||
|
|
canvasObject.AddComponent<GraphicRaycaster>();
|
||
|
|
|
||
|
|
PuzzleUI puzzleUI = canvasObject.AddComponent<PuzzleUI>();
|
||
|
|
|
||
|
|
Font font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
|
||
|
|
puzzleUI.objectiveText = CreateUIText(canvasObject.transform, "ObjectiveText", "Перетащите ключ в слот", font, 24, TextAnchor.UpperLeft, new Vector2(18f, -72f), new Vector2(620f, 44f));
|
||
|
|
puzzleUI.solvedText = CreateUIText(canvasObject.transform, "SolvedText", "Пазл решён!", font, 34, TextAnchor.MiddleCenter, new Vector2(0f, -12f), new Vector2(420f, 70f));
|
||
|
|
puzzleUI.debugText = CreateUIText(canvasObject.transform, "DebugText", "Key placed: false\nGem placed: false\nPuzzle solved: false", font, 18, TextAnchor.LowerLeft, new Vector2(18f, 18f), new Vector2(360f, 96f));
|
||
|
|
puzzleUI.messageText = CreateUIText(canvasObject.transform, "MessageText", "", font, 22, TextAnchor.UpperLeft, new Vector2(18f, -232f), new Vector2(620f, 40f));
|
||
|
|
|
||
|
|
Text title = CreateUIText(canvasObject.transform, "TitleText", "Лабораторная работа №6: Пазлы и логические игры", font, 26, TextAnchor.UpperLeft, new Vector2(18f, -18f), new Vector2(860f, 42f));
|
||
|
|
title.fontStyle = FontStyle.Bold;
|
||
|
|
|
||
|
|
CreateUIText(canvasObject.transform, "HintText", "ЛКМ — взять и перетащить предмет\nОтпустите ЛКМ над подходящим слотом", font, 20, TextAnchor.UpperLeft, new Vector2(18f, -126f), new Vector2(620f, 72f));
|
||
|
|
|
||
|
|
puzzleUI.solvedText.color = new Color(0.1f, 0.85f, 0.2f);
|
||
|
|
puzzleUI.solvedText.fontStyle = FontStyle.Bold;
|
||
|
|
puzzleUI.solvedText.gameObject.SetActive(false);
|
||
|
|
|
||
|
|
return puzzleUI;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Text CreateUIText(Transform parent, string name, string value, Font font, int size, TextAnchor anchor, Vector2 anchoredPosition, Vector2 sizeDelta)
|
||
|
|
{
|
||
|
|
GameObject textObject = new GameObject(name);
|
||
|
|
textObject.transform.SetParent(parent, false);
|
||
|
|
|
||
|
|
Text text = textObject.AddComponent<Text>();
|
||
|
|
text.text = value;
|
||
|
|
text.font = font;
|
||
|
|
text.fontSize = size;
|
||
|
|
text.alignment = anchor;
|
||
|
|
text.color = Color.white;
|
||
|
|
text.raycastTarget = false;
|
||
|
|
|
||
|
|
RectTransform rect = textObject.GetComponent<RectTransform>();
|
||
|
|
rect.sizeDelta = sizeDelta;
|
||
|
|
|
||
|
|
if (anchor == TextAnchor.LowerLeft)
|
||
|
|
{
|
||
|
|
rect.anchorMin = new Vector2(0f, 0f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 0f);
|
||
|
|
rect.pivot = new Vector2(0f, 0f);
|
||
|
|
}
|
||
|
|
else if (anchor == TextAnchor.MiddleCenter)
|
||
|
|
{
|
||
|
|
rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||
|
|
rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||
|
|
rect.pivot = new Vector2(0.5f, 0.5f);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
rect.anchorMin = new Vector2(0f, 1f);
|
||
|
|
rect.anchorMax = new Vector2(0f, 1f);
|
||
|
|
rect.pivot = new Vector2(0f, 1f);
|
||
|
|
}
|
||
|
|
|
||
|
|
rect.anchoredPosition = anchoredPosition;
|
||
|
|
return text;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Door CreateDoor(string name, Vector3 position, Vector3 scale, Material material, Vector3 openOffset)
|
||
|
|
{
|
||
|
|
GameObject doorObject = CreateCube(name, position, scale, material);
|
||
|
|
Door door = doorObject.AddComponent<Door>();
|
||
|
|
door.openOffset = openOffset;
|
||
|
|
door.openSpeed = 2.35f;
|
||
|
|
return door;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DraggableObject CreateItem(string name, PrimitiveType primitiveType, ItemType itemType, Vector3 position, Vector3 scale, Material normalMaterial, Material highlightMaterial, Material dragMaterial)
|
||
|
|
{
|
||
|
|
GameObject itemObject = GameObject.CreatePrimitive(primitiveType);
|
||
|
|
itemObject.name = name;
|
||
|
|
itemObject.transform.position = position;
|
||
|
|
itemObject.transform.localScale = scale;
|
||
|
|
itemObject.GetComponent<Renderer>().sharedMaterial = normalMaterial;
|
||
|
|
|
||
|
|
DraggableObject draggable = itemObject.AddComponent<DraggableObject>();
|
||
|
|
draggable.itemType = itemType;
|
||
|
|
draggable.normalMaterial = normalMaterial;
|
||
|
|
draggable.highlightMaterial = highlightMaterial;
|
||
|
|
draggable.dragMaterial = dragMaterial;
|
||
|
|
draggable.startPosition = position;
|
||
|
|
draggable.snapDistance = 1.25f;
|
||
|
|
draggable.dragLift = 0.35f;
|
||
|
|
|
||
|
|
return draggable;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Slot CreateSlot(string name, ItemType itemType, Vector3 position, Material normalMaterial, Material validMaterial, Material invalidMaterial, Material successMaterial)
|
||
|
|
{
|
||
|
|
GameObject slotObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
||
|
|
slotObject.name = name;
|
||
|
|
slotObject.transform.position = position;
|
||
|
|
slotObject.transform.localScale = new Vector3(1.15f, 0.08f, 1.15f);
|
||
|
|
slotObject.GetComponent<Renderer>().sharedMaterial = normalMaterial;
|
||
|
|
|
||
|
|
GameObject snapPoint = new GameObject("SnapPoint");
|
||
|
|
snapPoint.transform.SetParent(slotObject.transform, false);
|
||
|
|
snapPoint.transform.localPosition = new Vector3(0f, 4.55f, 0f);
|
||
|
|
|
||
|
|
Slot slot = slotObject.AddComponent<Slot>();
|
||
|
|
slot.requiredItemType = itemType;
|
||
|
|
slot.normalMaterial = normalMaterial;
|
||
|
|
slot.validPreviewMaterial = validMaterial;
|
||
|
|
slot.invalidPreviewMaterial = invalidMaterial;
|
||
|
|
slot.successMaterial = successMaterial;
|
||
|
|
slot.snapPoint = snapPoint.transform;
|
||
|
|
|
||
|
|
return slot;
|
||
|
|
}
|
||
|
|
|
||
|
|
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;
|
||
|
|
cube.GetComponent<Renderer>().sharedMaterial = material;
|
||
|
|
return cube;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void CreateWorldLabel(string text, Vector3 position, Color color)
|
||
|
|
{
|
||
|
|
GameObject labelObject = new GameObject("Label_" + text.Replace(" ", "_"));
|
||
|
|
labelObject.transform.position = position;
|
||
|
|
labelObject.transform.rotation = Quaternion.Euler(65f, 0f, 0f);
|
||
|
|
|
||
|
|
TextMesh label = labelObject.AddComponent<TextMesh>();
|
||
|
|
label.text = text;
|
||
|
|
label.fontSize = 48;
|
||
|
|
label.characterSize = 0.08f;
|
||
|
|
label.anchor = TextAnchor.MiddleCenter;
|
||
|
|
label.alignment = TextAlignment.Center;
|
||
|
|
label.color = color;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AddPersistentListener(UnityEvent unityEvent, UnityAction action)
|
||
|
|
{
|
||
|
|
UnityEventTools.AddPersistentListener(unityEvent, action);
|
||
|
|
}
|
||
|
|
}
|