Skip navigation

Monthly Archives: March 2011

Week one, I hope, will be the least exciting of weeks. I got my GitHub repo set up (sorry, I’m keeping this closed source for now), added a clone of the Cocos2D git repository as a subtree of my main project, and got Xcode set up to build Joyride and run a simple hello world. It’s not much to look at, but it scratches “The Player can start the game” of the list. Look!

Hello World!

With Cocos2D sitting in my repository, it should be easier to pull down patches from them, which was a huge pain last time. I’m a little worried though. I made a change to one of the Cocos2D files to remove a warning in Xcode and pulling the latest changes from the Cocos2D git overwrote those changes. I’m hoping it is just because it was binary file and the diff’ing doesn’t work in those cases. It’s something I’ll need to look out for. I think I might also need to look into getting a visual client for git. Working on the command line hasn’t been too bad, but I could see it getting annoying.

The next task is “The player starts in the center of hex field“. This will probably take a full week or two. I have to make some assets in Tiled using hexes. Last time I tried this, support wasn’t 100% in Tiled or Cocos2D for hex tiles, but I’m hoping the last year saw some improvements. There is sample code that has hex tiles, but I remember making some changes to the underlying engine to get it to work the way I wanted. This task has 3 points, just because I expect there might be a lot of little gotchas along the way.

There’s been enough talking about Joyride. It’s time to make actually make the freakin’ game! Next week, I’m actually going to start working on this thing. How is this going to go?

Tracking the work

I put my task list for everyone to see on Pivotal Tracker. This makes sure my account there is free and I’ve been very open so far, so why not continue with this? Pivotal Tracker is probably a bit overkill for this stage of development, but I like the way it works and matches my own personal workflow pretty closely. “Sprints” right now are at 4 weeks and each week I’m going to put in 5 hours of work.

Yes. That’s not a lot. I’m sure some indie devs are scoffing right now. Look: I have a day job making video games. A job I like very much. I have a wife. A wife I love very much. I have friends. Friends I like to hang out with. And then there is the other items of joy such as playing other people’s games or watching TV or reading or whatever. Joyride is a hobby and as such and I cannot let it be too consuming. 5 hours. Right now, no more and no less. I can revise as I go, but it’s a start.

Weekly progress reports

Each week, I’m going to briefly go over the work I have done, what work I will tackle next, and any issues or observances. This is like a weekly standup for my “sprints”.

No feature creep

I’m going to come up with new ideas. I will probably get great ideas from people following me here. I will not attempt them in the first version. I will right them up and add them to Future Ideas.

And here we go!

Wish me luck! This is going to be a lot of fun.

I’m making a game with a hex based grid. These are my notes on my implementation (so, far). This is dry and without much explanation, but if you want to do the same, maybe this will help you.

Moving between tiles

Now, a hex grid is a 2D so one might think that 2D coordinates would work best. It is my opinion they don’t. You don’t have the same X-Y movement in a Cartesian environment. It’s actually more like three directions of movement: up-down, NW-SE, and SW-NE. So, how about 3D coordinates?

trans

