Representing a board of Hexagonal pieces in a 2-dimensional array

When working on Hive and Proximity, we’re dealing with boards of hexagons. If you look at a bunch of hexagons together, you’ll notice that they don’t sit next to each other in a way that’s a straightforward analog to square pieces like you’d find in a chess board.

In the process of working on these two games, I came up with a system of mapping all the pieces to a 2-dimensional array (rows and columns).

As shown in the diagram: if you offset every other row by half of a tile, you can address every space using normal row/column coordinates. The red arrows show a path of traversing across columns in the same row and the blue arrows show a path moving down rows in the same column. In a board with square pieces such as chess, these would both just be straight paths instead of the blue lines zig-zagging. As an exercise, can you see where the next column to the right of the blue lines would be? The second column would start at (1, 0) and would go to (1,1), then back to (1,2), then (1, 3) and so-on. Not so complicated! 🙂

The math for finding the coordinates of a space in a specific direction from a starting-space is still slightly more complex than normal square boards because the calculation is different based on which row you start in. To completely remove the necessity for doing these calculations more than once, I started using helper functions to help get a piece in any direction or to get a collection of all adjacent spaces.

As you might be aware, Proximity is Open Source, so you can check out exactly how we handled things.

To make things quicker, I’ll post a peek at some of the helper functions we used in Proximity. One quick note: this code forces all pieces to have positive-integer coordinates because the board for Proximity is a predetermined size. Since Hive is a bit more dynamic, that game doesn’t have those restrictions. Fortunately, this coordinate system still works fine with negative coordinates.

Here is the helper-code for Proximity (in javascript):
[crayon lang=”js”]
/***** DIRECTIONAL HELPER FUNCTIONS *****/
this.leftOf = function( row, col ) { return new Proximity.Coords( row, col-1 ); }
this.topOf = function( row, col ) { return new Proximity.Coords( row-2, col); } // need to jump two rows in the array to work visually
this.rightOf = function( row, col ) { return new Proximity.Coords( row, col+1); }
this.bottomOf = function( row, col ) { return new Proximity.Coords( row+2, col); }
this.topLeftOf = function( row, col ) {
var coords;
if( row % 2 == 0 ){
coords = new Proximity.Coords( row-1, col-1 );
} else {
coords = new Proximity.Coords( row-1, col );
}
return coords;
}
this.topRightOf = function( row, col ) {
var coords;
if( row % 2 == 0 ){
coords = new Proximity.Coords( row-1, col );
} else {
coords = new Proximity.Coords( row-1, col+1 );
}
return coords;
}
this.bottomLeftOf = function( row, col ) {
var coords;
if( row % 2 == 0 ){
coords = new Proximity.Coords( row+1, col-1 );
} else {
coords = new Proximity.Coords( row+1, col );
}
return coords;
}
this.bottomRightOf = function( row, col ) {
var coords;
if( row % 2 == 0 ){
coords = new Proximity.Coords( row+1, col );
} else {
coords = new Proximity.Coords( row+1, col+1 );
}
return coords;
}

/**
* Returns an array of all of the coordinates surrounding the given coordinates.
*/
this.getSurroundingCoords = function( row, col ){
var allSurroundingCoords = [
self.topLeftOf(row,col),
self.topOf(row,col),
self.topRightOf(row,col),
self.bottomRightOf(row,col),
self.bottomOf(row,col),
self.bottomLeftOf(row,col),
];

// Only return coordinates which are on the board (not off the edge).
var validSurroundingCoords = [];
for(var index in allSurroundingCoords){
var coords = allSurroundingCoords[index];
if((coords.row >= 0) && (coords.col >= 0)
&& (coords.row < self.getNumRows()) && (coords.col < self.getNumCols())){ validSurroundingCoords.push( coords ); } } return validSurroundingCoords; }; [/crayon]

Proximity HTML5 game for Pokki is now Open Source

Last week, we announced Proximity for Pokki.

Tonight – in hopes of helping other game developers get off the ground with HTML5 games and/or developing new apps for Pokki – we’re making the code for Proximity open source.

If you have some questions about anything we did in the app, please let us know in the comments and we’ll try to respond right there or write some tutorials for more complex answers.

Here are the interesting links:

When you’re done grabbing the code, see it in action by downloading Proximity for Pokki!

Configurable-radius deadzone for thumbsticks in XNA

Yesterday, while co-working at The MADE (a cool game museum that lets Bay Area developers work out of some of their space), the topic of thumbstick deadzones came up. Ian Stocker mentioned that he had recently made a blog post about using the Xbox analog sticks as a DPad in XNA.

Since Hive deals with hexagons, I didn’t do my implementation quite the same. The deadzone code I used is separate from the code for getting directions, so it should work regardless of what your game is using the thumbsticks for.

We discussed the methods that we used for adding a “deadzone” to the analog sticks. A deadzone is the area near the center of the stick where you ignore input because slight movements (or even old controllers while their sitting still) could trigger unintended input otherwise. He explained that his deadzone was square and thought that people might benefit from my code which makes a circular dead-zone, so here it is!

I did the entry-level trigonometry so that you don’t have to! 😉

Example usage of the thumbstick “deadzone” code.
[crayon lang=”c#”]
PlayerIndex playerOne = PlayerIndex.One;
GamePadState gamePadState = GamePad.GetState(playerOne);
Vector2 leftThumbstickState = gamePadState.ThumbSticks.Left;
if ( ThumbstickMovementIsSignificant(leftThumbstickState) )
{
// Actually use the leftThumbstickState.
}
[/crayon]

And this is the general code that I put in my GamePadHelper.cs.
[crayon lang=”c#”]
///

/// Returns true if the movement is significant, false if the movement was so slight
/// that it shouldn’t be counted. This uses a reasonable default for how much to ignore.
///
///

/// ///
public static bool ThumbstickMovementIsSignificant(Vector2 thumbstickState)
{
float percentToIgnore_default = 35.0f;
return ThumbstickMovementIsSignificant(thumbstickState, percentToIgnore_default);
}

///

/// Determines if the thumbstickState passed in is significant enough, given the constraint
/// of how much movement should be ignored.
///

/// /// Percentage of the unit-circle which is ignored. If 25.0f, then the inner-quarter of movements will be considered too slight. If 50.0f, then the inner half will be ignored, etc.. public static bool ThumbstickMovementIsSignificant(Vector2 thumbstickState, float percentToIgnore){
bool isSignificant = true;
if (percentToIgnore > 0)
{
// Uses pythagorean theorem to see if the hypotenuse ends inside of the “significant” area or not.
float a = thumbstickState.X;
float b = thumbstickState.Y;

// Thumbstick numbers are in a unit-circle so scale the percentToIgnore to the range of 0.0 to 1.0
float minHyphotenuseLengthForSignificance = (percentToIgnore / 100);

// This function is likely to be called every tick, so we square the minimum hyptotenuse instead of comparing it the sqrt of a^2 + b^2 (square roots are a bit slow).
if (((a * a) + (b * b)) < (minHyphotenuseLengthForSignificance * minHyphotenuseLengthForSignificance)) { isSignificant = false; } } return isSignificant; } [/crayon] I haven't played around with the thumbsticks that much, so I'm not sure how big of a deadzone is ideal. I stuck with the default of percentToIgnore_default = 35.0f;, which means that the inner 35% of the thumbstick’s radius is ignored. Feel free to tweak the default or pass in a custom value as the second parameter to ThumbstickMovementIsSignificant().

Hope the code is helpful! 🙂