2

I am trying to build a randomized city made out of tiles and so far i can build an array, set the the city edge, place a random building such as a church or factory and can place tiles with random rotations within the set area.

But what i need is some kind of algorithm or routine to create an interconnected maze of streets by selecting the right tile and rotating it the right way so as to not end up with an area that cannot be reached in some way.

The tiles i have are - feature tile (such as church or factory) straight road t-junction crossroads corner left corner right square/roundabout/courtyard

I have found tons of examples based on dungeons but nothing along the lines of using fixed tiles and matching/rotating in a set area say 10 tiles x 10 tiles.

Any script hints would be very much appreciated as i am going round in circles making horrendously complicated looping functions thatch still don't work

Code of what i have so far -

public GameObject playerPrefab;
public GameObject cullGroup;
public GameObject cullPrefab;

//tile objects
public List<GameObject> _grid = new List<GameObject>();         //general buildings
public List<GameObject> _industrial = new List<GameObject>();   //industrial
public List<GameObject> _feature = new List<GameObject>();      //city feature
public List<GameObject> _largeSpecial = new List<GameObject>(); //large special building
public List<GameObject> _smallSpecial = new List<GameObject>(); //large special building
public List<GameObject> _docks = new List<GameObject>();        //docks
public List<GameObject> _roads = new List<GameObject>();        //outgoing roads
public List<GameObject> _edge = new List<GameObject>();         //city edge

public Vector2 citySize = new Vector2(10,10);       //how many tiles in total
private int[] tileRoatation = new int[5] {0,90,180,270,0};
private int[,,] _cityMap;
private int mapType = 0;

//ingress vars
public int[,] roadIngress;

//feature vars
private int _tmpFeature;
private Vector2 _tmpPlacement;

//special vars
private int _tmpFeature1;
private Vector2 _tmpPlacement1;

//docks vars
private Vector2 _tmpDock;
private string _strDock;
private float _xAdjustment;
private float _zAdjustment;

//industrial vars
private Vector2 _indSector;
private int _indTotal = 0;

// Use this for initialization
void Start () 
{
    _cityMap = new int[(int)citySize.x, (int)citySize.y, 2];

    CreateMap();
}

// Update is called once per frame
void Update () 
{

}

