Diamond Isometric map scrolling Part One

First off the reason this tutorial is referred to as diamond isometric is because we will be wrapping up on the simpler isometric method soon. This tutorial is split into two parts. Part one covers the simple scrolling and displaying only a visible area of the map. The second tidies up the offsets we have added as well as implementing a further method to keep our drawing minimal and overall speeding up our game.

What is this diamond method you speak of you ask?

It’s basically what we have been using so far. If you look at your isometric map it is a diamond. It is by far the simplest method of drawing out your tiles as well as keeping track of player positions, interactions and other such game requirements like path finding. The tutorial after this written up by Ed will cover the path finding and AI basics for this sort of isometric map. This tutorial will cover producing a large scrolling isometric map and some optimization techniques to help speed things up in canvas.

What we aim to have at the end of this is a large smooth scrolling 100×100 tile map which only draws the most required tiles. We will have a startX and startY range which when calculated will be the starting point in the array for our draw function. This alone would reduce the above screenshot like so:

With only the tile rows being drawn that are needed to fill the screen we have already reduced our 10,000 tiled map to 49 tiles at a time. If this is for multiple layers then that is a huge saving. On top of this we can use a second tile limiting method which I found also contributes to keeping that frame rate high meaning Ralph can avoid those possessed water coolers worry free.

Using startX and startY within our array we can work out easily what the middle tile is on screen. With a couple of small conditional checks you can check the distance of the surrounding tiles and make sure they are worth drawing. For example in the above screenshot, due to our diamond system we have the point unseen tiles on all four sides still being drawn. The outcome would look like this:

Taking the total drawn tiles from 49 down to 28.

So we’ll just dive straight in and fire out our scrolling.

Just following on from tutorial 7: http://glacialflame.com/tutorials/tiles/06/

