Skip to content

Instantly share code, notes, and snippets.

@Shaun-Meechan
Last active August 11, 2023 18:26
Show Gist options
  • Save Shaun-Meechan/ac53a7434d72993e839181d50bba2d40 to your computer and use it in GitHub Desktop.
Save Shaun-Meechan/ac53a7434d72993e839181d50bba2d40 to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
#endif
public class WorldGeneration : MonoBehaviour
{
[Tooltip("The biome/biomes that will be generated")]
public List<GameObject> tileTypesList;
List<GameObject> possibleTileTypes;
public GameObject tilePrefab;
public int gridWidth;
public int gridHeight;
public uint numberOfVillages;
public uint numberOfTowns;
public uint numberOfCities;
GameObject[,] tiles;
public GameObject powerOutIconPrefab;
public void generate()
{
tiles = new GameObject[gridWidth, gridHeight];
int randomNumber;
Debug.Log("Start called");
for (int i = 0; i < gridHeight; i++)
{
for (int j = 0; j < gridWidth; j++)
{
for (int k = 0; k < tileTypesList.Count; k++)
{
possibleTileTypes.Add(tileTypesList[k]);
}
if(i <= gridHeight /2)
{
for (int k = 0; k < possibleTileTypes.Count; k++)
{
if (possibleTileTypes[k].name == "Tundra")
{
possibleTileTypes.RemoveAt(k);
}
}
}
randomNumber = pickNewTileType();
//Generate an ocean at the bottom of the map
if (doesTileListContains("Water") && i <= 2)
{
randomNumber = 2;
assignTileType(randomNumber,j,i);
tiles[j, i].GetComponent<Tile>().setPosition(j, i);
possibleTileTypes.Clear();
continue;
}
//Generate a tundra area at the top of the map
if (doesTileListContains("Tundra") && i >= 35)
{
if(doesTileListContains("Mountains"))
{
randomNumber = Random.Range(5, 7);
}
else
{
randomNumber = 6;
}
assignTileType(randomNumber,j,i);
//Need to create a new go here
tiles[j, i].GetComponent<Tile>().setPosition(j, i);
possibleTileTypes.Clear();
continue;
}
while (checkRules(randomNumber, j, i) == false)
{
randomNumber = pickNewTileType();
}
assignTileType(randomNumber,j, i);
tiles[j,i].GetComponent<Tile>().setPosition(j,i);
possibleTileTypes.Clear();
}
}
generateBuildings();
#if UNITY_EDITOR
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
Debug.Log("Scene saved!");
#endif
}
bool checkRules(int randomNumber, int x, int y)
{
if (randomNumber == 5 && generateMountain(x, y) == false)
{
for (int k = 0; k < possibleTileTypes.Count; k++)
{
if (possibleTileTypes[k].name == "Mountains")
{
possibleTileTypes.RemoveAt(k);
}
}
return false;
}
//Check if we can generate some water
if (randomNumber == 2 && generateWater(x, y) == false)
{
for (int k = 0; k < possibleTileTypes.Count; k++)
{
if (possibleTileTypes[k].name == "Water")
{
possibleTileTypes.RemoveAt(k);
}
}
return false;
}
//See if we can generate some desert
if (randomNumber == 3 && generateDesert(x, y) == false)
{
for (int k = 0; k < possibleTileTypes.Count; k++)
{
if (possibleTileTypes[k].name == "Desert")
{
possibleTileTypes.RemoveAt(k);
}
}
return false;
}
//See if we can generate some plains
if (randomNumber == 0 && generatePlain(x, y) == false)
{
for (int k = 0; k < possibleTileTypes.Count; k++)
{
if (possibleTileTypes[k].name == "Plains")
{
possibleTileTypes.RemoveAt(k);
}
}
return false;
}
return true;
}
void assignTileType(int randomNumber, int gridXPosition, int gridYPosition)
{
switch (randomNumber)
{
case 0:
GameObject go = Instantiate(tileTypesList[getIndexOfTile("Plains")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile = go.GetComponent<Tile>();
go.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go;
tile.setTileType(Tile.tileTypes.Plains);
tile.sunCoverage = 10f;
tile.windSpeed = 10f;
tile.geothermalStrength = generateGeothermalPowerValue();
break;
case 1:
GameObject go1 = Instantiate(tileTypesList[getIndexOfTile("Hills")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile1 = go1.GetComponent<Tile>();
go1.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go1;
tile1.setTileType(Tile.tileTypes.Hills);
tile1.windSpeed = 20f;
tile1.sunCoverage = 5f;
tile1.geothermalStrength = generateGeothermalPowerValue();
break;
case 2:
GameObject go2 = Instantiate(tileTypesList[getIndexOfTile("Water")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile2 = go2.GetComponent<Tile>();
go2.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go2;
tile2.setTileType(Tile.tileTypes.Water);
tile2.tidalStrength = 10f;
tile2.windSpeed = 10f;
tile2.sunCoverage = 10f;
break;
case 3:
GameObject go3 = Instantiate(tileTypesList[getIndexOfTile("Desert")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile3 = go3.GetComponent<Tile>();
go3.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go3;
tile3.setTileType(Tile.tileTypes.Dessert);
tile3.sunCoverage = 20f;
tile3.windSpeed = 20f;
tile3.geothermalStrength = generateGeothermalPowerValue();
break;
case 4:
GameObject go4 = Instantiate(tileTypesList[getIndexOfTile("Forrest")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile4 = go4.GetComponent<Tile>();
go4.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go4;
tile4.setTileType(Tile.tileTypes.Forrest);
tile4.geothermalStrength = generateGeothermalPowerValue();
break;
case 5:
GameObject go5 = Instantiate(tileTypesList[getIndexOfTile("Mountains")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile5 = go5.GetComponent<Tile>();
go5.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go5;
tile5.setTileType(Tile.tileTypes.Mountains);
break;
case 6:
GameObject go6 = Instantiate(tileTypesList[getIndexOfTile("Tundra")], new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile6 = go6.GetComponent<Tile>();
go6.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go6;
tile6.setTileType(Tile.tileTypes.Tundra);
tile6.sunCoverage = 4f;
tile6.windSpeed = 10f;
tile6.geothermalStrength = generateGeothermalPowerValue();
break;
case 7:
GameObject go7 = Instantiate(tilePrefab, new Vector3(gridYPosition * 10, 0, gridXPosition * 10), Quaternion.identity);
Tile tile7 = go7.GetComponent<Tile>();
go7.name = "Tiles:" + gridXPosition + " " + gridYPosition;
tiles[gridXPosition, gridYPosition] = go7;
tile7.setTileType(Tile.tileTypes.Building);
break;
default:
break;
}
}
int generateGeothermalPowerValue()
{
return Random.Range(0, 11);
}
int pickNewTileType()
{
int randomNumber = Random.Range(0, 8);
int[] differences = new int[possibleTileTypes.Count];
int higestDifference = int.MinValue;
//We now need to see what possible tile type that number is closest to
for (int i = 0; i < differences.Length; i++)
{
differences[i] = Mathf.Abs((int)(randomNumber - possibleTileTypes[i].GetComponent<Tile>().getTileType()));
}
for (int i = 0; i < differences.Length; i++)
{
if(differences[i] == 0)
{
return (int)possibleTileTypes[i].GetComponent<Tile>().getTileType();
}
if (differences[i] > higestDifference)
{
higestDifference = (int)possibleTileTypes[i].GetComponent<Tile>().getTileType();
}
}
return higestDifference;
}
bool generateWater(int x, int y)
{
//Check neigbours to see if we are on the border
if(x == 0 || x == gridWidth - 1)
{
//On the side of the level
return true;
}
if(y == 0 || y == gridHeight - 1)
{
//On the bottom or top
return true;
}
//We aren't on a border tile
//Check our left
if (tiles[x - 1, y].gameObject.GetComponent<Tile>().getTileType() == Tile.tileTypes.Water)
{
return true;
}
//Check below
if (tiles[x, y - 1].gameObject.GetComponent<Tile>().getTileType() == Tile.tileTypes.Water)
{
return true;
}
return false;
}
bool generateDesert(int x, int y)
{
if (doesTileListContains("Tundra") && y >= gridHeight / 2)
{
return false;
}
//Check neigbours to see if we are on the border
if (x == 0 || x == gridWidth - 1)
{
if(y == 0)
{
return true;
}
//Check below
if (tiles[x, y - 1].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
return false;
}
if(y == 0 || y == gridHeight - 1)
{
if (tiles[x - 1, y].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
}
//We aren't on a border tile
//Check our left and bottom
if (tiles[x - 1, y].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra && tiles[x, y - 1].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
return false;
}
bool generatePlain(int x, int y)
{
//If the world has tundra and we are in the north return false
if (doesTileListContains("Tundra") && y >= gridHeight / 2)
{
return false;
}
//Check neigbours to see if we are on the border
if (x == 0 || x == gridWidth - 1)
{
if (y == 0)
{
return true;
}
//Check below
if (tiles[x, y - 1].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
return false;
}
if(y == 0 || y == gridHeight - 1)
{
if (tiles[x - 1, y].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
}
//We aren't on a border tile
//Check our left and bottom
if (tiles[x - 1, y].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra && tiles[x, y - 1].gameObject.GetComponent<Tile>().getTileType() != Tile.tileTypes.Tundra)
{
return true;
}
return false;
}
//This should be run AFTER world generation
void generateBuildings()
{
int counter = 0;
int x = 0;
int y = 0;
for (int i = 0; i < numberOfVillages; i++)
{
for (int j = 0; j < 4; j++)
{
if (counter == 0)
{
x = Random.Range(0, gridWidth - 1);
y = Random.Range(4, gridHeight - 1);
while (validBuildingLocation(x,y,2,1) == false)
{
x = Random.Range(0, gridWidth - 1);
y = Random.Range(4, gridHeight - 1);
}
}
if(counter == 4)
{
x = Random.Range(4, gridWidth - 1);
y = Random.Range(0, gridHeight - 1);
while (validBuildingLocation(x, y, 2, 1) == false)
{
x = Random.Range(0, gridWidth - 1);
y = Random.Range(4, gridHeight - 1);
}
counter = 0;
}
//0,1
if (counter < 2)
{
tiles[x + counter, y].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter, y].AddComponent<BuildingTile>();
tiles[x + counter, y].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
}
//2,3
if(counter >= 2)
{
tiles[x + counter - 2, y + 1].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter - 2, y + 1].AddComponent<BuildingTile>();
tiles[x + counter - 2, y + 1].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
}
counter++;
}
}
counter = 0;
for (int i = 0; i < numberOfTowns; i++)
{
for (int j = 0; j < 8; j++)
{
if (counter == 0)
{
x = Random.Range(0, gridWidth - 4);
y = Random.Range(4, gridHeight - 1);
while (validBuildingLocation(x, y, 4, 1) == false)
{
x = Random.Range(0, gridWidth - 4);
y = Random.Range(4, gridHeight - 1);
}
}
if (counter == 8)
{
x = Random.Range(4, gridWidth - 4);
y = Random.Range(0, gridHeight - 1);
while (validBuildingLocation(x, y, 4, 1) == false)
{
x = Random.Range(0, gridWidth - 4);
y = Random.Range(4, gridHeight - 1);
}
counter = 0;
}
//0,1,2,3
if (counter < 4)
{
tiles[x + counter, y].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter, y].AddComponent<BuildingTile>();
tiles[x + counter, y].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
getTile(x + counter, y + 1).GetComponent<Tile>().sunCoverage /= 1.5f;
getTile(x + counter, y + 1).GetComponent<Tile>().windSpeed /= 2;
}
//4,5,6,7
if (counter >= 4)
{
tiles[x + counter - 4, y + 1].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter - 4, y + 1].AddComponent<BuildingTile>();
tiles[x + counter - 4, y + 1].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
getTile(x + counter - 4, y + 2).GetComponent<Tile>().sunCoverage /= 1.5f;
getTile(x + counter - 4, y + 2).GetComponent<Tile>().windSpeed /= 2;
}
counter++;
}
}
counter = 0;
for (int i = 0; i < numberOfCities; i++)
{
for (int j = 0; j < 24; j++)
{
if (counter == 0)
{
x = Random.Range(0, gridWidth - 8);
y = Random.Range(4, gridHeight - 3);
while (validBuildingLocation(x, y, 8, 3) == false)
{
x = Random.Range(0, gridWidth - 8);
y = Random.Range(4, gridHeight - 3);
}
}
if (counter == 24)
{
x = Random.Range(4, gridWidth - 8);
y = Random.Range(0, gridHeight - 3);
while (validBuildingLocation(x, y, 8, 3) == false)
{
x = Random.Range(0, gridWidth - 8);
y = Random.Range(4, gridHeight - 3);
}
counter = 0;
}
//0,1,2,3,4,5,6,7
if (counter < 8)
{
tiles[x + counter, y].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter, y].AddComponent<BuildingTile>();
tiles[x + counter, y].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
getTile(x + counter, y + 1).GetComponent<Tile>().sunCoverage /= 1.5f;
getTile(x + counter, y + 1).GetComponent<Tile>().windSpeed /= 2;
}
//8,9,10,11,12,13,14,15
if (counter >= 8 && counter < 16)
{
tiles[x + counter - 8, y + 1].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter - 8, y + 1].AddComponent<BuildingTile>();
tiles[x + counter - 8, y + 1].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
getTile(x + counter - 8, y + 2).GetComponent<Tile>().sunCoverage /= 1.5f;
getTile(x + counter - 8, y + 2).GetComponent<Tile>().windSpeed /= 2;
}
if (counter >= 16)
{
tiles[x + counter - 16, y + 2].GetComponent<Tile>().setTileType(Tile.tileTypes.Building);
tiles[x + counter - 16, y + 2].AddComponent<BuildingTile>();
tiles[x + counter - 16, y + 2].GetComponent<BuildingTile>().powerOutIconPrefab = powerOutIconPrefab;
getTile(x + counter - 16, y + 2).GetComponent<Tile>().sunCoverage /= 1.5f;
getTile(x + counter - 16, y + 2).GetComponent<Tile>().windSpeed /= 2;
}
counter++;
}
}
}
bool validBuildingLocation(int xPosition, int yPosition, int tilesNeededX, int tilesNeededY)
{
for (int i = 0; i < tilesNeededX; i++)
{
if (tiles[xPosition + i,yPosition].GetComponent<Tile>().getTileType() == Tile.tileTypes.Building)
{
return false;
}
for (int j = 0; j < tilesNeededY; j++)
{
if (tiles[xPosition + i, yPosition + j].GetComponent<Tile>().getTileType() == Tile.tileTypes.Building)
{
return false;
}
}
}
return true;
}
//Function to check if the list contains a tile type
//Must be passed a tile type based on the prefab name
bool doesTileListContains(string prefabName)
{
for (int i = 0; i < tileTypesList.Count; i++)
{
if(tileTypesList[i].name == prefabName)
{
return true;
}
}
return false;
}
//Function to get the index of a tile type from tileTypesList
//Must be passed a tile type based on the prefab name
int getIndexOfTile(string prefabName)
{
for (int i = 0; i < tileTypesList.Count; i++)
{
if (tileTypesList[i].name == prefabName)
{
return i;
}
}
return -1;
}
bool generateMountain(int x, int y)
{
if(y < gridHeight/2)
{
int randomNumber = Random.Range(0, 11);
if(randomNumber <= 8)
{
return false;
}
}
return true;
}
public void clearAllTiles()
{
if(tiles == null || tiles.Length == 0)
{
fillArray();
}
for (int i = 0; i < gridHeight; i++)
{
for (int j = 0; j < gridWidth; j++)
{
DestroyImmediate(tiles[j, i]);
}
}
tiles = null;
#if UNITY_EDITOR
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
#endif
}
public GameObject getTile(int x, int y)
{
if(tiles == null)
{
fillArray();
}
return tiles[x, y];
}
public int getGridWidth()
{
return gridWidth;
}
public int getGridHeight()
{
return gridHeight;
}
public void testArray()
{
if(tiles == null)
{
Debug.Log("Tiles array is null");
}
if(tiles.Length == 0)
{
Debug.Log("Tiles array length is 0");
}
Debug.Log("Tiles array seems okay");
}
public void fillArray()
{
tiles = new GameObject[gridWidth, gridHeight];
for (int i = 0; i < gridHeight; i++)
{
for (int j = 0; j < gridWidth; j++)
{
tiles[j,i] = GameObject.Find("Tiles:" + j + " " + i);
}
}
}
public GameObject[,] getTilesArray()
{
if(tiles == null || tiles.Length == 0)
{
fillArray();
}
return tiles;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment