Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Tile based map via instantiate?

Discussion in 'Scripting' started by Kordanor, Dec 12, 2012.

  1. Kordanor

    Kordanor

    Joined:
    Oct 15, 2012
    Posts:
    12
    Heya,

    I tried to generate a rather small map with just 101*101 tiles and it took unity over 30 seconds to do just that.
    My project is completely empty apart from the standard assets. So I am wondering if instanciating is the right way to do this kind of stuff at all. In this case I just instantiated a prefab containing a plane with a small texture and I used this simple code to generate it:

    Code (csharp):
    1.         for(int x=-radius;x<=radius;x++)
    2.         {
    3.             for(int z=-radius;z<=radius;z++)
    4.             {
    5.                 GameObject temp=Instantiate(maptile,new Vector3(x*_width,0,z*_length)  ,Quaternion.identity)as GameObject;
    6.                 temp.transform.parent=startingpoint.transform;
    7.                 temp.name=count.ToString();
    8.                 count++;
    9.             }
    10.         }
    So with this already taking 30 seconds I am wondering if there is a better/faster way to generate a tile based map, where every tile can have different properties (somewhat like minecraft).
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It's not a good idea to have so many individual objects; that's over 10,000. (Which is even worse than being over 9000. ;) ) You should use the Mesh class to construct the map, that way it will be just one object, or a few objects if you do it in chunks.

    --Eric
     
  3. Kordanor

    Kordanor

    Joined:
    Oct 15, 2012
    Posts:
    12
    But as far as I understand it, it would not be possible with a mesh to dynamically alter it. Lets say that instead of a grid of 100x100 tiles there would be one mesh. Lets say that several of these tiles represent a wall and a player destroys this wall and therefore would alter the tile in terms of look, movement, line of sight and so on.
    Maybe you are familiar with Jagged Alliance 1/2 or the first X-Com games. Is there a way to make maps like these work in unity?
    Or is it a limitation in this system and one of the reasons why in a lot of modern games you can't destroy just any wall, but only use your dynamite in 3 pre-determined spots?
    A different example would be a game live Civ4, which also has more than 10 000 tiles in it's maps, All with their individual textures which can change during gameplay. What would be the right direction in creating such maps?
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yes it will, that's what all the 2D sprite/tile systems do, not to mention the various Minecraft systems. You just rebuild the mesh as necessary.

    --Eric
     
  5. mamoniem

    mamoniem

    Joined:
    Jul 23, 2012
    Posts:
    174
  6. Kordanor

    Kordanor

    Joined:
    Oct 15, 2012
    Posts:
    12
    I checked this 2D example before, but I don't think that it can really help me.
    As far as I see it in this project basically the is done as in my code above - except of two special things:
    1. the tiles itself consists of graphics used for collision detection
    2. there aren't objects for all tiles. Just for the walls basically.

    So with this system you could reduce a "room" of 10x10 tiles to maybe 60 planes instead of 100 and of course in empty regions you can save even more.
    But with this it would get more complicated if you wanted to do different backgrounds. I guess you can combine some background tiles to one plane in that way, but you would need to change the background plane from "outside" to "inside". It would be harder to do a path, change water to sand, to mud, to grass, to rock. Having a carpet would need to be a seperate object. In addition you would need to have another set of objects in the background to store all the rest of the data for the tiles not being displayed. Like if there are objects on it, if you can walk there and so on.
    So for this space shooter game it seems to be a good solution, but I am not sure what it would be in maps like Jagged Alliance, XCom or Civilization.

    I will take a deeper look about this combine mesh thingy Eric mentioned, but at the moment It is quite unclear to me how this should work (in code and in terms of mechanics).
     
  7. Ereous

    Ereous

    Joined:
    Aug 29, 2012
    Posts:
    163
    Do you need all of the 101x101 tiles to be seen? If not you could just disable all objects that are not within viewable radius. Beyond that you could make a pool system that will reuse objects.
     
  8. Kordanor

    Kordanor

    Joined:
    Oct 15, 2012
    Posts:
    12
    Yes, that was something I wanted to do anyways as my 101x101 example was just a "start small" thing (actually in my first attempt I tried 201*201 and unity crashed). But you may be right to keep it even smaller. I guess in the end 30*30 to 50*50 visible at once would do the job size wise. What I had in mind was to procedurally generate the map and make it unlmited, with loading and unloading stuff. But I guess this would be more effective if you already have a "big size" available at all times.
    But as I am still a newb in Unity, I take step after step.
    I was just shocked that unity already had that much of a problem with 101x101 planes and I guessed that there are better options.
     
  9. Kordanor

    Kordanor

    Joined:
    Oct 15, 2012
    Posts:
    12
    On the first look it works quite well to generate the mesh from scratch. Just tested it with 10000 tiles and only one material.
    The time needed for that is about zero. While I would need to do several more conditionals and so on for more complex stuff and several materials I guess it would be fine even if it took 10 times longer then. The only obstacle here is that a mesh can't have more than 65k vertices, but that equals more than 100x100 tiles per mesh and should work fine.
    So thanks to all for your help!

    For those finding this thread and looking for more information - I got the info about these mechanics by the following links:
    http://blog.nobel-joergensen.com/2010/12/25/procedural-generated-mesh-in-unity/
    and
    http://answers.unity3d.com/questions/51002/how-to-create-a-four-vertex-two-tri-square-polygon.html

    and the function I built for a simple test (straight line of 10000 tiles):
    Code (csharp):
    1.     void Start()
    2.     {
    3.         GetComponent<MeshFilter>().mesh = CreateTonsPlaneMesh();
    4.     }
    5.    
    6.     Mesh CreateTonsPlaneMesh()
    7.     {
    8.         int counter=10000;
    9.         Mesh mesh = new Mesh();
    10.         Vector3[] vertices = new Vector3[counter*4];
    11.         for (int i = 0; i < counter; i++)
    12.         {
    13.             vertices[i*4]   =new Vector3(1+i*2  ,0, 1);
    14.             vertices[i*4+1] =new Vector3(1+i*2  ,0,-1);
    15.             vertices[i*4+2] =new Vector3(-1+i*2 ,0, 1);
    16.             vertices[i*4+3] =new Vector3(-1+i*2 ,0,-1);
    17.         }
    18.        
    19.         /*
    20.         Vector3[] vertices = new Vector3[]
    21.         {
    22.             new Vector3( 1, 0,  1),
    23.             new Vector3( 1, 0, -1),
    24.             new Vector3(-1, 0,  1),
    25.             new Vector3(-1, 0, -1),
    26.            
    27.            
    28.             new Vector3( 3, 0,  1), /2nd run
    29.             new Vector3( 3, 0, -1), /2nd run
    30.             new Vector3( 1, 0,  1), /2nd run
    31.             new Vector3( 1, 0, -1), /2nd run
    32.            
    33.         };
    34.          */
    35.        
    36.         Vector2[] uv = new Vector2[counter*4];
    37.        
    38.         for (int i = 0; i < counter; i++)
    39.         {
    40.             uv[i*4]     =new Vector2(1,1);
    41.             uv[i*4+1]   =new Vector2(1,0);
    42.             uv[i*4+2]   =new Vector2(0,1);
    43.             uv[i*4+3]   =new Vector2(0,0);
    44.         }
    45.        
    46.         /*
    47.         Vector2[] uv = new Vector2[]
    48.         {
    49.             new Vector2(1, 1),
    50.             new Vector2(1, 0),
    51.             new Vector2(0, 1),
    52.             new Vector2(0, 0),
    53.             new Vector2(1, 1), /2nd run
    54.             new Vector2(1, 0), /2nd run
    55.             new Vector2(0, 1), /2nd run
    56.             new Vector2(0, 0), /2nd run
    57.            
    58.            
    59.         };*/
    60.         int[] triangles= new int[counter*6];
    61.        
    62.         for (int i = 0; i < counter; i++)
    63.         {
    64.             triangles[i*6]      =0+i*4;
    65.             triangles[i*6+1]    =1+i*4;
    66.             triangles[i*6+2]    =2+i*4;
    67.             triangles[i*6+3]    =2+i*4;
    68.             triangles[i*6+4]    =1+i*4;
    69.             triangles[i*6+5]    =3+i*4;
    70.         }
    71.        
    72.         /*
    73.         int[] triangles = new int[]
    74.         {
    75.             0, 1, 2,
    76.             2, 1, 3,
    77.             4, 5, 6, /2nd run
    78.             6, 5, 7, /2nd run
    79.  
    80.         };*/
    81.  
    82.         mesh.vertices = vertices;
    83.         mesh.uv = uv;
    84.         mesh.triangles = triangles;
    85.  
    86.         return mesh;
    87.     }