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).
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 (
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
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
// 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.