Skip to content

Instantly share code, notes, and snippets.

@KHalkjaer
Created May 21, 2019 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KHalkjaer/748d7978729d1e731fa4c675b30658f6 to your computer and use it in GitHub Desktop.
Save KHalkjaer/748d7978729d1e731fa4c675b30658f6 to your computer and use it in GitHub Desktop.
Level generator for procedural roguelike
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LevelGeneratorV2 : MonoBehaviour {
[Range(30, 100)]
public int width;
[Range(30, 100)]
public int height;
[Range(3, 20)]
public int roomCount;
[Range(1, 10)]
public int minRoomRadius;
[Range(1, 20)]
public int maxRoomRadius;
public int[,] mapData;
public float expandChance;
public float diagonalExpandChance;
public int seed;
public bool useSeed;
public GameObject[] floor;
public GameObject wall;
public GameObject wallDestructible;
public GameObject player;
public GameObject[] enemies;
public float enemySpawnChance;
public bool playTesting;
public GameObject levelLight;
private Color quadColor;
private float genTime;
private Vector2 curRoom;
public List<Vector3> roomPos = new List<Vector3>();
private List<float> roomDist = new List<float>();
private Vector2 startRoom;
private Vector2 endRoom;
private float minDist;
public bool enemy1Spawned;
public bool enemy2Spawned;
// Use this for initialization
void Start () {
if(useSeed)
Random.seed = seed;
genTime = Time.realtimeSinceStartup;
// Instantiate the map variable
mapData = new int [width,height];
// Set everything to 0
for(int w = 0; w < width; w++){
for(int h = 0; h < height; h++){
mapData[w,h] = 0;
}
}
// Pick Room Centers
for(int r = 0; r < roomCount; r++){
mapData[Random.Range(maxRoomRadius+2,width-maxRoomRadius-2),Random.Range(maxRoomRadius+2,height-maxRoomRadius-2)] = Random.Range(minRoomRadius,maxRoomRadius);
}
// Add room centers to list
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) != 0){
curRoom = new Vector2(w,h);
roomPos.Add(curRoom);
}
}
}
// For each room, find the closest room that's not connected to another room and make a path there
for (int y = 0; y < roomPos.Count; y++){
startRoom = roomPos[y];
minDist = 1000;
// For each room
for (int x = 0; x < roomPos.Count; x++){
float dist = Vector2.Distance(roomPos[y], roomPos[x]);
if(dist != 0 && dist < minDist && roomPos[x].z == 0){
minDist = dist;
endRoom = roomPos[x];
}
for (int z = 0; z < roomPos.Count; z++){
if (roomPos[z].x == endRoom.x && roomPos[z].y == endRoom.y){
endRoom = roomPos[z];
}
}
roomPos[x] = new Vector3(roomPos[x].x,roomPos[x].y,1);
}
// Pick randomly if the path to the next room should be created on the x-axis or y-axis first
float XorY = Random.value;
if (XorY >= 0.5){
// X AXIS FIRST
if(startRoom.x < endRoom.x){
for(int w = 1; w < (int)endRoom.x - (int)startRoom.x; w++){
mapData[(int)startRoom.x+w,(int)startRoom.y] = 2;
}
startRoom.x = endRoom.x;
}
if(startRoom.x > endRoom.x){
for(int w = 1; w < (int)startRoom.x - (int)endRoom.x; w++){
mapData[(int)startRoom.x-w,(int)startRoom.y] = 2;
}
startRoom.x = endRoom.x;
}
// Y AXIS
if(startRoom.y < endRoom.y){
for(int h = 1; h < (int)endRoom.y - (int)startRoom.y; h++){
mapData[(int)startRoom.x,(int)startRoom.y+h] = 2;
}
}
if(startRoom.y > endRoom.y){
for(int h = 1; h < (int)startRoom.y - (int)endRoom.y; h++){
mapData[(int)startRoom.x,(int)startRoom.y-h] = 2;
}
}
}
if(XorY < 0.5){
// Y AXIS FIRST
if(startRoom.y < endRoom.y){
for(int h = 1; h < (int)endRoom.y - (int)startRoom.y; h++){
mapData[(int)startRoom.x,(int)startRoom.y+h] = 2;
}
startRoom.y = endRoom.y;
}
if(startRoom.y > endRoom.y){
for(int h = 1; h < (int)startRoom.y - (int)endRoom.y; h++){
mapData[(int)startRoom.x,(int)startRoom.y-h] = 2;
}
startRoom.y = endRoom.y;
}
// X AXIS
if(startRoom.x < endRoom.x){
for(int w = 1; w < (int)endRoom.x - (int)startRoom.x; w++){
mapData[(int)startRoom.x+w,(int)startRoom.y] = 2;
}
}
if(startRoom.x > endRoom.x){
for(int w = 1; w < (int)startRoom.x - (int)endRoom.x; w++){
mapData[(int)startRoom.x-w,(int)startRoom.y] = 2;
}
}
}
}
// Expand Rooms from center
for (int x = 0; x < maxRoomRadius; x++){
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) != 0){
int nextVar = mapData[w,h]-1;
if (mapData[w,h+1] == 0)
mapData[w,h+1] = nextVar;
if (mapData[w+1,h+1] == 0)
mapData[w+1,h+1] = nextVar;
if (mapData[w+1,h] == 0)
mapData[w+1,h] = nextVar;
if (mapData[w+1,h-1] == 0)
mapData[w+1,h-1] = nextVar;
if( (mapData[w,h-1]) == 0)
mapData[w,h-1] = nextVar;
if (mapData[w-1,h-1] == 0)
mapData[w-1,h-1] = nextVar;
if (mapData[w-1,h] == 0)
mapData[w-1,h] = nextVar;
if (mapData[w-1,h+1] == 0)
mapData[w-1,h+1] = nextVar;
}
}
}
}
// Chance based expand
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) == 1){
if(mapData[w,h+1] == 0){
float randomizer = Random.value;
if (randomizer < expandChance){
mapData[w,h+1] = 1;
}
}
if(mapData[w+1,h+1] == 0){
float randomizer = Random.value;
if (randomizer < diagonalExpandChance){
mapData[w+1,h+1] = 1;
}
}
if(mapData[w+1,h] == 0){
float randomizer = Random.value;
if (randomizer < expandChance){
mapData[w+1,h] = 1;
}
}
if(mapData[w+1,h-1] == 0){
float randomizer = Random.value;
if (randomizer < diagonalExpandChance){
mapData[w+1,h-1] = 1;
}
}
if(mapData[w,h-1] == 0){
float randomizer = Random.value;
if (randomizer < expandChance){
mapData[w,h-1] = 1;
}
}
if(mapData[w-1,h-1] == 0){
float randomizer = Random.value;
if (randomizer < diagonalExpandChance){
mapData[w-1,h-1] = 1;
}
}
if(mapData[w-1,h] == 0){
float randomizer = Random.value;
if (randomizer < expandChance){
mapData[w-1,h] = 1;
}
}
if(mapData[w-1,h+1] == 0){
float randomizer = Random.value;
if (randomizer < diagonalExpandChance){
mapData[w-1,h+1] = 1;
}
}
}
}
}
// WALL CODE
// Create walls around rooms
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) == 1){
if(mapData[w,h+1] == 0)
mapData[w,h+1] = 30;
if(mapData[w+1,h+1] == 0)
mapData[w+1,h+1] = 30;
if(mapData[w+1,h] == 0)
mapData[w+1,h] = 30;
if(mapData[w+1,h-1] == 0)
mapData[w+1,h-1] = 30;
if(mapData[w,h-1] == 0)
mapData[w,h-1] = 30;
if(mapData[w-1,h-1] == 0)
mapData[w-1,h-1] = 30;
if(mapData[w-1,h] == 0)
mapData[w-1,h] = 30;
if(mapData[w-1,h+1] == 0)
mapData[w-1,h+1] = 30;
}
}
}
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) == 30){
if(mapData[w,h+1] == 0)
mapData[w,h+1] = 29;
if(mapData[w+1,h+1] == 0)
mapData[w+1,h+1] = 29;
if(mapData[w+1,h] == 0)
mapData[w+1,h] = 29;
if(mapData[w+1,h-1] == 0)
mapData[w+1,h-1] = 29;
if(mapData[w,h-1] == 0)
mapData[w,h-1] = 29;
if(mapData[w-1,h-1] == 0)
mapData[w-1,h-1] = 29;
if(mapData[w-1,h] == 0)
mapData[w-1,h] = 29;
if(mapData[w-1,h+1] == 0)
mapData[w-1,h+1] = 29;
}
}
}
for(int w = 1; w < width-1; w++){
for(int h = 1; h < height-1; h++){
if( (mapData[w,h]) == 29){
if(mapData[w,h+1] == 0)
mapData[w,h+1] = 28;
if(mapData[w+1,h+1] == 0)
mapData[w+1,h+1] = 28;
if(mapData[w+1,h] == 0)
mapData[w+1,h] = 28;
if(mapData[w+1,h-1] == 0)
mapData[w+1,h-1] = 28;
if(mapData[w,h-1] == 0)
mapData[w,h-1] = 28;
if(mapData[w-1,h-1] == 0)
mapData[w-1,h-1] = 28;
if(mapData[w-1,h] == 0)
mapData[w-1,h] = 28;
if(mapData[w-1,h+1] == 0)
mapData[w-1,h+1] = 28;
}
}
}
// Make sure there aren't any holes
for(int w = 0; w < width; w++){
if( (mapData[w,0]) != 0){
mapData[w,0] = 28;
}
if( (mapData[w,height-1]) != 0){
mapData[w,height-1] = 28;
}
}
// Same but other axis
for(int h = 0; h < width; h++){
if( (mapData[0,h]) != 0){
mapData[0,h] = 28;
}
if( (mapData[width-1,h]) != 0){
mapData[width-1,h] = 28;
}
}
//*/
// Build all map features
for(int w = 0; w < width; w++){
for(int h = 0; h < height; h++){
if( (mapData[w,h]) <= maxRoomRadius && mapData[w,h] > 0){
if(!playTesting){
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.position = new Vector3(w, 0, h);
quad.transform.Rotate(90.0f, 0.0f, 0.0f);
quadColor = new Color(1-(float)mapData[w,h]/maxRoomRadius,0,0,0);
quad.GetComponent<Renderer>().material.color = quadColor;
}
if(playTesting)
Instantiate(floor[Random.Range(0,floor.Length)], new Vector3(w, 0, h), Quaternion.identity);
}
if( (mapData[w,h]) == 30){
if(!playTesting){
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.position = new Vector3(w, 0, h);
quad.transform.Rotate(90.0f, 0.0f, 0.0f);
quad.GetComponent<Renderer>().material.color = Color.green;
}
if(playTesting)
Instantiate(wallDestructible, new Vector3(w, 0, h), Quaternion.identity);
}
if( (mapData[w,h]) == 29){
if(!playTesting){
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.position = new Vector3(w, 0, h);
quad.transform.Rotate(90.0f, 0.0f, 0.0f);
quad.GetComponent<Renderer>().material.color = Color.yellow;
}
if(playTesting)
Instantiate(wallDestructible, new Vector3(w, 0, h), Quaternion.identity);
}
if( (mapData[w,h]) == 28){
if(!playTesting){
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
quad.transform.position = new Vector3(w, 0, h);
quad.transform.Rotate(90.0f, 0.0f, 0.0f);
quad.GetComponent<Renderer>().material.color = Color.black;
}
if(playTesting)
Instantiate(wall, new Vector3(w, 0, h), Quaternion.identity);
}
}
}
if(playTesting){
for (int x = 0; x < roomPos.Count; x++){
float enemyChance = Random.value;
if (enemyChance < enemySpawnChance){
// Instantiate (enemies[Random.Range(0,enemies.Length)], new Vector3 (roomPos[x].x-2,0,roomPos[x].y), transform.rotation);
if(!enemy1Spawned){
Instantiate (GameControl.control.enemies[GameControl.control.firstEnemy[GameControl.control.currentLevel]], new Vector3 (roomPos[x].x-2,0,roomPos[x].y), transform.rotation);
enemy1Spawned = true;
}
if(!enemy2Spawned){
Instantiate (GameControl.control.enemies[GameControl.control.secondEnemy[GameControl.control.currentLevel]], new Vector3 (roomPos[x].x+2,0,roomPos[x].y), transform.rotation);
enemy2Spawned = true;
}
}
}
Instantiate (player, new Vector3 (endRoom.x+3,0,endRoom.y+-3), transform.rotation);
Instantiate (levelLight, transform.position, transform.rotation);
AstarPath.active.Scan();
}
genTime = Time.realtimeSinceStartup - genTime;
Debug.Log ("Level generated in " + genTime + " seconds");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment