Playing with sprites, walls and new game concepts

I’m always looking at new game designs and cool ways to implement them. I also have my own system for creating HTML5 games that has evolved over the last 12 months.
I don’t use frameworks or libraries or such, I just enjoy getting my hands dirty with my own code.
But if you’ve read this blog before you’ll know that.

I wanted to have a crack at building my own maze game.
I’ve created similar games in the past and enjoyed making them very much so the idea of bringing one to mobile web is quite exciting.

Initially I took the decision that I wasn’t going to build a level editor. I just don’t have the inclination right now. Perhaps that will change if this game works out pretty well.
For now I wanted to just hack around in JavaScript in such a way that I could visualise the level as I key in each element in to the level data array.

Something like this..

var leveldata = [];
leveldata[0] = [
		"+,+,+,+,+,+,+,+,+,+",
		"+, , , , , , , , ,+",
		"+, , , , , , , , ,+",
		"+, ,+,+,+,+,+,+, ,+",
		"+, , , , , , , , ,+",
		"+,+,+, ,+,+, ,+,+,+",
		"+, , , , , , , , ,+",
		"+, , , , , , , , ,+",
		"+, , , , , , , , ,+",
		"+,+,+,+, , ,+,+,+,+",
		"+, , , , , , , , ,+",
		"+, , , , , , , , ,+",
		"+,+,+,+,+,+,+,+,+,+",
		"+,+,+,+,+,+,+,+,+,+",
		"+,+,+,+,+,+,+,+,+,+"
];

As you can see I have defined an array to contain all the level data in and then populated each element with another array. It is this second array that will store the level specific data.
What you see above is a representation of tiles. Each tile on screen is 32 x 32. So a level array with 14 elements equates to 14 rows of 32 pixel height = 448 pixels. This in turn equates to a total tile height of 480pixels. Perfect for my prefered game resolution of 320 x 480.
You can also see that I’ve left the last few rows full of tiles. This is due to the iPhone leaving its status bars in place by default and therefore chewing up far too many screen pixels.

In my code I iterate through each element in the array and parse the string for the comma “,”.
You can see this below.

function setWalls()
{
	try
	{
		var l = leveldata[g.level];
		for (var y=0;y < l.length;y++)
		{
			var s = new String(l[y]);
			var a = s.split(",");
			for (var x=0;x < a.length;x++)
			{
				switch (a[x])
				{
					case "+":
						spawnWall(x*32,y*32,0);
					break;
				}
			}
		}
		g.mode = "pregame";
		g.resetting = 50;
	}
	catch (e)
	{
		write("Set walls: " + e.message);
	}
};

g is my global namespace. Quite a lot goes in there that is game specific as opposed to player or sprite specific.
spawnWall() is my function for pulling a wall sprite out of the sprite collection and assigning it a set of co-ordinates.
Something like this..

function spawnWall(x,y,row)
{
	try
	{
		for (var a=0;a < NUM.WALLS;a++)
		{
			var o = m.walls[a];
			if (!o.visible)
			{
				o.visible = true;
				o.targetx = x;
				o.targety = y;
				o.x = x;
				o.y = g.canvasheight + y;
				o.row = row;
				break;
			}
		}
	}
	catch (e)
	{
		write("Spawn wall: " + e.message);
	}
};

I am positioning the wall tiles below the canvas height. This is deliberate since I want them to scroll in to view in between levels. In my move() function I have code to shift a sprite from its x co-ordinate to its targetx co-ordinate. Same for the y.

So back to the leveldata array and where you see a white space no tile will be drawn.
Where you currently see a “+” a wall tile will be drawn.
Eventually the + will be replaced by single characters that represent the type of wall tile I want to display.
For now it simply translates to my default wall tile.

wall graphic
You can see that this wall tile is 64 x 32 in size and contains 2 frames of 32×32. I am going to animate my wall tiles.

When I run the game in test mode I see the following screen layout.

castle screenshot

I have deliberately defined the wall tiles as sprites.
This gives me a tremendous amount of flexibility since the sprite class and methods allow for a lot of animation and movement. It also makes life a lot easier when I come to consider collision. Rather than “overlaying” a collision map I simply test for position based on a ton of sprites.
It also gives me the freedom to move walls should my design require it.

