Hello,
Currently creating a randomly generated “top-down” viewed map of a city. Where you get to set a X and Y value, and set a density, and that’ll tell how many buildings you want in the city, and for the city generation I created a algorithm.
- Get X, Y, and Density value, set by myself
- Run through two loops, X and Y, and instantiate ‘something’
- that “something” is based on the density… For example, a Density of 0.5 will yield a 50% of generating a building or generating nothing
- Then it’ll get that building or empty lot and do a check if it can fit
- If it can’t fit, find another piece that can fit, otherwise instantiate that building.
Here the actual code, if you want to see
Grid Building
public void GenerateCity(int _height, int _width, float _density)
{
ClearCity();
GameObject temp = null;
for(int x = 0; x < _width; x++)
{
for (int y = 0; y < _height; y++)
{
float randDensity = Random.Range(0f, 1f);
int randBuilding = Random.Range(0, buildings.Length);
int randEmpty = Random.Range(0, empty.Length);
bool putEmpty = false;
if (randDensity <= _density)
{
if (isValidPlacement(buildings[randBuilding].GetComponent<Building>().gridPositions, x * offset, y * offset, _height, _width))
temp = Instantiate(buildings[randBuilding], new Vector3(x * offset, y * offset, 0f), Quaternion.identity) as GameObject;
else
putEmpty = true;
}
else
{
if (isValidPlacement(empty[randEmpty].GetComponent<Building>().gridPositions, x * offset, y * offset, _height, _width))
temp = Instantiate(empty[randEmpty], new Vector3(x * offset, y * offset, 0f), Quaternion.identity) as GameObject;
else
putEmpty = true;
}
if(putEmpty)
{
foreach (GameObject e in empty)
{
if (isValidPlacement(e.GetComponent<Building>().gridPositions, x * offset, y * offset, _height, _width))
temp = Instantiate(e, new Vector3(x * offset, y * offset, 0f), Quaternion.identity) as GameObject;
}
}
temp.transform.parent = this.gameObject.transform;
}
}
temp = null;
}
private void ClearCity()
{
foreach(Transform g in transform)
Destroy(g.gameObject);
}
private bool isValidPlacement(List<Vector2> _v, float _xOff, float _yOff, int _h, int _w)
{
int counter = 0;
foreach (Vector2 v2 in _v)
{
RaycastHit2D hit = Physics2D.Raycast(new Vector2(v2.x + _xOff, v2.y + _yOff), Vector2.down, 0.01f);
if (hit.collider == null)
if (v2.x + _xOff < (_w * offset) && v2.y + _yOff < (_h * offset))
counter++;
}
if (counter == _v.Count)
return true;
return false;
}
HOWEVER, this is where the main part of the question lies…
If you view my code, the function “isValidPlacement” uses Vector2 locations and checks a raycast to see if anything is there
And these Vector2 values come from this script that is placed in each building tile.
Hard-Coded Vector2
public List<Vector2> gridPositions
{
get
{
BoxCollider2D c = GetComponent<BoxCollider2D>();
float x = c.size.x;
float y = c.size.y;
List<Vector2> temp = new List<Vector2>();
if (x == 0.32f && y == 0.32f)
{
temp.Add(new Vector2(0.16f, 0.16f));
}
else if (x == 0.32f && y == 0.64f)
{
temp.Add(new Vector2(0.16f, 0.16f));
temp.Add(new Vector2(0.16f, 0.48f));
}
else if (x == 0.64f && y == 0.32f)
{
temp.Add(new Vector2(0.16f, 0.16f));
temp.Add(new Vector2(0.48f, 0.16f));
}
else if (x == 0.64f && y == 0.64f)
{
temp.Add(new Vector2(0.16f, 0.16f));
temp.Add(new Vector2(0.16f, 0.48f));
temp.Add(new Vector2(0.48f, 0.16f));
temp.Add(new Vector2(0.48f, 0.48f));
}
return temp;
}
}
As you can see in the code, I “hard-coded” the position, so for example if a sprite is (0.32,0.32), it’ll use the position (0.16,0.16), which is the center point, and this will work for (32,64) [essentially 2x1 tiles, and so on]
HOWEVER NOW THIS IS WHERE THE ACTUAL QUESTION LIES
Is there a certain Algorithm that I can implement that will locate center points of certain sprites based on a size, So if I have an irregular L-shaped sprite it can cut it into 3 piece and located the center points of those?
TL;DR Is there an algorithm that cuts a sprite into separate blocks, then returns the center points. Here’s a picture to illustrate this