void CreateMap()
{
    //calc roads into city
    RoadIngress();

    //calc feature
    Features();

    //calculate tile adjustment from center
    _xAdjustment = (_grid[0].transform.localScale.x * (citySize.x / 2) - (_grid[0].transform.localScale.x)/2);
    _zAdjustment = (_grid[0].transform.localScale.z * (citySize.y / 2) - (_grid[0].transform.localScale.x)/2);

    //place tiles
    for(int z = 0; z < citySize.y; z++)
    {
        for(int x = 0; x < citySize.x; x++)
        {
            //instantiate tile
            int tmpRot = tileRoatation[Random.Range(0,5)];
            GameObject go = Instantiate(_grid[Random.Range(0, _grid.Count-1)], 
                                        new Vector3(
                        (x * _grid[0].transform.localScale.x) - _xAdjustment, 
                        0 , 
                        (z * _grid[0].transform.localScale.z) -  _zAdjustment), 
                        Quaternion.Euler(0,tmpRot, 0)
                ) as GameObject;

            _cityMap[x ,z ,1 ] = 1;;
            _cityMap[x ,z ,0 ] = tmpRot;;
            go.name = x +"/"+z;
            go.transform.parent = this.transform;

            //instantiate culling areas
            /*
            GameObject go2 = Instantiate(cullPrefab, 
                                         new Vector3(
                (x * _grid[0].transform.localScale.x) - _xAdjustment, 
                0 , 
                (z * _grid[0].transform.localScale.z) -  _zAdjustment), 
                                         Quaternion.Euler(0,0, 0)
                                         ) as GameObject;
            go2.name = x +"/"+z;
            go2.transform.parent = cullGroup.transform;
            go2.transform.localScale = new Vector3(51, 20, 51);
            */

            //set map edges
            if(x == 0 || z == 0 || x == citySize.x-1 || z == citySize.y-1 )
            {
                //does map have beach
                if(mapType == 1 && z == 0)
                {
                    go.GetComponent<MeshRenderer>().material.color = Color.blue;
                }else if(roadIngress[x,z] == 1){
                    //set exit roads
                        go.SetActive(false);
                        GameObject rp = Instantiate(_roads[0], new Vector3(go.transform.position.x, 0 ,go.transform.position.z), Quaternion.Euler(0, 0, 0)) as GameObject;
                        rp.name = go.name;
                        rp.transform.parent = this.transform;
                        //go.name = "disabled";

                        //extend road
                }else{
                    //go.GetComponent<MeshRenderer>().material.color = Color.green;
                    int tmpRot1 = tileRoatation[Random.Range(0,5)];
                    go.SetActive(false);
                    GameObject ep = Instantiate(_edge[Random.Range(0, _edge.Count-1)], new Vector3(go.transform.position.x, 0 ,go.transform.position.z), Quaternion.Euler(0, tmpRot, 0)) as GameObject;
                    ep.name = go.name;
                    ep.transform.parent = this.transform;

                    go.name = "disabled";
                }

            }
        }
    }

    Debug.Log((citySize.x * citySize.y) * 0.1f);
    Industrial();
    Industrial();
    Debug.Log(_indTotal);
    if(citySize.x <((citySize.x * citySize.y) * 0.2f))
        Industrial();

    PlaceFeature();
    PlaceLargeSpecial();

    //docks
    if(mapType == 1)
    {
        //go.GetComponent<MeshRenderer>().material.color = Color.red;
        _tmpDock = new Vector2(Random.Range(1,citySize.y-1),0);
        //_strDock = _tmpDock.x +"/"+_tmpDock.y;

    }

    PlaceDocks();

    // spawn player
    Instantiate(playerPrefab, new Vector3(0,2,0),Quaternion.identity);
}


//set roads leaving city
void RoadIngress()
{
    //set roads leaving city
    roadIngress = new int[(int)citySize.x, (int)citySize.y];
    roadIngress[(int)Random.Range(1,citySize.x-1), 0] = 1;                  //east road or dock
    roadIngress[0, (int)Random.Range(1,citySize.y-1)] = 1;                  //south road
    roadIngress[(int)Random.Range(1,citySize.x-1), (int)citySize.y-1] = 1;  //west road
    roadIngress[(int)citySize.x-1, (int)Random.Range(1,citySize.y-1)] = 1;  //north road
}

// choose main feature
void Features()
{
    //choose main feature and placement
    _tmpFeature = Random.Range(0,4);// 5x feature tiles
    _tmpPlacement = new Vector2((int)Random.Range(2,citySize.x-2),(int)Random.Range(2,citySize.y-2));

    //choose special large building and placement
    _tmpFeature1 = Random.Range(0,4);// 5x feature tiles
    _tmpPlacement1 = new Vector2((int)Random.Range(2,citySize.x-2),(int)Random.Range(2,citySize.y-2));
    if(_tmpPlacement1 == _tmpPlacement)
    {
        _tmpPlacement1.x = _tmpPlacement1.x + 4;
        if(_tmpPlacement1.x > citySize.x-2)
            _tmpPlacement1.x -= citySize.x;
        _tmpPlacement1.y = _tmpPlacement1.y + 4;
        if(_tmpPlacement1.y > citySize.y-2)
            _tmpPlacement1.y -= citySize.y;
    }
}

