Behind the Klod

Klod is our submission to the second Bevy game jam. It was made in 10 days by Devil Dahu, our 2 people team. Nicola (me) at programming and music, and Xo at 3d art.

Jargon

to klod, klodding, klodded: verb, to add to the klod ball.

Preparing

Pre-jam, I prepared a template based on our entry in the last jam, Warlock’s Gambit.

The template menu

Since the game was still running on bevy 0.7, it was a challenge to bring the code up to date. But it helped a lot, since UI is definitively the most annoying part of bevy, and all the UI I ended up needing was in the template.

A saving grace was the addition of the focus_follows_mouse field in the input mapping resource of bevy-ui-navigation. I will pat myself on the back for caring for existing users, because sometimes that user is just me 🙂.

The Idea

The theme choice fell at 22:00, I did want to have a reasonable night sleep, but we first started throwing around game ideas. Xo quickly suggested something similar to Katamari, and I was in. I love Katamari Damacy, and programming a clone seemed like a very fun challenge.

I jokingly went:

Let’s make our own twist: Katamari Damacy, but dark souls (smirking face emote)

Puzzle game with Katamari mechanics? Where depending on what you pick up, you get different abilities

Then realization dawned upon me:

Oh man, Katamari, but the ball is just an agglomeration of corpses

I started implementing the klod mechanic and waited on Xo for more feedback. At this point I was not sure about the dark fantasy setting, but Xo seemed more onboard than myself.

We discussed what other mechanics we could add to the game, failure and win states. I proposed a time trial object collection challenge.

We had some more crazy ideas including multiplayer, which might feed into a larger game, but at the end we settled with:

Trivia

the formula for mana is just bone weight × time left, it was the initial formula, and it was so good it didn’t need improvement.

The game would be mostly going downhill, trying to steer the ball enough to pick up items for secret paths and score. In the end, it would look a lot like Rock of Ages.

The Music

At the start of the jam, I didn’t feel like programming at all! So, after settling on the setting, “dark fantasy,” I immediately went on jummbox and did what can only be described as “jamming,” and in 3 hours, the game soundtrack was complete. The track was later cut to fit the game length.

The music was to be split into several tracks, triggering by reaching certain game areas.

At first, I implemented a very fancy music queue, waiting until the last track ends before running new ones, to avoid jarring music transitions. Tracks, however, were too long for that, so you wound up never hearing the final staircase scale.

The very last-minute change to play the music immediately after reaching an area is still quite buggy. This, for example, results in audio cutting if you die in the first area of the game.

Klod soundtrack

Game jam tip

I strongly recommend using jummbox for game jam music. I have no formal music education and do not play any instrument, yet I can get some compelling crap out of it.

The Editor

This is the single most damaging mistake I made.

We “needed” an editor to design the level. I wanted something in-engine so that it would be trivial and quick to test out the level and edit it.

However, no such level editor exists for bevy. So obviously… I made one. I used bevy_editor_pls as a base, added bevy_transform_gizmo for manipulating objects, added keybindings similar to blender to move objects around, created a scene system with prefabs, and wrote the UI for adding Klod-specific object, saving and loading a level, just for the jam.

This took more or less 7 days out of the 10 we were given for the jam. It didn’t help us much, but it did help other people.

Early editor prototype demo.

I ended up designing the level in Blender using exclusively 1×1×1 cubes and spheres resized using scale, and writing a tinny importer based off bevy-scene-hook to convert it into the internal scene format. What was imported included the environment and the items such as the bones and shovels.

Trivia

Klodable items are also 1×1×1 cubes, if you open the game files with Blender, you’ll notice that everything, including shovels and bones, are stretched to fit a 1×1×1 cube.

The level is imported as a bunch of invisible fixed colliders, and the actual visible geometry is just a single entity located at the origin of the level.

The editor was however useful at the end: to place lights in the level, do last-minute fixups for balance and filling huge holes in the walls.

Trivia

Until the very last moment, the final staircase doors didn’t have a doorstep, making it nearly impossible to use the shovels, I just added a cube with the editor.

In the end, I bundled the editor with the native build artifacts, so I have an excuse for having wasted so much of my time doing something only tangential.

The sound effects

We had music, but we needed some sound effects. Physics become empirically 1195.93% better if combined with sounds.

This was easy, I downloaded the Kenny “Impact Sounds” audio pack, wrote a very lengthy and extremely fancy audio system to handle all the possible sound effects and configure them with the editor.

Yet, only a single impact sound effect is used in the whole game…

Trivia

The ball has a roll sound, the sound used is found in the “Sci-Fi sounds” Kenny audio pack, under the thrusterFire_002.ogg name. The roll sound is almost never heard, because it requires the ball to roll smoothly for a while, which becomes impossible after the first bone you pick up.

Trivia

The game has 127 “impact” audio files totalling 1.4M, yet only uses 5 tracks for 75K. I’m sorry to waste your bandwidth 😢

The Gameplay

The gameplay ended up relatively minimal, it only required:

Controls

So how should the game control?

Katamari controls themselves are unique: You use the two sticks of the controller to steer the ball in a direction, as if the left stick and right stick were mapped to the left and right hands of the Prince.

Katamari controls are notoriously disorienting, so reproducing them wasn’t a priority. I opted for an orbit cam with WASD/left stick directional movement, because I was expecting most players to be familiar with such controls. It also would make it possible to play the game on keyboard. I actually planned Katamari controls as an option, if only as a nod to an amazing game, but I didn’t have enough time to implement them.

Trivia

Gamepad support was added in 5 minutes.

The Camera

Klod has a classical 3d plateformer orbit camera, which is known to be disorienting, especially indoors. This was a contentious point in the team at the beginning of the jam, because we opted for an indoor setting despite knowing we would depend on an orbit cam.

Knowing that, I made sure there is ample space for the camera to move around when designing the level. But there is still a few cramped places, and indeed the camera in those is really bad, I’m sorry.

The orbit cam code is straight up cut from a previous unfinished game, which itself is cut out of a very old crate running only on bevy 0.4.

I am very proud how camera-relative input works in Klod, it simply rotates the input by the camera’s x rotation.

pub(crate) struct OrbitCamera {
    distance: f32,
    x_rot: f32,
    y_rot: f32,
    follows: Entity,
}
impl OrbitCamera {
    pub(crate) fn horizontal_rotation(&self) -> f32 {
        self.x_rot % TAU
    }
}
fn ball_input() {
    let force = ;// input force …
    let force = Vec2::from_angle(-camera.horizontal_rotation()).rotate(force);
}

The trick is just to use the x_rot of the camera rotation, and rotate the force by it, now input forward is forward for the camera.

Physics

The physics were surprisingly both difficult and easy to get right.

(2nd day Katamari-like physics)

I opted to use bevy_rapier for the physics, as I am familiar with it and there isn’t much of an alternative anyway.

The klodding mechanic was relatively trivial to implement: bevy_rapier allows specifying composite collider shapes as a parent RigidBody and a collection of children Collider. So theoretically, I only had to convert the transform of an entity I can klod into the klod-local coordinate space, remove the entity’s RigidBody and set its parent to the klod ball itself.

fn transform_relative_to(point: &GlobalTransform, reference: &GlobalTransform) -> Transform {
    let relative_affine = reference.affine().inverse() * point.affine();
    let (scale, rotation, translation) = relative_affine.to_scale_rotation_translation();
    Transform { translation, rotation, scale }
}
// ...
// `agglo_trans` is the transform of the entity to add to the klod.
let trans = transform_relative_to(agglo_trans, klod_trans);

However, bevy_rapier has a few, rough, edges which made the straightforward solution simply not work.

Once those bumps were surpassed with monstrous workarounds, including splitting the components of the added entities into multiple entities, that was it. It just worked.

Well, not quite. I got the Katamari mechanic working, but it was nearly impossible to navigate the level, because you invariably ended up with a shape preventing you from moving or too big to go through doors. The solution had many elements:

fn within_radius(&self, distance: f32) -> bool {
    let max_distance = self.weight / KLOD_INITIAL_WEIGHT;
    distance < max_distance
}
fn agglo_to_klod() {
    //...
    let mut trans = transform_relative_to(agglo_trans, klod_trans);
    trans.translation = trans.translation * 0.8;
    //..
}

Level Design

The blender greybox version of the Klod level

The level design was very awkward. The best tool I had at hand was Blender, but it’s not well suited for that kind of tasks.

Furthermore, I made the level before Xo made the tileset, and this resulted in incompatible designs. So I made due, and just added the textures Xo made to the base collider cubes (the “greybox” level), adjusting the UVs so they don’t feel too stretched.

Game design tip

Greyboxing is the practice of developing a 3D game exclusively with filler grey boxes. This permits to focus exclusively on gameplay. If your game is fun with grey boxes, it will definitively be fun with cool graphics as well.

And in a pinch, you can always do like me, keep the box geometry and add a simple texture.

The visuals of Klod is a massive downgrade compared to Warlock’s Gambit. I tried to salvage it last-minute, adding more visual diversity with lights, but then the problem was performance, so I had to add a way to disable lighting.

Final touches

18 hours before the end of the jam, I felt like the game was not fun at all! I was very sad. However, after adjusting the physics and adding a goal, it magically became fun and addictive.

I think the best part of the game is when you die. Everything goes in every direction, including the hands, and a “you lose” sound effect plays. This was difficult to do due to the rapier issues I’ve mentioned, but it was 159.1% worth it.

I was tempted to make the game nearly impossible so that people would naturally see the death animation. In insight, I should have played the death animation on any loss condition.

The spawn animation with the hands joining the ball and the ball growing is also excellent flavor, even if it lasts less than half a second, I love it for how silly it is.

Results and learning

I eventually came around to enjoy the game. Despite the sub-par graphics, it is still a fun game to play. (reminder that you can play it in browser for free)

However, this time, the competition is fierce! I think at least two games out of the ones I played are better than Klod, and I’ve only played 15 out of the 89 submitted games.

I think our weakness is still unfamiliarity with game development processes and a lack of environmental artists. The weakness bevy showed are: