Souljack/Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs

484 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
namespace _Project.Scripts.LevelGenerating
{
public class WallsGenerator : MonoBehaviour
{
[SerializeField] private int floorsCount;
[SerializeField] private int lengthWallMin;
[SerializeField] private int lengthWallMax;
[SerializeField] private int lengthStartRoom;
[SerializeField] private int lengthFloor;
[SerializeField] private int corridorLength;
[SerializeField] private int corridorWigth;
[SerializeField] private GameObject GameObjectA;
[SerializeField] private GameObject GameObjectB;
private int RoomCount;
private LevelManager levelManager;
void Start()
{
levelManager = LevelManager.Instance;
GenerateFloor();
}
void GenerateFloor()
{
CreateStartRoom();
Instantiate(GameObjectA, new Vector3(0,-1,0), Quaternion.identity);
foreach (var room in levelManager.GetRooms())
{
float x = room.Position.x;
float z = room.Position.y; // В Vector2 ось Y отвечает за Z в 3D пространстве Unity
float length = room.Length;
float width = room.Width;
// 4 угла комнаты:
// 1. Нижний левый (X, Z)
Instantiate(GameObjectB, new Vector3(x, 0, z), Quaternion.identity);
// 2. Нижний правый (X + Length, Z)
Instantiate(GameObjectB, new Vector3(x + length, 0, z), Quaternion.identity);
// 3. Верхний правый (X + Length, Z + Width)
Instantiate(GameObjectB, new Vector3(x + length, 0, z + width), Quaternion.identity);
// 4. Верхний левый (X, Z + Width)
Instantiate(GameObjectB, new Vector3(x, 0, z + width), Quaternion.identity);
}
}
Room CreateCorridor(Vector2 posRoom, int Length, int Wigth, ExitsInRoomType exitType)
{
Vector2 corridorPos = Vector2.zero;
int cLength = 0;
int cWidth = 0;
EntranceToRoomType entranceToRoomType = EntranceToRoomType.Null;
List<ExitsInRoomType> exitsInRoomType = new List<ExitsInRoomType>();
switch (exitType)
{
// Выход направо (+X)
case ExitsInRoomType.XAxisP:
// Начинается у правой стены комнаты (posRoom.x + Length)
// Центрируем коридор по высоте/оси Z: смещаем на половину разницы ширин
exitsInRoomType.Add (ExitsInRoomType.XAxisP);
entranceToRoomType = EntranceToRoomType.XAxisN;
corridorPos = new Vector2(
posRoom.x + Length,
posRoom.y + (Wigth - corridorWigth) / 2f
);
cLength = corridorLength;
cWidth = corridorWigth;
break;
// Выход налево (-X)
case ExitsInRoomType.XAxisN:
// Начинается слева от комнаты, отступая на длину коридора
exitsInRoomType .Add (ExitsInRoomType.XAxisN);
entranceToRoomType = EntranceToRoomType.XAxisP;
corridorPos = new Vector2(
posRoom.x - corridorLength,
posRoom.y + (Wigth - corridorWigth) / 2f
);
cLength = corridorLength;
cWidth = corridorWigth;
break;
// Выход вперед/вверх (+Z / в Vector2 это Y)
case ExitsInRoomType.ZAxisP:
entranceToRoomType = EntranceToRoomType.ZAxisN;
exitsInRoomType.Add (ExitsInRoomType.ZAxisP);
// Начинается у верхней стены комнаты (posRoom.y + Wigth)
// Центрируем коридор по горизонтали/оси X:
corridorPos = new Vector2(
posRoom.x + (Length - corridorWigth) / 2f,
posRoom.y + Wigth
);
// По оси X коридор узкий, по оси Z — длинный:
cLength = corridorWigth;
cWidth = corridorLength;
break;
// Выход назад/вниз (-Z / в Vector2 это Y)
case ExitsInRoomType.ZAxisN:
entranceToRoomType = EntranceToRoomType.ZAxisP;
exitsInRoomType.Add (ExitsInRoomType.ZAxisN);
// Начинается ниже комнаты, отступая на длину коридора
corridorPos = new Vector2(
posRoom.x + (Length - corridorWigth) / 2f,
posRoom.y - corridorLength
);
cLength = corridorWigth;
cWidth = corridorLength;
break;
}
// Создаем коридор как отдельную комнату
Room corridor = new Room(corridorPos,
cLength, cWidth, RoomType.Corridor,false,
EntranceToRoomType.Null,exitsInRoomType);
LevelManager.Rooms.Add(corridor);
// // Визуализация коридора (расставляем маркеры по углам коридора для наглядности)
// Instantiate(GameObjectB, new Vector3(corridorPos.x, 0, corridorPos.y), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(corridorPos.x + cLength, 0, corridorPos.y), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(corridorPos.x + cLength, 0, corridorPos.y + cWidth), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(corridorPos.x, 0, corridorPos.y + cWidth), Quaternion.identity);
return corridor;
}
void TryPlaceRoom(Room prevRoom,ExitsInRoomType exitForCor)
{
if (prevRoom == null || prevRoom.exits.Count == 0) return;
// if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2),
// exitForCor))
// {
// Room newRoom = GenerateRandomRoom();
// newRoom.Position = new Vector2();
// newRoom.rt = RoomType.Undefined;
// newRoom.entrance = EntranceToRoomType.XAxisP;
// newRoom.exits = new List<ExitsInRoomType>();
// if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2),
// newRoom.Length, newRoom.Width, exitForCor))
// {
// newRoom.isWallable = false;
// levelManager.AddRoom(newRoom);
// CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor);
// }
// else
// {
// newRoom.isWallable = true;
// EditRoomFoFitting(newRoom);
// levelManager.AddRoom(newRoom);
// CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor);
// }
// }
Room newRoom = GenerateRandomRoom();
newRoom.rt = RoomType.Undefined;
newRoom.exits = new List<ExitsInRoomType>();
Vector2 newRoomPos = Vector2.zero;
// Вычисляем позицию новой комнаты и откуда в нее входит коридор
switch (exitForCor)
{
// Если вышли направо, новая комната слева получает вход (-X)
case ExitsInRoomType.XAxisP:
newRoom.entrance = EntranceToRoomType.XAxisN;
newRoomPos = new Vector2(
prevRoom.Position.x + prevRoom.Length + corridorLength, // Сдвигаем на ширину пред. комнаты и коридор
prevRoom.Position.y + (prevRoom.Width / 2f) - (newRoom.Width / 2f) // Центрируем по оси Y (Z)
);
break;
// Если вышли налево
case ExitsInRoomType.XAxisN:
newRoom.entrance = EntranceToRoomType.XAxisP;
newRoomPos = new Vector2(
prevRoom.Position.x - corridorLength - newRoom.Length, // Отступаем влево на коридор и ширину новой комнаты
prevRoom.Position.y + (prevRoom.Width / 2f) - (newRoom.Width / 2f)
);
break;
// Если вышли вверх (+Z/Y)
case ExitsInRoomType.ZAxisP:
newRoom.entrance = EntranceToRoomType.ZAxisN;
newRoomPos = new Vector2(
prevRoom.Position.x + (prevRoom.Length / 2f) - (newRoom.Length / 2f), // Центрируем по оси X
prevRoom.Position.y + prevRoom.Width + corridorLength
);
break;
// Если вышли вниз (-Z/Y)
case ExitsInRoomType.ZAxisN:
newRoom.entrance = EntranceToRoomType.ZAxisP;
newRoomPos = new Vector2(
prevRoom.Position.x + (prevRoom.Length / 2f) - (newRoom.Length / 2f),
prevRoom.Position.y - corridorLength - newRoom.Width
);
break;
}
// Устанавливаем просчитанную позицию
newRoom.Position = newRoomPos;
// Проверяем, помещается ли комната с ее реальными размерами
if (IsRoomCanFit(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor))
{
newRoom.isWallable = false;
levelManager.AddRoom(newRoom);
CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor);
}
else
{
newRoom.isWallable = true;
EditRoomFoFitting(newRoom); // Подгоняем размеры под границы карты
// Проверяем, вмещается ли хотя бы комната минимального размера после обрезки
if (newRoom.Length >= lengthWallMin && newRoom.Width >= lengthWallMin)
{
levelManager.AddRoom(newRoom);
CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor);
}
else
{
// Места не хватило даже для минимальной комнаты.
// Отменяем создание этой комнаты и завершаем ветку.
// При необходимости здесь можно удалить сгенерированный к ней коридор.
return;
}
}
if (exitForCor != ExitsInRoomType.XAxisN) TryPlaceRoom(newRoom, ExitsInRoomType.XAxisP);
// 2. Влево (-X): идем, только если TryPlaceRoomНЕ слеа (XAxisP)
if (exitForCor != ExitsInRoomType.XAxisP) TryPlaceRoom(newRoom, ExitsInRoomType.XAxisN);
// 3. Вверх/Вперед (+Z): идем, только TryPlaceRoomпришли НЕ верху (ZAxisN)
if (exitForCor != ExitsInRoomType.ZAxisN) TryPlaceRoom(newRoom, ExitsInRoomType.ZAxisP);
// 4. Вниз/Назад (-Z): идем, только если TryPlaceRoomишли НЕ сниу (ZAxisP)
if (exitForCor != ExitsInRoomType.ZAxisP) TryPlaceRoom(newRoom, ExitsInRoomType.ZAxisN);
}
private void EditRoomFoFitting(Room room)
{
if (lengthFloor - room.Position.x + room.Length <= 0)
{
room.Length = lengthFloor - Convert.ToInt32(room.Position.x);
}
if (lengthFloor - room.Position.y + room.Width <= 0)
{
room.Width = lengthFloor - Convert.ToInt32(room.Position.y);
}
if (room.Position.x < 0)
{
room.Position.x = 0;
}
if (room.Position.y < 0)
{
room.Position.y = 0;
}
}
private bool IsRoomCanFit(Vector2 vector2, ExitsInRoomType exitForCor)
{
switch (exitForCor)
{
case ExitsInRoomType.XAxisP:
{
if ((lengthFloor - (vector2.x + lengthWallMin) >= 0)
&& (lengthFloor - (vector2.y + lengthWallMin / 2f) >= 0)
&& (vector2.y - lengthWallMin/ 2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.XAxisN:
{
if ((vector2.x - lengthWallMin >= 0)
&& (lengthFloor - (vector2.y + lengthWallMin / 2f) >= 0)
&& (vector2.y - lengthWallMin/ 2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.ZAxisP:
{
if ((lengthFloor - (vector2.y + lengthWallMin) >= 0)
&& (lengthFloor - (vector2.x + lengthWallMin / 2f) >= 0)
&& (vector2.x - lengthWallMin/ 2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.ZAxisN:
{
if ((vector2.y - lengthWallMin >= 0)
&& (lengthFloor - (vector2.x + lengthWallMin / 2f) >= 0)
&& (vector2.x - lengthWallMin/ 2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.Null:
default:
return false;
}
}
private bool IsRoomCanFit(Vector2 vector2,int lengthX,int lengthZ, ExitsInRoomType exitForCor)
{
switch (exitForCor)
{
case ExitsInRoomType.XAxisP:
{
if ((lengthFloor - (vector2.x + lengthX) >= 0)
&& (lengthFloor - (vector2.y + lengthZ / 2f) >= 0)
&& (vector2.y - lengthZ/2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.XAxisN:
{
if ((vector2.x - lengthX >= 0)
&& (lengthFloor - (vector2.y + lengthZ / 2f) >= 0)
&& (vector2.y - lengthZ/2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.ZAxisP:
{
if ((lengthFloor - (vector2.y + lengthZ) >= 0)
&& (lengthFloor - (vector2.x + lengthX / 2f) >= 0)
&& (vector2.x - lengthX/2f) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.ZAxisN:
{
if ((vector2.y - lengthZ >= 0)
&& (lengthFloor - (vector2.x + lengthX / 2f) >= 0)
&& (vector2.x - lengthX/2) >= 0)
{
return true;
}
return false;
}
case ExitsInRoomType.Null:
default:
return false;
}
}
Room GenerateRandomRoom()
{
int a = Random.Range(lengthWallMin, lengthWallMax);
int b = Random.Range(lengthWallMin, lengthWallMax);
Room room = new Room();
room.Length = a;
room.Width = b;
return room;
}
void CreateStartRoom()
{
float randValue = Random.value;
int xR, zR;
Vector2Int posStartRoom = new Vector2Int();
Room room = new Room( lengthStartRoom, lengthStartRoom, RoomType.Start);
if (randValue < 0.25f) //1 квадрант
{
xR = Random.Range(0,lengthFloor/2-lengthStartRoom);
if (xR + lengthStartRoom <= lengthFloor / 4)
{
room.exits.Add(ExitsInRoomType.XAxisP);
zR = Random.Range(0, lengthFloor/2-lengthStartRoom);
}
else
{
room.exits.Add(ExitsInRoomType.ZAxisP);
zR = Random.Range(0, lengthFloor/4-lengthStartRoom);
}
}
else if (randValue < 0.5f) // 2 квадрант
{
xR = Random.Range(lengthFloor/2, lengthFloor-lengthStartRoom);//от половины до конца
if (xR + lengthStartRoom <= lengthFloor * 3/4)
{
room.exits.Add(ExitsInRoomType.ZAxisP);
zR = Random.Range(0, lengthFloor/4-lengthStartRoom);
}
else
{
room.exits.Add(ExitsInRoomType.XAxisN);
zR = Random.Range(0, lengthFloor/2-lengthStartRoom);
}
}
else if (randValue < 0.75f)
{
xR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom);
if (xR + lengthStartRoom <= lengthFloor * 3 / 4)
{
room.exits.Add(ExitsInRoomType.ZAxisN);
zR = Random.Range(lengthFloor * 3 / 4, lengthFloor - lengthStartRoom);
}
else
{
room.exits.Add(ExitsInRoomType.XAxisN);
zR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom);
}
}
else
{
xR = Random.Range(0, lengthFloor / 2 - lengthStartRoom);
if (xR + lengthStartRoom <= lengthFloor / 4)
{
room.exits.Add(ExitsInRoomType.XAxisP);
zR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom);
}
else
{
room.exits.Add(ExitsInRoomType.ZAxisN);
zR = Random.Range(lengthFloor * 3 / 4, lengthFloor - lengthStartRoom);
}
}
room.entrance = EntranceToRoomType.Null;
LevelManager.Rooms.Add(room);
// Instantiate(GameObjectA, new Vector3(0,-1,0), Quaternion.identity);
//
// Instantiate(GameObjectB, new Vector3(xR,0,zR), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(xR+lengthStartRoom,0,zR), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(xR+lengthStartRoom,0,zR+lengthStartRoom), Quaternion.identity);
// Instantiate(GameObjectB, new Vector3(xR,0,zR+lengthStartRoom), Quaternion.identity);
CreateCorridor(new Vector2Int(xR, zR),lengthStartRoom,lengthStartRoom,room.exits.First());
Room firstCorridor = CreateCorridor(new Vector2(xR, zR), lengthStartRoom,
lengthStartRoom, room.exits.First());
if (firstCorridor != null)
{
TryPlaceRoom(room,room.exits.First());
}
}
}
}