In a place where your fantasy can roam free, there won't be any boundaries to what your imagination can create.
Misha’s Tech Playground
graphics, fun and code play
I'm crazy - but who cares? My ideas are constantly dwelling and this is the place for them to pour out and form into something good. Only active participation will ultimately make this place come to life.
Choosing the right Graphics Technique for a Browser Based Game
Whether if you are doing a puzzle game, a tricky jump ‘n run or a full fledged mmorpg, be it a simply casual or a long term persistent browser based game, you’ll certainly need one thing: images and animations.
As mentioned in last weeks article, you have the choice of implementing the right drawing technique. However, there are vast performance differences. So there is no technique that fits them all, merely you’ll need to decide on a case by case basis what you are going to use.
Since trying out everything only to realize that there were some tiny details you weren’t aware of in the first place isn’t actually fun, I am providing an in depth review of each technique.
We’ll go into detail about each techniques pro’s and con’s and you’ll learn how you would go about animating your game graphics in the technique of your choice.
At the end of this article you’ll also find a matrix containing the most important facts from this review.
A Short side-note for Those Looking to Create Flash Games:
This article won’t include information about Flash or Actionscript. There are already a lot of really great tutorials and articles on this topic out there. I don’t think I need to be making another tutorial containing the same information. Have a look at GotoAndPlay.it which is an awesome source for anyone interested in making Flash games.
Tags: code performance, game engine, Games, JavaScript Library, tile graphics
Animating with Scroll Properties, A view on Performance
Having had some time to polish up the AnimSprite Object of the game engine I had a chance to make a small performance test. I decided to give some insights on ow this style of animation works and to post the code that goes along with it for your personal joy.
The following html is generated by the script for each sprite that is placed on the stage.
Of course there is a stylesheet having defined the sprite class:
-
.CGE_sprite {
-
overflow: hidden;
-
position: absolute;
-
}
Utilizing the ScrollTop and ScrollLeft properties of the sprite box (the surrounding div) I can display 50 animated sprites @ 25fps on a page using Firefox 3 Beta 4 with a processor load of about 98% on my MBP 2.16GHz Core Duo.
Safari on the other hand is quite fast and has only 19% processor load for 50 sprites.

Having 100 sprites lets Firefox peak out at 100.9% load and slows down the animation to about 50% speed.
I'd say this is still not optimum, but it's quite a good start.
Here's my JS code for the sprites.
-
var CGE = {
-
// globals attributes
-
LEFT: 3,
-
TOP: 0,
-
RIGHT: 1,
-
BOTTOM: 2,
-
-
HEIGHT: 1,
-
WIDTH: 0,
-
-
X: 0,
-
Y: 1,
-
Z: 2,
-
-
STYLE_SPRITE: "CGE_sprite",
-
-
// the game instance if needed
-
game: null,
-
};
-
-
CGE.Game = new AJS.Class({
-
animSprites: [],
-
init: function (keys) {
-
for (var i=0; i <50; i++) {
-
this.animSprites[i] = new CGE.MirroredAnimSprite("_img/jumping_shadow.png", [Math.random()*300,Math.random()*250], [32,32], AJS.$("map"), true);
-
};
-
-
this.run(this);
-
},
-
-
run: function (game) {
-
game.hero.move(CGE.moveDir);
-
for(var i = 0; i <game.animSprites.length; ++i) {
-
game.animSprites[i].next();
-
}
-
game.mainLoop = window.setTimeout(function(){game.run(game)}, 40); //25fps
-
}
-
});
-
-
CGE.Sprite = new AJS.Class({
-
box: null, // for tiles this is the tile container, pos is relative to it
-
img: null,
-
spriteH: 0,
-
spriteW: 0,
-
// get x and y directly from object, faster for anim
-
z: 0,
-
-
frames: null,
-
-
init: function(url, pos, size, parent, useBox) {
-
this.img = AJS.IMG({src: url});
-
if(useBox)
-
this.box = AJS.DIV({className: CGE.STYLE_SPRITE}, this.img);
-
-
if(pos)
-
this.setPos(pos);
-
-
if(size)
-
this.setSize(size);
-
-
if(parent)
-
AJS.ACN(parent, this.box);
-
},
-
-
get: function() {
-
return this.img.src;
-
},
-
-
set: function(url, size) {
-
this.img.src = url;
-
},
-
-
getPos: function() {
-
return [this.box.offsetLeft, this.box.offsetTop];
-
},
-
-
setFrame: function(name, n) {
-
this.box.scrollTop = this.frames[name][n][CGE.Y];
-
this.box.scrollLeft = this.frames[name][n][CGE.X];
-
},
-
-
setPos: function(pos) {
-
AJS.setLeft(this.box, pos[CGE.X]);
-
AJS.setTop(this.box, pos[CGE.Y]);
-
},
-
-
setSize: function(size) {
-
this.spriteH = size[CGE.HEIGHT];
-
this.spriteW = size[CGE.WIDTH];
-
AJS.setHeight(this.box, this.spriteH);
-
AJS.setWidth(this.box, this.spriteW);
-
}
-
});
-
-
CGE.AnimSprite = CGE.Sprite.extend({
-
isPlaying: false,
-
isMirrored: true,
-
sign: true, // true=add, false = substract
-
-
frames: null,
-
key: null,
-
-
init: function(url, pos, size, parent, isPlaying) {
-
this.parent(url, pos, size, parent, true);
-
this.key = {name: "base",num: 0}
-
this.isPlaying = (isPlaying);
-
-
this.frames = {base: [[0,0],[32,0],[64,0],[96,0],[128,0],[160,0]]};
-
},
-
-
getFrame: function() {
-
return this.key;
-
},
-
-
setFrame: function(name, n) {
-
if(n>= this.frames[name].length)
-
n = 0;
-
this.parent(name, n)
-
this.key = {name: name, num: n};
-
},
-
-
next: function() {
-
if(this.isPlaying)
-
this.setFrame(this.key.name, ++this.key.num);
-
},
-
-
pause: function() {
-
this.isPlaying = false;
-
},
-
play: function(name) {
-
if(name)
-
this.key.name = name;
-
-
this.isPlaying = true;
-
},
-
stop: function() {
-
this.pause();
-
this.setFrame("base", 0);
-
}
-
});
-
-
CGE.MirroredAnimSprite = CGE.AnimSprite.extend({
-
sign: true, // true=add, false = substract
-
-
setFrame: function(name, n) {
-
switch(n) {
-
case this.frames[name].length-1:
-
this.sign = false;
-
break;
-
case 0:
-
this.sign = true;
-
};
-
(this.sign) ? ++n : --n;
-
-
this.parent(name, n);
-
},
-
-
next: function() {
-
if(this.isPlaying)
-
this.setFrame(this.key.name, this.key.num);
-
},
-
});
-
-
function init() {
-
CGE.game = new CGE.Game();
-
}
-
-
AJS.AEV(window, 'load', init);
As you can see, I make extensive use of AJS. You can get the stock version of it at the official website: AJS JavaScript Library.
The code shown here should be fully functional. I just removed the methods and members which aren't used in this example. And as a little caveat, there is no depth management as of yet.
The image I used in my code is the same as in the Javascript Sprite Animation post.
The classes to use would be:
- CGE.Sprite - which is a single not animated sprite
- CGE.AnimSprite - which is an animated sprite running in a loop
- CGE.MirroredAnimSprite - which is an animated sprite that plays in reverse when it's last/first frame is reached
- CGE.Game - which coordinates the loop in which all animations are run
Have fun ![]()
Tags: code performance, Firefox, Games, JavaScript Library, pbbg, Safari, tile graphics
Game Engine Preview
Since the class hierarchy is almost finalized I thought I post a little sneak peek of what is to be expected.
Not everything shown here will make it into the first release, unfortunately. But be assured that development is in progress...
You might notice that this looks a lot like pseudo code, but I just don't want to throw around pieces that aren't finalized yet.
So without further ado, here's some code to stick your nose in...
Tags: code performance, Games, JavaScript Library, pbbg, tile graphics
Dynamically loading external Javscript Files
Some weeks ago I read a short tutorial over at JavaScript Kit about how to load JavaScript files into your document on demand. This was a thought that I already pursued for some time as I had seen something similar already in the Scriptaculous Library. The difference on the Scriptaculous side was that you appended the additional files you wanted to load as a parameter to the main scripts url (scriptaculous.js?load=effect,dragdrop).
The idea is basically great. In modern languages you have the ability to import or include files for compilation (i.e. the C Family Languages, Java and Actionscript) or at runtime (i.e. Python and PHP).
So why should JavaScript be any different ?
Mainly it is because JavaScript wasn't designed with such behavior in mind . JavaScript wasn't supposed to build big applications like the now so popular Web 2.0 Apps (i.e. Google Maps, Google Calendar and others).
Why would I want that?
Once you start to develop larger Applications with JavaScript (or other languages for that matter) you usually end up having the same functionality in different places. But you also have bits of code that are unique to certain parts.
What makes sense in my opinion is to split up your monolithic JavaScript files into pieces that are:
- easier to maintain
- faster to load
- more reusable
But once you split up your files it can get messy rather quick too. On some occasions I had 6 or more Script nodes in one HTML file. Also keeping track of dependencies gets difficult.
Wouldn't it be a lot easier to have just a single script node where you would define what you need? Or better yet, let the script itself take care of what it needs.
How to do it?
I stumbled upon a great concept today that takes the initial idea a bit farther. A few days ago Remy Sharp blogged how to do On Demand Script Loading. Since I was working on the same idea I found this extremely interesting.
His idea is basically probes for the existence of an object and if it isn't found loads it.
My idea however was more similar to the initially mentioned Scriptaculous or Java approach.
You would need just a single script node in your html file to load either some
-
<script src="_js/opencsg/opencsg.js?load=event,input,util" [more attributes]></script>
for all your scripts.
-
<script src="_js/opencsg/opencsg.js" [more attributes]></script>
Okay, up until now this doesn't work different from Scriptaculous. So what I did further was to add a check for script dependencies.
For example I have one script that deals solely with event handling. Though this script is dependent on methods to check for different browsers and searching for nodes. I make a check if this object exists and if not I'll simply load it.
-
if (!CSG.CLASSES.util) {
-
CSG.include('util');
-
};
These checks are implemented in each file to make sure all dependencies are met. And since these checks are performed only when the script is loaded there is no performance hit.
The include function in turn looks like this:
-
include: function(libName) {
-
var src = CSG.path + libName + ".js";
-
-
if ((document.createElement && document.getElementsByTagName("head")[0].appendChild)) {
-
// insert script nodes to head node in all compatible browsers
-
var s = document.createElement("script");
-
s.setAttribute("type","text/javascript");
-
s.setAttribute("src", src);
-
document.getElementsByTagName("head")[0].appendChild(s);
-
} else {
-
// inserting via DOM fails in Safari 2 and other older browsers
-
document.write('<script type="text/javascript" src="' +src+ '"><\/script>' );
-
}
-
CSG.CLASSES[libName] = true;
-
}
Only the script name is submitted as parameter. Anything else is already stored in the object at the initial load.
Also note the fallback for browsers that have problems with inserting nodes via DOM.
This is just part of the whole script, though you could use this function independently. Once I have removed the kinks and quirks of this library I'll post the full version here too.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.