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. Dismiss Notice

Trying to build a dynamically sized Hex Grid

Discussion in 'Scripting' started by count23, Apr 13, 2012.

  1. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    Howdy Folks, I'm stumped on where to begin with unity on a little project I'm wroking on.

    simply put, all I want to be able to do is produce a dynamically sized grid of hex tiles for a turn based game concept I'm working on.

    I'm quite familiar with the logic and provisioning of a grid, I havent quite descided if i want to restrict the game grid to an arbitrary size and use a fixed 2d array for the grid contents, I'm considering using a 2d array of pointers instead so i can allocate extra memory and have a truely dynamic size for the map. however, my problem is, I simply don't know how to draw the hexagonal grid on screen. Since it's space based, the tiles themselves will actually be transparent, I want to use hexagons for a visible territory border and "selected" indicator only, I have no idea what I can use for this. I've been trying to draw hexagons using the create mesh function but I can't seem to figure it out.

    My plan was to create hexagonal tiles and try to use a proceedural texture to colour the tiles (with a ramp) based on the ownership of the tile. The only other thing I could think of is to generate a long, medium and close resolution of a hexagon with an alpha channel, use a ramp to colour it and map them to planes instead. But again, I still don't even know how to do that.

    So after all my rambling, I guess my real question is, how to I draw hexagons in a scene in unity, that'll achieve what I want.

    EDIT: I should mention i'm doing this in C#, but I've got a good enough understanding of javascript to be able to translate that into what I need.
     
    Last edited: Apr 13, 2012
  2. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
  3. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    Thanks, but you've kinda missed the point. I know how the logic and the coding backend works for actually generating, I need to actually know how to get unity to DRAW it.
     
  4. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    Oh... well, in that case, why not use the LineRenderer??
     
  5. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    Line renderer looks like it could work. Can i create a hexagonal plane using line renderer? I was trying to use mesh but I couldn't get anything more then simple triangles.
     
  6. virror

    virror

    Joined:
    Feb 3, 2012
    Posts:
    2,963
    Well, a hexagon is nothing more than a bunch of connected lines, right?
     
  7. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    What's your problem with drawing it? A bit more detail there would let us help you, I think. As it is, all I can suggest is going through the provided documentation for displaying code-generated meshes.

    You can do whatever you want using a line renderer. You give it a bunch of points and it draws a line through them.

    If they're small, I'd suggest drawing them in a 3D package (Blender is fine for this), bringing them into Unity, making a prefab from them and instantiating that in code to show your grid. You can then change the materials however you need, no dramas.

    If they're big I might consider a different approach. Also if you only want to draw the outlines, I'd do something different. We don't really have a lot to go on, here.
     
  8. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    as line renderer can get a bit messy fe when you want to draw many not connected lines or with different colors i would suggest using vectrosity. this works with a mesh and does all the dirty work for you. and its performant as it uses a 1 mesh draw call.

    you need to be carefull with this approach depending on which platform you target and how big your array is. when you do physics or frequent checks with each prefab this can reduce performance.

    also look at http://forum.unity3d.com/threads/107656-FX-Hex-Grid-(Hex-Grid-Generator).
     
  9. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    Yes, but this goes for any approach, regardless of how you get them into the game.

    Good link though!
     
  10. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    Windows platform, I hadn't planned on needing any physics for them, the tiles are there are "border markers" only for a space based TBH games. So they'll just be visibly there, there wont be any changes needed to them except for colour based on ownership.

    I get the feeling that I may be wasting resources, there's gotta be an easier way to do this (sure, hex tiles that are meshes for a ground based TBH it makes sense to render a series of planes, but for a space based one, there's gotta be a less memory intensive approach).
     
  11. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    ok, I managed to build a hex grid that's dynamically generated, it's great :)

    Now, If found some tutorials on how to select, either by using mouseclick or raytrace. But I have one question I can't quite seem to figure out the answer to.

    my script stores the entire game board into a hexGridBoard game object (they're all instanced and parented to it), when i click on a tile, how would i tie that into a tile's contents and it's terrain type? I was thinking of turning the board gameobject into an arraylist but I dont think that'll work.

    I want to store all my tile details into an array list (what's on it, terrain type, movement penalties, etc...) but only because that seemed to be the most efficient approach, but that means I have to use mathishness to determine the tile coordinates from the gameobject position. Is doing it in this manner hte correct approach? or is there a better way? (if my explanation made no sense, feel free to mock me).
     
  12. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    Actually, in regards to teh other question. Would the more appropriate solution be to generate a global array list AT THE SAME TIME as the game object generation which stores the "real coordinates" from the hex tile GO as it's created, and then give it a virtual reference based what position it is in the "game world"?

    I'm just not quite sure how to tie in the visual representation of the game grid with the back end position and terrain-info logic.
     
  13. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    you could use this approach to determine the position in space the user clicked on the plane and use this to determine the tile at this position.

    this sounds as if you have a game object for every tile? i have understood that you display the hexgrid as one mesh for performance reasons but when you have an gameobject for every tile this may also lead you into performance problems. consider you have 100x100 tiles and only 20x20 displayed (zoom). this way you reach the limits of unity and hardware very fast. you should also consider displaying the terrain as a mesh. create a hexagon procedurally and have all terrain tiles in a texture. then adjust the uv coordinates of the vertices to the position in the texture of the terrain type you want to display for that tile. add as much tiles as possible to one mesh (65k vertices) and you have a much faster and more extendable solution than with a gameobject for every tile.
    only when you can be sure you will always have a limited number of tiles (say 50x50) you could use your approach but when you plan to support larger fields this may be too slow.

    the rest of your questions is a bit confusing for me. i would have a 2d array and store a class inside wich contains all info you need and has references to units, buildings etc (which are all gameobjects).

    so my structure would be one gameobject for terrain having as much child objects with the meshes and the hexgrid as required (this should be created automatically from the width and height of the field), an invisible cube collider stretched to the terrain extend to be able to place/move units etc on it and a list of the terrain data class (movement costs, terrain type enum etc).
    and then a gameobject for each unit/building with its own mesh and functionality. these can be referenced by ai and player to give commands read stats etc.
     
  14. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    This is what i have. During the grid creation i create instances of the prefab and parent them to a single Board GO once the grid generation loops are completed. The only other GOs created are instanced temporary iterations of the prefab terrain tile until they're positioned and placed in the correct position. Is this what you're describing? I want to be able to dynamically create the size, to pre-building the mesh with certain dimensions would cause restrictions on the grid creation down the line. However, since I was hoping to get up to 128x128 size grids for gameplay, it may be necessary down the line.

    In regards to the rest of the terrain, I was going to store a class/terrain type that would have all the details like enums, and movement costs and whatnot, I just wasn't sure how to translate that from the "tile selected" aspect to retreiving the data from the array. This is the part that's troubling me. What I was trying to explain would have been an array list being populated at the same time as the Game objects, this array list would have a key based on the "virtual" position of the tile that's selected out of the Board game object and would use that key as a reference to retreive all the terrain properties out of arraylist. (it's also have the expected grid reference, (x,y) ). I just dont know if that's the appropriate solution to this.

    I hope that makes more sense.
     
  15. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    no. i suggested instead of using a prefab for every terrain tile to create a mesh for several terrain tiles and draw the mesh. this should be much more perfomant than your approach. the decision for prefab or mesh can only be done by you as only you know what your game should be capable of. but 128² tiles is over 16k game objects (afaik unity supports 65 k) and i dont know if your target hardware likes that. you must decide wether its necessary to interact with a tile as gameobject or as "virtual" object as element of a list. so when you require any functionality of a monobehavior on your tile then you can only choose the prefab approach. when you can emulate it somehow (fe like you do to calculate the selected tile) then you should consider using my suggested approach.
    in short you do a mesh fill in vertices for the hexagon tiles (65k per mesh) and set their uv coordinates to the position in the tile atlas texture. when the mesh is full you add another child object containing a mesh and repeat until all the vertices are stored. the mesh is automatically drawn each frame then. similar for drawing the border of the tiles via vectrosity. add points to the line element to frame your tiles.
    hint: when you have a neutral standard color for the borders include it into the tile atlas texture and only draw special colors (ownership, selection, visibility) with their color ontop with line renderer or vectrosity. but when it is likely that all tiles change their border color this is not usefull. then construct it on the fly when a border color changes.

    do you mean the math how to calculate the tile from a position (fe selection)? there are plenty of non-unity-specific tutorials out there. also the package linked above by me should provide such a function.

    appropriate is what is working for you. i would not suggest to use a game object for every tile unless you need it. in this case you have only the list with the tile class data and construct the mesh out of it as explained above. then you make a function to calculate the position of the tile from a mouseclick fe. from this position you can determine the index of the tile in the list. so you have a fast lookup of tiles and dont need heavy raycasting like with you game object approach.
     
  16. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    ok, that's starting to make more sense. For reference, the code i've written is pretty similar to this blog one here with some fair changes (not really that many) http://tbswithunity3d.wordpress.com/2012/02/21/hexagonal-grid-generating-the-grid/

    The difference between his code and mine are that mine used 0,0 as the starting point in the scene, just positioned tiles and then ran a transform on the parent GO to centre it on the scene after the fact (And I ran all the math in the same function as the generator) but the implementation is the same. So you're saying this implementation is not appropriate for a larger game grid? Say 100x100 elements, or even 50x50 elements?

    so create the game logic in the backend as scripts, leave the virtual board as something global and only draw the visible tiles as required? That makes sense, it'd how i used to write games in C++, but I was under the impression that unity didnt' render things that were not visible in the camera line of sight. But the rest of what you're describing, using a raycasted tile's coordinates as a key to get the tile out of an arraylist was what i had invisioned.

    It does make more sense, your approach, If i do the grid population first THEN only populate the screen based on the zoom level and camera position, to cut down processing time. For testing though, i'd probably just skip that and draw the whole grid first, get the game working right before I optimize it.

    EDIT: It also just occured to me that I've been trying to create the script and arraylist to handle objects through the grid generation class, rather then attaching the script directly to the terrain prefab tile.
     
    Last edited: Apr 18, 2012
  17. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    no. what i want to say is it MIGHT be inappropriate and i dont know your requirements. just 128x128 = 16k gameobjects may lead you into problems performance wise. thats why i suggest that you either try it out right at the beginning of development or you decide for a better approach when you dont require game object functionality for a tile.

    you could easily draw the whole terrain in a mesh (if it fits) or a handfull of meshes. you dont need to cull this manually as unity does this for you. having 10000 single objects (each generating its own draw call) is much more costly than having one object (mesh) drawing 10000 objects in one draw call. and when you do it right you could easily extend this suggested solution to support bigger fields (say 256 x 256) later without reaching the limits of unity (65k game objects) and hardware.

    what also could be possible is when you only ever see a small portion of the game world (say 20x20 grid) have this as game objects and change the appearence when player scrolls to always represent the actual view and dont have gameobjects for tiles that are not visible. do you need to display the whole world at once or only a fraction of it?

    they are not rendered does not mean they are not included in other calculations (collisions, updates, raycasts) so they cost performance anyway. also they require much more memory leading to more memory cache changes all eating up your performance.

    raycast means your prefab needs a collider. having 16k coliders in the scene may make the physics engine choke. i have never tried such amounts of go's so i suggest you try before you build on it.

    this is not required. simply display all meshes this is not that costly. in the game view you can enable a statistics window showing you triangles, draw calls, and fps.

    yes. probably you can even stay with that. keep in mind that recreating the mesh to show new position/zoom may take while and cause the game to stutter. thats why i would draw everything all the time first and see if it works fast enough.
     
    Last edited: Apr 18, 2012
  18. count23

    count23

    Joined:
    Apr 13, 2012
    Posts:
    30
    ok, sorry, I think i've been getting mesh and game object confused for a bit, at least from what you're saying in your older messages.

    Now, you say mesh, i presume you mean 3d model, as in something that's made in maya and/or unity for display purposes only?

    If so, from what you're saying earlier, you're proposing make a larger mesh, say a 3x3 grid of hexagons in the approprate shape and/or size for my game grid (so i can create multiples of this), use UVs to place a texutre in each of the 9 tile positions, and then use the game object to administrate 9 tiles at once instead of one at a time? Especially if i dont need the tiles to be game objects by themselves. Then use an Atlas texture to map the UVs to the mesh, and a transparent texture for any row/column that I'm not using out of that group. Is that correct?

    i'd rather not use vectrosity because it'd defeat the purpose of me learning unity properly, and line renderer seems as intensive as using game objects.

    If not, i'm confused and would like clarifications please :)

    also, 16k game objects chugs when i try to load a basic grid :)
     
  19. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    do you mean i wrote something wrong or you understood it wrong?
    the gameobject is the container for unity to place inside what the developer needs. a transform for position rotation etc, a particle system, a camera, a light, a script or a mesh. so the mesh is the comonent of a certain game object. the mesh consists of vertices which contain several information like position, uv coordinates etc.

    i mean a collection of vertices but they are not created in a 3d app but within your code as they follow "simple" rules and are all at one plane for your purpose (assuming you ignore height).

    no. you create the mesh on the fly and place vertices for every heaxong in it. if you take multiples of 3x3 you cant get a field 8x8 for example. and have similar problems with less impact.

    here is how i would do it for a quadratic grid (for simplicity) but i must confess i havent tried it yet.
    have a texture with your terrain tiles (2x2 here)
    -----------
    |land|see |
    -----------
    |t1 |t2 |
    -----------
    so when you want a tile to show land you set the uv of the 4 corners of the mesh in this way:
    0.0 0.0 - 0.5 0.0
    0.0 0.5 - 0.5 0.5
    t2 would be:
    0.5 0.5 - 1.0 0.5
    0.5 1.0 - 1.0 1.0

    your game object with a mesh filter is placed in 0.0. the mesh shall be on the x-z plane. the tile index is counting towards positive x and negative z direction:
    00-------->x
    |11 21 31
    |12 22 32
    |13 23 33
    -z
    your resolution of tiles is 1 unit.

    so you being to create a mesh with the vertices. the first vertex is at 0,0 the second at 1,0 the third at 1,1 this forms your first triangle (upper right corner). i think the order must be clockwise but i'm not sure. when you dont see it reverse 2 values to change the order to prevent backface culling. then you add the lower right triangle and so on. until you reach the end of your terrain or the maximum vertex count. in that case you add another (child) gameobject with a mesh and repeat the process.
    and dont forget to set the uv values to the proper terrain atlas coordinates.
    after you have added all vertices your mesh is drawn and shows the tile textures in a really cheap way.

    you could also directly use index buffers. as you have each vertex in the middle shared with 4 triangles which means you must add it 4 times. its usually faster to add it once and index it in the 4 triangles (the index is the position in the associated vertex buffer). so essentially you construct the triangle out of positions in the veretx array instead of vertices itself. look in the documentation for this.
    also after creation you could optimize the mesh with the method to make it even faster drawn.

    have a look at the procedural examples for the mesh manipulation stuff.

    you can only draw connected lines with line renderer. that means you must draw lines multiple times and/or use multiple line renderers to get your border drawn. so vectrosity is a big and performant help.
    and unity is a tool same as all the packages available for it. so you need to learn unity as well as the packages you require. there is lots of usefull stuff out there and you would waste your time reinveting it or replace it with inproper methods. use what you can get. you learn unity anyway. and when you look in the source of vectrosity you will learn much more about mesh manipulation than from my description ;).

    thats what i wanted to tell you. now try it with the explained mesh stuff (try the quadratic approach first for learning and esasier debugging). once the mesh is generated you should have no big performance issues displaying it.
    but keep in mind that a hexagon consists of 6 triangles and thus has triple the triangles of a quad. so maybe make the test-terrain 3 times larger (number of tiles) to simulate this effect for performance measurements.

    edit:
    the y coordinate of the vertex is 0 and the z coordinate is negativ for this example. but you can use any system you want or have already.

    edit2:
    the thing with indices will not work as you have different uv coordinates of each point at a position. so you need a vertex for every triangle you add. sorry for confusion.
     
    Last edited: Apr 20, 2012
  20. ZoomDomain

    ZoomDomain

    Joined:
    Aug 30, 2012
    Posts:
    150
    Dynamically sized! That makes it tricky! Also the length of this thread shows someone serious about doing something!

    to make the mesh, doing procedurally is quite an advanced task and you be scratching your head for a very long time unless you are used to making meshes procedurally. you have to figure the formula about yourself. The triangles the use except sure, difficult.

    Otherwise, you can just use individual triangles and arrange them in lines, or you can use individual hexagons that you arrange from triangles or in a separate program, and tiled those, or you can make squares made of triangles like in this picture but smaller- for example 16 or 32 triangles per side, which is fast for unity to deal with anyway. And then tiles them. That's practically the logical ways to do it in unity that you can do less than one day, writing a formula will take you a long time and probably would be a bit stressful and a waste of time.

    I think you can edit this http://sketchup.google.com/3dwarehouse/details?mid=f5a87ed2dae741d243dbce79a9d5dbb&prevstart=0 in Google sketch up and export them as OBJ ,, chop this into squares of different sizes and use them as tiles. otherwise send them through blender and they should import okay.
     
    Last edited: Feb 6, 2013