Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Making Sprite-based Games with Canvas (jlongster.com)
101 points by jlongster on March 19, 2013 | hide | past | favorite | 23 comments


One thing not mentioned in the article: you don't have to render everything on a single canvas, you can use multiple canvases as layers. This is specially useful to separate what is updated often with what changes rarely, for instance the characters layer, the background layer and the HUD layer can potentially have very different update rates, so it makes sense to redraw them at a different pace each. In fact, you can also get creative and combine DOM elements with canvases.

These tricks matter because redrawing the entire screen every frame is usually an expensive operation; this is not noticable on small examples but it can become an issue on larger, more complex games.

Great article otherwise.


Thanks! I don't think you really need to do that on desktop devices, but that definitely helps on mobile. There's a lot of things I could have mentioned but I was focusing on beginners.

It may be worth following up this article with another one that includes techniques like this.


Do you know of any good resources that talk about using multiple canvases as layers? I have tried searching for some good examples, but I have been coming up empty.

Thanks


I don't think there'd really be any trick to it -- you just have multiple canvases, and render different stuff on each one. The most trivial example would be to have a single background canvas that has stuff that'll never be redrawn.

Remember that each canvas element is still part of the DOM, so you can put one on top of another just like you could with ordinary HTML.


Just dealt with some of these issues last week in 7drl.

>image-rendering: optimizeSpeed;

In some cases, you will want to scale the images drawn to the canvas, but not the canvas itself. This causes a lot of headache because of image smoothing and is not resolved by the above CSS. The answer is to set the image smoothing property of the canvas context to false. For example:

ctx.mozImageSmoothingEnabled = false;

ctx.webkitImageSmoothingEnabled = false;

Worked great on Chrome and Firefox. For some reason, though, this does not appear to work in Safari. I'm still amazed that something so simple is so hard to accomplish across browsers (after all you're asking to turn off extra, slower functionality). A good article on the intricacies: http://phoboslab.org/log/2012/09/drawing-pixels-is-hard


I had forgotten about those js properties, thanks. If you do that, and scale your graphics with setScale instead, I think that is the best option.

I plan on tweaking this article with improvements like that.


There is a pitfall with the approach of update loop using variable time steps. Depending on the game type this can matter quite a great deal. Essentially it is analogous to an iterated solution of the three body problem. 50 tiny steps produces a different result to 10 big steps.

There was a Google contraption editing game(a Google IO demo?) that suffered from this approach quite badly. It was a set-up-and-go game which should perform deterministically, but was influenced by variations in frame-rate.

The easiest approach to fixing this is simply quantised time.

    var now = Date.now();
    while(gameAge < now) {
       update();
       gameAge+=stepDuration;
    }
    render();
    //with usual caveats of resyncing if now-gameAge is too large
The much harder (but possibly ideal) approach is to not even have such a time step at all and move in variable increments calculated at the point of interaction between entities. An example of this would be a snooker simulation which moves in steps when the balls make contact. Balls slowing, rolling and curving become calculus problems. Produces a very nice result but your brain explodes.


I know the Crafty engine uses this technique; I was surprised by how well it works in practice.


This is a great article, but if you're really going to make a canvas game then you're much better off using a game engine. I recommend MelonJS[1] or Impact[2] if you don't mind the cost. I also have a side project that compares JavaScript game engines in much the same way TodoMVC compares MV* frameworks: http://city41.github.com/breakouts

[1]http://www.melonjs.org [2]http://www.impactjs.com


Hmm, you seem to have missed that Crafty can do scaling/rotating/moving/fading animations through the "Tween" component. (I'm not actually sure what "Sequencing" is in that context.)

http://craftyjs.com/api/Tween.html


wow, I did miss that. So has many other people who have looked at it, including the original creator of Crafty :) Not sure how that happened, but thanks for the heads up.


Much more useful than the Udacity HTML5 games class, which bizarrely dives into the bookkeeping minutia of looking up sprites in a collection of spritesheets for an entire unit (edit: unit of the class, I mean)


Minor nitpick. The bullet update code is a bit wordy:

   bullets.push({ pos: [x, y],
                       dir: 'forward',
                       sprite: new 
  Sprite('img/sprites.png', [0, 39], [18, 8]) });
and

  var bullet = bullets[i];

        switch(bullet.dir) {
        case 'up': bullet.pos[1] -= bulletSpeed * dt; break;
        case 'down': bullet.pos[1] += bulletSpeed * dt; 
  break;
        default:
            bullet.pos[0] += bulletSpeed * dt;
        }
You could consider simply adding a velocity to the bullet at spawn time like so:

  bullets.push({ pos: [x, y],
                       dir: [0,10],
                       sprite: new 
  Sprite('img/sprites.png', [0, 39], [18, 8]) });
and then in the update code replace the switch stuff with:

  bullet.pos[0] += bullet.dir[0] * dt;
  bullet.pos[1] += bullet.dir[1] * dt;
That should eliminate branching and make the interpreter much happier.

Additionally, by making the speed/velocity a member of the bullet instance, you can do things like have bullets that slow down or speed up if they have a think method or something, or that do homing (for this, look up dot-products and cross-products for steering).


Thanks this is a good article. I've been looking at HTML5 for game development recently for 1GAM [1]. One of the things that has really annoyed me is there does not seem to be any kind of standard way of structuring games. Is there anything like MVC for games?

[1] http://www.onegameamonth.com/


I have very little knowledge in this domain, but why do so few of these demos ever have sound? Is there something lacking with canvas and sound/music?


I haven't followed html5 development too closely, but audio support in current browsers hasn't been uniform. I'm guessing the lack of one size fits all for audio in browsers is why.

http://en.wikipedia.org/wiki/HTML5_Audio

edit: I'd also guess because audio is hard and that it is probably easier to make graphics and gaming logic than making sounds/music properly.


Probably because that's harder or outside of the scope of a demo. The first search result for "html5 games sound music" was this case study: http://www.html5rocks.com/en/tutorials/webaudio/fieldrunners...

From the first paragraph:

"Fieldrunners is an award-winning tower-defense style game that was originally released for iPhone in 2008. Since then it has been ported to many other platforms. One of the most recent platforms was the Chrome browser in October 2011. One of the challenges of porting Fieldrunners to an HTML5 platform was how to play sound."


I discussed it briefly near the end of the article under "Adding Sounds". The main reason this article doesn't do it is because it's focusing on rendering with canvas, and there's already a lot of information for beginners to go through there.

I plan on writing a followup to include sound, though, or possible extending this article.

What the other comments say is true, also. It's not extremely straightforward. The state of APIs on the web is very mixed, but I think in a year or so the Web Audio API will in most places.


Canvas doesn't have any kind of support for playing music, but there is a (flash) based sound manager that works everywhere and Chrome has some facility for playing sound too.

However making music is an art not all programmers have mastered, so most would likely skip that step.


All modern browsers support the HTML5 audio tag.


Yeah but that isn't really good enough to play sounds in (for a game).


I disagree, it's not the best, but it's decent enough for most games. Most HTML5 game engines use the audio tag. My game uses a good amount of sound effects and background music just fine with the audio tag: http://cityfortyone-mattgreer.dotcloud.com/dragonPlunder/


Nicely done, James. Well written for getting beginners comfortable working with canvas.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: