Here at the laboratory we look forward to Friday afternoons. Ordinarily you might think that this qualifies us for the nice padded room, but we have a secret. Friday afternoon is game jam time, when we drop everything and work on something quick and cool.
For the past couple of weeks we’ve been jamming on a derivative of the venerable Curveball, a sort of 3D Pong. What we came up with is a neon-soaked retro-future experience. We call it Absolution Velocity.
Fire up some jams by Daft Punk or Power Glove and have a go:
Behind the Scenes
This game does something that you don’t see often in Kiwi.js: 3D. The ball moves in and out of the screen. How do we do that?
Well, we fake it.
All 3D graphics are fake, of course. Even the Oculus Rift is just feeding you two flat images. But you’re smart, and your brain is great at adding depth. We just need to feed you enough hints for that wonderful brain to fill in the gaps.
What we’ve done is a simple perspective trick. We put the ball (and the ball guide) into a group, offset the group’s anchor point to the middle of the screen, and then scale it.
The setup is easy:
// Code simplified for clarity
var ball = new Kiwi.GameObjects.Sprite( this, this.textures.ball, this.game.stage.width / 2, this.game.stage.height / 2 );
var ballGuide = new Kiwi.GameObjects.Sprite( this, this.textures.ballGuide, 0, 0 );
var ballGroup = new Kiwi.Group;
ballGroup.anchorPointX = this.game.stage.width / 2;
ballGroup.anchorPointY = this.game.stage.height / 2;
Perspective is a little bit trickier. For this, we need to know how far away the objects are. We’ve done this by manually adding a
z value to the ball group. Once we know the z position, we can do a simple calculation to get the apparent size:
ballGroup.scale = 1 / ballGroup.z;
Of course, this leads to certain problems. If the ball reaches a depth of 2, it will be half as wide. At a depth of 4, it will be a quarter as wide. This is already very small. But the game area is several hundred pixels across! If we gave it a depth of a few hundred units to match the other dimensions, the ball would be smaller than a single pixel.
We can solve this by setting the near and far planes of the level, and using them in the equation. We store these z values in a simple
Kiwi.Geom.Point object. We simply assume that the near plane is where scale = 1, and the equation becomes:
ballGroup.scale = level.near / ballGroup.z;
Our level is 100-400. This works well with calculations using ball radius and velocity.
The name of the game was determined while designing the physics. Bouncing off rectangular walls is a fairly easy problem because you can compute each axis independently, but it has some pitfalls.
For example, consider a ball that hits x = 0. We can assume that its velocity is negative, because it’s heading in a negative direction. So perhaps we should multiply that velocity by -1 so it will head the other way.
This seems neat and logical. It is also wrong.
You cannot guarantee that the velocity is actually negative. In fact, we’ve just proved that it isn’t – we multiplied by -1 to turn it positive! If the ball doesn’t rise above 0 on the next frame, perhaps because it lost energy in a bounce, its velocity will reverse again, and now it will be headed back out. The ball will get stuck in the wall!
A more robust solution will make sure that the ball is heading in the correct direction, no matter what direction it was going before. For this we use absolute values. If we say
velocity.x = Math.abs(velocity.x), all is well; it makes the velocity positive. We can also say
velocity.x = -Math.abs(velocity.x) for the upper bound, to redirect it inwards.
While brainstorming this simple physics paradigm, I used the term “absolution velocity” on our whiteboard. The phrase was too cool to forget. So we named the game after it.
We were fortunate to begin development on Absolution Velocity shortly before the release of Kiwi.js v1.1.0. As in every game design project, we had to invent new solutions. And sometimes using the tools in new ways revealed unexpected bugs. Which we were then able to fix.
A fun way to let off stress for us is also a great way to make Kiwi.js even more reliable for you. We know our tools are great because we use them, and we have to be satisfied with our own work.
Finally, we made extensive use of the new Kiwi.js blend modes to get that 80s feel just right. Everything glows and flickers and pulses. We do this by creating a new renderer, setting its blend mode to ADDITIVE, and then cloning all the assets to create glows. We’ll be discussing this technique in more detail in an upcoming article here at kiwijs.org, so keep an eye out; or jump the gun and have a look at the API docs in our handy reference section.
That’s all for today. See you soon!
Benjamin D. Richards