Out of Gas

Out of Gas

Out of Gas is my entry for the recent Ludum Dare 48 game jam. It was intended to be a blatant FTL rip-off, but in having much simplified clicker-like combat mechanics and an unusual cars-in-space aesthetic, I think it is sufficiently its own thing (I hope anyway!)


My initial thought was more of a straight sci-fi concept of travelling into deep space, facing combat and resource management challenges similar to those which ended up in the game. The first thing that came to mind as a title for this was “Out of Gas”, after the Modest Mouse song of the same name.

Thinking about that song got me thinking in another direction - essentially the same mechanics, but Earth-bound, set in a Modest Mouse world of highways and drifters, fleeing problems and starting over. The problem to flee in this case would obviously be debt - something that you can get deeper and deeper into.

As you can probably tell by now I ended up combining these two ideas! I didn’t want to let either of them go, and I quickly fell in love with the idea of a universe where space combat meant winding down your window and firing a handgun at your enemy.

The combined concept suggested that a new, sci-fi twist on the debt problem was required, and that’s where the idea of a constantly growing cryptocurrency debt came in. I’ve been thinking about cryptocurrencies a lot lately since they’re going through another hype cycle. One commonly touted feature of them (or some, like Bitcoin, at least), is that they’re deflationary, so any debt denominated in them would constantly grow in value instead of decreasing in value like debts denominated in inflationary fiat currencies. This seemed like the perfect notion for the bizarre world of my game. It doesn’t really have any impact on the gameplay, but I think it’s a nice bit of narrative flavour, and it fits the theme perfectly.

Late payment

The final piece of the conceptual puzzle was the characters. I couldn’t very well have two anonymous nobodies riding along with the player on a trip like this! I turned to two characters I had vague notions of making a game about years ago, Haze & Lee, a gun-toting, post-apocalyptic outlaw couple. Unfortunately I don’t think their personalities really come across in the game due to time constraints, but at least they have names!


As usual, I did all the art in Pyxel Edit. I started off very rough with just pink boxes for the ships and a partial circle for the background, and moved immediately onto the gameplay with those placeholders. This is a somewhat unusual approach for me as I usually try to tie down the look of a game early on.

First mockup

The thing about rough mockups is that by the time I came back to the art a bunch of stuff in the game was already tied to the resolution and shape of the outlines. I wasn’t even sure I had done the perspective correctly, but I was stuck with it anyway, and I guess it was close enough because nobody has complained!

First ships

I had planned to do some character portraits as well for the narrative side of the game, and express encounters as dialogues between characters, but unfortunately there wasn’t time for that.

The map screen also didn’t get much love, with the initial placeholder art surviving into the final game.

Map screen


As for my last Ludum Dare entry, Gophers, a cutscene graph editor plugin for Godot that I had previously developed was essential to getting this game done within the time constraints of the jam.

Those darn teenagers!

I had done a lot of work on this plugin in recent months, applying lessons learned from using it for Gophers to improve the workflow, functionality, and stability. This paid huge dividends, and I found almost no issues while churning out encounter cutscenes. The cutscene graphs created by this plugin power every encounter in the game up to and after combat.

My main task on the first day was to get the map screen working - it wouldn’t be much of a game if you couldn’t travel between systems. I implemented it as a graph defined by custom MapSystem and MapConnection control nodes.

Map graph

The new fun thing about this for me was declaring the MapConnection class to be a “tool” script, allowing the connections between systems to be drawn in the editor. This kind of custom tooling is important for the efficient design of systems in larger games, so it was fun to give it a try. Here, it mostly served to prevent me from getting confused about which MapSystem nodes I had already connected to each other and which I hadn’t.

func _draw():
    if usable or used or _can_draw_in_editor():
        # TODO: Decide on proper colours for this
        var color = Color.gray
        if usable:
            color = Color.hotpink
        # No idea why the offset is required
        var source_center = _source_node.rect_global_position + CENTER_OFFSET
        var target_center = _target_node.rect_global_position + CENTER_OFFSET
        var start = source_center + ((target_center - source_center).normalized() * SPACE)
        var finish = target_center + ((source_center - target_center).normalized() * SPACE)

