Dirty rectangles
Recently I’ve been experimenting in HTML5 game development and like my last post, this post is to document my findings.
Dirty Rectangles, what are they?
Imagine canvas animation is similar to cel animation, in that you compose your animation using serveral layers. Cel animators don’t want to have to draw the entire character for each frame if the only thing that is moving is the character’s mouth. (thanks to @speakersfive for this analogy)
With dirty rectangles, we detect which areas of our game have changed and therefore need updating.
How do we detect a dirty rectangle
The simplest way is to keep an array of ractangles, foreach
over them on the next draw pass and clear those areas of our canvas.
You might be thinking; “what about my background or HUD?”, remember the cel animation analogy? Well just like cel animation we’d create our game in layers, leaving our background unaffected by our player’s movement.
Whenever we make a change to the player’s position, we’d mark the player sprite as dirty and add its rectangle to the array of dirty rectangles
How do we code this>
Coding this is fairly straight forward, so lets start with our game object.
// Game is our game object and hold all data about our game // as well as update and draw methods Game.dirtyRectangles = [];
function Player(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
* Move player by x and y increments
* @param {Number} x player x increment
* @param {[type]} y player y increment
* @return {void}
*/
Player.prototype.move = function Player_move(x, y) {
var original_x = this.x;
var original_y = this.y;
this.x += x;
this.y += y;
// if some change to the position was made
if (original_x != this.x || original_y != y) {
this.dirty = true;
// add this rectangle to the dirty rectangles array
// note: it's the rectangle before the movement was made
Game.dirtyRectangles.push({
x: original_x,
y: original_y,
width: this.width,
height: this.height
});
}
};
So let me explain what we are doing here.
This prototype is configured to have an x and y position and a width and height. These properties control the position of the player and dirty rectangle size and position.
When we call move() to move out player we first store
the existing position and then update it. Next we check if the
position changed since the start of the method, when we stored the
position, if it did then we set the dirty property and
push an object holding the bounding rectangle of the previous position
into the dirty rectangle array.
Next we move on to our game loop’s draw method.
Game.draw = function Game_draw() {
var ctx = Game.canvasContext;
var i, dirtyRectangleCount = this.dirtyRectangles.length;
for (i = 0; i < dirtyRectangleCount; i+= 1) {
var rect = this.dirtyRectangles[i];
// clear this rectangle from the canvas
ctx.clearRect(rect.x, rect.y. rect.width, rect.height);
}
// clear the dirty rectangle list
this.dirtyrectangles = [];
// then redraw any dirty sprites
var spritesCount = this.sprites.length;
for(i = 0; i < spritesCount; i += 1) {
var sprite = this.sprites[i];
// is the sprite dirty?
if (sprite.dirty) {
sprite.draw(ctx); // pass canvas context to the sprite
}
}
};
Okay, here we iterate of the the dirty rectangles array and clear those parts of the canvas. then we iterate over the sprites and redraw any sprites that have been marked as dirty. Simple.
Next we’ll need to mark our sprite as clean again. The best place to do this is probably the sprite’s draw method.
/**
* Draw the player
* @param {CanvasContext} ctx canvas context
* @return {void}
*/
Player.prototype.draw = function Player_draw(ctx) {
/*
...
our drawing code
...
*/
// set our sprite to clean again
this.dirty = false;
};
And that’s it. Only the changed parts of our screen will be updated using dirty rectangles.
Feel free to give me feedback on twitter @bytespider
requestAnimationFrame and HTML5 game loops
When looking at writing a HTML5 game, I first went down the usual route of using setTimeout(run, 1000/60);. However due to the nature of javascript, this isn’t always optimal. Javascript is single threaded so you can’t always guarantee that your frame will be rendered when you expected it.
In walks requestAnimationFrame
Thankfully there’s a new kid on the block, requestAnimationFrame, and the browser will call your function when it has rendering time free and passing the time.
But how do we update our game loop to use this? In much the same way as setTimeout() thankfully.
function main(time) {
run();
window.requestAnimationFrame(main);
}
window.requestAnimationFrame(main);
Gotcha
This one stumped me for a while, but in my simple game the CPU was hitting 100%. So I added code to reduce the frame rate.
var skipTicks = 1000 / 30, nextTick = new Date().getTime();
function run(time) {
while (time > nextTick) {
update();
draw();
nextTick += skipTicks;
}
};
However my CPU usage was still 100%. I had a think and it dawned on me, requestAnimationFrame makes a request for rendering time and the browser will give the next available spot. But the browser is so fast, we’re practically requesting a frame every millisecond, no wonder my CPU hits 100%.
So I’ve updated my code, to wait 10ms before requesting the next animation frame.
function main(time) {
run();
setTimeout(function () {
window.requestAnimationFrame(main);
}, 10);
}
window.requestAnimationFrame(main);
Object cloning using ES5
function clone(object) {
var cloned = Object.create(object.prototype || null);
Object.keys(object).map(function (i) {
cloned[i] = object[i];
});
return cloned;
}
jsOAuth developer questionnaire
Please let all your developer friends know, I’d like you to fill in this short questionnaire to give your feedback so that I can better focus my development.
https://docs.google.com/spreadsheet/viewform?formkey=dDItRWVfMmoxU3U4bVpocE9LbFpiT3c6MQ
Using CommonJS modules for UI View components in Titanium
I’ve been playing with using CommonJS modules in Appcelerator Titanium to create reusable components and prototypes. I start with a basic object structure:
function Car() {
this.init.apply(this, arguments);
}
Car.prototype.init = function (make, model) {
this.make = make;
this.model = model;
};
Car.prototype.make = null;
Car.prototype.model = null;
Car.createWithMakeAndModel = function (make, model) {
return new Car(make, model);
};
module.exports = Car;
Whilst you may argue there is some redundancy in the pattern I use, I makes sections of code easy to override later on if I decide to use it as a prototype.
You may also frown upon the use of module.exports = Car;. However I find that
var Car = require("Car");
looks and feels better than
var Car = require("Car").Car;
You may argue that you should never have access to the constructor and that you should use factory methods. Whilst your argument is valid, I prefer to be able to make sure that my object X is an instance of Y using the built in instanceof operator.
How this applies to views and windows
For views and windows I add .view and .wnd properties to my object inside my init() method, which is where I call all other parts of my view construction. Take the following example of a list view.
function UIListView()
{
this.init.apply(this, arguments);
}
UIListView.prototype.init = function () {
this.view = Ti.UI.createTableView();
};
UIListView.prototype.populate = function (data) {
var i = 0, len = data.length, row;
for (; i < len; ++i)
{
row = Ti.UI.createTableViewRow(data[i].asTableViewRow());
this.view.appendRow(row);
}
};
module.exports = UIListView;
As you can see I can now call populate() at anytime to update my view with new data.
I’d like to experiment more with patterns like this. I’d love to hear your opinions and suggestions for other patterns or structures, so tweet me or send me an email.
Chosen does allow you to set when the search box should show
I started using chosen in a few projects but it frustrated me that the search box would always show regardless of how many options I had.
I read through the website and discover theres no mention of a setting, so being a good little community developer I decide to implement the functionality.
After getting my head round the coffeescript source, which in my opinion is far worse to read and grok than javascript, I add the code. Then i think I’ll be really good and make it configurable before I submit a pull-request.
Thats when I discover disable_search_threshold, and wondering what it was I try it. Turns out that it’s exactly the functionality I had just written and wasted time on.
So next time you’re using chosen and you need to hide search for the first, lets say, 10 items do this:
$(".chzn-select").chosen({
disable_search_threshold: 10
});
jsOAuth in the browser, my response to OAuth in web browsers
- Developer:
- We are on a look out for a Javascript OAuth library that works in browsers.
- Rob Griffiths:
- There are some things you need to consider when trying to get OAuth working in the browser using Javascript.
- Firstly, Javascript source is viewable by anyone with the inclination to do so, this means that your OAuth Key and Secret are publicly accessible, meaning that an attacker could use your credentials to sign requests and gain access tokens, in theory at least. In my opinion the attacker would have to fool a user into thinking they were your site, which isn't too hard but users are stupid and can be fooled easily.
- Secondly, if your site contacts a third party webservice, you'll be bound by in build browser security as you are making a cross domain request. The security disables any XHR from talking to a domain other than the one it was created on.
- Unless you use CORS (cross origin resource sharing), however most web services dont support this, which is a shame as this would make the web a better place allowing sites to interact at the client level creating interesting application mashups.
- So I'd ask this;
- - Does the webservice you're planning to use support CORS?
- - Do you have a plan to hide your secret in plain sight?
- Most people solve these issue by building a server-side script to proxy their XHR.
Why make Promises
Whatever you may call them, Promises, Futures or even Deferred the concept is the same. You ask an asynchronous task to do something, and it gives you a promised result back instantly which you can then act upon.
Take this trivial example in javascript:
var results = searchTwitter("Starwars");
filterByAuthor("@darthvader1977", results);
displayTweets(results);
Now wouldn’t that be great? Looks synchronous but behaves asynchronously? Sadly, I believe that this would require a language construct not native to most programming languages.
There are a few promise libraries written in Javascript that provide an API we can utilise on our previous example.
searchTwitter("Starwars").
then(filterBydarthvader1977).
then(displayTweets);
An heres where I’m confused. Why is this better then doing:
searchTwitter("Starwars", function (results) {
displayTweets(filterByAuthor("@darthvader1977", results));
});
Yes I guess, yes it does look prettier and more concise, and the API is explicit in its intent, but is that enough? This covers the Promises/A proposal as detailed on the CommonJS wiki. In my opinion pretty useless, at least in Javascript. From what I can tell, all of the proposals seem require the supply of a callback of some sort. This to me is interesting as I thought the whole idea behond promises was to get rid of the layers of nested callback, not just to reduce them.
So this leads me to an idea, which after a conversation with a collegue seems to make sense. So lets start with an example.
var tweets = searchTwitter("Startwars");
tweets.filterByAuthor("@darthvader1977");
tweets.display();
As you can see, we call method on the tweets variable. I’m assuming that the
searchTwitter method instantly returns a tweets object, with each method
queuing the call until the asynchronous call to searchTwitter completes, which
then calls each method in turn in the order it was invoked.
Now I’m certain this isn’t a new idea, and there must be a library out there or a specification, can someone tell me where?
Labeling the Back button
Good thinking. I don’t think it’s THAT easy in complex apps, but a good principle to guide you.
Most “deep” apps require some amount of navigation, moving the user deeper into child views and then back out to the parent view. That navigational backtracking is typically done with a “Back” button, positioned in the top-left corner, and denoted by a pointed left side. You’ve all seen it:
…
Using OpenStreetMap.org with the Google map API
Using a custom map type, its really simple to use the Google map API with tiles from open street map.
function OSMMapType() {}
OSMMapType.prototype = {
tileSize: new google.maps.Size(256,256),
maxZoom: 18,
getTile: function(coord, zoom, ownerDocument) {
var tileUrl = 'http://tile.openstreetmap.org/' + zoom + '/' + coord.x + '/' + coord.y + '.png';
var tile = ownerDocument.createElement('img');
tile.width = this.tileSize.width;
tile.height = this.tileSize.height;
tile.src = tileUrl;
return tile;
}
};
With this map type we instantiate a google map, and tell it to use our custom type
var latLng = new google.maps.LatLng(54.572061655658494, -3.7408447265625);
var map = new google.maps.Map(document.getElementById("map"), {
zoom: 5,
center: latLng,
mapTypeId: 'osm'
});
map.mapTypes.set('osm', new OSMMapType());
map.setMapTypeId('osm');