So just now I’m playing with ideas but ultimately I’d like to plant entity starting points in to the leveldata array.
Perhaps try a PacMan approach to a game where the whitespaces are taken up with “o” which will be translated by the game in to small coins that the player must collect.
I don’t know. It’s early days.
The most important thing is that my codebase allowed me to create this proof of concept in around 15 minutes.
Exciting times.

The pain of fixing canvas dimensions across all devices

In an ideal world I would develop all of my games at a fixed resolution. That resolution just now would be something like 320 x 460. Largely because according to my analytics data from Google the majority of people playing the games do so on an Apple device such as iPhone or iPod Touch.

Of course the problem here is that for every 10 Apple players there is going to be at least 1 Android player equipped with an HTC Desire or possibly a Galaxy Tablet or… the list is endless.

Fixing the canvas size is also great for knowing where items can initialise on screen. You are able to set an accurate scale to your games, you know just how big the sprites are and just how much freedom of movement they can have.
With more fluid dimensions you run in to the territory of working with relative positioning – which is no bad thing and certainly not a difficult thing to work with if you are able to consider it from the outset.

A quick glance at my analytics title sends a shiver down my spine:

48,552 visits used 730 screen resolutions + operating systems

730 different screen resolutions !

So I delve a little deeper to see just what has been viewing these games.

320×480 iPhone
320×480 iPod
768×1024 iPad
320×401 Android
320×480 Android
320×452 Android
320×396 iPod
320×396 iPhone
319×50 Android
320×341 Android
240×320 Android
320×399 Android
320×345 Android
800×480 Android
480×320 Android
480×241 Android
320×240 Android
320×488 Android
267×309 Android
427×235 Android
480×800 Android
1280×1024 Windows
533×239 Android

So at this point I start to wonder about a few things. What exactly are my options ?

  1. Just fix the canvas width and height to the available width and height of the browser window
  2. Ignore it and continue to force dimensions to 320 x 460
  3. Take the window dimensions and try to calculate some kind of a scalable dimension based on height / width ratio
  4. Take the window dimensions and offer canvas dimensions based on a number of presets. e.g. 320 x 460, 480, 690, 640 x 920 – possibly centering the content with CSS

Considering each of these options of course introduces other questions.
For starters at the point when you grab the window dimensions how has the player got the handset held ? Landscape or Portrait ?

For example, if the screen dimensions come back as 640 x 480 is that just because the handset is on its side ? Or is it a desktop resolution.
We can of course check window.orientation for this.
Generally a value of 0 (zero) indicates a default orientation of portrait.
90 and -90 indicate the alternative orientation of landscape.
However, I notice that the Samsung Galaxy Tablet 10.1 sets its default to 0 in a landscape orientation. Very useful indeed. Not.

If, in the case of option 4, I decide to continue fixing dimensions do I need to offer multiple sized sprite sets to avoid sprite scaling ? Most probably. Scaling is a performance dog just now and can yield unwanted visual effects.

So how do you solve a problem like this ?
What exactly can you do to give the player a good full screen experience AND ensure that you are catering for all devices ?
Does anyone have their own experiences / solutions that they might wish to share ?

I ask this question deliberately since I have coded a number of solutions, none that I am truly happy with. Please let me know your thoughts. If comments close (after 7 days to restrict spammers) please mail me. You can find the address in the about page. I will publish your comments if you so wish.

 

Development update

  • Danger Ranger now live. Ditched the idea of a branded game character for now.
  • HyperGunner updated to be more challenging and a little more responsive.
  • HyperGunner now using textdata.js to help localisation.

drawImage performance on iOS vs CSS

I noticed something interesting earlier whilst trying to improve the performance of Dragons that I thought I should share. When I first considered how the game would look I settled on a full screen scene. I blogged how excited I was about this and that I could finally sit back and create full screen renderings in Photoshop. I’m using .png files for the backdrops. I tend to use that format for everything these days.

The theory was simple in that I would run through setLevel() once per level and set everything up. One of the things to set up is the current stage backdrop. For this I set the backgroundImage property of the canvas’ style to be whatever background I choose.
Something like this:

g.canvas.style.backgroundImage = “url(‘…’);”;

Very basic CSS stuff. g is my global namespace.
I figured that this would save me a hefty drawImage() call during the main game loop and therefore preserve some frame rate.
This was a poor assumption. At least on iOS. And even then it appears more so on iPhone 4.

