Tiny game #7: Ascent – my first game jam!

This is my submission for the GameDev.tv 2022 10-day Game Jam – first game jam ever. It’s been intense, but totally worth it!

You can download a Windows executable (and the Unity source code, if you’re interested) at the above link, or play the game in your web browser by clicking on the image below:

click on the image to open the game in a new window – webgl-enabled browser required!

The theme for the game jam was “Death is just the beginning”. I’ve always been fascinated about the great circle of life – how life began from nothing, and evolves in a constant cycle of reproduction and decay, where the deceased provide the raw materials for the next generation of life. Struggle for survival and pressure to evolve.

So, huge concept, and almost no time – an ideal combination 😀

The major challenge (and charm) in doing these “game thumbnails” is to find a way to boil your highflying ideas down to a workable solution. Narrow the scope to a central mechanic that expresses the idea. And don’t forget it should be fun to play!

Game mechanics

What I came up with is a game about evolving a tiny deep sea creature, to eventually reach the surface and leave the ocean behind. It’s meant to be a rather chill experience, so the game play is not too tough. I had to throw away most of the ideas popping into my head all the time, but the major elements of the concept are there:

  • Your creature starts as a baby on a primitive level, feeding on the plankton floating around. It’s vulnerable at this stage, likely to get eaten by bigger fish.
  • Once grown up, go look for a mate! The only phase of the game where there’s some time pressure.
  • To produce offspring, the player needs to collect biomaterials left behind by deceased sea creatures. These get more complex as evolution progresses.
  • The baby becomes the new incarnation of the player, slightly more evolved, and the cycle continues.

I had this idea about a “spark of life” or “soul” that exists independently of the body. That made it into the game as a sort of failsafe:

  • When the player creature dies (gets eaten, for instance), you enter a “netherworld”, where your spirit needs to find a new suitable body.
  • Only baby creatures of your own species are suitable. Find one and the game continues, the only penalty being thrown back one evolution level.
  • Touching any other adult creature in that state means “Game Over”. The only way you can truly die in this game.

Lessons learned

These mechanics are still pretty complex, and not anything players will be familiar with from the get go. So, the major problem turned out to be how to communicate what’s going on to the player. All the required sprites and animations would have broken my back for sure – so in the end I had to resort to text messages explaining some things to the user. That actually worked out ok, and I ended up with “only” around 50 handdrawn sprites.

The scope of the game felt just right coding-wise: Develop the concept at speed, disregarding a lot of production code best practices, just to make it work in time. Knowing the code is discardable anyway made this a very relaxing and fun experience (of course, there was still cursing and pulling of hair).

Prototyping the prototype: I spent the first 2 days just thinking and making notes on paper. The first implementation used squares and circles as sprites, no animations. That approach really paid off, and saved a lot of time, even when the final result is still just a prototype.

This was the first game where I was able to add sound! Had to resort to free assets available on the internet, but it adds so much. Learned a lot about how to do sound mixing in Unity.

So what?

All things considered, I’m pretty happy with the result. Just exploring the concept conjured up a vision of “the real game”, which would be at least 10x larger, involve majestic underwater visuals, tons of cool creatures, more challenges, etc. This could look fantastic in Unreal Engine, with partly procedurally generated 3D creatures, lighting effects, and so on. There’s a project!

Also, I’m absolutely planning to participate in more game jams. It’s intense and exhausting, but a priceless experience. And who knows, someday there might be real commercial game coming out of one of these.

Tiny game #6: Bones

A tiny edutainment game, inspired by the “find & click” prompt from the list of prompts from an RMIT Games class. Learn about the human skeleton!

click on the image to open the game in a new window – webgl-enabled browser required!

This took a lot longer than expected – I jumped at the opportunity to 3D model a basic human skeleton in Blender (it’s rough, but still anatomically correct), and went a little further than strictly necessary with designing the 3D environment as well.

Also, even though this is a simple game, the interaction handling proved really complex. Very limited use of physics simulation (otherwise, there’s bones flying about everywhere), defining and dealing with attachment points on the skeleton, user feedback (the talking skull, color markers, colored bones), auto-aligning a bone when the user picks it up, etc. The devil’s in the detail!

