Check out my new course Learn you some Lambda best practice for great good! and learn the best practices for performance, cost, security, resilience, observability and scalability.
The logical next step would be to made animations, and give you a way to interact with the animation. So how about a little game that lets you shoot moving targets like those classic Point Blank games? Hands up who’s up for that?
Good good, that’s decided then! :-)
To Start Off..
First, we’ll need a simple HTML page, something like my previous demos would do:
Nothing fancy here, the CSS for this page is also pretty basic too, the only thing worth noting is that to get the crosshair cursor inside the canvas I included this in my CSS:
The onSelectStart line in the canvas HTML is to ensure that the crosshair cursor is used when you click and hold inside the canvas element.
You might have also noticed that I had specified two canvas elements in the HTML, this is to simplify the task of drawing moving targets onto the main canvas. With the 2D context object’s drawImage function, you can draw an img, canvas, or video element so I can draw the target onto the target canvas during initialization and then reuse it in the main canvas.
Drawing the Target board
Next, I need to draw the target boards, and make them look like this, but without the score on the rings:
(Why not just use an image? Because where’s the fun in that! ;-) )
As you can imagine, we can create a target board looking like this by drawing 6 circles, with the innermost 2 circles having roughly half the radius of the other 4 and the outermost 2 circles having the inversed fill/stroke colour combination. Expand the below section to see the initializeTargetCanvas function which takes a canvas element and draws a target board in inside it:
Animating the Target Boards
Being able to draw an already created target board onto the canvas page is one thing, but how do I animate them using the canvas? Having looked at a few other examples it seems the common way to do animation with the canvas is to simply clear the canvas and redraw the contents on a regular interval. This seems a little low level and requires a bit of plumbing but I’m sure it won’t be long (if not already) before some good, solid frameworks emerge to make these tasks easier.
For now though, let me illustrate how you might create this frame by frame animation yourself.
If you separate the responsibilities of the app, broadly speaking you end up with:
- a View – i.e. the canvas element, responsible for displaying the targets
- a Model – the objects representing the targets in the scene, responsible for keeping track of their current position, etc.
If you’ve dealt with any sort of MVC/MVP/MVVM pattern then this kind of separation of duty should be familiar to you already. On each frame (or if you prefer, every time the setInterval delegate function gets invoked), you update the position of the targets in the model, then redraw the targets onto the canvas to reflect their updated positions:
This is all you need to do to create a basic animation. So in my case, I need a simple Target object to keep track of:
- X, Y coordinates of the top left hand corner of the target
- the radius of the target
- the direction and speed (per frame) it’s moving at
using MooTools here’s the class I arrived at this Target ‘class’:
The draw function, which is invoked at regular intervals, first clears the canvas (by filling it with the background colour) then goes through all the targets in the targets array and updates their location and then draw them onto the canvas:
This will give you the basic animation loop, here’s how it looks with 10 moving targets on screen at the same time:
Now that the animations are in place, let’s add some player interactions. The interactions I’m after here is simple, click in the canvas and knock out any (can be one or more) target that’s clicked on.
I’ve already gone over the process of calculating the coordinates of the click in respect to the canvas in a previous blog post here, this is what that code looks like:
If I can work out where you’ve clicked in the canvas’ coordinate system, then I can simply run a hit test against each moving target and compare the distance between the click and the centre of the target and the target’s radius:
If the distance is smaller or equal to the radius then the click happened INSIDE the target and therefore it’s a hit, otherwise it’s a miss. Sounds reasonable enough? Here’s the code that takes a position (a simple object with X and Y position of the click inside the canvas’ coordinate system) and return the targets it has hit:
To hook this up, I added an event handler to the mousedown event on the canvas during initialization:
And now, when you ‘hit’ a target it’ll be removed from the array of moving targets and therefore won’t be drawn again when the canvas is refreshed in the next frame.
Finally, for this first-pass implementation of a mini-shooting game, I’d like to add some notifications to tell you when you’ve hit something, or when you’ve missed completely!
This is slightly trickier than the targets as the messages should not stay around forever until some user-triggered action, instead it should be shown for a given amount of time (or frames). To facilitate this requirement, I created another ‘class’ called Message:
The Message objects can only been drawn a number of times, after which it will remove itself from the array of messages currently being displayed.
To make it a bit more interesting, I defined a number of messages which will be displayed depending on how many targets you’ve managed to hit at once:
On the mousedown event handler (see above) I added these couple of lines to push a new message to the messages stack to be displayed for 30 frames, and the message is determined by how many targets was hit:
For example, if you managed to hit three targets one shot:
Pretty neat, eh? :-)
Here is the full demo, over the next couple of days, I will polish it up and add some more features to make it feel more gamey and post another update. In the mean time though, feel free to play around with it and let me know of any suggestions you have on how to improve it!
I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.
Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.
Check out my new course, Learn you some Lambda best practice for great good! In this course, you will learn best practices for working with AWS Lambda in terms of performance, cost, security, scalability, resilience and observability. Enrol now and enjoy a special preorder price of £9.99 (~$13).
Are you working with Serverless and looking for expert training to level-up your skills? Or are you looking for a solid foundation to start from? Look no further, register for my Production-Ready Serverless workshop to learn how to build production-grade Serverless applications!
Here is a complete list of all my posts on serverless and AWS Lambda. In the meantime, here are a few of my most popular blog posts.
- Lambda optimization tip – enable HTTP keep-alive
- You are thinking about serverless costs all wrong
- Many faced threats to Serverless security
- We can do better than percentile latencies
- I’m afraid you’re thinking about AWS Lambda cold starts all wrong
- Yubl’s road to Serverless
- AWS Lambda – should you have few monolithic functions or many single-purposed functions?
- AWS Lambda – compare coldstart time with different languages, memory and code sizes
- Guys, we’re doing pagination wrong