I scratched my head as to why first gen iPod Touch could render the game at roughly 20FPS and iPhone 4 struggled along at around 6FPS.
So I played around with it a bit and took stuff out. I also killed shadows on text and cut back on the number of sprites on screen. None of it made a difference.

Meanwhile over on Android the game was flying along like a train.

I then decided to take a closer look at the “big” stuff. By big stuff I mean the operations that involve the most pixels. I use drawImage for everything so I reduced the size of the sprites and took out sprite scaling and rotation. No real difference was recorded. So I put it all back in.
I then took a look at the CSS call to paint the backgroundImage of the canvas in what I thought was a one-time-per-level operation that exists outside of the loop.
I stripped out the CSS bit and rendered the full screen scene on every game tick. To try and help it along a bit I also reduced the file size of the .png files from 43k to 3k. I also ignored diffusion since this doubles the file size even at 8bits.

I uploaded the new game code and assets and refreshed Safari on the iPhone4.

To my amazement the frame rate had more than doubled to (a still poor but more acceptable) 16-20FPS. Android was, to be frank, no different. It still motored on beautifully.

So the valuable lesson that I’ve learned here is that the best course of action on iPhone (at least it is right now before iOS5 arrives) is to do all full screen drawing with drawImage and not rely on CSS. Alternatively of course don’t do ANY full screen drawing.
One of the smoother games I’ve completed, Galactians, works against a plain black backdrop a la the arcade games of the early 1980s. Perhaps there’s something in this.

I’d love to hear some thoughts on this. I really am not a great coder so muddling through this stuff is often mesmerising at best. Be interesting to hear what other HTML5 game developers are doing to steal back some FPS.

Re-thinking sprite movement

All of the object movement in my games to date has been fairly rudimentary. I generally try to stick to the old joystick locking movement of yesteryear which saw just 8 directions of movement.
I count from zero (North) clockwise through to 7 (North West).
sprite movement directionsAs you can see I also (where the player sprite is concerned) implement Move flags. With every key release I reset the flags and re-assign them onkeypress.
Of course all of this is pretty restrictive and to achieve any variation I have added simple x,y modifiers. The formation sequence in HyperGunner for example sees the procession of aliens moving in direction 4 (South). To make the movement a little more graceful I simply modified the x value by anything from 0.1 to 1 depending upon the position that the alien was in relative to the screen edges.

What I really want to achieve is a much more calculated approach to sprite movement such that I can implement the sort of thing you see in Breakout where the ball moves at different angles depending on the collision with the bat.
So I started to think about how best to do it. I came up with a solution but having never written this kind of stuff before I’m open to suggestions for alternative methods or best practises.

So here’s how it works.
Step 1. Assess the x,y of the sprite object versus it’s intended destination.
assess target x, y In most cases the target x, y (90, 0 in the above illustration) will correspond with the co-ordinates of another object. For example I may want to launch a bomb from an alien to a playership at the base of the screen. I could easily capture the co-ordinates of each sprite and move on.
But in some cases it may be that I am firing from the other starting point. i.e. a laser from a player’s ship that if left alone could sail off the top of the screen. I may not necessarily want to angle the ship since the laser burst may be part of a special move. So in this case I simply pick an x value and a zero y value as my target.

Step 2. Calculate an x increment / decrement based on the speed of the moving sprite.
x modifier So let’s assume that the sprite has a move speed of 16 pixels. With every game loop the sprite will move North (direction 0) in steps of 16 pixels.
The total height it has to move is 160 pixels so this will be achieved in 10 steps.
How much therefore must we modify our x value to arrive at the desired location.
Well this is pretty simple theory. We take the difference between the two x values (in the example above 38) and divide it by the number of steps that the sprite will take to reach its y target.

So whilst the y value is decreasing by 16 the x value is decreasing by 38 / 10  = 3.8
I implemented a simple example to illustrate what I’m doing. You should see it in the iframe below. Notice how the alien bombs (square blobs) appear to home in on the player. Fairly basic stuff but something that I’m pretty happy to have finally got my head around.
I wrote a simple function to handle the calculation of the modifier.

function calculateMods(a,p,o)
{
var steps = ((p.y + p.h) - (a.y + a.h)) / o.speed;
o.xmod = (p.x - a.x) / steps;
};

As you can see I simply pass the alien, player and object (in this case an alien bomb) in. The function assigns the xmod value based on the calculated number of steps.

Look here: Distant Orbit HTML5 Galaxians style game in development.

%d bloggers like this: