using System.Collections.Generic; using UnityEngine; namespace _Project.Scripts.LevelGenerating { public class ShellResult { public Transform Root; public List Views = new List(); // индекс совпадает с FloorData.Rooms } // ===================================================================== // Спавнит пол, потолок и стены из одного префаба-плоскости. // Для каждой комнаты создаётся объект Room_N_Тип с компонентом RoomView. // Материалы здесь НЕ назначаются: этим занимаются генераторы комнат (RoomTheme). // // Требования к префабу: // - Unity Plane (3D Object -> Plane): лежит в XZ, нормаль +Y, размер 10x10 при scale 1. // Если размер другой (например 1x1), поменяй planeBaseSize. Quad не подойдёт: у него нормаль -Z. // - Меш и Renderer на корне префаба. Коллайдеры на префабе игнорируются и заменяются на Box. // // Все плоскости видны только с одной стороны (внутрь комнаты): // стены смотрят внутрь, пол вверх, потолок вниз. // // НЕ ЗАБЫТЬ: сейчас сюда попадает и комната лифта. Позже у неё будет свой фиксированный префаб. // ===================================================================== public class ShellSpawner : MonoBehaviour { [SerializeField] private GameObject planePrefab; [SerializeField] private float planeBaseSize = 10f; [SerializeField] private float wallHeight = 3f; [SerializeField] private float colliderThickness = 0.2f; public ShellResult Spawn(FloorData floor) { if (planePrefab == null) { Debug.LogError("ShellSpawner: не назначен planePrefab"); return null; } var result = new ShellResult { Root = new GameObject($"Floor_{floor.Index}_Shell").transform }; // 1. Объект на каждую комнату + пол и потолок for (int i = 0; i < floor.Rooms.Count; i++) { var room = floor.Rooms[i]; var roomGo = new GameObject($"Room_{i}_{room.rt}"); roomGo.transform.SetParent(result.Root, false); var view = roomGo.AddComponent(); view.Data = room; view.Index = i; view.Height = wallHeight; result.Views.Add(view); var scale = new Vector3(view.SizeMeters.x / planeBaseSize, 1f, view.SizeMeters.z / planeBaseSize); Vector3 c = view.CenterMeters; // пол: нормаль вверх var floorGo = Make(roomGo.transform, "Floor", new Vector3(c.x, 0f, c.z), Quaternion.identity, scale, true); floorGo.layer = LayerMask.NameToLayer("Ground"); view.FloorRenderers.AddRange(floorGo.GetComponentsInChildren()); // потолок: перевёрнут, нормаль вниз var ceilingGo = Make(roomGo.transform, "Ceiling", new Vector3(c.x, wallHeight, c.z), Quaternion.Euler(180f, 0f, 0f), scale, false); view.CeilingRenderers.AddRange(ceilingGo.GetComponentsInChildren()); } // 2. Стены раскладываются по комнатам-владельцам foreach (var run in floor.Walls) { if (run.RoomIndex < 0 || run.RoomIndex >= result.Views.Count) { Debug.LogWarning($"Стена ссылается на несуществующую комнату {run.RoomIndex}"); continue; } SpawnWall(result.Views[run.RoomIndex], run); } return result; } private void SpawnWall(RoomView view, WallRun run) { float len = run.Length * LevelGrid.Module; float y = wallHeight / 2f; float sx = run.Start.x * LevelGrid.Module; float sz = run.Start.y * LevelGrid.Module; Vector3 pos; Quaternion rot; Vector3 scale; switch (run.Facing) { case WallFacing.ZP: // идёт вдоль X, нормаль +Z pos = new Vector3(sx + len / 2f, y, sz); rot = Quaternion.Euler(90f, 0f, 0f); scale = new Vector3(len / planeBaseSize, 1f, wallHeight / planeBaseSize); break; case WallFacing.ZN: // идёт вдоль X, нормаль -Z pos = new Vector3(sx + len / 2f, y, sz); rot = Quaternion.Euler(-90f, 0f, 0f); scale = new Vector3(len / planeBaseSize, 1f, wallHeight / planeBaseSize); break; case WallFacing.XP: // идёт вдоль Z, нормаль +X pos = new Vector3(sx, y, sz + len / 2f); rot = Quaternion.Euler(0f, 0f, -90f); scale = new Vector3(wallHeight / planeBaseSize, 1f, len / planeBaseSize); break; default: // XN: идёт вдоль Z, нормаль -X pos = new Vector3(sx, y, sz + len / 2f); rot = Quaternion.Euler(0f, 0f, 90f); scale = new Vector3(wallHeight / planeBaseSize, 1f, len / planeBaseSize); break; } var go = Make(view.transform, "Wall", pos, rot, scale, true); view.WallRenderers.AddRange(go.GetComponentsInChildren()); } private GameObject Make(Transform parent, string name, Vector3 pos, Quaternion rot, Vector3 scale, bool withCollider) { var go = Instantiate(planePrefab, pos, rot, parent); go.name = name; go.transform.localScale = scale; // коллайдеры префаба не используем: у плоскости нет толщины foreach (var c in go.GetComponents()) Destroy(c); if (withCollider) { // Box прячем за видимой стороной (локальный -Y), чтобы он не съедал место внутри комнаты var box = go.AddComponent(); box.size = new Vector3(planeBaseSize, colliderThickness, planeBaseSize); box.center = new Vector3(0f, -colliderThickness / 2f, 0f); } return go; } } }