I've never worked with the new <canvas> element of HTML5 so I played with it and created a really really simple game at the weekend. Normally, I don't share such experiments, but maybe you can find something useful in it.
Let's start with the basic rules of the game. You control a red circle with your mouse on a yellow court and have to catch a red rectangle. This is quite simple, but you must not hit one of the gray circles. The number of gray balls increases with every new catch. By a simple click you can inverse the direction of all balls - which is sometimes helpful if you urged in the top left corner for example.
If you're just interested in playing the game and use already one of the modern browsers like Firefox 3.6, Opera 10.6 or Chrome click to play the game.
For all others who are interested in the mathematical background of this game should continue reading. Moving the balls should be clear, so I focus on the hittest, which is not so trivial in JavaScript. My first idea to detect a hit with another point was checking the distance of these two points. This can be done by using the sum of both radii as the smallest possible distance between two circles. Geometrically this can be conceive by the following:
This is quite simple by using the Pythagoras to determine the distance. But the problem with Pythagoras is, that we need 2 powers and one square root in the equation, which will slow down the whole thing if there are 100 flying balls and 50 calculations per second.
A much better idea would be to approximate it for the first step. So I sketched a hair cross in my mind over the scene like this:
Okay, let's dig a little deeper. I decided to make the flying balls half size of the big ball attached to the mouse, which allows us to safe one addition, because we can use the coordinate directly instead of using the right border offset (as the small ball fits in the first half of the big circle):
Now we can describe the matching condition with
(m.x <= b.x-5 <= m.x+10 OR m.x-10 <= b.x+5 <= m.x+10)
which can be better expressed by
(m.x+5 <= b.x <= m.x+15 OR m.x-15 <= b.x <= m.x+5)
Now it's possible to simplify the expression to
(b.x <= m.x+15 AND m.x <= b.x+15)
which is our final check if we hit a point at the x-axis. If the condition is true for any point, we can use the slow distance formula to make a more precise decision:
(m.x-b.x)*(m.x-b.x)+(m.y-b.y)*(m.y-b.y) == (m.radius+b.radius)*(m.radius+b.radius)
As I used PHP as macro language, everything on the right hand side is substitutable and remains constant in the resulting JavaScript source. I used PHP for every offset calculation to reduce the number of operations on the client. At the end of my work, I also removed some unnecessary functions to avoid function calls.
Update of 06.03.2008:
- New scoring model: the faster you play, the more point's you'll get
- Fixed bug that you loose immediately. It's only possible to loose if you move against a new created barrier which is also directed to you. But this is your fault.
- Fixed bug that you can cheat by pausing movements
BTW: My record is a score of 145; beat this ;-)