Implementing the combat was a lot tougher. The battle scene is almost entirely UI nodes, which was perhaps a mistake, and for some reason I struggled most of day two to even get player input to register properly. I don’t really remember now what the obstacle was to this - maybe I was just tired.

Battle UI

Sound and Music

There’s nothing special about the sound this time around. Unlike for Gophers I didn’t have time to do any foley work, and I figured I would probably have a hard time creating gunshot and explosion sounds anyway. Instead I fell back to SFXR (specifically, jsfxr).

The music I put together in BeepBox, my favourite game jam tool for chiptune music these days due to its simplicity. I tend not to get as bogged down with it as I do with LMMS. I initially wanted to try to create something in the style of Modest Mouse, given the game’s inspiration, but it was hard to recreate a guitar sound. Instead I ended up with a simple arpeggiated chord progression over a bass drone that I hope feels kind of epic, kind of longing and lonesome, I dunno.

The battle music is a variation of the same tune but just swaps out one of the instruments, doubles up the drone, and compresses and spreads the arpeggios across more octaves for a more urgent and chaotic feeling. The two tracks play in sync throughout the game and just cut between each other as necessary.

Abandoned Ideas

As usual there were many ideas that I had to put aside due to time constraints. I had planned to include a small number of missiles which could be fired during combat with devastating effect, to allow the player to pull themselves back from the brink of defeat. I had also intended to have targetable/damageable systems on the ships, including injury to the characters, so that you could take out the enemy’s weapon to gain a reprieve from being fired upon, or their engines and reduce their chance to dodge. You can see the proposed UI of these mechanics in the initial mockup above. Finally, I had planned a system of weapon upgrades which almost made it in, but not quite.

On the art side, I had wanted to include a number of different backgrounds to improve the sense of travelling between systems.

A big regret that I have is that I wasn’t able to include the character portraits, and express the encounters primarily as dialogue between characters. I think this would have introduced a lot more personality to the narrative side of the game, as opposed to the third-person narration that I had to go with.


I like this game a lot, and I feel it is one that could be polished up and rounded out into a complete experience with relative ease, so I am determined to do a post-jam release with some of the missing features described above, and some of the problems with the jam release resolved (such as the RNG sometimes producing the same encounter multiple times in a row). I have already begun work on this, and I hope to have it completed in the next few months. I’ll do another post about my progress on it so far, but for now here’s a little sneak peek:

Haze speaks!

Coroutine Callbacks

I’m working on a cutscene/dialogue graph editor plugin for the Godot game engine (I mentioned using it for the Ludum Dare in a previous post). When I came to deciding how to actually process the graphs it creates in order to display the dialogue and perform actions in the game, I discovered an interesting use for coroutines that I haven’t seen described elsewhere. I’m not all that used to working with coroutines so maybe what I’ve done is completely normal and everybody does it all the time, or indeed it might be ill-advised for some reason. Either way, I will describe it here and you can ignore me if I’m being an idiot!

Graph editor

Processing a graph that results in activity in-game is a task which frequently needs to be put on hold - waiting for text to be displayed in the UI in a juicy manner, moving characters around, waiting for input etc. This could be achieved in a Node by implementing _process() and maintaining state about whether you’re currently walking a graph or waiting on something, and having methods that other nodes can use to indicate when processing can continue. I have found such methods to be quite messy in the past.

I decided instead to process the graph in a while loop and yield as necessary while other nodes perform tasks initiated by a number of signals. Where tasks are expected to take some time to complete, a coroutine state object is passed to the signal which the listener can use to indicate that processing should continue, or in some cases return values.

Let’s See Some Code

Below is an abridged version of the main method that processes the graphs. Processing a dialogue node yields so that the UI that displays the text can wait for player input to continue. Processing a branch node and others like it just proceed directly to the next iteration of the loop.

func process_cutscene(cutscene):
    _local_store = {}
    _current_graph = cutscene
    _current_node = _current_graph.root_node
    while _current_node != null:
        if _current_node is DialogueTextNode:
            yield(_process_dialogue_node(), "completed")
        elif _current_node is BranchNode:

Here is the code that processes dialogue nodes and raises the signal for their text to be displayed in-game. A coroutine is put in a frozen state to be passed with the signal, and the call to emit the signal is deferred so we can make sure we are waiting for the coroutine to complete before any signal listeners have a chance to resume it.

func _await_response():
    return yield()

func _emit_dialogue_signal(

func _process_dialogue_node():
    var text = _current_node.text

    var process = _await_response()
    yield(process, "completed")

    _current_node = _current_node.next

The code that consumes the signal can take however long it likes to do its thing, and when it’s ready it can just call resume() on the coroutine state and the graph processing will proceed to the next node.

func _on_CutsceneController_dialogue_display_requested(
    _process = process

func _on_ContinueButton_pressed():
    if _process != null:

If a node in the graph needs a response in order to know what to do next (e.g. a choice between multiple dialogue options), we can just accept the return value of the coroutine passed in the signal. The consumer can just pass the value to the resume() call.

func _process_choice_node():
    var process = _await_response()
    var choice = yield(process, "completed")
    _current_node = _current_node.branches[choice]

Potential Pitfalls

There are two pitfalls that come to mind with this approach, but they’re not really any different than what could occur with a _process() based approach like the one I described above.

  1. Processing of another graph could be triggered while one is still in progress. If the previous one is yielding it would end up processing the new graph as well when it resumes. This is quite easy to avoid by just noping out of the method if there is already work in progress.
  2. If there are multiple listeners connected to the signals there could be ambiguity about which one is responsible for resuming. If there are multiple resume calls, all but the first will result in a runtime exception.

In the event that you actually want multiple listeners to report in before resuming, it might be possible to craft a different coroutine that takes the number of listeners and yields until they have all resumed. I think it would look something like this:

func _await_many(count):
  while count > 0:
    count -= 1

func _await_many_responses(count):
  var responses = []
  while count > 0:
    count -= 1
  return responses

I haven’t tested that though.


I don’t really have one, I just thought it was a neat pattern that doesn’t require the listeners to keep a reference to the node doing the processing or have any knowledge of it aside from the signals it emits. You can check out the full code on GitHub as it stands currently. I haven’t tested it in a game yet, but I will probably enter the Ludum Dare later this month and I might get a chance to use it then. I will update afterwards whether it is a disaster or a triumph!

America Wins Again

Chess lives here

This post contains spoilers for the TV show “The Queen’s Gambit”

I loved pretty much everything about The Queen’s Gambit, and as you’ve probably gathered if you’ve read any of my other posts, I don’t have much to say about things if I’m not complaining about them!

What I do feel obligated to talk about, however, are the differences between this show and “For All Mankind” in terms of how they deal with the Soviet Union. I’ve written previously about how “For All Mankind” re-imagines the space race such that the USA remains the underdog after several successful Soviet moon landings - erasing real Soviet accomplishments in favour of fictional ones, and providing an impetus for the US to include women in its space program, something that it didn’t do in reality until the 1980’s.

The Queen’s Gambit does not rewrite history to the same extent. The chess world was dominated by Soviet players in the 50s, 60s and beyond, and the show acknowledges that readily, with “The Russian”, Vasily Borgov, being Beth Harmon’s ultimate opponent. Her breakthrough somewhat reflects that of American prodigy Bobby Fischer, so it’s not unprecedented. However, where For All Mankind featured a number of real-life historical figures, all the competitors in The Queen’s Gambit are fictional.

Team USA

In a way, however, Beth’s real opponent is not Borgov or any of the other men she defeats on the road to face him, but herself, her emotional problems, and her addictions. The games she plays are almost entirely without malice, with just a touch of smug arrogance on occasion, and everybody she faces ends up with enormous admiration for her. This is especially true of the Soviet players she faces, who almost seem happier to have been beaten by her than they would have been to have won. What cold war political animosity is present comes mostly from her CIA handler, and is treated as a ridiculous, petty distraction by Beth. Doesn’t he know that there’s chess to be played??

For All Mankind, in contrast, has that animosity at its core. Its the motivation behind all of the American government’s actions in the show, though not necessarily of everybody at NASA, while the one Soviet character seems to validate their suspicions.

The Queen’s Gambit’s portrayal of the Soviet Union is actually extraordinarily sympathetic as a result of being viewed through the lens of chess enthusiasm. Whereas at home chess is a niche interest, when Beth arrives in the USSR she discovers that it is a national obsession. At home her prospects are probably akin to those of Benny Watts, the US chess champion before her - obscurity, and a dingy basement apartment at best. In the USSR she is mobbed by an adoring crowd after every match, which she plays in a dedicated chess hall instead of whatever spaces are available. She even has to adopt their strategy of cooperating during adjournments before she is able to achieve victory, with a team of all the chess friends she’s acquired on her journey advising her on how to approach the rest of the game - an apparent admission of the superiority of collective cooperation over competition and individualism.

Welcome home

The final scene sees Beth slipping her handler’s grasp on the way to the airport. She wanders the streets of Moscow unmolested to find the old guys playing chess in the park, and they greet her warmly before inviting her to play. There’s a distinct sense that she has found a home here, where the game she loves is played openly in the park instead of hidden away in the basement, as in the orphanage where she grew up.

Although this series is still about an American character and mostly set in America, it is much closer to being the view from “the other side” that I hoped for in my previous post.


You're a wizard Wade!

This post contains spoilers for the movie “Ready Player One”

I finally gave in and watched Ready Player One, prompted by seeing the Internet dump on the sequel to the novel. I avoided it before now because the commentary on the novel made it sound like pandering nonsense, and I assumed the movie would be much the same. But, I wanted to see for myself.

Perhaps as a result of those lowered expectations, I actually found it quite entertaining on a surface level. The pop culture references were certainly omnipresent, but maybe not as tiresome as having them explained in writing would be. In movie form, a lot of them that are not plot-relevant just form a visual backdrop that actually help define a plausible metaverse, albeit one with a culture that is inexplicable stuck 30 years in the past.

But on the other hand, the centrality of pop culture to the plot, and why it is central, is also what leaves a bad taste in my mouth. In the universe of Ready Player One, the online world is dominated by a metaverse-like virtual reality game called the OASIS, a game owned and controlled by a single corporation, and ultimately a single man, its creator, James Halliday. When he dies, he decrees that his successor will be decided by a tripartite fetch quest within the virtual world. In a monumental act of narcissism, the quest’s challenges are not based on the skills required to run a massive company or a piece of essential infrastructure, or tests of morality or wisdom, but on intimate knowledge of his own life and his pop cultural obsessions. This might be an interesting setup if Halliday were the antagonist, but he’s not, he’s practically worshipped by the users of the OASIS.

Wow!! Cool Future!!

This movie has the trappings of cyberpunk, but little of the critique. Victory in this story is not the smashing of a corporate monopoly or frustrating of its goals, but the passing of the reins of power from a virtuous benevolent founder to a handful of virtuous disciples, through an absurd faux-meritocratic process where merit means liking the right books and games and movies.

The antagonist, Sorrento, is the CEO of a company that runs debtor’s prisons, yet somehow the movie gives the impression that his greater sin is being a poseur who’s only pretending to “get” the stuff that Halliday liked. The denouement even reveals that Halliday could have used his monopoly power to end the practice of indentured servitude at any time, but apparently chose not to, or just didn’t think to, and this is not framed as a critique of monopoly capitalism, but is just a throwaway line to demonstrate how benevolent the protagonist is in his new role.

Remember Tracer? Remember Chun-Li? Remember various skeletons?

The third act involves an epic battle in the OASIS, with the user-base coming together to fight Sorrento’s forces and prevent them from completing the quest. It’s presented as an empowering grass-roots uprising to save the OASIS from an evil corporation, and fine, they are pretty evil… But the status quo is also intolerable. They’re not fighting for their own empowerment, but merely to keep the unaccountable corporate power that dominates their lives out of even more abusive hands. It’s a pretty uninspiring cause.

The movie’s true feelings on the nature of power, and the relationship of ordinary people to it, is revealed most starkly at its climax. The conflict in the OASIS has spilled over into the real world, with our intrepid heroes being chased through the streets in a van, exposed at every turn by CCTV tracking technology and drones. While Sorrento sets out to confront them personally, they put out a call for aid, for their supporters to gather in the slums and defend them. When Sorrento reaches them, a huge crowd of people stream out of the stacks to oppose him.

It's dangerous to go alone! Take this!

For a moment, it seems as though the plot really is going to be resolved by collective direct action. People power, woo! Instead, Sorrento pulls out a gun, and the crowd parts. They could easily disarm him, there are hundreds of them all around him. Instead they gawp uselessly at him, right up to the point where he is threatening to shoot some children in the face. It is only the police arriving that prevents him from committing murder right in front of them.

With Sorrento out of the way thanks to the police, a bunch of lawyers arrive to certify the protagonist’s completion of the quest and acquisition of complete control over the OASIS. The crowd are reduced to placid spectators in a boardroom drama that doesn’t involve them or empower them. This is, I feel, the perfect encapsulation of the movie’s worldview. The crowd are the audience - expected to worship and trust benevolent CEOs, to react strongly in defence of a commodified culture where they are otherwise passive consumers, but to look on silently and not interfere as control over that culture changes hands, maintaining the status quo.



I’m not very good at doing these art posts in a timely manner; I did this still-life of a couple of avocados for pixel dailies back in September!





I was inspired to create this when I won a postcard and sticker pack giveaway on twitter by my friend Stefanie, and I was eagerly waiting for it to arrive! I actually did this a while ago but I forgot to post it here.

Postcard and stickers

Go check out Stefanie’s work, it’s amazing. Thanks for the goodies Stef!



Stars Trek - Failures of Imagination

Where did it all go wrong?

This post contains spoilers for the TV show “Picard”

Star Trek: The Next Generation, and its follow-ups, Deep Space 9 and Voyager, are some of my favourite TV shows. They are set in a future post-scarcity utopia where poverty, disease and war (amongst humans and most of the alien species they encounter, at least) have been largely eliminated.

Although they sometimes deal with deep topics, like the humanity or personhood of artificial intelligences, the economic reality of their universe and how it came about goes largely unexamined. There is no money, we are told (except sometimes, when there is). There is property, apparently, but whether it works the same way as property does today is not discussed. Abundant energy and the technology to conjure most of the essentials of life from thin air mean that nobody goes hungry, but whether everybody can have the opportunity to own a vinyard in France without inheriting one is a question that goes unasked.

The utopianism is usually established instead through a gentle mocking of the preoccupations and vices of present-day society, or lecturing about how humanity has moved past them. A bemused Picard takes a cigarette offered by a 20th century character on the holodeck, and coughs aggressively. Imagine smoking! Even the Ferengi, themselves caricatures of grubby, grasping capitalists, are shocked at our stupidity when they learn about tobacco. Janeway lectures the omnipotent Q about resolving conflicts with diplomacy instead of violence. An arrogant 20th century revival is revealed to be a buffoon when he demands to be allowed to speak to his lawyer. No lawyers here sir - this is the lawyerless utopia of Lionel Hutz’s nightmares.

Occasionally the admonishment is more direct - such as when Sisko time travels to a ghetto in a North American city, in our near future, looks directly into the camera, and says “sort your fucking shit out”.

The point is that in the Star Trek future, society is better than it is today, but its material basis is vague to the point of absurdity. It’s unfortunate, because that would be an interesting topic to explore, but it is what it is - light-hearted science-fantasy more concerned with the personal growth of characters than with the economic basis of their society.

A Shallow Dystopia

Sacre bleu!

Star Trek: Picard, the latest attempt at continuing the Star Trek franchise on television, is set, in contrast to its predecessors, in a fractured, broken society. The Federation has turned inward, failing to live up to its values of diplomatic and humanitarian outreach. Money has returned with a vengeance, and nobody does anything unless they’re getting paid. There’s a disaffected, under-appreciated working class, who apparently don’t even get the same quality of replicators as other sections of society. Where characters in other series’ have interests and hobbies, in Picard they have vices, addictions and psychological damage. One character constantly has a fat cigar hanging out of his mouth and nobody is shocked about it because he looks, just, so cool.

In a show without an established universe, these aspects would be unremarkable - just a different set of assumptions about human nature and the future development of society, and with different stories to tell. In Picard, the departure from the previous utopianism is not examined, much less explained, and it is jarring.

But the above examples are trivialities compared to a problem that is at the very heart of the show. Toiling alongside the human workers are a class of sentient android slaves whose abolition and genocide by the Federation serves as a major plot motivator.

More than a Fistful

Seriously bro?

These are the “Datas on every starship” that Maddox expresses a desire for in the TNG episode “The Measure of a Man”. In that episode (one of the best in the Star Trek canon), Picard defends Data’s personhood and his right to self-determination. He’s ready to sacrifice his career over the possibility that his society would view even one android as property. In Picard, the same character disagrees with the ban on “synthetics”, but hardly comments on their genocide, or their previous condition of slavery. He quits Starfleet over their failure to provide humanitarian aid to the Romulans, not over the fact that the Federation had somehow come to rely on slave labour. Apparently, he would be perfectly happy to return to a situation that he fought to prevent when he was Captain of the Enterprise.

It’s a disappointing missed opportunity. It seems to me that the show wanted to say something about the socio-political situation in America today, but utterly fails to understand that situation, the shows that came before it, or the character of Picard.

If it really wanted to portray the dissolution of a utopia, a crumbling society betraying its ideals, it could have done so by clarifying the nature of the Federation economy, and provided some systemic explanation for the introduction of slave labour, money, and inequality, where those things did not exist before, or at least some believable political force pushing for those things. Picard could have been cast in the role of defending the fundamental rights of the Androids from a society that is determined to exploit them, as he has many times in the past. Perhaps he could even have taken on the new role of defending the rights of human labourers, whatever the reason that they’re suddenly being disenfranchised. It could have been a great opportunity to introduce some economic depth to the Star Trek universe that has long been lacking.

Instead, we get a complete mess where exploitation is ignored, the dissolution of Federation society is apparently due to infiltration by an inherently sinister other, and the androids are the ultimate villain for not being sympathetic to their oppressors or being understanding about the genocide of their race.



An animation I made for Asteroid day to continue my space-themed art streak! Thanks to my friend Stefanie for the suggestion! Please click that link and check out her absolutely stunning art, you won’t regret it.


Prints are available through RedBubble, INPRNT and coming soon to Displate.


Observatory Timelapse


Celestial 1

Only a few days after the last inspiring pixel dailies prompt, another one appeared that I couldn’t resist - “Celestial”. I had three ideas for it immediately but I only had time to do the one above on the day. I’m glad I spaced them out anyway because I think I achieved a lot with the extra time.


The second idea I worked on was originally only a planet-rise over some mountains, but it evolved quite a bit as I worked on it until it was about spaceships racing over a peaceful alien village.

I’m quite pleased with the palette and animation on this one.

Celestial 2

The final concept I only completed yesterday, a view of the night sky through some trees.


Prints are available through RedBubble (linked individually above), and Displate.


Celestial 1


Available from 2020-06-25:

Celestial 2