начал сам писать генерацию
This commit is contained in:
parent
3ec3254efd
commit
458e0cc98b
18
Assets/_Project/Scripts/LevelGenerating/LevelManager.cs
Normal file
18
Assets/_Project/Scripts/LevelGenerating/LevelManager.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using _Project.Scripts.Utilities;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
public class LevelManager : MonoSingleton<LevelManager>
|
||||
{
|
||||
public static List<Room> Rooms = new List<Room>();
|
||||
[SerializeField] private readonly int curFloor;
|
||||
|
||||
void AddRoom(ref Room room)
|
||||
{
|
||||
Rooms.Add(room);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4998e3ff3051468998a4d4d904be1956
|
||||
timeCreated: 1790353372
|
||||
@ -1,272 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ProceduralLevelGenerator : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки генерации")]
|
||||
public int numberOfRooms = 8;
|
||||
public Vector2Int minRoomSize = new Vector2Int(5, 5);
|
||||
public Vector2Int maxRoomSize = new Vector2Int(12, 12);
|
||||
public float tileSize = 2f;
|
||||
public float wallHeight = 8f; // Ты указал высоту 8
|
||||
|
||||
[Header("Префабы строительных блоков")]
|
||||
public GameObject floorPrefab;
|
||||
public GameObject wallPrefab;
|
||||
|
||||
// Структура клетки
|
||||
private class Cell
|
||||
{
|
||||
public int roomID;
|
||||
public int floorHeight;
|
||||
}
|
||||
|
||||
// Структура для прохода (двери)
|
||||
private class Passage
|
||||
{
|
||||
public Vector2Int cellA; // Клетка из одной комнаты
|
||||
public Vector2Int cellB; // Клетка из другой комнаты
|
||||
}
|
||||
|
||||
private Dictionary<Vector2Int, Cell> levelMap = new Dictionary<Vector2Int, Cell>();
|
||||
private List<RectInt> rooms = new List<RectInt>();
|
||||
|
||||
// Список всех прорубленных проходов
|
||||
private List<Passage> passages = new List<Passage>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
GenerateLayout();
|
||||
ApplyVerticality();
|
||||
BuildMesh();
|
||||
}
|
||||
|
||||
void GenerateLayout()
|
||||
{
|
||||
// --- ШАГ 1: Стартовая комната (10x10) ---
|
||||
int startWidth = 10;
|
||||
int startHeight = 10;
|
||||
int startX = -startWidth / 2;
|
||||
int startY = -startHeight / 2;
|
||||
|
||||
RectInt startRoom = new RectInt(startX, startY, startWidth, startHeight);
|
||||
rooms.Add(startRoom);
|
||||
SaveRoomToMap(startRoom, 0);
|
||||
|
||||
// --- ШАГ 2: Первая комната с врагами ---
|
||||
int firstEnemyWidth = Random.Range(minRoomSize.x, maxRoomSize.x);
|
||||
int firstEnemyHeight = Random.Range(minRoomSize.y, maxRoomSize.y);
|
||||
|
||||
int firstEnemyX = startRoom.x + Random.Range(-firstEnemyWidth / 2, startRoom.width - firstEnemyWidth / 2);
|
||||
int firstEnemyY = startRoom.yMax;
|
||||
|
||||
RectInt firstEnemyRoom = new RectInt(firstEnemyX, firstEnemyY, firstEnemyWidth, firstEnemyHeight);
|
||||
rooms.Add(firstEnemyRoom);
|
||||
SaveRoomToMap(firstEnemyRoom, 1);
|
||||
|
||||
// ПРОРУБАЕМ ПРОХОД между стартовой и первой вражеской комнатой
|
||||
CreatePassage(startRoom, firstEnemyRoom);
|
||||
|
||||
// --- ШАГ 3: Остальные комнаты ---
|
||||
for (int i = 2; i < numberOfRooms; i++)
|
||||
{
|
||||
bool roomPlaced = false;
|
||||
int attempts = 0;
|
||||
|
||||
while (!roomPlaced && attempts < 50)
|
||||
{
|
||||
attempts++;
|
||||
|
||||
// Выбираем случайную комнату (кроме стартовой)
|
||||
int baseRoomIndex = Random.Range(1, rooms.Count);
|
||||
RectInt baseRoom = rooms[baseRoomIndex];
|
||||
|
||||
int newWidth = Random.Range(minRoomSize.x, maxRoomSize.x);
|
||||
int newHeight = Random.Range(minRoomSize.y, maxRoomSize.y);
|
||||
|
||||
int side = Random.Range(0, 4);
|
||||
RectInt newRoom = new RectInt();
|
||||
|
||||
if (side == 0) // Север
|
||||
newRoom = new RectInt(baseRoom.x + Random.Range(-newWidth/2, baseRoom.width - newWidth/2), baseRoom.yMax, newWidth, newHeight);
|
||||
else if (side == 1) // Юг
|
||||
newRoom = new RectInt(baseRoom.x + Random.Range(-newWidth/2, baseRoom.width - newWidth/2), baseRoom.yMin - newHeight, newWidth, newHeight);
|
||||
else if (side == 2) // Восток
|
||||
newRoom = new RectInt(baseRoom.xMax, baseRoom.y + Random.Range(-newHeight/2, baseRoom.height - newHeight/2), newWidth, newHeight);
|
||||
else if (side == 3) // Запад
|
||||
newRoom = new RectInt(baseRoom.xMin - newWidth, baseRoom.y + Random.Range(-newHeight/2, baseRoom.height - newHeight/2), newWidth, newHeight);
|
||||
|
||||
if (!CheckOverlap(newRoom))
|
||||
{
|
||||
rooms.Add(newRoom);
|
||||
SaveRoomToMap(newRoom, i);
|
||||
|
||||
// ПРОРУБАЕМ ПРОХОД между базовой комнатой и новой
|
||||
CreatePassage(baseRoom, newRoom);
|
||||
|
||||
roomPlaced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Выбирает одну случайную общую стену между двумя комнатами и делает там проход
|
||||
void CreatePassage(RectInt room1, RectInt room2)
|
||||
{
|
||||
List<Vector2Int[]> potentialPassages = new List<Vector2Int[]>();
|
||||
|
||||
// Проходим по всем клеткам первой комнаты
|
||||
for (int x = room1.xMin; x < room1.xMax; x++)
|
||||
{
|
||||
for (int y = room1.yMin; y < room1.yMax; y++)
|
||||
{
|
||||
Vector2Int cellA = new Vector2Int(x, y);
|
||||
Vector2Int[] dirs = { Vector2Int.up, Vector2Int.down, Vector2Int.left, Vector2Int.right };
|
||||
|
||||
// Проверяем соседей
|
||||
foreach (var dir in dirs)
|
||||
{
|
||||
Vector2Int cellB = cellA + dir;
|
||||
// Если соседняя клетка находится во второй комнате — это потенциальная дверь!
|
||||
if (cellB.x >= room2.xMin && cellB.x < room2.xMax &&
|
||||
cellB.y >= room2.yMin && cellB.y < room2.yMax)
|
||||
{
|
||||
potentialPassages.Add(new Vector2Int[] { cellA, cellB });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если нашли точки соприкосновения, берем ОДНУ случайную и делаем там проход
|
||||
if (potentialPassages.Count > 0)
|
||||
{
|
||||
Vector2Int[] chosen = potentialPassages[Random.Range(0, potentialPassages.Count)];
|
||||
passages.Add(new Passage { cellA = chosen[0], cellB = chosen[1] });
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyVerticality()
|
||||
{
|
||||
for (int i = 1; i < rooms.Count; i++)
|
||||
{
|
||||
RectInt room = rooms[i];
|
||||
|
||||
if (Random.value > 0.5f)
|
||||
{
|
||||
int platformWidth = room.width / 2;
|
||||
int platformHeight = room.height / 2;
|
||||
int offsetX = Random.Range(1, room.width - platformWidth - 1);
|
||||
int offsetY = Random.Range(1, room.height - platformHeight - 1);
|
||||
|
||||
for (int x = 0; x < platformWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < platformHeight; y++)
|
||||
{
|
||||
Vector2Int pos = new Vector2Int(room.x + offsetX + x, room.y + offsetY + y);
|
||||
if (levelMap.ContainsKey(pos))
|
||||
{
|
||||
levelMap[pos].floorHeight = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BuildMesh()
|
||||
{
|
||||
Vector2Int[] directions = { Vector2Int.up, Vector2Int.down, Vector2Int.right, Vector2Int.left };
|
||||
float[] wallRotations = { 0f, 180f, 90f, -90f };
|
||||
|
||||
foreach (var kvp in levelMap)
|
||||
{
|
||||
Vector2Int pos = kvp.Key;
|
||||
Cell cell = kvp.Value;
|
||||
|
||||
// Вычисляем высоту (чтобы балконы были логичной высоты, умножаем на половину высоты стены)
|
||||
float worldHeight = cell.floorHeight * (wallHeight * 0.5f);
|
||||
|
||||
Vector3 floorPos = new Vector3(pos.x * tileSize, worldHeight, pos.y * tileSize);
|
||||
GameObject floor = Instantiate(floorPrefab, floorPos, Quaternion.identity, this.transform);
|
||||
floor.name = $"Floor_{pos.x}_{pos.y}";
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector2Int neighborPos = pos + directions[i];
|
||||
bool needsWall = false;
|
||||
|
||||
if (!levelMap.ContainsKey(neighborPos))
|
||||
{
|
||||
// Соседа нет -> глухая внешняя стена
|
||||
needsWall = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cell neighborCell = levelMap[neighborPos];
|
||||
|
||||
if (neighborCell.roomID != cell.roomID)
|
||||
{
|
||||
// Это граница двух комнат. Проверяем, есть ли здесь проход.
|
||||
if (IsPassage(pos, neighborPos))
|
||||
{
|
||||
needsWall = false; // ПРОПУСКАЕМ СТЕНУ (оставляем дыру для двери)
|
||||
}
|
||||
else
|
||||
{
|
||||
needsWall = true; // Ставим стену
|
||||
}
|
||||
}
|
||||
else if (neighborCell.floorHeight > cell.floorHeight)
|
||||
{
|
||||
// Сосед выше, нужна стена-ступенька внутри комнаты
|
||||
needsWall = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsWall)
|
||||
{
|
||||
Vector3 wallPos = floorPos + new Vector3(directions[i].x * (tileSize / 2), wallHeight / 2, directions[i].y * (tileSize / 2));
|
||||
GameObject wall = Instantiate(wallPrefab, wallPos, Quaternion.Euler(0, wallRotations[i], 0), this.transform);
|
||||
wall.name = $"Wall_{pos.x}_{pos.y}_{i}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяет, является ли граница между двумя клетками проходом
|
||||
bool IsPassage(Vector2Int a, Vector2Int b)
|
||||
{
|
||||
foreach (var p in passages)
|
||||
{
|
||||
if ((p.cellA == a && p.cellB == b) || (p.cellA == b && p.cellB == a))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SaveRoomToMap(RectInt room, int id)
|
||||
{
|
||||
for (int x = room.xMin; x < room.xMax; x++)
|
||||
{
|
||||
for (int y = room.yMin; y < room.yMax; y++)
|
||||
{
|
||||
levelMap[new Vector2Int(x, y)] = new Cell { roomID = id, floorHeight = 0 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckOverlap(RectInt newRoom)
|
||||
{
|
||||
foreach (RectInt room in rooms)
|
||||
{
|
||||
if (newRoom.xMin < room.xMax && newRoom.xMax > room.xMin &&
|
||||
newRoom.yMin < room.yMax && newRoom.yMax > room.yMin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05c6005aaf0a4e4ab66fd5a02bcde0e1
|
||||
timeCreated: 1790254468
|
||||
25
Assets/_Project/Scripts/LevelGenerating/Room.cs
Normal file
25
Assets/_Project/Scripts/LevelGenerating/Room.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
public class Room
|
||||
{
|
||||
public Room(Vector2 position, int wigth, int length, RoomType rt)
|
||||
{
|
||||
Position = position;
|
||||
Wigth = wigth;
|
||||
Length = length;
|
||||
this.rt = rt;
|
||||
}
|
||||
|
||||
public Room()
|
||||
{
|
||||
}
|
||||
|
||||
public int Wigth { get; set; }
|
||||
public int Length { get; set; }
|
||||
public Vector2 Position;
|
||||
public RoomType rt { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
3
Assets/_Project/Scripts/LevelGenerating/Room.cs.meta
Normal file
3
Assets/_Project/Scripts/LevelGenerating/Room.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af744d57618340969ba8690e9dc177ff
|
||||
timeCreated: 1790352651
|
||||
15
Assets/_Project/Scripts/LevelGenerating/RoomType.cs
Normal file
15
Assets/_Project/Scripts/LevelGenerating/RoomType.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
public enum RoomType
|
||||
{
|
||||
Start,
|
||||
Lift,
|
||||
Laboratory,
|
||||
Boss,
|
||||
Office,
|
||||
Penthouse,
|
||||
Storage,
|
||||
SwitchboardRoom,
|
||||
BoilerRoom
|
||||
}
|
||||
}
|
||||
3
Assets/_Project/Scripts/LevelGenerating/RoomType.cs.meta
Normal file
3
Assets/_Project/Scripts/LevelGenerating/RoomType.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c424d1e4c364d2f961f8d2fdd959c51
|
||||
timeCreated: 1790352839
|
||||
44
Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs
Normal file
44
Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
public class WallsGenerator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private int roomCountMin;
|
||||
[SerializeField] private int roomCountMax;
|
||||
[SerializeField] private int floorsCount;
|
||||
[SerializeField] private int lengthWallMin;
|
||||
[SerializeField] private int lengthWallMax;
|
||||
[SerializeField] private int lengthStartRoomA;
|
||||
[SerializeField] private int lengthStartRoomB;
|
||||
[SerializeField] private int lengthFloorMax;
|
||||
[SerializeField] private int lengthFloorMin;
|
||||
|
||||
private int RoomCount;
|
||||
private LevelManager levelManager;
|
||||
|
||||
void Start()
|
||||
{
|
||||
levelManager = LevelManager.Instance;
|
||||
}
|
||||
|
||||
void GenerateRooms()
|
||||
{
|
||||
RoomCount = Random.Range(roomCountMin, roomCountMax);
|
||||
LevelManager.Rooms.Add(new Room(Vector2.zero,lengthStartRoomA, lengthStartRoomB,RoomType.Start));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CreateRoom()
|
||||
{
|
||||
int a = Random.Range(lengthWallMin, lengthWallMax);
|
||||
int b = Random.Range(lengthWallMin, lengthWallMax);
|
||||
Room room = new Room();
|
||||
room.Length = a;
|
||||
room.Wigth = b;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2197e0e0f0e04dbaa19b690f03f10300
|
||||
timeCreated: 1790353086
|
||||
Loading…
Reference in New Issue
Block a user