On a side note, I went almost insane about MeshColliders with WebGL again. Only by chance, after hours of frustration, I discovered I had to check “read/write” in the import settings of the skeleton model. Otherwise, the MeshColliders in the WebGL build simply wouldn’t collide. Everything was running just fine in the editor, of course.

Tiny game #5: Life in 10

A 10-second game! This is the first in a list of prompts from an RMIT Games class I decided to follow.

click on the image to open the game in a new window – webgl-enabled browser required!

Along with the prompts come some pointers at related games for inspiration. These are a few years old, so only some are still working out of the box – one of these is Queers in Love at the End of the World, a piece of interactive fiction in 10 seconds. I found the combination of urgency, intimacy, and epic end-of-the-world setting really appealing, so I went for “life in 10 seconds” as my topic – think big, right?

First lesson: the time limit is ridiculous! I had tons of subtle ideas for this game, but after implementing the first prototype that ran through in 10 seconds, about 90% went straight out the window. It was cool, though, because it forced me to strip down and streamline everything to the bare minimum. For instance:

  • Free player movement was discarded in favor of simple lane switching.
  • A numeric score display in the corner? there’s no time to even look at it. So I put symbols right below the player avatar.
  • I reduced the number of items to just 2 per lane, a “regular” and a “special” item.

Still, there is way too much going on. You probably need to play a few times to even realize how this works 🙂 Which is partly intentional, I wanted to play with the feeling of having no control, life speeding up, and not knowing what just hit you. As it stands, I don’t feel it’s too successful a game, but as an exploration off the beaten track, this was immensely valuable.

Note to self: I really need to add sound one of these days!

Tiny game #4: Groundhog Downhill