//place feature
void PlaceFeature()
{

    int tmpRot1 = tileRoatation[Random.Range(0,5)];
    GameObject go1 = Instantiate(_feature[Random.Range(0, _feature.Count-1)],
                                 new Vector3((_tmpPlacement.x * _grid[0].transform.localScale.x - (_grid[0].transform.localScale.x *.5f) - _xAdjustment),
                0,
                (_tmpPlacement.y * _grid[0].transform.localScale.z + (_grid[0].transform.localScale.z*.5f) - _zAdjustment)), 
                                 Quaternion.Euler(0,tmpRot1, 0)) as GameObject;

    //clear feature area
    GameObject tp = GameObject.Find(_tmpPlacement.x + "/" + _tmpPlacement.y);
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement.x + "/" + (_tmpPlacement.y+1));
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement.x-1 + "/" + _tmpPlacement.y);
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement.x-1 + "/" + (_tmpPlacement.y+1));
    tp.SetActive(false);
    tp.name = "disabled";
}

//place large special
void PlaceLargeSpecial()
{
    //check distance between feature and large special
    int dist = (int)Vector2.Distance(_tmpPlacement, _tmpPlacement1);

    //if to close move away
    if((int)Vector2.Distance(_tmpPlacement, _tmpPlacement1)<3)
    {
        _tmpPlacement1.x = _tmpPlacement1.x+3;
        if(_tmpPlacement1.x > citySize.x-2)
            _tmpPlacement1.x = 3;
        _tmpPlacement1.y = _tmpPlacement1.y+3;
        if(_tmpPlacement1.y > citySize.y-2)
            _tmpPlacement1.y = 3;
    }

    //Debug.Log(dist);
    int tmpRot2 = tileRoatation[Random.Range(0,5)];
    GameObject go2 = Instantiate(_largeSpecial[Random.Range(0, _largeSpecial.Count-1)],
                                 new Vector3((_tmpPlacement1.x * _grid[0].transform.localScale.x - (_grid[0].transform.localScale.x *.5f) - _xAdjustment),
                0,
                (_tmpPlacement1.y * _grid[0].transform.localScale.z + (_grid[0].transform.localScale.z*.5f)) - _zAdjustment), 
                                 Quaternion.Euler(0,tmpRot2, 0)) as GameObject;

    //clear large special area
    GameObject tp = GameObject.Find(_tmpPlacement1.x + "/" + _tmpPlacement1.y);
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement1.x + "/" + (_tmpPlacement1.y+1));
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement1.x-1 + "/" + _tmpPlacement1.y);
    tp.SetActive(false);
    tp.name = "disabled";
    tp = GameObject.Find(_tmpPlacement1.x-1 + "/" + (_tmpPlacement1.y+1));
    tp.SetActive(false);
    tp.name = "disabled";

}

//place docks
void PlaceDocks()
{
    if(mapType == 1)
    {
        GameObject go3 = Instantiate(_docks[Random.Range(0, _docks.Count-1)],
                                     new Vector3((_tmpDock.x * _grid[0].transform.localScale.x - (_grid[0].transform.localScale.x) - _xAdjustment),
                    0,
                    (_tmpDock.y * _grid[0].transform.localScale.z) - _zAdjustment), 
                                     Quaternion.Euler(0,0, 0)) as GameObject;

        //clear dock area
        /*
        string[] tmp = _strDock.Split("/"[0]);
        int t1 = int.Parse(tmp[0]);
        for(int a=0; a<3; a++)
        {
            GameObject.Find(t1-a + "/" + 0).SetActive(false);
        }
        for(int b=0; b<3; b++)
        {
            GameObject.Find(t1-b + "/" + 1).SetActive(false);
        }
        */
    }
}

