Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Pre-alpha tile-based, hexagon 4X engine

Discussion in 'Made With Unity' started by Tasarran, May 15, 2011.

  1. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Been working seriously with Unity for about a week now, planning a 4X type game, in the same vein as Master of Magic or Age of Wonders.

    http://www.youtube.com/watch?v=DAzZuxWzeH0

    You can pan around by clicking, and mouse-wheel in and out.
    The terrain is just a random spread of tiles, no trees yet, but there is animated weather in some hexes, and animated smoke coming out of the volcanoes.

    I'll keep this thread going with updates, if anyone expresses interest.
     
    Last edited: Jun 1, 2011
  2. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    This is very cool. Is this just placed hexagonal models at the moment? Or are they stored in some sort of Tiles data structure for later processing like pathfinding and tiledata?
     
  3. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Well, there is an array right now, that just holds one int for each tile, that is the terrain type.
    I'm not doing anything with it at the moment, I'm going through a possible change in the way I am thinking about my game data...

    I am not sure I need to keep a big array of structures, the game objects themselves ARE an array.
    I'm starting to think that maybe I don't have to deal with them as an array that has tiles associated with it, but rather the tiles themselves can hold their own variables.

    If the user clicks on a tile, I can grab that OnMouseUp target, and I can have access to data that determines which tiles it is connected to, which tiles those are connected to, etc...

    I started realizing that having an array of data just made for an extra layer to deal with.
    I found myself having to move from game object, to abstract data, then associate that back to the game objects, and I thought, "I should just do this directly"

    Maybe I'm just having the moment where I finally move from my old-school programming skills to a more modern, object-oriented approach?
    I've always had problems shifting my paradigm from 1990's programming, maybe I just needed some hands-on lab work to break my brain out of its rut...
     
  4. CharlieSamways

    CharlieSamways

    Joined:
    Feb 1, 2011
    Posts:
    3,424
    Very interesting. Keep it up
     
  5. c-Row

    c-Row

    Joined:
    Nov 10, 2009
    Posts:
    853
    Ohhh, this is just the stuff that gets me excited. I can already see myself moving units across that landscape. :) Keep those updates coming, please. I will keep an eye on this thread.
     
  6. nickyoso1

    nickyoso1

    Joined:
    May 2, 2011
    Posts:
    85
    looks very nice!
    Actually I am working on the same thing, but for me it is going to be for the battle system of my rpg.
    I also got movement and ai movement done.
    But it is always nice to see someone else makes something similar.
     
  7. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Thanks for the feedback, friends!

    I decided the next part I was going to work on was pathfinding; hopefully, I'll be able to have a new video in the next couple of days.
     
  8. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    I changed the array so that it now holds a reference to the GameObject that is each tile.
    So I can call a given tile number and do whatever I want there.
    Get variables stored there for Pathfinding or whatever, get the position, check for structures or units, whatever...

    It's just a one-dimensional array, because I had a lot of trouble getting two-dimensional arrays to work.

    But its no trouble to convert, the array position is equal to (Row # * Width in tiles) + Column #

    So, if I have say, a ten-by-ten map, the second tile from the left on the second row is actually tile 1, of row 1.
    Both the coordinates and the array start with 0, so the top left tile is 0,0.

    So: (1 * 10) + 1 = Map[11]

    It's almost as easy to go back:
    Row = integer ( Array# / Width )
    Column = Array# - ( Row * Width )

    I just wrote a couple of helper functions to do this conversion for me, and viola!
    No more fiddling with trying to get two-dimensional arrays to work.
     
  9. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Sounds good, a one dimensional array should work just fine and dandy as long as it's easy to find all "connected" nodes (for pathfinding purposes).

    Is each hex tile a separate mesh? If so was just curious if you ran into any size limitations? I'm new to the whole "combining meshes" thing.... was just curious if you even had to consider something like that yet or if decent sized terrains were already possible.
     
  10. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Well, I don't combine my meshes, they are individual tiles, and they only have a single sphere collider, so they can be clicked.
    So, I've never run into any limitation as far as that.

    There is some lag during creation, and it does get up to around three minutes to create a 100x100 map.
    The bigger the map is, the longer it takes, you can generate a 50x50 in about 20-30 seconds, but it takes six times longer to create a map that is four times the size.
    Apparently, I still have some optimization to do; but I think that some of it can be attributed to the random rolls in the creation process. Later on, it will be being loaded, rather than created on the fly.

    I have my tiles grouped under top GameObjects that are called Hexes.
    Under those are the Tile objects that contain the meshes.
    Grouped with those are what I call Elements. Most tiles don't have any Elements, except for the Volcano, which has a pulsing orange light and a particle system.

    I'm thinking that there will be some sort of Pather object grouped under the Hex that will contain the pathfinding variables.
    I''m just planning on using standard A*, so I'll have an F, G, H variable slots, a six-slot array that holds references to the adjacent Hexes, and I suppose I'll need a move cost var, too.
    The connected hexes will get initialized on map creation, the move cost too.
    The other vars will just be there waiting for pathfinding to be run.
     
  11. Sammual

    Sammual

    Joined:
    Oct 28, 2008
    Posts:
    176
    This looks fantastic. I am very interested in your project. A Hex tile based Master of Magic game is my dream game.
     
  12. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    My true goal is to turn this into a persistent-world game that happens in an accelerated time frame...

    A multiplayer hybrid of RTS and turn-based strategy. You'd log on, input your moves and orders, and either wait and watch the world run, or log off and come back later to see how your guys did.

    This would be my goal, but I might end up just making this a traditional load it and play it game...

    I also want there to be an RPG element, like in MoM, but in my game, all entities will be able to learn skills by being taught, and with experience. To make soldiers, you'll have to train troops with a weapon skill, perhaps an armor skill, and maybe a couple of other skills to round them out, like observation, or pathfinding. Then you equip them with gear, and the type of troop they are will be determined by the skills/gear combo you train them for.
    Certain combos would open up certain special tactics that otherwise wouldn't have been available...

    Have guys trained in light armor, spear, short sword, and large shield, and you have a Phalanx, with the ability to make themselves almost immune to arrow fire with their shields.
    Train them in missile weapons and stealth, you get Snipers, with the ability to shoot and stay hidden, or to shoot and move away.
    etc...

    There will be some limit on how many skills an entity will be able to train in, so nobody can end up with units that have every skill, can use every weapon and also build any building.

    You could have things like, a unit of peasant Fletchers that follow your arrow-using army around, and make arrows for them...

    I also want the resource gathering to be more specific.
    Instead of having your people around a city automatically produce X food, Y production, and Z trade, like in Civ and MoM, you'll train some peasants with, say, woodsman/lumberjack skill, give them axes, and give them orders to go out to a forest and get some trees and bring them back.
    Skill level will affect speed and amount harvested, and also the chance that you might find something special (in this case, perhaps some units of special or magical wood, or some rare spell components.

    So your city might end up with several teams of Farmers, Ranchers, Lumberjacks, Fishermen, Miners, etc., all working the area, bringing in resources to the city for the home-body peasants, like the Bakers, Blacksmiths, Carpenters, Bowyers, etc to make stuff with...

    If you want to set up permanent or ongoing resource harvesting, you will be able to build structures near the resource, such as a sawmill, that will increase the productivity of your workers.
     
    Last edited: May 26, 2011
  13. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Update: Pathfinding

    http://youtu.be/3Eru2OZZciQ
     
  14. spg

    spg

    Joined:
    Aug 6, 2009
    Posts:
    79
    Nice work man, Masters of Magic is one of my favorite games ever - good luck moving forward!
     
  15. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Wanted to post a slight technical discussion, for those of you who are interested...

    I'm using just plain A-star pathfinding, although I'm still tweaking the heuristic.
    It seems to be tricky to get the right value on a map with variable move costs.
    Anyway, that's just optimizing; at this point, I don't care that it takes a few seconds to plot a long path, because the actual pathfinding routine is a CoRoutine. The pathing happens in the background.
    You can see in the video that there's no pause in the animating start and end cubes when the path is being calculated.

    So, the way I set this up is each Hex is an empty gameObject, called Hex-{terrain_type}, ie. Hex-Desert, Hex-Hills, etc
    The actual geometry sits under the Hex, and it is named Tile-{terrain_type}.
    To this little family, I added a script called "Pather". This script is just a list of variables.
    During map creation I set up all the hex connections in an array called Direction[], that has six entries, containing a reference to the gameObject of the neighboring Hex.
    I also set up variables for FCost, GCost, HCost, MoveCost.
    Whenever I need to refer to a variable in the pather, I just use GameObject.GetComponent(Pather).whateverVar
    If I'm going to refer to it a lot, I make a variable, and set it thusly:
    var nextHexPather = GameObject.GetComponent(Pather);
    Then I can shorten the above line to simply: nextHexPather.whateverVar

    There is an empty gameObject in the scene called PathManager, where the actual pathing routine lives.

    One point to note for anyone about to go through this process yourself, keep in mind that you will need to reset most of these variables when you get done finding the path, so that you can have a clean slate to find the next path.
    In particular, you will need to reset FCost, GCost, HCost, the Parent variable, as well as clearing the Open and Closed lists, so that these variables won't interfere with your next run.
    I tried at first to get away without a Closed List, instead using an isClosed flag on the Pather, but when time came to tweak the code to make it able to path a second time, I realized I would have to cycle the whole map to reset all the closed ones, so I added an array for the Closed List.
     
  16. Sammual

    Sammual

    Joined:
    Oct 28, 2008
    Posts:
    176
    I have been addicted to Blight of the Imortals so I know exactly what you are talking about. Sounds fantastic.

    I read the rest of what you want to do and it sounds VERY ambitious.
     
  17. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Some tips for the A*...

    The heuristic should return the minimum distance from the current position to the target in terms of movement steps. If you have different terrain types then the heuristic should assume that the remainder of the path is going across the most advantageous type of terrain. Basically, the heuristic should be as accurate as possible but it should also be an underestimate. Also, if you are using Vector3.Distance or Vector3.magnitude to calculate distances in the heuristic then you can improve its speed by leaving these out and just multiplying the number of steps by the width of a hexagon. Since the heuristic function will be called many times, you want it to be as fast as possible.

    Also, the closed list will help efficiency greatly but you should use a Hashtable or Dictionary to implement it, since this will give much faster lookups than searching through an array.
     
  18. Sammual

    Sammual

    Joined:
    Oct 28, 2008
    Posts:
    176
    To quickly find the distance between two hexes read this.

    The short version is that you use a triple coordinate system (X,Y,Z) and the (min) distance is always = max(abs(X1-X2),abs(Y1-Y2),abs(Z1-Z2).

    For pathfinding I don't bother with a 'hex connections array' as each hex has six neighbors (as long as X, Y, Z are not at the min or Max amounts) of X -1, X + 1, Y -1, Y + 1, Z -1, Z + 1.

    And after you have your A* working correctly read this to learn about binary heaps to make your A* as fast as it can be.
     
    Last edited: Jun 2, 2011
  19. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    Thanks for the tips, guys.

    I can figure distance exactly, no problem. My coordinates are set up with an XY coordinate system, such that all the totals of the X Y are even.
    In other words, there is a 0,0 but no 0,1. It lays out like this:

    0,0 --- 2,0
    --- 1,1 --- 3,1
    0,2 --- 2,2


    If I were actually storing these in an array, it would be 50% wasteful, but since the only array that holds the gameobjects is one-dimensional, and the coordinates are just numbers, it's not a problem to refer to them this way.

    With the coordinates this way, its a simple matter to use a straight multiplication to place them, and not have to worry about the odd columns being shifted down half a hex. No if statement needed to check odd/even, just multiply Z(Y) by half the hex height and multiply X by the hex width.

    So, my algorithm using this system is Distance = (abs(X1-X2) + abs(Y1-Y2)) / 2

    So, I guess its best to just leave that number unmodified, since it gives the true distance in hexes, and my lowest move cost is 1.

    I read an article on binary heaps a while back, it does seem like a lot faster way to sort the lists; I'll see about modifying that later.

    Next, I want to get some units in the game to actually USE the pathfinding now :)

    Wow, I never knew about Hashtables... Looking at the description, I can see how that would be very useful in this application. Especially since my main map array is a one-dimensional array. I could replace this with a hashtable if its faster.
     
    Last edited: Jun 2, 2011
  20. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
  21. Tasarran

    Tasarran

    Joined:
    Jan 20, 2011
    Posts:
    327
    For those of you who were following this thread, it is back in development again, with a highly revamped engine...
    This map doesn't have discrete tiles any longer, it is all one big mesh, and it is fractalized, to create a very realistic terrain where no two hexes look exactly the same. (Check the hills and mountains in the screen below).
    It also uses a Raycast instead of a series of Sphere Colliders to find the hex the mouse is over, which seems to increase performance quite a bit.

    Follow the new thread in the WIP forum...
    http://forum.unity3d.com/threads/143632-Glyph-Fantasy-4X-TBS

    Here is an image!
    $Glyph1.jpg
     
    Last edited: Jul 14, 2012