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 , , | 4 Comments

Happy New Year!

Posted in Uncategorized | Leave a comment

Back, with multiples.

Merry Christmas.

Posted in Uncategorized | 2 Comments

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

Our previous tutorial covered loading our structured maps from a database via PHP as XML into canvas. This second part will cover saving over our loaded map record with any changes we have made.

Step One – Our small PHP write
Create a PHP page titled worldSave.php with the following rather small segment of code:

<?php
$id = $_POST["id"];
$groundTiles = $_POST["groundTiles"];

// -------------------------------------------
mysql_connect("localhost","username","password");
mysql_select_db("glacial_website");
// -- connect to the DB
// -------------------------------------------
// -------------------------------------------
$insert = mysql_query("UPDATE maps SET tiles='$groundTiles' WHERE id='$id';");
?>

Rather self explanatory really, we will be passing our data to this PHP page via POST. The page will update our table where the row ID is matching. Step one finished already!? Yehp.

Step Two – Canvas map array converted to an XML structure
To keep the code separated and easier to follow we will create a new JS page for our database writing. Last time we created XMLPopulate.js for loading our XML page, we will now create DBSave.js for sending structured data to PHP pages for writing to our database.

Create DBSave.js with the following code:

function DBSave() {

	this.saveMap = function (id,groundTiles) {
	var mapData ="";
	   	  for(var i =0;i<groundTiles.length;i++){
				mapData += "<row>";
				for(var j=0;j<groundTiles[i].length;j++){
					mapData += groundTiles[i][j];
					if(j!= groundTiles[i].length-1){mapData += ",";}
				}
				mapData += "</row>";
			}

			xmlhttp=new XMLHttpRequest();
			data = "id="+id+"&groundTiles="+mapData;

			xmlhttp.open("POST","worldSave.php",true);
			xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			xmlhttp.setRequestHeader("Content-length", data.length);
			xmlhttp.setRequestHeader("Connection", "close");

			xmlhttp.onreadystatechange = function() {
				if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
					alert("Map Saved");
				}
			}
			xmlhttp.send(data);
    };

}

So all we need is one function within DBSave for our map storing which is saveMap which can be called as so:

var db = new DBSave();
db.saveMap(zoneID,map);

We pass the ID of the map as well as the map array itself. saveMap then runs through the length of the map array forming a large XML structured string. It starts each row with a node, separates each array entry with a comma and finally ends the row with a closing node. Once completed it creates a new XMLHttpRequest with our data using the POST method. Using xmlhttp.send(data) we send the id and map with xmlhttp.onreadystatechange listening for success.

Step Three – Updating your main code
Again you will need to add the inclusion of your latest script to the family so your top part looks similar to:

<script src="XMLPopulate.js" type="text/javascript"></script>
<script src="DBSave.js" type="text/javascript"></script>
<script type="text/javascript">

In your function init() add the following code which will listen in for keyboard presses:

document.onkeydown = checkKeycode;

And Last but not least add the following checkKeycode function which will work in all browsers:

function checkKeycode(event) {
var keycode;
  if(event == null)
  {
    keyCode = window.event.keyCode;
  }
  else
  {
    keyCode = event.keyCode;
  }
  switch(keyCode)
  {
	case 83:
		  var db = new DBSave();
		  db.saveMap(1,map);
	 break;
	  default:
    break;
	}
}

On keyCode 83 (key S) we will call our saveMap(1, map). Where 1 is the ID of the map we wish to change and map is the array itself.
That should be all that is needed to now load and save your database entry.

All of this could be further expanded on to load and save specific entries without having IDs hard coded into your syntax using XML.getAttribute to take in the zone id and pass back when saving.
Example code and output of tutorial can be seen here: http://glacialflame.com/tutorials/tiles/04/

Posted in Uncategorized | 12 Comments

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

This should be the last of the delays with Glacial Flame finally over now. As promised here is the final tutorial on creating a simple map editor which saves your changes and loads your layout up from a database. This tutorial will be split into two parts with this post covering loading while the second will deal with saving.

Step One – Database and first map setup

In our database for just now all we will need is our map ID and map layout to be stored, however it will be easy enough to expand on this to have starting coordinates, title, object layout etc.

To start off we need to create a table called maps with two fields id (int(3) primary auto_increment) and tiles (text).

Insert and store the first record just now with the tiles value as the following:

<row>0,0,0</row>
<row>0,0,0</row>
<row>0,0,1</row>

This XML structure will be our new method of storing our map data rather than hard coding our tile values straight into the multidimensional array.

Step Two – Reading the map via PHP and outputting as XML

Now we hook up our PHP page to the database with a method that outputs the data as XML. Using GET we pass a map ID that our mysql_query uses for getting the map we wish to load. Setting content header type as XML we can output our table record as the desired XML format and our soon to be written JavaScript can load this no bother. Title this page as world.php.

<?php
// -------------------------------------------
header('Content-type: text/xml');
// -------------------------------------------
// -- connect to the DB and select the correct map via GET
mysql_connect("localhost","username","password");
mysql_select_db("glacial_website");
$id = $_GET['id'];
// -------------------------------------------
// -------------------------------------------
$getall = mysql_query("SELECT * FROM maps WHERE id='$id'");
// -------------------------------------------
// -- Begin executing XML output --
$_xml = '<?xml version="1.0" encoding="utf-8"?>';
$_xml .= "<maps>";
while ($get = mysql_fetch_array($getall)) {
	$_xml .= "<zone id='".$get['id']."'>";
			$_xml .="<groundTiles>";
					$_xml .= $get['tiles'];
			$_xml .="</groundTiles>";
	$_xml .= "</zone>";
	}

$_xml .= "</maps>";
// -------------------------------------------
// -- Spit out the XML
header("content-type: text/xml");
print  $_xml;
// -------------------------------------------
?>

Saving and uploading this page and going to your URL ***/world.php?id=1 should give you an output similar to the following:

<maps>
<zone id="1">
<groundTiles>
<row>0,1,0</row>
<row>0,0,0</row>
<row>0,1,0</row>
</groundTiles>
</zone>
</maps>

Simple? So now we have our saved map ready to be loaded in. Onwards to the JavaScript canvas side of things!

Step Three – Reading in your XML with JavaScript

This took some time to get working originally due to the lack of dated information however it works in all browsers capable of the Canvas element.

Create a new .js file called XMLPopulate.js. This will be our main set of functions that will load in the generated XML returning both requested attributes as well as populating our multi-dimensional array that contains our map layout.

I’ll paste this entire script in just now and then run through what each function does afterwards (not sure if that’s the easiest way but at least keeps the script together making it easier to take in).

function XMLPopulate() {

     this.loadXML = function (fileName) {
        xmlhttp=new XMLHttpRequest();
		xmlhttp.open("GET",fileName,false);
		xmlhttp.send();
		xmlDoc=xmlhttp.responseXML;

    };

	this.getContent = function(name){
		var tempArray = Array();
		var generatedArray = Array();
		var row;
		var toGet = xmlDoc.getElementsByTagName(name)[0];
		for(var i=0;i<toGet.getElementsByTagName("row").length;i++){
			 var rowSplit = toGet.getElementsByTagName("row")[i].childNodes[0].nodeValue;
			 rowSplit = rowSplit.split(",");
				for(var j=0;j<rowSplit.length;j++){
					tempArray.push(rowSplit[j]);
				}
				generatedArray.push(tempArray);
				tempArray =[];
		}
		return generatedArray;
	};

	this.getAttribute = function(name,attribute){
		var toGet = xmlDoc.getElementsByTagName(name)[0];
		attribute = toGet.attributes.getNamedItem(attribute).value;
		return attribute;
	};

}

loadXML
Rather simple, just takes in the location of your XML. This will be used initially like so:

var XML = new XMLPopulate();
XML.loadXML(‘world.php?id=1′);

getContent
This could probably be edited to be a little more dynamic and less tied to our structure however this part of the script populates and returns our tile layout as an array to fit in with our already programmed tile engine.

Called like so:
map = XML.getContent(‘groundTiles’);

This means should you have a second set of tiles for example objects which you overlay on your ground tiles you can easily populate a second array.

Basically our script loops through the number of rows and splits each entry by comma, before inserting the individual tile values into an array. At the end of each row the array is inserted into our final array which produces our multi-dimensional array. Once all rows have been ran through, we then return our map.

getAttribute
Just as it sounds this returns the desired attribute of a node. Useful if you want to get the ID or after further progression you may have the map title or starting coordinates as attributes of the map. For example in Glacial Flame we have .

If we wanted to get the title all we do is:

zoneTitle = XML.getAttribute(‘zone’,'title’);

Step Four – Reading in your XML with JavaScript

In your source code from last time in our tile engine clear the initial map Array declaration and add the include of XMLPopulate.js.

The top of your script will look similar to:

<script src="XMLPopulate.js" type="text/javascript"></script>
<script type="text/javascript">
var map = Array();

In your innit() function add the following:

var XML = new XMLPopulate();
XML.loadXML('world.php?id=3');
map = XML.getContent('groundTiles');

And that’s all you need for loading in a map from a database!

I will begin writing up the saving part and have it posted early next week. The source for all of this can be seen at:

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

Till next time!

Posted in Uncategorized | 10 Comments

Mouse Control on Isometric Canvas tiles

Quite a delay in updates due to holidays and then being tied down with work deadlines but the game and tutorials go on!

This tutorial will cover applying a mouse over to tiles and updating the tile array when a specific one is clicked. We will be using the source code from the previous tile tutorial and updating where required (http://glacialflame.com/tutorials/tiles/01/). So let us go back to the fields Felderon and actually add some dynamic interaction to our developing world that has been lost in time.

Our previous tutorial didn’t require any sort of screen updating loop as there weren’t visual updates taking place, instead we basically built a static image using tiles.

In order to be able to apply a mouse effect over the current tile we will need to have canvas constantly update the visualisations, taking into consideration where the mouse is and calculating the coordinates accordingly.

By the end of this small tutorial you will have the basic interaction required to make a HTMl5 canvas map editor.

First thing we do in building our interactive map is initiate a timer for updating the display. In the previous tutorial we had our loadAll() function call drawMap() once all images where ready, this is changed to call gameUpdate() using a timer like so.


function loadAll(){

if(loaded == tileDict.length){

clearInterval(loadTimer);

loadTimer = setInterval(gameUpdate,100);

}

}

With the gameUpdate() looking like this:


function gameUpdate(){

ctx.clearRect(0,0,210,120)

drawMap();

}

Simple. Use clearRect with your game screen width and height in order to clear it and then redraw the map.

Next within the init() function place in the following line:


canvas.addEventListener("mousemove", mouseCheck, false);

This will allow us to take in mouse movement which we will use for the drawing of our tile roll over effect as well as updating the correct array position when clicked. Now we have to apply our mouse coordinates and for this we will be using these two global variables.


var ymouse;

var xmouse;

We then create our mouseCheck() function to gather and update the location of the mouse within the canvas area. The logic for this is probably as complex as this tutorial will get.


function mouseCheck(e){

var x = e.pageX;

var y = e.pageY;

ymouse=(2*(y-canvas.offsetTop-mapY)-x+canvas.offsetLeft+mapX)/2;

xmouse=x+ymouse-mapX-25-canvas.offsetLeft;

ymouse=Math.round(ymouse/25);

xmouse=Math.round(xmouse/25);

}

var x and y are set as e.pageX and e.pageY which are simply the mouse coordinates within the browser screen.

We then set ymouse as the coordinate of the Y position first taking in the offsets of the canvas box within the browser and then taking in the offset of our tiles that we applied within the box.

Xmouse is setup the same way taking in the result of ymouse and subtracting the mapX offset. The 25 subtraction within this code is the width of our tiles and will need to be changed to match that of the sizes you are using.

Finally we then divide both outcomes by the tile width (25 in this case) in order to get the tile coordinate.

So to visually have a rollover effect in the field of Felderon we make canvas draw out a transparent diamond on top of the current tile hence the need for xmouse and ymouse to be global.

After your ctx.drawImage(tileImg[drawTile],xpos,ypos); within the drawMap() function we make it check if the current array position being drawn matches our newly generated xmouse and ymouse coordinates by adding the following:


if(i == xmouse && j == ymouse){

ctx.fillStyle = 'rgba(255, 255, 120, 0.7)';

ctx.beginPath();

ctx.moveTo(xpos, ypos+12.5);

ctx.lineTo(xpos+25, ypos);

ctx.lineTo(xpos+50, ypos+12.5);

ctx.lineTo(xpos+25, ypos+25);

ctx.fill();

}

Viewing your map now you should be able to rollover each tile and a yellow overlay will appear. If you are using different sized tiles you will need to alter the moveTo offsets accordingly, alternatively you could just use a transparent .png matching your tile size and have it drawn similar to the tile itself.

We will finish this up by adding some simple interaction to the map by making tiles clickable. First of all add the following swamp tile to your directory as well as including it in your array like so:

var tileDict = Array("water.png","land.png","swamp.png");

Now add the following event to your innit(){}

canvas.addEventListener("mousedown", mouseClick, false);

This will allow us to call the mouseClick function when a tile is clicked and using our global xmouse and ymouse coordinates not only update the screen visually but update the tile array at the same time.


function mouseClick(e){

map[xmouse][ymouse] = 2;

}

Extremely simple?

Further additions to this would be to add more images to your tile array and using a dropdown list allow the user to choose their tile.

Through a small clipping of code like the following you could have JS change the array value to that of the drop down value chosen.


var tile = document.getElementById('tile').value;

map[xmouse][ymouse] = tile;

The drop down would reflect the following:

 <select id="tile">
            <option value="0">Sand Simple</option>
            <option value="1">Sand Path</option>
            <option value="2">Sand Grill 1</option>
</select>

And there you have it, simple mouse interaction that will take in page and tile offsets allowing users to click and change tiles.

The source and product of this tutorial can be seen at:

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

Next tile based tutorial will cover saving and loading your map to a database via PHP using XML.

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

There was going to be a delay at some point!

After a couple of weeks on holiday and having a mountain of emails and work to catch up on, Glacial Flame sadly got put a few slots down on the list of things to do. However do not panic, I am in the midst of writing the next tutorial just now on creating an ISO tile based map editor continuing on from the last tutorial. This will be up over the next couple of days and there will be a video some point next week of current features within the game. Stay tuned and sorry for taking so long!

Posted in About Glacial Flame | Leave a comment

Delay in video but not in projectile action!

We were wanting to have a short video up of how the engine is currently taking form in its early state, however there is a few little kinks to iron out first. To make up for the lack of video here is a little screenshot to look at. We now have basic projectiles working, as seen here with flame arrows which can be interchanged and developed to create a wide range of spells and attacks. Still a lot of work ahead of us but it is a little milestone for the greater good! As always, come back soon for more updates and tutorials. We’ll be writing up a short JavaScript block on how you can get images in canvas to rotate and point towards the mouse soon.

Glacial Flame fire arrows

A flurry of arrows.

Posted in About Glacial Flame | 1 Comment

New screenshot section

Current HUD mock up over the game engine.

We’ve added some of the latest screenshots of our engine to the new (funnily enough) screenshot section. We will try and get a small video put together of the current game with all its tile and particle glory on display over the weekend.

Screenshots will be added randomly so be sure to check back here often: http://glacialflame.com/screenshots/.

Posted in Uncategorized | Leave a comment

Canvas isometric tiles made simple.

Isometric tiles are just as easy to achieve as a standard tile map. With a bit of shape alteration and minor positioning adjustment, you can change your flat 2D game concept into a mind blowing “2D.5″ isometric engine, capable of graphical destruction and full user awe.

But where do you begin in creating such an experience?

To the drawing board!

So you start off with a 50×50 pixel square which represents part of the fields of Felderon, which gives your hero enlightenment while walked on, at the risk of a slight game ending seizure. Such a tile may look like this:

However this hero isn’t walking on any standard field of Felderon, he is standing on an isometric field of Felderon. So how do we change our tile to meet these requirements?

Basically we rotate it and half the height so our tile is now 50px wide and 25px tall. Instantly our field tile looks like it has some slight depth to it with the grass blades of possible healing growing out. pngs are used for the alpha and to allow image overlap. This tile when placed into our soon to be coded engine would look like this:

So we have our tile and now we need to alter our previous example on creating a tile engine to match the isometric view.
First however we will change the code to load in this image rather than drawing a tile.
A very simple way to do this is to create an array of images. Although our Felderon field tile is of a graphically inspiring status, we will need some other tiles to go along with it. Feel free to use this tile which represents the sea of despair, that when drank generously offers -8 Charisma with a 30% chance of growing an 11th finger. Not to be confused with the river of despair that we shall not go into.


var map = Array([1,0,0,0],[1,0,0,1],[0,0,1,1],[1,1,1,1]);
var tileDict = Array("water.png","land.png");
var tileImg = new Array();
var loaded = 0;
var loadTimer;

So in this simple method for loading multiple tiles, tileDict will hold all our tile images for loading and tileImages array will contain the loaded images for accessing.
Loading the images in can be achieved with the following loop:

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

Pretty simple code really, runs through the length of your tileDict and as each image is successfully loaded it increments loaded by 1.
If you create an initialize function which contains your ctx setup, then using the following code we can call the loadImg function as well as creating a timer used for checking if all tiles have been loaded.

function init(){
	ctx = document.getElementById('main').getContext('2d');
	loadImg();
	loadTimer = setInterval(loadAll,100);
}

Our loadAll function is setup as the following:

function loadAll(){
	if(loaded == tileDict.length){
		clearInterval(loadTimer);
		drawMap();
	}
}

Again pretty simple. Every 100ms loadAll is called and we check if the loaded counter is equal to the tileDict length. If both are equal we cancel the canvas loadTimer using clearInterval and call the drawMap function.

function drawMap(){
var tileH = 25;
var tileW = 50;
// Set as your tile pixel sizes, alter if you are using larger tiles.
var mapX = 50;
var mapY = 50;
// mapX and mapY are offsets to make sure we can position the map as we want.
		for(i=0;i<map.length;i++){
				for(j=0;j<map[i].length;j++){
					var drawTile= map[i][j];
					var xpos = (i-j)*tileH + mapX;
					var ypos = (i+j)*tileH/2+ mapY;
					ctx.drawImage(tileImg[drawTile],xpos,ypos);
				}
		}
}

Exactly the same as the last tile post we loop through the array lengths however the tile positioning code is slightly different.
Taking in the changes in size and the fact that we are now positioning for an isometric view we calculate the position accordingly.
drawTile is set as the value of the current map array tile, and used for getting the matching tile image from the tileImg array.

And behold the fields of Felderon with the sea of despair flowing powerfully through it. That really is all there is to it. As you can see in the screenshot there is slight lines between each tile. This could be fixed by setting tiles to have an Anti-Alias edge rather than hard, or by just increasing the tiles width by a couple of pixels.
For the full source code of the above see here:

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

Our next tile post will cover selecting isometric tiles with the mouse and changing tiles via mouse clicks.

Posted in Canvas, Javascript, Technology, Tile World, Tutorial | 21 Comments