A Unity card based action game built in a weekend with Julien Collée and Thomas Paterson
public class Generator : MonoBehaviour {
public static Generator instance;
public List<Room> rooms = new List<Room>();
public Dictionary<int,int> map = new Dictionary<int,int>();
public GeneratorConfig config;
public Dictionary<int, bool> enemyLocations = new Dictionary<int, bool>();
public Dictionary<int, bool> manaGenerators = new Dictionary<int, bool>();
public Dictionary<int, int> obstacles = new Dictionary<int, int>();
public List<Vector2> spawns = new List<Vector2>();
public Vector2 end = new Vector2();
private System.Random rand = new System.Random();
}
for (int r = 0; r <= config.maxRooms; r++) {
int w = rand.Next (config.minRoomSize, config.maxRoomSize);
int h = rand.Next (config.minRoomSize, config.maxRoomSize);
float u1 = (float)rand.NextDouble(); //these are uniform(0,1) random doubles
float u2 = (float)rand.NextDouble();
float randStdNormal = Mathf.Sqrt(-2.0f * Mathf.Log(u1)) *
Mathf.Sin(2.0f * Mathf.PI * u2); //random normal(0,1)
float randNormal = (float)(config.mapWidth /2)
+ config.standardDeviation * randStdNormal; //random normal(mean,stdDev^2)
int x = (int)randNormal;
u1 = (float)rand.NextDouble(); //these are uniform(0,1) random doubles
u2 = (float)rand.NextDouble();
randStdNormal = Mathf.Sqrt(-2.0f * Mathf.Log(u1)) *
Mathf.Sin(2.0f * Mathf.PI * u2); //random normal(0,1)
randNormal = (float)(config.mapHeight /2)
+ config.standardDeviation * randStdNormal; //random normal(mean,stdDev^2)
int y = (int)randNormal;
Room newRoom = new Room();
newRoom.SetSize (x, y, w, h);
}
bool failed = false;
foreach (Room otherRoom in rooms) {
if (newRoom.IsIntersecting (otherRoom)) {
failed = true;
r--;
failCount++;
break;
} else if (newRoom.x1 < 0 || newRoom.x2 >= config.mapWidth){
failed = true;
r--;
failCount++;
break;
} else if (newRoom.y1 < 0 || newRoom.y2 >= config.mapHeight){
failed = true;
r--;
failCount++;
break;
}
}
private int PlaceRectangle (int x1, int x2, int y1, int y2)
{
int smallX = Mathf.Min (x1, x2);
int bigX = Mathf.Max (x1, x2);
int smallY = Mathf.Min (y1, y2);
int bigY = Mathf.Max (y1, y2);
for (int x = smallX; x <= bigX; x++) {
for (int y = smallY; y <= bigY; y++) {
map[x + y * config.mapWidth] = 0;
}
}
return 0;
}
if (!failed) {
// places a rectangular room on the map
PlaceRectangle(newRoom.x1, newRoom.x2, newRoom.y1, newRoom.y2);
foreach (Room otherRoom in rooms){
int corridorWidth = rand.Next (config.minCorridorWidth, config.maxCorridorWidth);
int halfCorridorWidth = Mathf.Min(2, corridorWidth / 2);
// carve out corridors between rooms based on centers
// randomly start with horizontal or vertical corridors
// plots from previous center to new center
int corridorChance;
if (otherRoom.connections == 0){
corridorChance = rand.Next (0, 1);
otherRoom.connections++;
} else {
corridorChance = rand.Next (0, otherRoom.connections * 50);
}
if (corridorChance == 0) {
// vertical
PlaceRectangle((int)newRoom.center.x - halfCorridorWidth, (int)newRoom.center.x + halfCorridorWidth,
(int)newRoom.center.y, (int)otherRoom.center.y);
// horizontal
PlaceRectangle((int)newRoom.center.x, (int)otherRoom.center.x,
(int)otherRoom.center.y - halfCorridorWidth, (int)otherRoom.center.y + halfCorridorWidth);
otherRoom.connections++;
}else if (corridorChance == 1){
// horizontal
PlaceRectangle((int)newRoom.center.x, (int)otherRoom.center.x,
(int)newRoom.center.y - halfCorridorWidth, (int)newRoom.center.y + halfCorridorWidth);
// vertical
PlaceRectangle((int)otherRoom.center.x - halfCorridorWidth, (int)otherRoom.center.x + halfCorridorWidth,
(int)newRoom.center.y, (int)otherRoom.center.y);
otherRoom.connections++;
} else if (corridorChance == 3){
// horizontal
PlaceRectangle(0, 0,
(int)newRoom.center.y - halfCorridorWidth, (int)newRoom.center.y + halfCorridorWidth);
// vertical
PlaceRectangle((int)otherRoom.center.x - halfCorridorWidth, (int)otherRoom.center.x + halfCorridorWidth,
0, 0);
}
}
// add newRoom to end of rooms list
rooms.Add (newRoom);
}
if (failCount >= config.errorLimit)
break;
}
// add noise
foreach (int x in width) {
foreach (int y in height) {
if (Mathf.PerlinNoise((float)x / 5.0f, (float)y / 5.0f) >= 0.55f)
map[x + y * config.mapWidth] = 1;
}
}
// add noise
foreach (int x in width) {
foreach (int y in height) {
if (Mathf.PerlinNoise((float)x / 8.0f, (float)y / 8.0f) >= 0.6f){
map[x + y * config.mapWidth] = 2;
if(rand.Next (0, 10) == 0){
obstacles[x + y * config.mapWidth] = 1;
}
}
}
}
// add noise
foreach (int x in width) {
foreach (int y in height) {
if (Mathf.PerlinNoise((float)x / 6.0f, (float)y / 6.0f) >= 0.65f){
map[x + y * config.mapWidth] = 3;
}
}
}
// add noise
foreach (int x in width) {
foreach (int y in height) {
if (Mathf.PerlinNoise((float)x / 5.0f, (float)y / 5.0f) >= 0.7f) {
map[x + y * config.mapWidth] = 0;
if(rand.Next (0, 10) == 0){
obstacles[x + y * config.mapWidth] = 3;
}
}
}
}
Vector2 mapCenter = new Vector2 (config.mapWidth / 2, config.mapHeight / 2);
// generate enemy information
foreach (Room room in rooms) {
room.difficulty = (int)Vector2.Distance (mapCenter, room.center);
int enemies = rand.Next(2, Mathf.Max(3, room.difficulty / 5));
for (int e = 0; e < enemies; e++){
int enemyX = rand.Next (room.x1, room.x2);
int enemyY = rand.Next (room.y1, room.y2);
enemyLocations[enemyX + enemyY * config.mapWidth] = true;
}
}
List<Room> orderedRooms = rooms.OrderBy(r=>r.difficulty).ToList();
spawns.Add (orderedRooms.First ().center - Vector2.down);
spawns.Add (orderedRooms.First ().center - Vector2.up);
spawns.Add (orderedRooms.First ().center - Vector2.left);
spawns.Add (orderedRooms.First ().center - Vector2.right);
end = orderedRooms.Last ().center;
for (int x = orderedRooms.First ().x1; x < orderedRooms.First ().x2; x++) {
for (int y = orderedRooms.First ().y1; y < orderedRooms.First ().y2; y++) {
map[x + y * config.mapWidth] = 0;
}
}
for (int x = orderedRooms.Last ().x1; x < orderedRooms.Last ().x2; x++) {
for (int y = orderedRooms.Last ().y1; y < orderedRooms.Last ().y2; y++) {
map[x + y * config.mapWidth] = 0;
}
}
foreach (Room room in rooms) {
int genX = rand.Next (room.x1, room.x2);
int genY = rand.Next (room.y1, room.y2);
manaGenerators[genX + genY * config.mapWidth] = true;
}
public int SpawnMonsters () {
for (int x = 0; x < config.mapWidth; x++) {
for (int y = 0; y < config.mapHeight; y++) {
if (this.enemyLocations[x + y * config.mapWidth] == true){
int monsterType = rand.Next (0, 4); // set second argument to monster number - 1
Vector3 location = new Vector3(1.5f * ((float)x - (float)config.mapWidth / 2), 2.0f, 1.5f * ((float)y - (float)config.mapHeight / 2));
GameObject enemy = (GameObject) Instantiate(LevelManager.instance.monsters[monsterType], location, Quaternion.identity);
enemy.GetComponent<Character>().faction = 4;
}
}
}
return 0;
}