ProjectZ/Assets/Scripts/Level/BuildModules/ProceduralPrefabs.cs
2024-03-20 19:15:58 +03:00

252 lines
9.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Mirror;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.Serialization;
using Random = UnityEngine.Random;
namespace Level.BuildModules
{
public class ProceduralPrefabs : NetworkBehaviour
{
public Room[] roomPrefabs;
public Room startingRoom;
private Room[,] _spawnedRooms;
public List<Room> flattenSpawnedRooms = new();
private int _size;
private int _startCellX = 0;
private int _startCellY = 0;
private CustomNetworkManager networkManager;
public GameObject enemyPrefab;
private List<Vector3> _enemySpawnPoses = new();
public List<GameObject> enemyList = new();
private IEnumerator Start()
{
if(!isServer) yield break;
_size = PlayerPrefs.GetInt("LevelSize");
_spawnedRooms = new Room[_size, _size];
_spawnedRooms[_startCellX, _startCellY] = startingRoom;
networkManager = NetworkManager.singleton.GetComponent<CustomNetworkManager>();
for (int i = 0; i < _size; i++)
{
if (_size > 200)
{
yield return new WaitForSecondsRealtime(0.1f);
}
PlaceOneRoom();
}
print("<---Rooms Spawned--->");
flattenSpawnedRooms[0].GetComponent<NavMeshSurface>().BuildNavMesh();
print("<---Surface builded--->");
networkManager.OnPlayerSpawned += OnPlayerSpawned;
print("pizda");
}
private void OnPlayerSpawned()
{
if (enemyList.Count == networkManager.maxMonsters) return;
if (networkManager.players.Count == networkManager.maxConnections)
{
for (int i = 0; i < networkManager.maxMonsters; i++)
{
Vector3 pos = _enemySpawnPoses[Random.Range(0, _enemySpawnPoses.Count)];
GameObject go = Instantiate(enemyPrefab, pos, Quaternion.identity);
NetworkServer.Spawn(go);
enemyList.Add(go);
}
}
print("<---Monster spawned--->");
}
private void PlaceOneRoom()
{
HashSet<Vector2Int> vacantPlaces = new HashSet<Vector2Int>();
for (int x = 0; x < _spawnedRooms.GetLength(0); x++)
{
for (int y = 0; y < _spawnedRooms.GetLength(1); y++)
{
if (_spawnedRooms[x, y] == null) continue;
int maxX = _spawnedRooms.GetLength(0) - 1;
int maxY = _spawnedRooms.GetLength(1) - 1;
AddVacantPlaceIfValid(x - 1, y, vacantPlaces);
AddVacantPlaceIfValid(x, y - 1, vacantPlaces);
AddVacantPlaceIfValid(x + 1, y, vacantPlaces);
AddVacantPlaceIfValid(x, y + 1, vacantPlaces);
}
}
Room newRoom = Instantiate(roomPrefabs[Random.Range(0, roomPrefabs.Length)]);
NetworkServer.Spawn(newRoom.gameObject);
int limit = 500;
while (limit-- > 0)
{
Vector2Int position = vacantPlaces.ElementAt(Random.Range(0, vacantPlaces.Count));
// newRoom.RotateRandomly();
if (ConnectToSomething(newRoom, position))
{
newRoom.transform.position = new Vector3(position.x - _startCellX, 0, position.y - _startCellY) * newRoom.roomSize;
_spawnedRooms[position.x, position.y] = newRoom;
flattenSpawnedRooms.Add(newRoom);
_enemySpawnPoses.Add(newRoom.transform.position);
return;
}
}
NetworkServer.Destroy(newRoom.gameObject);
Destroy(newRoom.gameObject);
}
private void AddVacantPlaceIfValid(int x, int y, HashSet<Vector2Int> vacantPlaces)
{
if (x >= 0 && x < _spawnedRooms.GetLength(0) && y >= 0 && y < _spawnedRooms.GetLength(1) &&
_spawnedRooms[x, y] == null)
{
vacantPlaces.Add(new Vector2Int(x, y));
}
}
private bool ConnectToSomething(Room room, Vector2Int p)
{
List<Vector2Int> neighbours = new List<Vector2Int>();
AddNeighbourIfValid(room.DoorU, p.x, p.y + 1, Vector2Int.up, neighbours);
AddNeighbourIfValid(room.DoorD, p.x, p.y - 1, Vector2Int.down, neighbours);
AddNeighbourIfValid(room.DoorR, p.x + 1, p.y, Vector2Int.right, neighbours);
AddNeighbourIfValid(room.DoorL, p.x - 1, p.y, Vector2Int.left, neighbours);
AddNeighbourIfValid(room.DoorU2, p.x, p.y + 1, Vector2Int.up, neighbours);
AddNeighbourIfValid(room.DoorD2, p.x, p.y - 1, Vector2Int.down, neighbours);
AddNeighbourIfValid(room.DoorR2, p.x + 1, p.y, Vector2Int.right, neighbours);
AddNeighbourIfValid(room.DoorL2, p.x - 1, p.y, Vector2Int.left, neighbours);
AddNeighbourIfValid(room.DoorU3, p.x, p.y + 1, Vector2Int.up, neighbours);
AddNeighbourIfValid(room.DoorD3, p.x, p.y - 1, Vector2Int.down, neighbours);
AddNeighbourIfValid(room.DoorR3, p.x + 1, p.y, Vector2Int.right, neighbours);
AddNeighbourIfValid(room.DoorL3, p.x - 1, p.y, Vector2Int.left, neighbours);
if (neighbours.Count == 0) return false;
Vector2Int selectedDirection = neighbours[Random.Range(0, neighbours.Count)];
Room selectedRoom = _spawnedRooms[p.x + selectedDirection.x, p.y + selectedDirection.y];
DisableDoors(room, selectedRoom, selectedDirection);
room.Finish();
return true;
}
private void AddNeighbourIfValid(GameObject door, int x, int y, Vector2Int direction, List<Vector2Int> neighbours)
{
if (door != null && x >= 0 && x <= _spawnedRooms.GetLength(0) - 1 && y >= 0 &&
y <= _spawnedRooms.GetLength(1) - 1 && _spawnedRooms[x, y] != null)
{
neighbours.Add(direction);
}
}
private void DisableDoors(Room room, Room selectedRoom, Vector2Int direction)
{
int rand = Random.Range(1, 4);
if (direction == Vector2Int.up)
{
switch (rand)
{
case 1 :
room.DisableDoor(RoomDoor.U);
selectedRoom.DisableDoor(RoomDoor.D);
break;
case 2 :
room.DisableDoor(RoomDoor.U2);
selectedRoom.DisableDoor(RoomDoor.D2);
break;
case 3 :
room.DisableDoor(RoomDoor.U3);
selectedRoom.DisableDoor(RoomDoor.D3);
break;
}
}
else if (direction == Vector2Int.down)
{
switch (rand)
{
case 1 :
room.DisableDoor(RoomDoor.D);
selectedRoom.DisableDoor(RoomDoor.U);
break;
case 2 :
room.DisableDoor(RoomDoor.D2);
selectedRoom.DisableDoor(RoomDoor.U2);
break;
case 3 :
room.DisableDoor(RoomDoor.D3);
selectedRoom.DisableDoor(RoomDoor.U3);
break;
}
}
else if (direction == Vector2Int.right)
{
switch (rand)
{
case 1 :
room.DisableDoor(RoomDoor.R);
selectedRoom.DisableDoor(RoomDoor.L);
break;
case 2 :
room.DisableDoor(RoomDoor.R2);
selectedRoom.DisableDoor(RoomDoor.L2);
break;
case 3 :
room.DisableDoor(RoomDoor.R3);
selectedRoom.DisableDoor(RoomDoor.L3);
break;
}
}
else if (direction == Vector2Int.left)
{
switch (rand)
{
case 1 :
room.DisableDoor(RoomDoor.L);
selectedRoom.DisableDoor(RoomDoor.R);
break;
case 2 :
room.DisableDoor(RoomDoor.L2);
selectedRoom.DisableDoor(RoomDoor.R2);
break;
case 3 :
room.DisableDoor(RoomDoor.L3);
selectedRoom.DisableDoor(RoomDoor.R3);
break;
}
}
}
}
}