I competed in the 2014 GD.SE Anniversary Game Jam and created Traces, a top-down pseudo-3D shooter.
In Traces, the goal is to power each building with a laser beam in sequential order all while killing or avoiding the enemy blobs. Activate the first building in sight and find the next building at the end of laser beam. Eat meat to restore your health.
I decided to make a web canvas game this time because I had a huge barrier to entry problem in my last game jam game, Super Bounce (you had to download the executable and then register the UI system I was using).
For this game, I used CraftyJS, a JavaScript canvas game engine library which worked great. I found it very easy to work with because of its mix and match entity and component system with scenes(similar to Unity). I also liked that it doesn't lock anything down to a particular method. I was even able to do custom canvas drawing with the normal canvas/context draw API.
You can check out the full source on GitHub.
Some pitfalls I found with Crafty was positioning the viewport (see the LerpCamera
component for reference), translating a mouse click into the game space, and working with a rotated entity. You can find a snippet on how to translate a click into game space in the source. I had to make a 2DExtended
component which solved the rotated entity problem and added a few utility methods such as getActualPosition
that would get the actual (x
, y
) coordinate of the rotated entity. I suggest using this BoxOverlays debug component (pictured below) to make sense of how Crafty's 2D component works.
Another issue I ran into was using SVG's and resizing sprites. The built-in sprite component was missing features for what I needed, even for my simple use case. But since Crafty is not constraining, I just used canvas context.drawImage(...)
with a scratch canvas. You can checkout the Meat
component to see a simple example. One note when working with the raw canvas context: make sure you are setting the x
, y
, w
, h
on the 2D
component properly. This allows Crafty's draw manager to know when to redraw the entity appropriately. Also, use context.translate(e.pos._x, e.pos._y);
at the beginning of the draw call (see source for examples) and then draw from reference (0, 0). This is the proper way to draw something at the appropriate position and rotation will be funky if you do not do this.
I referenced the Crafty source code many times to see what happens behind the scenes. The online documentation looks like it is generated from the source's comments which makes the source very easy to follow and great for offline reference.
Another thing to be aware of is event binding and making sure to clean up binds completely when changing scenes or removing an entity/component. To make all of this easy, I made an EventManager
component which turned binding into a fire and forget type experience. All you have to do is add the EventManager
component to the entity and make a cleanBind
call.
// Add the `EventManager` component
// Params:
// Event name
// Callback when the event fires
// Entity/Component name of parent Entity/Component. This is optional but necessary if you are removing components from entities.
this.cleanBind('damaged', this._onDamaged, 'PlayerCharacter');
An aspect missing in Crafty is built-in graphical gizmos for debugging. I made a very simple colored square entity called DebugMarker
which I used heavily to find out where things were spawning, etc. A text gizmo would be another helpful addition.