[UPDATE: I’ve published a slightly more polished version of this game here, give it a shot: https://scruffyowl.itch.io/groundhog-downhill]

This time I wanted to do something with 3D terrain and physics. Did you know groundhogs love having downhill contests in winter? Try to finish the course in under one minute! (My personal best is around 50 seconds.)

click on the image to open the game in a new window – webgl-enabled browser required!

I didn’t spend much time on optimization – the terrain is essentially a giant mesh, and there are a lot of unneccessary realtime light and shadow computations. It should run OK on a current PC, but my old laptop was aching a lot in fullscreen mode.

At first, I though about using Unity’s terrain engine and editor, but that turned out to be unsuitable for a game like this. It’s meant for huge natural terrains, as in an open-world game, but it’s based on height fields – and sculpting a race track with precision is pretty much impossible. So in the end, I modelled the track in Blender using curves, and added a simple polygonal terrain and a few extras here and there.

The physics engine is based on rigid bodies, so our little friend behaves much more like a tennis ball than a floppy soft creature. But it’s fun that way 🙂 I did add an extra force to make him stick to the ground just a little more.

Having this really rough implementation working in WebGL with decent performance out of the box is pretty cool! There’s a bug regarding mesh collisions in Unity with WebGL, though, which has been around for FOUR years and will likely never get fixed. If you check the bug tracker issue and related forum discussions, it is rather disheartening to see how a problem such as this is treated. It’s unfortunately not the first time I see quite relevant issues remaining on the table for many years without getting fixed in Unity. With any luck, someone in the community has come up with a clever workaround (which helped me out this time, too). But in the long term, these things make you wonder about their priorities and whether it’s time to explore other options.

Tiny game #3: Escape

It’s NaNoWriMo, and even though I’m not writing a novel, it’s the perfect month to work on a game with narrative!

There are some great GDC videos on narrative in video games by Jon Ingold from inkle. Over the years, they have developed a scripting language for games based on branching narrative called “ink”, which has recently been open-sourced. The system is completely text-based. They do provide a very lean C# API, too, so it’s almost a no-brainer to use ink for authoring the story backbone of a graphical adventure-type game!

In ink, a “game” is essentially constructed around pieces of content (text) presented to the player, and sets of choices to direct flow to other pieces of content. Programming logic is provided to allow state tracking and flow control. There are no concepts for “rooms”, “objects”, “containers”, “actors”, though. What about action adventure / rogue-like gameplay, where you wander around a dungeon, encounter NPCs, collect and use items?

So that was my challenge, and here’s the result:

click on the image to open the game in a new window – webgl-enabled browser required!

This is very much a proof of concept rather than a full game, but I am quite happy how it all worked out! Gameplay is completely driven by the following .ink text file:

// items that can be picked up

LIST items = nothing, soap
VAR inventory = ()

// states

LIST playerState = walking, (inBed), soaked, soaped
LIST bedState = (down), up
LIST manholeState = (closed), open, examined
LIST showerState = (off), activated

// locations
LIST locations = (none), BED, CELL, SHOWER, SHAFT

VAR playerLocation = BED
VAR prevPlayerLocation = none

VAR bedItems = (BED)
VAR cellItems = (CELL)
VAR showerItems = (SHOWER, soap)
VAR shaftItems = (SHAFT)

-> hub

// functions for moving around

// did we enter location x for the first time?
=== function first(x) ===
~ return x == 1

// did we just enter the current location from somewhere else?
=== function enter ===
~ return prevPlayerLocation != playerLocation

=== function moveTo(x) ===
~ playerLocation = x

=== function removeItem(ref itemList, item) ===
~ itemList -= item

// pick up an item from current player location
=== function getItem(item) ===
{ playerLocation:
  - BED: ~removeItem(bedItems, item)
  - CELL: ~removeItem(cellItems, item)
  - SHOWER: ~removeItem(showerItems, item)
  - SHAFT: ~removeItem(shaftItems, item)
}
~ inventory += item

// main story hub, switching flow to the available locations

=== hub ===
{ playerLocation:
  - BED: <- bed(->hub)
  - CELL: <- cell(->hub)
  - SHOWER: <- shower(->hub)
  - SHAFT: <- shaft(->hub)
}
<- inventory_actions(->hub)
~ prevPlayerLocation = playerLocation

-> DONE

=== bed(->back) ===
#cut
E S C A P E

The same dream, night after night.
A prison cell.
No way out.
One day after the other, your life passes by.
"Hope" is just a faint shadow of a word without meaning.
%%
You awake from restless slumber...
%%
%%
(any key to start)
%PAUSE%
#player
Zzzzz.... hrm?
Where am I?
Oh.
\*Sigh*
How do I get out of here?
%WAIT%

* [!anyaction!Get up] Ouch, my back! This "bed" is killing me. #player
  ~ moveTo(CELL)
- -> back
  
=== cell(->back) ===

+ [!trigger!shower]
    ~moveTo(SHOWER)
* [!pull!bed]
  ~bedState = up
+ {bedState ? up && manholeState ? (closed,examined)} [!pull!grating]
  Uaarrggh! Heavy! #player
  ~manholeState = open
  -> examine_manhole
* (examine_manhole) {bedState ? up} [!examine!grating]
  {examine_manhole == 1 : {manholeState ? closed : The gutter, covered with a grating.|This shaft looks REALLY tight!}} #player
  ~manholeState += examined
+ {manholeState ? open} [!use!manhole]
  {playerState ? soaped:{Are you serious?? It stinks!|It still smells!|Ewww!}|It's too tight, I'll get stuck!}#player
  + + {playerState ? soaped} [!use!manhole]
      Aah, all right.
      Down the rabbithole! #player
      %WAIT%
  ~moveTo(SHAFT)
  + + [!noaction!manhole] -> back
  - -
-
-> back

=== shaft(->back) ===
#cut
Carefully, you lower your soaked, soaped, slippery body down the hole, head first.
One last push, and off you go!
Holding your breath, you're hoping for the best.
%%
Freedom, at last!
%%
%%
(any key to restart - but why would you?)
%END%
->END

=== shower(->back) ===
{enter():{Take a shower, maybe?|}} #player

* [!examine!button] A big red button. #player
* [!push!button]
  ~ showerState = activated
  Yikes! #player
  Why didn't I undress first?
  ~ playerState = soaked
  * [!examine!soap] Disgusting.#player
    How can SOAP be so dirty?! 
  * [!get!soap] This slimy thing gives me the creeps. #player
  ~ getItem(soap)
+ [!trigger!leaveshower]
  ~moveTo(CELL)
  
-
-> back
  
 === inventory_actions(->back)
 * {inventory ? soap && !(playerState ? soaked)} [!use!soap] It's too dry! #player
 + {inventory ? soap && playerState ? soaked} [!use!soap] Yay, foam bubbles! #player
 Hmmm - lavender?
    ~inventory -= soap
    ~playerState = soaped
 - ->back

(Disclaimer: There may well be better ways to do this – it’s my first time using ink!)

On the Unity side, incoming text is processed by a StoryAdapter wrapper around the ink API. Player choices in the text are mapped to actions in the game environment by custom markup, which I made up in a very ad hoc fashion. E.g.:

  • the choice [!push!button] will be presented as a menu on the “button” object in the scene, when the player approaches it.
  • Location changes are choices, too: a choice with the !trigger! markup will be executed when the player crosses a special invisible object in the scene.
  • The #player tag sends text to a balloon displayed as the player’s thoughts.
  • #cut sends text to a cut scene screen (at the beginning and end of the game)
  • … and so on.

What you end up with, is a sort of MVC architecture of a game: the ink description is the model, being visualized by the game graphics. The player actions in the scene are sent back to the model, which then updates itself to advance the story.

Now, this is really exciting! It means:

  • the game can be played entirely in its text form! You can paste the above text into the Inky editor and play through. It’s not going to be very pretty, due to all the markup, but…
  • … authoring story and game logic is a breeze after the foundation is laid, or at least a lot easier;
  • … the game can be tested without any UI, for instance using automated randomized picking of choices;
  • … games could also be completely or in part procedurally generated.

The one thing I didn’t get around to is dialogue, which is a real shame. But something has to be left for another game, right?

Tiny game #2: Neat-O-Droid

This game took about two weeks from start to finish. “Two games a month” instead of “a game a week” still doesn’t sound too bad, right?

The gameplay is somewhat inspired by the good old Paradroid C64 game, with some Pacman mechanics sprinkled in (gobble up the pellets, avoid and kill the monsters, clear the maze, you name it).

click on the image to open the game in a new window – webgl-enabled browser required!

The most interesting programming challenge was the map generator- I spent the bigger part of the first week on it. The levels in the game are fairly small, but the algorithm can generate arbitrarily big maps, which I hope will come in handy in future games. The general structure is a nested set of rectangular rooms and hallways, such as this:

a bigger maze

The algorithm is based on a simple binary space partitioning scheme, essentially going through these steps:

  • divide an initial rectangle with a few wide separators (the hallways)
  • recursively divide the parts with thinner separators (rooms separated by walls)
  • identify all separator spans shared by two rooms (potential doors)
  • create a random path covering all rooms (this will be the set of required doors)
  • randomly delete a subset of the remaining doors

This way, all rooms are guaranteed to be reachable with an adjustable overall amount of doors.

One major lesson: With the number of moving parts, the parameters that have to be balanced explodes. Even in a simple games as this, tweaking things like

  • size and complexity of the map
  • amount of initially distributed junk
  • player speed and fire rate
  • enemy speed and “litter rate”
  • rate of enemies respawning
  • speed of “junk unloading” at the chute
  • number of junk items the player can carry

do not only make the difference between easy and hard, but also change how the game needs to be played to win.

Tiny game #1: Elsie in the woods

Thinking more about how to unify my interests in programming and art, I’ve been turning to games again – it’s been a while! After spending nearly two months on a prototype platformer game, I had to realize

  • it would take a lot longer to properly finish the game with nice artwork and really smooth gameplay
  • even though developing the game was a lot of fun, I really don’t have that much experience with game design, so ultimately it wouldn’t even have been all that interesting to play.

Inspired by a video on “a game a week”, I decided to abandon the big project and go for way smaller, focused mini games that could actually be implemented in a short time. This is the first of them – situated in what used to be just the intro of my original larger game.

My main goal here was to have a “complete” game – with a beginning, middle, and end, revolving around a simple core game mechanic.

click on the image to open the game in a new window – webgl-enabled browser required!

Despite its simplicity, there were quite a few interesting technical bits here to experiment with:

  • importing the rigged player model from Blender into Unity
  • an outline shader for the player
  • some postprocess bloom in the background
  • Cinemachine virtual camera controls
  • a particle system for the exploding mushrooms
  • 2d physics