First change to make if you are still using a small viewport is to increase its width and height to a decent size. Perhaps even centre it. (make sure you update the clearRect to match your new sizes e.g. ctx.clearRect(0,0,500,500).

Using the following little script I had a random array of 100×100 tiles made up:

http://glacialflame.com/tutorials/tiles/07/gen.php?x=100&y=100&type=array

The array it generates is just made up of 0s and 1s.

If you replace the current contents of both the map and objectMap with a random generate array as well.

If you declare at the top with the rest of your global variables:

var mapXD;

var mapYD;

These two variables will hold the direction we are scrolling.

In the mouseCheck(e) function add the following anywhere under where x and y are set. As the width I’m using is 500, I set it to have a 100 space

	  if(x - canvas.offsetLeft> 400 ){
	   	  mapXD= 1;
	  }else if(x -canvas.offsetLeft < 100){
		  mapXD =2;
	  }else{
		  mapXD = 0;
	  }
   	   if(y - canvas.offsetTop > 400){
		  mapYD= 2;
	  }else if(y - canvas.offsetTop < 100){
		  mapYD =1;
	  }else{
		  mapYD = 0;
	  }

In the drawMap() function add the following before the draw loops:

if(mapXD == 1){mapX -= 5;}

if(mapXD == 2){mapX += 5;}

if(mapYD == 1){mapY += 5;}

if(mapYD == 2){mapY -= 5;}

And that’s all that is required for the scrolling part. Using the mouse we can now move around our large world as we please. The first issue here is we have 10,000 tiles being drawn at the same time, and although it may or may not run smooth depending on your pc specs there is some demanding improvements to be made.

Add the following to the drawMap after the previous addition of code:

		startY= mapY+(mapX/2);
		startX=(startY-mapX);
		startY=Math.round(-startY/25);
		startX=Math.round(-startX/25);
		if(startX  < 0){startX = 0}
		if(startY < 0){startY = 0 }

And update your two tile drawing for loops to reflect the following:

for(i=startX;i<map.length;i++){

for(j=startY;j<map[i].length;j++){

The startX and startY defines where to start within the map array from position of your map according to its mapX and mapY values.

If you test your code now you will see that you always have a pointing tip to your map.

Next up we will add a range of tiles to draw.

Declare another two variables within the drawMap()

var rangeY = 10;

var rangeX = 10;

Then add the following before draw your for loops once again

if(startY+rangeY > map.length){ rangeY =  map.length-startY;}

if(startX+rangeX > map.length){ rangeX =  map.length-startX;}

Finally update your loops to take in the range.

for(i=startX;i<startX+rangeX;i++){

for(j=startY;j<startY+rangeY;j++){

rangeX and rangeY represent how many tiles you wish to draw. If you run your code you will see it should scroll properly but may need some adjustments. If your finding your map keeps running away then the following will need updated:

var xpos = (i-j)*tileH+ mapX;

var ypos = (i+j)*tileH/2+ mapY;

In my case my mapX needed reversed with a further offset applied:

var xpos = (i-j)*tileH - mapX + 235;

var ypos = (i+j)*tileH/2+ mapY+50;

These offsets and ranges will all need customized to your specific tiles and how much you wish to draw. With the right offset and tile range you can fill your screen no bother and keep drawing to a minimum.

var mapX = 0;
var mapY = 0;

For the purpose of this part of the tutorial I set the initial mapX and mapY globals to zero.

The next part of the tutorial will cover fixing the mouse for your new offsets and adjusting the range to fill your viewport as well as the second distance from centre tile speed-up method. Will have the next part of this up in a couple of days, probably Monday.

As always the full source code so far can be seen here:

http://glacialflame.com/tutorials/tiles/07/

Let me know if you run into any issues!

Posted in Uncategorized | 4 Comments

Delay for another week

Just a wee update on things. Once again just as momentum was building university/work steps in and says no not today mates. Ed has his final honours exams for his electronics and electrical engineering degree this week and I’m staring at iOS stuff for a good while. We do have a list of tutorials we are going to fire out though as soon as next week ends.

Diamond based isometric map scrolling,

Diamond based isometric path finding

Some more random stuff for diamond based isometric maps like player projectiles and collisions as well as a simple method to speed up your game.

Then.

We will cover rectangular based isometric maps (which we use) and everything that we covered previously but to work with this different and more optimized layout method.

Also… Should have some updates on Rabbit Zombies in the next couple of weeks.

Catch you all in a week!

Posted in Uncategorized | 5 Comments

Rabbit Zombies

As we mentioned in a previous post, we are working on a game with the current engine state to highlight the capabilities of what we have created.
So I give you. Rabbit Zombies.

We aim to have the alpha testing up for this soon, be sure to stay tuned.

http://www.rabbitzombies.com/

Posted in Uncategorized | 2 Comments

Canvas Isometric Tutorial – Add a player and throw in some objects Pt2.

Walls and other solid objects

This will be pretty easy to do and apart from a few extra condition checks in your movement code everything else is really just a case of duplicating.

Obviously to begin with we are going to need a wall tile, for this tutorial I decided to go with the orange wall of blockade. Took a while to plan out and design before creating such a tile but here it is if you wish to use it, carefully.

The wall as usual is a .png. The .png canvas height is made to be 50 pixels, double the ground tile height. This means our object can be any height between 0 and 50 pixels and by halving the height attribute of the object we can always line it up with ground tile it is on top of.

For speed and ease I’ll be going back to the original source of tutorial 02 where the map is just directly in the array rather than loaded as XML from a database. Ralph, our playable character has also been added in. It shouldn’t be hard at all though to use a later code version as I said it really is just a case of repeating some steps.

Current source of all the isometric tutorials minus the loading/saving can be seen here:

http://glacialflame.com/tutorials/tiles/06/source.html

Step One – loading our isometric objects

Adding objects is simple. Duplicate the ground tile code and then draw it on top once our ground layer has been drawn. Using a second array for objects means for simplicity all we have to do is look up the array coordinates relating to the players desired position, if there is an entry then that coordinate is impassable.

So duplicate the map array and imagine for just now zero is passable and one is a wall.

var objectMap = Array([0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,1,1,0,0],[0,1,1,0,0,1],[1,0,1,1,0,1],[0,0,0,0,0,0],[1,0,1,0,1,0],[1,1,1,0,0,0]);

Also similar to when you added your playable character, duplicate the image arrays and update the loader. Around the same area as your tileDict and tileImg add:

var objectDict = Array("wall.png");
var objectImg = new Array();

In your loadImg() function add:

	for(var i=0;i<objectDict.length;i++){
		objectImg[i] = new Image();
		objectImg[i].src = objectDict[i];
		objectImg[i].onload = function(){
			loaded++;
		}
	}

in your loadAll() function update your loaded condition to check if all object images have been loaded like so:

if(loaded == tileDict.length + charDict.length + objectDict.length){

All done!

Step Two – Let the user personally reflect over our wall object

In order to draw the objects into our map go the function drawMap() and within the loops add the following, underneath var drawTile = ma… is just fine:

var drawObj = objectMap[i][j];

Now we want objects to be drawn on top of our ground so under our ctx.drawImage(tileImg[drawTile],xpos,ypos) and before our character drawing add the following:

if(drawObj){
ctx.drawImage(objectImg[drawObj-1],xpos,ypos-(objectImg[drawObj-1].height/2));
}

This should explain itself, if drawObj (which is equal to the current drawing coordinate in our array ) is anything above zero then… well… draw it. The reason for drawObj-1 is because our object images start at zero however in our object array we start at 1. Otherwise every 0 in our array would represent a wall.

You should now be able to run Ralph around the map behind and in front of walls.

Step Three – HALT! You can’t walk there Ralph

Finally we update our movement code to check if there is an object or not.

Within our checkKeycode(event) function we can throw in the following around our current movement code:

if(!objectMap[playerX-1][playerY]){
playerX--;
}

The if check makes sure that the desired players coordinates within the objectMap array is false allowing the player to move that direction. This is done for each direction like so:

case 38:
if(!objectMap[playerX-1][playerY]){
playerX--;
}
break;
case 40:
if(!objectMap[playerX+1][playerY]){
playerX++;
}
break;
case 39:
if(!objectMap[playerX][playerY-1]){
playerY--;
}
break;
case 37:
if(!objectMap[playerX][playerY+1]){
playerY++;
}
break;

And that’s it. Ralph can now run about our fields with only the orange walls of blockade preventing his fun.

Full source can be found here:

http://glacialflame.com/tutorials/tiles/06/

As always let me know how you get on!

All the best.

Posted in Canvas, Javascript, Tile World, Tutorial | 9 Comments

Canvas Isometric Tutorial – Add a player and throw in some objects Pt1

With Ed finishing up his honours at uni and myself being chained to work over the last month things have slowed down again. However with all the great feedback and emails we have been getting it’s about time this was pushed on!

Currently all we have covered is creating a map. Not any old map though, a map which is generated from an XML feed, a map which brings graphical jealousy to those with even the upper most advanced Photoshop skills. For this is an isometric map. An isometric map we will now add a magnificent controllable cuboid square pyramid. A square pyramid like Ralph.

As we will be moving Ralph over our fields he will need to be like everything else a .png for the transparency, plus it is his preferred file type, bless him. You can download Ralph from this and bump him into your image folder:

Step One – removing the map editor save code (only if using Pt2 code of the saving tutorial)

The following tutorial stages are fine and ready to go with:

Mouse Control on Isometric Canvas tiles

http://glacialflame.com/tutorials/tiles/02/

Saving and loading from a database with PHP & XML in canvas Pt1

http://glacialflame.com/tutorials/tiles/03/

First thing we will do is remove any of the Save code you may have from the previous tutorial. As this is the actual game and not the editor none of it is required. (You will only have this code if you are editing the version created from the saving map tutorial.)

If you have the following remove:


<script src="DBSave.js" type="text/javascript"></script>
------
case 83:
          var db = new DBSave();
          db.saveMap(3,map);
break;
------

<select id="tile">
         <option value="0">Water</option>
         <option value="1">Grass</option>
         <option value="2">Swamp</option>
</select>

- Hit <strong>s</strong> to save.
------

if(map[xmouse][ymouse]){
         map[xmouse][ymouse] = document.getElementById('tile').value;
}
------

Step Two – loading up your character object

We will duplicate our tile images script for the most part so that we can load up Ralph in preparation for his interactivity.

We will add our character image holder at the top around the same area you have your tile dictionary and image holder array.


var charDict = Array("ralph.png"); // -- rename ralph.png to mimic your player image if Ralph wasn't good enough

var charImg = new Array();

We will use an array for the character images for multiple future reasons. You may want to keep non playable characters in this or multiple versions of your playable character relating to movement directions and so on.

Next up we need to edit our loadImg() function to include our character dictionary. Add in the additional loop:

	for(var i=0;i<charDict.length;i++){
		charImg[i] = new Image();
		charImg[i].src = charDict[i];
		charImg[i].onload = function(){
			loaded++;
		}
	}

Similar to the tile loop this just runs through all our images in the character array, loads them and increments the loaded variable.

In our loadAll() function edit the if statement so that it reflects the following:


if(loaded == tileDict.length + charDict.length){

Pretty obvious this will now make sure the loaded variable is equal to that of the arrays holding our images meaning every image is loaded and ready.

Step Three – get in there Ralph

We can throw Ralph into the map pretty simply really. Add the following global variables:


var playerX = 4;
var playerY = 4;

These will be the X and Y coordinates of Ralph and shall be updated whenever a player uses the arrows keys.

Finally add the following to the drawMap() function after the drawing of the tile:


if(i == playerX &amp;&amp; j == playerY){
          ctx.drawImage(charImg[0],xpos,ypos-(charImg[0].height/2));
}

One thing to note here is we make use of the image height attribute to make sure the bottom of Ralph matches up with the bottom of the tile. Also for just now we will just use charImg[0] as Ralph is the 1st array entry.

Testing your script now you should see your player standing somewhere on your map. Obviously Ralph can move so last up to our simple player addition is to add key movement.

Step Four – I give you legs Ralph

For this I’ll be using the arrow keys however WASD as an alternative can be easily used etc.

Should you want to use different keys the easiest way to get the code is to add

document.title = keyCode;

after the initial conditional if check in the checkKeycode(event) function.

We can then add to the case statement to reflect our key movements like the following:


case 38:

        playerX--;

break;

38 is the key code for up, we decrease playerX by 1 when pressed, which will update the players position on screen as our graphics update loop is ran through. So our final checkKeycode function reflects the following:


function checkKeycode(event) {
var keycode;
  if(event == null)
  {
    keyCode = window.event.keyCode;
  }
  else
  {
    keyCode = event.keyCode;
  }
  document.title = keyCode;
  switch(keyCode)
  {
	   case 38:
			playerX--;
	   break;
	   case 40:
			playerX++;
	   break;
	   case 39:
			playerY--;
	   break;
	   case 37:
			playerY++;
	   break;
	   default:
	   break;
		}
}

And that should be everything you need to add a moveable player.

As always the final code can be seen here:

http://glacialflame.com/tutorials/tiles/05/

Will write up the objects tutorial tomorrow which will include a quick simple passable and non passable condition check allowing for trees/grey walls etc.

After that I think I will cover changing some of this stuff to objects to allow for individual tile properties and so on. But might need to wait a week or so for that part… work :( .

Let me know how you get on with this!

All the best.

Posted in Canvas, Javascript, Tile World, Tutorial | Leave a comment

Glacial Flame Video

And here it is. The first video of our canvas project so far… No sound or anything, it speaks for itself. :)

Posted in About Glacial Flame, Canvas, Javascript, Particle System, Technology, Tile World | 4 Comments

Video right around the corner.

While on holiday from university/work Edward and I have really pushed ourselves on getting the game video ready (as well as the starting stages of being ready for our side game which will showcase everything so far). Expect frequent guides, screenshots, game information, videos and eventually our side game in the upcoming weeks. Be sure to check out our screenshot gallery for the latest captures and as always feel free to leave a comment or mail us directly :) .

Posted in About Glacial Flame, Canvas, Javascript | Leave a comment

Websockets and multiplayerness

So recently with glacialflame we toyed with the idea of adding a multiplayer element to the game.

There were a few options available to us but we opted to stick with new developments and try out html5 websockets.

Brief lowdown: http://en.wikipedia.org/wiki/WebSockets

Even though html5 websockets are still new and recently have had a few bugs attached (http://hacks.mozilla.org/2010/12/websockets-disabled-in-firefox-4/), in the long run it will be a viable option for multiplayer browser based games.

Anyway on with the basics:

Client

Lets start with the client side stuff, i’ve written up a basic sample page which demonstrates all of the basics of websockets.

<html>
<head>
<script type="text/javascript">

var websocket;

function onLoad()
{
	websocket = new WebSocket('ws://localhost:1234'); 

	websocket.onopen = function(){ onOpen() };
	websocket.onclose = function(){ onClose() };
	websocket.onmessage = function(input){ onMessage(input) };
	websocket.onerror = function(input){ onError(input); };
}

// Event Handlers -------------------------
function onOpen()
{
	output("Connected");
}
function onClose()
{
	output("Disconnected");
}
function onMessage(input)
{
	output('Recieved: ' + input.data);
}
function onError(err)
{
	output('Error:' + err.data);
}  

// Send Msg -----------------------
function wsSend()
{
	var input = document.getElementById('input');
	var msg = input.value;
	input.value = ''; // Clear Text Box

	output("SENT: " + msg);
	websocket.send(msg);
}

// Output -----------------------
function output(message)
{
	var output = document.getElementById("output");
	output.value += (message + "\n");
	output.scrollTop = output.scrollHeight;
}

</script>
</head>

<body onload="onLoad();">
	<h2>Input</h2>
	<input type="text" id="input">
	<input type="button" value="Send" onclick="wsSend();">

	<h2>Output</h2>
	<textarea id="output"></textarea>
</body>
</html>

The main things to be noted from the above code is firstly the creation of the websocket,

websocket = new WebSocket('ws://localhost:1234'); 

Then functions are assigned to handle the different events that can happen,

	websocket.onopen = function(){ onOpen() };
	websocket.onclose = function(){ onClose() };
	websocket.onmessage = function(input){ onMessage(input) };
	websocket.onerror = function(input){ onError(input); };

The different events are pretty self explanatory and for now the functions that are called simply output a value to a textbox. However in the future we can use these to tie into different events happening in the game.

The last thing is sending messages to the server, this is achieved by:

websocket.send(msg);

Server
Now we have a client that can send and receive messages we need to create a server to for it to connect to.

For this tutorial I will create a simple server using node.js, the main reasons for doing so is its ease of development and the fact its coded in javascript makes it nice a familiar :)

There are also a number of modules available that will handle the handshake and other features for you. The one i quite like is https://github.com/miksago/node-websocket-server

This is the code for a simple socket server created using node.js and the node-websocket module that will echo back all messages sent to it.

// Import Module
var ws = require("websocket-server");

// Create Server
var server = ws.createServer({debug: true});

console.log('>> Sever Started');

// Listener waiting for connections
server.addListener("connection", function(connection){

	// Handle new Connection

	// Listner for incoming messages
	connection.addListener("message", function(msg){

		// Handle Incoming Messages

		connection.send(msg); // Send Message Back to connection
	});
});

server.listen(1234);

Then its simply a matter of saving it up and running it,

So what next?
Next stages are to being communicated player positions and so forth between the server and client and other fun things!

Currently with glacialflame we have multiplayer working with chat, movement and projectiles and are in the process of developing a small demo game to showcase what we have so far while we continue working on the main game :)

Posted in Uncategorized | Tagged , , | 2 Comments

Happy New Year!

Posted in Uncategorized | Leave a comment

Back, with multiples.

Merry Christmas.

Posted in Uncategorized | 2 Comments