It may seem a bit odd, but trust me, it’s really nice. This system has some handy properties:

  1. The sum of coordinates (a,b,c) will always equal zero. Handy for validation.
  2. Distance from origin is max(abs(a), abs(b), abs(c)). I think that might be cheaper computationally than Cartesian distance mostly because I don’t have that square root.
  3. Distance from p1 and p2 is max(abs(a2-a1), abs(b2-b1), abs(c2-c1)).
  4. (a',b',c') = a+Δa, b+Δb, c+Δc
  5. (x', y') = x+Δa, y-floor(x/2)+Δb+floor((x+Δa)/2)

Line 5 is the sort of reason why the 3D coords work so much better. That math is just ugly. My first implementation had something much like that and it just causes so many bugs and brain twisters figuring things out.

Storing the tiles in memory

While this system is nice, it fails memory storage. It still has to be shoved in an array. Thankfully, translating from hex coords (a,b,c) to 2D coords (x,y) is straight forward. First, some basic principles.

(x, y) 
    = (a, b+floor(a/2))
    = (a, b + a >> 1)
(a,b,c) 
    = (x, y-floor(x/2), -(a+b)) 
    = (x, y - x >> 1, -(a+b))
    = (x, y - x >> 1, (x>>1)-x-y)

Pretty simple code that can be optimized; just adds, subtractions, and bit shifts. But still more work needs to be done to get it into an array. First, let’s define some spaces:

even odd

Any tile could be considered a playable space in the game, but for Joyride, I was thinking having the colored tiles be the actual play space and the clear tiles would just be unused space. I like it because we have a hexagon made from hexagons! The pictures also indicate how a even-radius hex space and an odd-radius hex space would fit into the space. With this, I can translate into an array.

w = h = HexSpaceRadius * 2 + 1
(xMax, yMax) = (w-1, h-1)
Array length = w * h
Array index 
    = (x * h) + y
    = (a * h) + b+ (a>>1)
(x,y) = floor(i/h), i%h

That will get me a hex grid with the following coordinates:

coord

The “origin” in my hex space isn’t the same as my array, but here is the translation:

2D origin 
    = (x0, y0)
    = (floor(xMax/2), floor(xMax/2))
    = (xMax>>1, xMax>>1)
3D origin
    = (a0, b0, c0)
    = (x0, y0 - x0>>1, (x0>>1)-x0-y0)

To demonstrate through example, here is the stuff we would pre-compute for the 2-radius hex space above:

w = h = 2*2+1 = 5
xMax, yMax = 4, 4
Array length = 25
2D Origin = (2,2)
3D Origin = (2, 2 - 2 >> 1, 2>>1 - 2 - 2) = (2, 1, -3)

There’s is a lot of conversion to and from the different coordinate systems. I’m planning hide most of it away though convenience functions, type converters, and caching. I haven’t give that much thought yet. I can also figure out my wasted space (those clear tiles). The number of tiles use for my Hex Space is calculated as thus:

totalTiles = 1
for ( i=1; i<=r; i++)
    totalTiles += i*6
waste = Array length - totalTiles

Just to put some real numbers on it, for a 3-Radius Hex Space and a 20-Radius Hex Space:

  • 3-Radius
    • Array Length = 7*7 = 49 tiles
    • Total Tiles = 37 tiles
    • Waste = 12 tiles (24.49%)
  • 20-Radius
    • Array Length = 41*41 = 1,681 tiles
    • Total Tiles = 1,261 tiles
    • Waste = 420 tiles (24.99%)

Interesting that the waste is always about 25%, but not too surprising. That’s quite a bit of memory that could end up being wasted and that might be something I’ll need to be wary of going forward.

Converting Screen Space to Hex Space

I have implemented this, but I haven’t done a write up on it yet. When I get back around to doing this again, I will fill this out. This is one of the things that’s pretty easy to find in a google search. It was one of the first topics I found when researching this. But, if for some reason you need this before I get to it, leave a comment and I will write it out.

An idea just occurred to me and I want to write it out. This is a note to myself, so I don’t forget, but I wanted to share, too. So, HexSpace is Burmuda Triange of space travel, right? What if, instead of the player being sucked in, he is a daring (even foolish) treasure hunter that purposely enters HexSpace for loot? Normally, the unlucky have something go wrong while traveling through a wormhole to survive. These treasure hunters have found a way to force the relative safety of faster-than-light travel and inject themselves into wormholes voluntarily. They cannot exactly control where they will dump out of the wormhole, it’s practically random! And there we have a handy little fictionally consistant reason why the maps are different each time. Bonus idea: wormholes in different regions of space have different feeling HexSpaces. No one knows why, but the danger, loot, and affinities are more in-sync with some wormholes than others. This gives a good additional mechanic for player progression and preference. As they player levels, additional wormholes are opened up, allowing tougher maps or new gameplay hooks. Also, players might prefer HexSpace sectors from Wormhole X as opposed to Wormhole Y and can keep playing sectors there.