How to scroll hex tiles?

I don't seem to be able to find an answer to this one. I have a map of hex tiles. I wish to implement scrolling.

Code at present:

drawTilemap = function() {
actualX = Math.floor(viewportX / hexWidth);
actualY = Math.floor(viewportY / hexHeight);
offsetX = -(viewportX - (actualX * hexWidth));
offsetY = -(viewportY - (actualY * hexHeight));

for(i = 0; i < (10); i++)
{
for(j = 0; j < 10; j++)
{
if(i % 2 == 0) {
x = (hexOffsetX * i) + offsetX;
y = j * sourceHeight;
} else {
x = (hexOffsetX * i) + offsetX;
y = hexOffsetY + (j * sourceHeight);
}

var tileselected = mapone[actualX + i][j];

drawTile(x, y, tileselected);
}
}
}

The code I've written so far only handles X movement. It doesn't yet work the way it should do. If you look at my example on jsfiddle.net below you will see that when moving to the right, when you get to the next hex tile along, there is a problem with the X position and calculations that have taken place.

It seems it is a simple bit of maths that is missing. Unfortunately I've been unable to find an example that includes scrolling yet.

http://jsfiddle.net/hd87E/1/

Make sure there is no horizontal scroll bar then trying moving right using the -> right arrow on the keyboard. You will see the problem as you reach the end of the first tile.

Apologies for the horrid code, I'm learning!

Cheers

• I've managed to find this. xnaresources.com/default.asp?page=Tutorial:TileEngineSeries:3 Unfortunately it works out the display correctly but uses incorrect co-ordinates. If you look at the picture, I don't think these will work with hex math. – Chris Evans Nov 22 '11 at 6:05
• I've adjusted the code further and is cleaner and easier to understand in the bit that matters. You can find a full example here: jsfiddle.net/wg45T/2/embedded/result and the code here: jsfiddle.net/wg45T/2 You will find it scrolls right just fine now and recreates the map etc ok. The problem is now that it doesn't maintain the position of the on coming tile when the old tile is removed. Try scrolling right to see. – Chris Evans Nov 22 '11 at 6:13
• I've found the answer but cannot post yet. Will upload when the time limit ends. – Chris Evans Nov 22 '11 at 6:29

Whether hex or not, I'd suggest keeping your location variables (x, y) pointing to the game world, and converting to/from the screen coordinates only when needed. When you convert from screen to world you add (cameraX, cameraY) then divide by (tileStepX, tileStepY). When you convert from world to screen you multiply by (tileStepX, tileStepY) then subtract (cameraX, cameraY). Note that there's a minor complication with hexes, which you handle with columnOffset.

Here's a simpler version of your code, with x, y, firstX, firstY in world coordinates:

drawTilemap = function() {
// Convert top left of the screen (0, 0) to world coordinates
firstX = Math.floor(cameraX / 45);
firstY = Math.floor(cameraY / 50);

for( x = firstX; x < firstX + 10; x++ )  // world coordinates
{
var columnOffset = oddRowOffset * (x % 2);

for( y = firstY; y < firstY + 10; y++ )  // world coordinates
{
// Make sure this world coordinate is part of the map
if ( 0 <= y && y < mapone.length && 0 <= x && x < mapone[y].length )
{
// Convert world coordinates to screen coordinates
drawTile((x * tileStepX) - cameraX,
(y * tileStepY + columnOffset) - cameraY,
mapone[y][x]);
}
}
}
}
• What superb simplification! Cheers :) – Chris Evans Nov 23 '11 at 2:42

Found the answer! View here: http://jsfiddle.net/ck6Vq/1/embedded/result/

Not sure if anybody can come up with anything tidier than the code below?

drawTilemap = function() {
firstX = Math.floor(cameraX / 45);
offsetX = cameraX % 45;
if(firstX > 0) {
firstX = firstX - 1;
offsetX = offsetX + 45;
}

console.log(offsetX);

firstY = Math.floor(cameraY / 50);
offsetY = cameraY % 50;

for(x = 0; x < 10; x++)
{
var rowOffset = 0;
var columnOffset = 0;

if((firstX + x) % 2 == 1)
{
columnOffset = oddRowOffset;
}

for(y = 0; y < 10; y++)
{
drawTile((x * tileStepX) - offsetX,
(y * tileStepY) - offsetY + columnOffset,
mapone[y+firstY][x+firstX]);
}
}
}