//set out industrial area
void Industrial()
{
    //pick random spot industrial area
    _indSector = new Vector2((int)Random.Range(2,citySize.x-2),(int)Random.Range(2,citySize.y-2));

    int indSizeX = Random.Range(2,5);
    int indSizeY = Random.Range(2,4);
    _indTotal += (indSizeX*indSizeY);

    //create area
    for(int y = (int)_indSector.y; y < (int)_indSector.y+indSizeY; y++)
    {
        for(int x = (int)_indSector.x; x < (int)_indSector.x+indSizeX; x++)
        {
            //GameObject.Find(x + "/" + y).GetComponent<MeshRenderer>().material.color = Color.magenta;
            GameObject tp = GameObject.Find(x + "/" + y);
            //Debug.Log(x + "/" + y);
            GameObject go4 = Instantiate(_industrial[Random.Range(0, _industrial.Count-1)],
                                             new Vector3(tp.transform.position.x, 0, tp.transform.position.z), Quaternion.Euler(0,0, 0)) as GameObject;
            tp.SetActive(false);
            tp.name = "disabled";
            go4.name = x +"/"+y;
            go4.transform.parent = this.transform;
        }
    }
}

Hybrid1969
  • 29
  • 5
  • See for example: http://gamedev.stackexchange.com/questions/59314/procedural-river-or-road-generation-for-infinite-terrain – CodeSmile Jul 26 '14 at 16:51
  • and this great article covers most of the *basics* of terrain generation: http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/ – CodeSmile Jul 26 '14 at 16:52
  • Thanks but Im not interested in terrain generation as i have this covered, its city made from tiles that im interested in – Hybrid1969 Jul 26 '14 at 21:34
  • ive added my code to make things clearer i hope – Hybrid1969 Jul 27 '14 at 00:59

1 Answers1

0

Could you not use an array (or multi-dimensional array if needed) and fill it up with positions then use the "Random" class to extract those positions from the array?

like...

s
Random rnd = new Random();
int i;
i = rnd.next(1,5);

Random rnd = new Random();
int i;
i = rnd.next(1,5);

int Positions[] = new Positions[5] {100, 200, 300, 400, 500};
Tilepos1 = Positions[i];
Tilepos2 = Positions[i];
Tilepos3 = Positions[i];
Tilepos4 = Positions[i];
Tilepos5 = Positions[i]; 


//you would have to make up your own Tileposition and figure out how to implement it into your system

//then make sure that the Tilepositions (Tilepos) don´t land on the same place

if (Tilepos1 == Tilepos2)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos3)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos4)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos5)
    {
    Tilepos1 = Positions[i];
    }


 //then just repeat this process with Tilepos 2, 3, 4,`int i;
i = rnd.next(1,5);

int Positions[] = new Positions[5] {100, 200, 300, 400, 500};
Tilepos1 = Positions[i];
Tilepos2 = Positions[i];
Tilepos3 = Positions[i];
Tilepos4 = Positions[i];
Tilepos5 = Positions[i]; 


//you would have to make up your own Tileposition and figure out how to implement it into your system

//then make sure that the Tilepositions (Tilepos) don´t land on the same place

if (Tilepos1 == Tilepos2)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos3)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos4)
    {
    Tilepos1 = Positions[i];
    }
if (Tilepos1 == Tilepos5)
    {
    Tilepos1 = Positions[i];
    }


//then just repeat this process with Tilepos 2, 3, 4, 5

But this would only work if the tile are squared, otherwise you could just spice things up a little with the array.

I hope it helped a little and gave you a basic idea of what to do :)

Stephan
  • 2,863
  • 1
  • 17
  • 14
Rawmouse
  • 77
  • 8
  • Sorry im obviously not making myself clear. – Hybrid1969 Jul 26 '14 at 23:59
  • So i have an array say 10x10 and then i iterate thru the array setting the tile type and its rotation. So what im trying to find is a method to go thru the array of tiles changing or rotating them so i end up with paths that creat a road network by changing or rotating the pre-defined road tiles – Hybrid1969 Jul 26 '14 at 23:59
  • Wish I could have been more of assistance but I´m not that good at programming yet, although I hafto admit, that´s some impressive code – Rawmouse Jul 27 '14 at 20:41