Some Of The Things You Didn't Want To Know About State Tree In UE5 And Weren't Afraid To Ask

UPDATE 02/10/2024 - the Unreal 5.5 preview has updated the State Tree system a lot, which means some of the bugs / headaches / perceived miseries listed below may not be there any more- but if you’re not ready to make the jump to 5.5, the solutions and tips will still work.

The interface is also much clearer, and there are some new features. Particularly nice is the option to select states by evaluating a utility function - that is, rather than having to say explicitly where you’d like execution to go after a particular state completes, you can assign and modify weights that can be used to determine which state is currently most important, and then go to that. So, for example, you can assign a weight to a ‘fight’ task that scales with character health, and a weight to the ‘flee’ task that is inversely proportional to it.

This was something I’d implemented myself separately, but it’s now available right out of the box.

Handy!

But also slightly annoying given I’d spent a day writing a small, nicely templated library for selecting items probability distributions. That’s life.

ORIGINAL POST BELOW

I’ve been working with Unreal Engine 5 for a little while now, in between various contracts that pay actual money. The previous game idea is on the back-burner for now, partly because it’d require too much content to actually be good, and partly because VR is a tiny market. So, now I’m working on something more conventional, provisionally entitled The Last Gig.

Whilst UE5 is mostly a superb piece of software, it does have some niggles. The C++ macros, for example- these mostly let you forget about memory management and write things to interact nicely with the editor, but also hide a ton of complexity. That complexity is definitely better off hidden, but occasionally it will poke through and hit you with an error message even less comprehensible than the usual C++ error messages are.

In general though, that side is fine once you get used to it. But I don’t want to talk about that, I want to talk about the fancy new AI framework - State Tree - and some of the headaches I’ve had when using it. Some of these pain-points are simply due to how they work, but some are genuine bugs that I’ve had to work around.

It’s not all bad though! On balance I like State Trees, and so I’ve included some handy tips at the end.

But first:

What is a State Tree?

Wikipedia lists these as the official trees of the US States.

The State Tree of Idaho is the Western White Pine. Nevada has a couple of stumps, whilst New Jersey has the most basic tree ever. I find this very appropriate for a place that is basically Ultra Essex.

BUT IN THE CONTEXT OF AI, a State Tree is a hybrid of a Behaviour Tree and a State Machine, notionally giving you the best of both worlds. From Behaviour Trees they take the hierarchical structure, from State Machines they take the concept of states and easy transitions.

State Trees let you see at glance what your AI is (or should) be doing at a particular point, and allow you to jump to different behaviours as you wish without having to stick rigidly to the structure of a Behaviour Tree. This makes them very flexible. There’s also fewer concepts involved - no blackboards, no decorators, although there are things that perform similar roles.

This is what a (simple, incomplete) Behaviour Tree looks like:

A Behaviour Tree that I abandoned when State Trees came out

And this is what (more complicated) State Tree looks like:

A State Tree that I'm currently working on. It looks nicer in 5.5.

The latter is much nicer to reason about, and has most of the information you need available at a glance. I really like them.

What is in a State Tree?

You can skip this part if you just want to get to the headaches.

A State Tree has several top-level concepts:

  • Context: an object describing and storing what the State Tree is controlling- typically an actor or an AI Controller.
  • Parameters: global variables that you can set and read from, although as of 5.4 setting them at runtime is a bit awkward.
  • States: logical groupings of tasks to be executed, and transitions that can happen whilst that state is active. States can have child states (which is where the ‘tree’ bit comes in). States can also have enter conditions that need to be met before entry.
  • Tasks: things you actually want the AI to do. These can also provide information to other tasks, or claim resources, and can be run globally- that is, not tied to a particular state. Usually. We’ll get to that. Tasks can also (optionally) finish, reporting either success or failure, by calling their Finish Task function.
  • Transitions: these direct execution flow from one state to another. Like states, transitions can have conditions that need to be met before being activated. There’s three main flavours of transition- On Task Succeeded / Failed, which are triggered when tasks succeed and fail respectively; On Task Completed, which is triggered when a task succeeds OR when it fails; and On Event, which has to be triggered manually, either from inside a task or from outside the tree. Transitions can also have a priority, to resolve conflict if two or more are triggered at the same time.
  • Evaluators: these provide outside data to the tree. They are essentially pseudo-tasks with no inputs (beyond what is in the context), and that don’t have transitions attached. They can update the information they provide as execution progresses… usually. We’ll get to that in a bit.
  • Bindings: using bindings, tasks can expose input variables to be set when their containing state is activated. When you add a task to the tree, you can choose what to bind these exposed properties to from any variables that will be available when that task is executed. You can use the output of an evaluator, a parameter, the context, or another task. This means as the overall state of the game progresses, the behaviour of tasks can be dynamically modified to respond to new information. There is some hidden complexity here however, which we’ll get to later.

So, how do they work? Each tree has a ‘root’ state where execution starts. The State Tree will then try and find states to activate by running the following algorithm, running from top to bottom of the tree.

  1. Move consideration to the next child state of the last state checked (which is initially the root state).
  2. Check this state for enter conditions. If the conditions pass, or there are no conditions:
    1. This state is marked as active.
    2. If this state is a Leaf State- one that has no child states- stop searching and move to 5.
    3. Otherwise, set consideration to this node, and go back to 1.
  3. If the enter conditions fail, move consideration to the next child of the last state checked.
  4. If no states remain to be checked, and there are no active states, the tree exits.
  5. If the tree is still running, start any tasks on states that are active, stop any tasks on states that are not, and wait for a transition to be triggered.
  6. When a transition occurs, move consideration to wherever the transition points to, and go back to 2.

What can possibly go wrong?

Again, I like State Trees. But there are some things you should be aware of so you don’t spend as much time as I did wondering why they’re not fucking working properly.

Headache number 1: multiple active states and tasks

What do you think this is going to do exactly?

Multiple states can be active at the same time. Multiple tasks can be active at the same time. Each state can have its own transitions.

As mentioned, one of the most common transitions is “On State Completed”, which is fired whenever a task finishes execution by calling the Finish Task function. The problem is that all tasks in active states will receive the notification from all active tasks at or below their own level, meaning that a transition you thought only applied in a parent state may end up firing when something in a child state completes.

In the above example, states A, B, and C will all become active simultaneously- C is the leaf node, but the tasks on A and B will also be started. C completing will trigger the transitions on A, B and C, though because it’s furthest down C will be the one that takes precedence. Probably? Unfortunately, it’s not always obvious, particularly when there’s lots of different tasks and transitions.

This isn’t too much of an issue if you’re aware of it, but it’s not exactly highlighted in the docs, and it brings us to another problem:

Headache number 2: doing two things at once

Say you’ve got two or more tasks that you want to happen at once- for example, you want (A) your character to speak a line of dialogue and (B) walk to a position. Unfortunately you don’t know how long the voice line you’re playing is compared to how long the walk is, so whilst you want both to start at the same time, you want them to complete at different times, and then move execution elsewhere.

Two tasks in the same state- but as above, they could be in different states

You cannot use the On State Completed transition for this. This will fire if either A or B complete, which is almost guaranteed to be premature, causing the task that hasn’t finished to be stopped before completion.

If you’ve got another voice line to play when your character gets to where they’re going and it’s a really short walk, this could lead to the previous line getting cut off, or both playing at once. Likewise, if it’s a short voice line and a long walk, they could start playing their ‘interact’ animation (or whatever) in totally the wrong position.

Again this isn’t too bad if you’re aware of it, and there’s ways of mitigating both of the things in that example outside of the tree, but it’s still something to be worked around. In general there’s two options, depending on how essential that concurrency is.

Option 1: if you know (or don’t really care) that one is going to finish before the other, just make it so one of the tasks never calls the Finish Task function. If only one task is finishing, there’s only one transition trigger. A slightly more complete solution is to subclass the UStateTreeTaskBlueprintBase C++ class and add something like UPROPERTY(BlueprintReadOnly, EditAnywhere) bool ShouldCallFinishTask that lets you set whether it finishes or not in the State Tree overview.

This is what I’ve done in the ExecuteSubtask task I created. I consider ‘sub tasks’ - which is not an official term - to be simple tasks that do something cosmetic or incidental, such as play a sound. They never call the Finish Task function, so they don’t affect the flow of the tree- they just trigger an event on the controlled Pawn, and when execution moves on they simply do any clean up they need to, and then stop.

Option 2: do something more involved, and add a specific task that counts the number of times other tasks below it finish. If you do this you’ll also need to define a transition that isn’t On State Completed to actually break out of this bit of the tree. Event transitions will work for this.

Option 2, however, requires being aware of another possible headache…

Headache number 3: receiving multiple EnterState and ExitState events in tasks residing in parent states

Let’s say you’ve grouped some behaviour together like this:

Grouping behaviours is great! Until it fucks up.

This is good! This is what State Tree is for! You’ve got a parent State grouping a set of behaviours, and you’ve got a clear sequence of things will happen in the order you’ve specified. If this state gets activated, the tree will immediately start any tasks in A, B and C; when C finishes, execution will go to D, and when D finishes execution will go to E, and then your Evil Space Knight character leaves this particular grouping to go and blow up the Innocent Space Children’s Hospital in the way you’ve defined elsewhere in the tree.

But there’s an issue:

Abandon all hope all ye who EnterState here

Tasks have three main events that get fired- Enter State, Exit State and Tick. Tick does what you expect, but Enter State and Exit State will be called on any task that is active when a transition happens. In the above example, A, B and C will all become active at the same time, and the associated tasks will get an Enter State at the same time. When C completes, tasks on all three will get an Exit State event.

But when D starts, tasks on A and B will get another Enter State event. When D completes, tasks on A and B will get an Exit State event again, and the same will happen when execution moves to E.

If you’re not doing anything significant in response to those events you’ll be fine, except obviously that’s when want to do a bunch of stuff- setting up and tearing down event listeners, and possibly firing other events off or getting your actor to do something.

Luckily there is a setting for this! In the tasks used in A and B, go to the Class Defaults tab, and uncheck Should State Change on Reselect, which is on by default.

Toggle this off and you won't receive multiple Enter / Exit events if the task is already active

However: this has to be set on the task itself, rather than on the task when you add it to the Tree, so if you want to have tasks that sometimes care and sometimes don’t, you’ll need to extend StateTreeTaskBlueprintBase and add an appropriate flag. Alternatively you can check the TransitionType property on the transition and make sure it’s Changed rather than Sustained, but again this has to be done on the task itself.

Check the transition type. The other properties on this struct are (as of UE 5.4) only useful in C++ however

Even more infuriating: there’s a case where this just doesn’t work.

Headache number 4: Subtrees, AKA Linked Assets

The previous things on this list are things that are awkward, but mostly a result of the way State Trees work. The next couple are actual bugs.

This is a linked asset, also known as a SubTree

There’s a great feature in the UE implementation of State Trees that lets you to split off behaviour into sub-trees. To do this, you create a state, and then set its type to Linked Asset. This allows you to specify a different tree, so you can split your logic into more manageable chunks, as well as share groups of behaviours between different AI types.

Big problem: that Should State Change on Reselect property gets totally ignored if you’re running in a subtree, UNLESS you manually recompile the subtree before running it.

Sometimes. Intermittently. It’s annoyingly inconsistent.

So, you quit work for the day, start up the editor the next morning, and find that things aren’t working the way you left them the previous evening. You’ll inspect the tree, make a tweak, recompile… and it’ll work. It’s working again so obviously that was the correct fix. Quit at the end of the day, try again the next day, and… it’ll be broken again. But you’ve worked on something else so it was probably that, right? Right? So you muck around with that for a bit, trying to chase down the problem, until you accidentally recompile the sub tree and OH YEAH THAT FIXED IT.

Except that it didn’t, because it’s not actually anything you’ve done.

This is the worst kind of bug.

I’ve not been able to reproduce a minimal example, but when a tree gets sufficiently complex it seems to pop up. There’s a bug report open for this on the Unreal Engine Issue Tracker.

I figured out a work-around, but you’ll need to get into the C++ to apply it. Create a base class that extends StateTreeTaskBlueprintBase, override both EnterState and ExitState and put in the following implementation (plus anything else you fancy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
EStateTreeRunStatus USTT_EnemyTaskBase::EnterState(FStateTreeExecutionContext& Context,
const FStateTreeTransitionResult& Transition) {

if (!bShouldStateChangeOnReselect && Transition.ChangeType == EStateTreeStateChangeType::Sustained) {
// Unreal has fucked up if this happens, so just exit with what it was going to do anyway
return EStateTreeRunStatus::Running;
}

// Setup any events you want to have on all your tasks etc

return Super::EnterState(Context, Transition);

}

void USTT_EnemyTaskBase::ExitState(FStateTreeExecutionContext& Context, const FStateTreeTransitionResult& Transition) {

if (!bShouldStateChangeOnReselect && Transition.ChangeType == EStateTreeStateChangeType::Sustained) {
// Unreal has fucked up if this happens, so just exit without doing anything
return;

}

// Tear down any events etc

Super::ExitState(Context, Transition);
}

Hopefully there’ll be an actual fix for this soon. I’ve tried tracking it down in the source but I’ve not been able to find the root cause, and either way I’ve got a game to write.

Headache number 5: crashes

Another fun thing with Linked Assets: if you put global tasks in them, and that sub-tree has any parameters whatsoever… they crash! Hard! So don’t do that.

You can get around this by moving whatever your global task was to the root node of the subtree, but be aware you may well run into problem described above of getting Enter and Exit events for every single task in the tree. This crash was how I discovered Headache #4. I’ve submitted a bug report. Other crashes have been reported, but this is the one I found.

Headache number 6: Parameters, Bindings, and Tags

Being able to bind things to influence behaviour is great, but bindings may not work entirely how you expect them to. Whilst all bindings are passed as values rather than references, it’s better to think of them as two categories: Value Types - which are floats, structs, Gameplay Tags, and so on - and Pointer Types, which reference UObjects like Actors. Bindings seem to behave like UPROPERTYs, and have a few quirks.

One wrinkle of Unreal is that you cannot have a UPROPERTY that stores a pointer or a reference to a struct- you’ll get a compiler error if you try. Therefore, any structs you have exposed on objects will be passed by value, and copied. If they get updated, you need to make sure the new value makes its way into the State Tree somehow, and that requires a bit of extra engineering.

If you could bind to a function that would be great, but you can’t, so you can’t have something that along the lines of UFUNCTION(BlueprintCallable) float GetLatestValue() to ensure the latest value is available. Blueprint property getters are also ignored if you’ve defined them in C++; they will be bypassed, so existing code may give unexpected results. In general State Tree seems to sometimes behave as part of the Blueprint world and sometimes behave as part of the C++ world, and it can get very frustrating working out which part you’re dealing with at any one time.

You can bind to a property found on an object that a pointer references, but that pointer may wind up being null, and you’ll get a crash. As such you’ll need to make sure that pointer is valid, which leaves us with the original problem.

Evaluators (sometimes) seem to ignore updates driven by Events outside of the ones they come with in TreeStart and Tick. It’s possible some values are being cached, or that the execution context doesn’t always get updated correctly, or it could be a hidden race condition. I’ve not been able to find where in the source code this happens, and again, I’ve not been able to reproduce this reliably. It’s also possible I’ve just done something wrong, but if I have, it’s not remotely clear what.

Properties bound from global tasks always get set… but then you might run into the problems listed in Headaches #4 and #5.

Properties bound from parameters are fine, but as mentioned at the start of this article, updating a parameter isn’t very easy, and is currently impossible in Blueprint. It can be done in C++, but that’s no good for prototyping, and the chances are you’ll be chopping and changing a lot in your State Tree whilst you nail down the behaviour you want.

Of course, if you subscribe to the ‘Waterfall’ model of software development, this won’t be an issue for you, but then you’re also likely living in 1994 and Unreal version 1 won’t be released for another four years.

So, again, a ‘watcher’ task on the root of the tree is the best compromise, assuming you implement the code mentioned in Headache #4 so it doesn’t constantly setup and remove events you need to listen to or produce other unwanted behaviour.

All this is mostly an issue for transitions and state enter conditions- if you want to check against a value to see if you can enter a state or move to another, that value may be stale, and if it’s stale you’ll get the wrong behaviour.

So: Gameplay Tags.

Gameplay Tags are incredibly handy, particularly for replacing enums when choosing states and guarding transitions. However, they are structs, they’re typically passed around in Gameplay Tag Containers (FGameplayTagContainer in C++), which are also structs, and bound structs get passed by value, not by reference or pointer.

All together this means that if you’ve got an evaluator that outputs tags and you’re relying on it for directing the flow of execution, unless you copy them on tick you may wind up getting whatever was there when the tree started.

Not that copying on tick won’t work- it will- but it seems a bit excessive.

If you want to update the tags, you’ll need to do that on the actor you’re controlling- there’s no point updating a copy. Once they’re updated, you need to get them back into the tree and flush out whatever value was there before.

The best solution I’ve found for this is to create an Actor Component that is specifically for holding and updating tags you care about. Give it a GetTags() function and a SetTags(FGameplayTagContainer Tags) function, and an Event Dispatcher that is triggered with new contents whenever SetTags is called. Listen for that event in a global task (or watcher task on the root), use the value in the event to update an exposed variable, and then use that for your transition and enter conditions.

I’ve got a steadily growing library of functions to fill in the missing blanks of the Gameplay Tag implementation- at some point I’ll clean it up and put it on the Marketplace.

Headache number 7: watcher tasks on root

I said this was a solution, right? Well it is, just bear in mind you may need to add a delay task to make sure whatever value you’re driving transitions and enter conditions with is updated before the tree starts using it. This delay can last for 0 seconds, which is the equivalent of the Delay Until Next Tick node in regular Blueprints, but you may find things don’t work without it. Again, when a state is chosen for selection, all the tasks in the selected branch of the tree start at the same time.


So, would I recommend using State Trees?

Yes!

Probably.

None of this is intractable, but if you’re happy with Behaviour Trees maybe stick with them for another couple of releases. 5.5 is supposed to be fixing some of this, and they may even be properly reliable come 5.6 or 5.7.

Some quick tips so this doesn’t sound like I’m just bitching about someone else’s code

1. Subclass StateTreeBlueprintBase

There’s a fair bit of repetition when setting up tasks, and usually common things you want some or all of them to do, such as listening for events that let you know when an animation is finished. If you don’t want to constantly be doing that over and over again, and/or you want to be able to have a bit more control over transitions, and you’re not afraid of a bit of C++, subclass the UStateTreeBlueprintBase class. You can also do this in Blueprint, but there’s a lot more that is exposed in C++.

2. You can create an evaluator that returns an Interface.

Sick of casting to your interface? Create an evaluator that does the casting at the start of the tree’s execution and outputs the correct class.

3. You can modify the behaviour of a task by exposing public variables

You don’t need to bind everything to existing variables in the tree. Tasks have three reserved variable categories- Input, Output and Context. Anything in ‘Context’ is bound automatically, assuming the Context is of the correct type. Anything in ‘Input’ needs to be bound, or the tree won’t compile. Anything in Output will be exposed to other tasks.

But, you can simply make a value public- if it’s not in Input or Context, you can then set those values directly by typing them in whilst in the tree overview. You can also still bind to these if you want to.

As an example, we have our Execute Subtask task here with the Subtask Tag set as public:

Input, Output and Context are special categories

When I want to use that in the tree, whilst I still need to bind everything under the Input category to an existing variable, I can just type the tag I want to use directly into the task on the tree. One task has now become (potentially) many different ones.

Bindings in the State Tree view

This pattern is great for Gameplay Abilities too… which is what this whole subtask thing should probably be anyway, but that’s for another blog post.

4. There’s a debugger

USE THE BLOODY DEBUGGER

There’s a debugger. Don’t spam Print Strings when it starts behaving wrong, you don’t need to. However, if you’re using Linked Assets / Subtrees, you’ll need to activate it in the parent Tree.

5. You can use this for stuff other than AI

Want to track a player’s progress through a puzzle? Well, State Trees can do that. I don’t know if you’d want to use this for a full quest system in an open world, but for tracking a particular set of interactions it’s ideal.

6. You can have a dedicated task for deciding what to do next

One place State Trees can start getting hairy is if you have lots of transitions with particular rules in different parts of the tree. You can see this as a strength- after all, being able to see what transitions can happen where just by looking is very useful- but it also makes changing that logic a bit tedious, as you have to remember what you’ve done in different places and make sure you don’t have any conflicting rules.

An alternative is to create a dedicated decision task so you can keep most or all of these decisions in one place.

Example of using a decision task to consolidate some complexity into a single task

In this example, consider a watcher task in a parent state that is always running, hooked up so that whenever a Gameplay Tag is changed on the controlled actor’s Gameplay Tag Container it can provide it to the tree, where it can be used in the enter conditions for child states.

The loop then proceeds as follows: pick the State that matches that tag, thus executing the tasks within. When these tasks and their associated states complete, they all have the same transition: go to the decision task.

The decision task gets what the current tag is, checks the actor, player, and world state as required, and chooses a new tag. It then updates the Gameplay Tag Container on the controlled actor - giving the global watcher task a new tag to be used in the enter conditions - and calls Finish Task.

Execution then transitions up to the ‘Melee Loop’ state, and we repeat the process until this NPC manages to blow up the Innocent Space Children’s Hospital, ushering in a new age of Democracy on Cyber Basingstoke Prime.

This isn’t something you’d want to use everywhere, but it does mean you always know where to look when you want to change this particular piece of logic, and you don’t have to pick through the tree and re-bind a load of conditions and transitions.


I hope this all helps someone. If it helped you, why not buy my screensavers?. Also, if anyone has any corrections, feel free to get in touch.

The Jean-Paul Software Screen Explosion- A Brief Post-Mortem

So, this is done:

And you can buy it here!

And it’s had some wonderful reviews, from actual journalists! First, this piece on Eurogamer:

“I’ve been hypnotised by the Screen Explosion… it’s a joyous, mysterious, witty thing, a quick-change artist, one screensaver conjuring brutalist city layouts, another rendering streetcorners as buzzing pointillist swarms of lights, another taking you on a tour of the pylons of the world, seen from an endlessly cruising blacktop, colours changing, designs switching around as you travel without moving, the whole thing drawing me in until the pylons themselves start to look like mecha one minute and religious statues the next.

and also this piece on Rock Paper Shotgun:

“I enjoyed restarting screensavers to see them with new colours or new patterns. I really enjoyed that drive past international pylons. I enjoyed watching colours. I felt the childhood magic of screensavers again.”

Massive thanks to everyone who helped with testing, and to everyone who bought it. Pending any fatal bugs I’m now done with it, and moving onto a game, but before I do here’s some things I learned whilst dragging it from a nice little sketch to an actual product.

Writing your own engine is mostly a terrible idea but has some advantages

Perhaps it wasn’t necessary to write my own engine, but I wasn’t sure if I’d be able to write a screensaver any other way- Unity and Unreal are both a bit heavy, and you lose a lot of control over the low-level stuff like windowing and resolution. I didn’t entirely do it on my own- it’s all written on top of OpenFrameworks, which gets rid of a lot of the misery of the OpenGL API, but there’s large chunks of functionality I had to put together from scratch.

Fortunately the structure of the project meant that effort was just done as needed; the downside of that being that progress on producing things to actually look at was slower than I’d hoped, because I was having to muck about with the internals. Writing things that people won’t see gets demoralising, because despite any improvements you know you’ve made, none of it is evident to someone just looking at the screen.

One big advantage, however, is not having to find a way to express what you want to do within the confines of some larger structure. I was writing my own shaders directly; I could feed them the data I wanted. This makes some things a lot neater… but then again I’m nowhere near the fidelity of something like Unreal.

There’s a massive gap in expertise required to use C++ and JavaScript

I don’t think this is a surprise to anyone, but it really is a massive gap. Most of the work I’ve done for the last 10 or so years has been with JS and it’s various flavours, such as TypeScript. Before doing the Screen Explosion I’d not written any C++ since University, and picking it up again was essentially like learning a new language from scratch.

Now, there’s a lot of things that annoy me about open source JS projects- the stupid names, everything being “made with love”, even the most mundane shit having a logo- but they’re a hell of a lot easier to understand than the C++ ones. This is partly down to my familiarity, but also partly down to the language; aside from a few things like RXJS where the code is covered in decorators, nobody tries to overload operators or write macros or specify their own type of floating point number in JavaScript. But these turn up in C++ libraries pretty regularly, meaning you have to do a lot more reading to understand what’s going on, and even more if you get an error message.

An example of something I didn’t expect: Open GL redclares nearly every numeric data type with the prefix ‘GL’- GLint, GLfloat, GLdouble, and so on. Now, given that OpenGL is liasing with the hardware and different operating systems running on different types of processor there’s a good reason for this- the library needs assurances that it will function in the same way regardless of each environment- but there’s no explanation for this anywhere in the documentation, and in TypeScript all of these except GLboolean would just be number. And the Windows API terrifying if you go into it cold; I can see why the O’Reilly books sell so well now.

Getting perfectionist about something isn’t always bad, unless you do it too early

Most of the time I was happy to get things to ‘good enough’ and move on, but there are a few things that spending time on really helped with. First, the fish:

I knew I wanted to do a flocking simulation because it was a relatively easy win, but making an interesting flocking simulation is actually a bit of a challenge. If you just apply the basic rules, the different actors will go off endlessly into the distance, or bunch up, or ignore each other, or go in a straight line until they hit a wall. To make them actually look like a school of fish, I had to do a lot of experimentation.

Here’s a few additional things over and above the usual boids algorithm that I added in.

  1. Containment. Having the fish swim off endlessly meant they need to be contained, but abrupt changes in direction when they get to the edges looks crap. As such, they’re encased in a sphere, with each fish gaining a force reflecting their velocity back into the sphere that ramps up from an inner boundary to the outer boundary.
  2. Homing. Having the fish swim around the edges of the ‘tank’ also looks boring- they’ll line up and flock, but only around the edges. To counter this there’s a periodic homing force that gets applied, guiding them back to the center. This ramps up and fades away over time, giving the impression that the fish actually want to do something other than simply mooch about.
  3. Current. There’s a subtle 3D noise field that gets added into the simulation that evolves over time, which mostly works to divert the lead fish in a school away from a linear path. This makes any chains that form flow into a more interesting pattern.
  4. Variable stupidity. Each fish has a number which says how much it will follow each of the above forces, varying between 0.9 and 1. That adds a bit of chaos to the system, and makes things a little less robotic.

If I hadn’t got a bit precious about getting this right it would have been shit; as it is, I’m extremely happy with the result.

The counterpoint to this is: shadow maps. I burnt an absolutely stupid amount of time trying to get shadows right for the pylons, before taking them out and realising I didn’t really need them in the first place. The pylons have a non-realistic rendering scheme where the brightness calcuation is mapped onto a palette of colours, and if anything it looks better when it’s allowed to be weird and shadows aren’t present.

I don’t think there’s any non-obvious lesson here- I suppose this could fall under the category of premature optimisation- but when you’re doing something on your own it can be hard to prioritise.

If you want to write a game-like thing, you also need to get good at editing videos and copywriting and 3D modelling and whatever you’ll need next week

Guess what: everyone wants a trailer these days. Perhaps that’s obvious but I hadn’t really thought about it before, and so I found myself learning how to use DaVinci Resolve. On top of that, while there’s some great free 3D models out there, if you’ve got something specific in mind you’ll need to either pay for it or make it yourself. The budget I had for this project was “as close to nothing as possible”, so I had to learn Blender. And then there’s the press releases, patch notes, and so on. None of this stuff is hard as such, and I got better the more I did, but it’s time-consuming work that I didn’t expect, and work you don’t expect is always the hardest to do. Which leads us on to…

Keep going even when you think it’s all shit (despite the fact that sometimes something is shit and you need to get rid of it)

Again, no big non-obvious lesson here, but I had a hundred opportunities to give up, and it took a lot of effort to will myself to keep going.

I had a lot of self-doubt when I was looking at something and hating it, and then wanting to change it… and sometimes I was completely right to hate it, and sometimes I just needed a break.

Pushing through nigh-incomprehensible C++ error messages was hard; pushing through more semantic bugs with the rendering, where nothing was appearing on screen but everything looked like it was correct, was even harder.

Finding that my Windows 11 upgrade had made the multi-screen video player stop working, and then deciding to cut it rather than spend an unknown amount of time fixing it, was also very difficult, as were the failed experiements that seemed great in my head but not on the screen.

Particularly hellish was when I did an initial release into Early Access… and then hardly anyone bought it, and nobody responded to my emails except to say “sorry, I just want to cover games on site of moderately high-profile games journalist, I can’t imagine anyone would want to cover screensavers”.

But finishing it, and getting the press, and the positive user reviews, and now selling enough to at the very least get the app submission deposit back from Steam… that feels very good. Also knowing that I’ve learned a huge amount, and that I can do something like this, that’s a big thing to. Who knows if I’ll ever top it, but I’m going to try.

Writing a Game in Ten Years or Less - Part 2

So I’ve got a game concept and now we need to build it. How do you actually do that?

Well at this point I don’t know entirely, and that’s where all the fun is going to come from. It’s also where all of the headaches are going to come from. But let’s start with what I do know:

  1. Game engines exist. Game engines mean you don’t have to write all of the code, just the bits that make your game interesting.
  2. Some of them are free (or mostly free).
  3. Some of them have VR support.

Now I could write my own game engine but honestly fuck that, so let’s pick someone else’s. It’s basically a choice between Unreal, Godot and Unity. You can do VR in all of them; they’re all free (aside from profit share for Unreal and a license for Unity if you break $100k in sales). There’s also CryEngine, but I still remember them saying that a “frozen jungle” was a great idea for Crysis so that one’s out.

There’s a lot written about how to pick between them, and nearly all of the conclusions are along the lines of “they’re all great but you should consider which is right for your project”, which doesn’t fucking help anyone. What it really comes down to is this: how scared are you of C++

A friend of mine once described C++ as “the Latin of programming languages”, which is to say it’s got a weird set of rules and conventions that are hard to learn and that you’re unlikely to have encountered unless you went to the right kind of school, but ultimately C++ is what most other languages spring from (functional programming languages excluded).

If you’re scared of C++, pick Unity, because that’s in C#. If you’re not, pick Godot or Unreal.

C++ in it’s newest form isn’t nearly as hard work as it was 20 years ago, and I’ve just finished The Jean-Paul Software Screen Explosion which was written in C++ with OpenFrameworks, so right now I’m OK with C++. On top of that I’ve not done anything non-trivial in C#, and life’s too short to be learning new programming languages all the time.

Now it’s between Godot and Unreal, and I think I’m just going to pick Unreal. My reasoning is: I’m probably not going to make a lot of money out of this, but there’s a lot more jobs out there for Unreal devs than there are for Godot devs, so it sets me up for the future a bit better, and if I want to pick up collaborators it’ll be much easier to find one who’s interested.

Unreal also has excellent learning resources, it’s far more mature, and the VR starter project puts you in a room with a gun… which is basically the game I’ll be making, so I can immediately start thinking about the interesting bits.

Chekhov's Gun

Now that’s decided, what are the problems I need to solve?

  1. Work out how to make the gun shoot properly fast bullets, as discussed in the previous post. Right now it shoots out balls that move incredibly slowly; what I need is a raycast weapon, which is to say one which projects out a line the instant you press the trigger and destroys any targets it touches.
  2. Work out the mechanics of transitioning between lots of small levels in a seamless way.
  3. Work out how game mechanics actually work in Unreal.

After I’ve worked these out I can start prototyping some levels.

As it turns out, I was able to do number 1 in about five minutes:

Blueprints in action

Unreal’s Blueprint system is pretty amazing, and remarkably intuitive. I’ve not had to write a single line of code and already I’m a third of the way there. It’s not actually destroying any targets yet, but that’s not going to be a big ask- there’s a course that goes through doing exactly that, albeit not in VR.

Number 3 seems pretty trivial, but number 2 is going to be a bit harder, because it will require some experimentation. There’s two options that I can see:

  1. Use the new UE5 World Partition system and teleport the player around after each game, having the engine take care of all the asset streaming. Will this still be quick if there are 200 minigames? I don’t know.
  2. Construct a separate level for each minigame. Will the levels load fast enough like this? I don’t know.

So unfortunately I’m going to have to try both. The second option is simpler, but I don’t know what the loading overhead is going to be like. The first option is more complex, but will it be a big drag loading loads of stuff when you first start the game? That’s going to be the subject of the next post.

Writing a Game in Ten Years or Less - Part 1

There’s three main steps to writing a game:

  1. Decide you want to write a game
  2. Write the game
  3. Profit

So, with step one out of the way, let’s move onto step two, which has a few sub-tasks.

First, what game is it I want to make? I’ve had a few ideas over the years.

Einstein on the Rampage

Albert Einstein did not die in 1955; he simply became sick of public life. He moved to Winnepeg, Canada, and worked in his shed on a tachyon-powered anti-ageing chamber that could be used to extend his life. He tended his garden. He bred dogs. He started following the local folk and country circuit.

In the 1960s Albert became a big fan of a local musician by the name of Neil Young. Albert loved his work- Neil couldn’t really sing or play, but if you listened past the shoddy musicianship the ideas were always great.

Years pass.

In 1974 Neil Young releases ‘On The Beach’. Einstein loves it. Inspired, he starts learning guitar and harmonica. A plan starts to form: he will make a big comeback to the world, by releasing a cover album of ‘On The Beach’, and doing the talk show circuit to market both his anti-ageing research and new record. In 1975 EMI has the rights to ‘Einstein: On the Beach’, and the release date is set for July 30th 1975.

But then disaster strikes: five days before release, modernist composer Phillip Glass premiers his opera ‘Einstein on the Beach’.

It is a huge success. EMI pulls Albert’s album; Glass is all over the press, and there is no way for Albert’s release to get the publicity it requires.

And so, Albert buys a shotgun, grabs his dark matter glove, opens a wormhole, and goes back in time to 1937 in order to kill Phillip Glass’ parents.

Chop

Chop is a helicopter simulator, except the helicopter blades are operated manually by the player whirling a motion controller above their head, and they have to steer by putting their keyboard on the floor and using the buttons with their feet.

Haringay’s Ladder

A psychological horror / management simulator / puzzle game set in North London where a landlord is forced to come to terms with the misery he’s inflicting on his tenants, all while trying to increase his property empire.

The Haringey Ladder

Each turn has a ‘planning’ phase and a ‘haunting’ phase- the planning phase has you buy new properties, adjust rents and attempt to divide up existing ones into ever smaller flats (whilst maintaining “legal standards” for living spaces), the ‘haunting’ phase has you deal with the wretched bastard you have become.

ANYWAY

All of these have problems- unknown complexity, potentially massive scope, etc- but the main one is I thought of the name first and then attempted to work backwards to a game idea.

What I should be doing is coming up with a game idea first and then worrying about the name later. So here’s that idea: Point Blank VR

If you’re not familiar with Point Blank, it’s a 90s arcade shooting game, made up of lots of smaller minigames. Here’s some guy with a lot of spare space and income playing it:

This idea ticks a lot of boxes:

  • It’s in VR. I want to do something in VR, because I find it interesting.
  • It’s pretty simple. Shooting a gun in VR is just about the simplest thing you can program
  • It’s got a lot of room for trying out different ideas. Like with The Jean-Paul Software Screen Explosion if I decide I need to learn something new, I can write a minigame that includes some element of it.
  • It’s easy to work out whether it’s going to be fun or not. I don’t have to write a deep character progression system or a plot or special balancing rules or anything like that- you have a gun, that’s it. I can work up a prototype and test it relatively quickly, so I can fail things quickly if they’re not entertaining.
  • It’s easy to extend with other actions- maybe you get a bow and arrow this level, maybe it’s a two-handed rifle, maybe it’s two guns, maybe it’s a cricket bat, maybe you have to touch a particular bit of a horse… whatever. If I want to shake it up I can.
  • I don’t have to worry too much about having a coherent art style. In fact, it might be better if it’s all over the place.
  • It’s an easy experience to share with other people in the same room. Many of the best VR experiences are the ones you can take turns on- Beat Sabre, Ragnarock, Gorn.

But it’s also got some challenges

  • It’s in VR. I’ve not done anything in VR before.
  • Requires a lot more ideas. I need to come up with enough game ideas and modules to keep things interesting. Five isn’t enough, 20 might be, the latest WarioWare has 200 and that’s a big ask.
  • Potentially awkward technical structure. It needs to be responsive, and support rapid switching between games, and rules. It should be like WarioWare in that regard- you play something, one second later you’re playing something else. No long loading screens, but also a variety of scenery.

Here’s WarioWare if you’ve not played it- there’s a new game every ten seconds. I don’t think I need it that frantic, but every 60 seconds for 20 minutes is still 20 games.

  • More games = more art - I think I can get around this by adopting a collage-like style, but there’s potentially a lot of art that needs to be created, and that could get challenging.

Prior Art

So what’s out there that’s similar to this?

Hotdogs, Horseshoes and Hand Grenades

This one is basically gun porn with a few shooting range modes thrown in, but the dev has given a great deal of thought into how the guns work in VR. It’s more of a toybox than a game- you get to muck about with guns and grenades, without moving to the United States or the Ukraine. It’s also got this whole thing about meat, which I don’t quite understand. Is it some sort of GOP code signal? I think they’re just trying to have a Sense Of Humour, but it comes across as wacky, which is a death sentence for comedy in my book.

What it does really well: gun handling, large variety of actions.
What it does less well: sterile environments, creepy obsession with sausages

Space Pirate Trainer

It’s a wave-based FPS shooter- drones fly about, you shoot them with a selection of weapons.

My main problem with this game is that the guns all fire slow-moving projectiles, which makes actually hitting anything a real pain in the arse. There’s also not a lot of feedback when you do hit something, giving it that horrible swimming-through-treacle feeling that I really want to avoid. But, it’s focussed, it does one thing very well, and it’s very easy to understand what’s going on.

What it does really well: very easy to understand what you’re supposed to do: you shoot the things
What it does less well: plays like a game about swatting flies with a feather duster

The sound track is terrible though. This leads me on to:

Pistol Whip

“Beat Sabre with Guns” is the pitch here, but really it’s closer to Virtua Cop, the grandfather of arcade light gun games

It gets right pretty much everything Space Pirate Trainer gets wrong- shooting an enemy happens instantly, and most of the enemies you only have to hit once, so if you hit something you know it, and that always feels great.

My main issue with Pistol Whip is that a) it takes itself incredibly seriously and b) it’s full of fucking dubstep.

STOP PUTTING DUBSTEP AND GLITCHY BEATZZZ IN GAMES PLEASE. I get it, Beat Sabre casts a long shadow, and that’s packed with what the US media called EDM in 1998, but that doesn’t mean everyone has to do it. Pistol Whip, Synth Riders, Audica, Until You Fall, Against, a game I just saw called Hard Bullet… it’s not good, it’s not interesting, and it frequently goes with that psuedo-80s pink-and-blue colour scheme over an image of a car driving into an extra-thick wireframe sunset that wasn’t ever cool, particularly not in the 1980s. I was nine at the end of the 80s and even I know that.

Remember Outrun? The thing you’re trying to hark back to? You know what music that had? It a mad mix of disco and latin jazz. It was synthesised, sure, because that’s what the chip running the software could do. But in the composers’ heads it didn’t sound like sawtooth waves, it sounded like this:

So make your game sound like that! Look I can’t criticise too much because I haven’t written the game yet, but I can promise that the music isn’t going to sound like Pistol Whip’s.

What it does really well: good shooting, instant response, good feedback. It also has a degree of auto-aim applied- possibly something to consider.
What it does less well: fucking dubstep, takes itself too seriously, general stench of carb-watching tech-bro Displate-buying culturally-impoverished Redditcentric US suburbian crypto brony gun-buying dankmeme gamingchair paintball RGB mancave nerds trying to recapture their first memory of seeing Optimus Prime

Nuclear Throne

This isn’t a VR game but it is one of the best games about shooting things ever.

The main thing that I want to take from Nuclear Throne is the level of skill that it will respond to, as opposed to the raw difficulty. It’s a hard game- I’m not sure I want to make a hard game. But, I would like to make a game that has optional challenges, and responds well to those who manage to meet them. Nuclear Throne has a number of hidden bosses and areas, and getting to them all requires a lot of skill. But it’s a great feeling when you get through.

It’s also got wonderful feedback when you shoot something- there’s a noise and a flash, and it never feels like bullets have no impact.

What it does really well: amazing feedback visual and audio feedback, very tight gameplay
What it does less well: it’s not in VR; for many this will be a benefit

Pre-registering Game Design Goals

So with all that, I’d like to take a slightly rationalist approach and pre-register some goals that I can use to work out if I’ve made the game I want to make or if I’ve got lost on the way.

1. My Dad should be able to play it without me telling him what to do

Pick up and play, as far as is possible with VR. Any instruction should be obvious; very few instructions should be required

2. Getting it right should feel good

When you shoot something it should a) explode immediately, b) make a noise, and c) have some haptic feedback on the motion controller if availble

3. Getting it really right should feel even better

If you complete a level perfectly, you get a special prize. The special prize is possibly a harder challenge that makes you feel really smug for beating.

4. Getting it wrong shouldn’t matter too much

There’s prizes for getting things right, but you can still have fun if you can’t shoot for toffee.

5. Easy to pass the headset around

You should be able to get this out with your mates round and have a good time. I’ve also got some ideasa about a party mode, but I need to get the basics in place.

6. Good weird, not bad weird

Playing Boggle with guns at a simulated motorway service station: good weird. Sausages everywhere: bad weird.

7. No fucking dubstep

The kids aren’t into it. Nobody is into it. Anyone who likes Skrillex is in their 30s now, give it a rest.

Step 3: Profit

In the next post I’m going to go into my thinking about how I’m actually going to build this, and how I’m going to go about finding out how to do the things I don’t yet know to do.

Games (and Screensavers) of the Year 2021

These are my entries for The Gameological Society’s yearly games of the year awards. The Gameological Society was once a subsection of The Onion AV Club, and was one of the most interesting and progressive areas in games writing while it was around.

The ‘What are you playing this weekend?’ article format originated there; another favourite was their ‘taste test’ feature, where they would ‘taste test’ a game along with some user-submitted food item.

I sent them some Marmite; they tried eating it with a spoon.

Gameological evaporated after a few years of general brilliance, but the wonderful community has stuck around on Steam and Discord, and I occasionally stick my head in.

Anyway, these are the categories:

  1. Game of the Year
  2. Single-player GOTY
  3. Multiplayer GOTY
  4. “Hindsight is 20/21” (a game you thought you liked only to discover you don’t)
  5. Favorite Replay ( / ongoing)
  6. Backlog GOTY Award (games from a previous release year)
  7. Didn’t Click Award
  8. Most Forgettable Award
  9. Unexpected Joy
  10. Best Music
  11. Favorite Game Encounter
  12. Best DLC of the Year
  13. Most accessible game
  14. “Waiting for Game-dot” (‘I’ll get around to it eventually’ suggestion, for those games gathering dust)
  15. Game that made me think (from “slightly dubious essay” suggestion)
  16. Girlfriend Reviews Reward (your favorite game to watch playthroughs / streams of)
  17. “Glad I stuck with it” Award
  18. WILDCARD (could be art direction, plot, anything you want to recognize!)

And here are my picks

Game of the Year: The Jean-Paul Software Screen Explosion

I am picking this because despite it not strictly speaking a game, it’s the first non-web game-like thing I have written and released entirely by myself, and because writing it has been, almost literally, my game of the year. It’s not perfect, but I’ve done it, and even sold a few copies, so that, for me, is good enough. Not good enough to retire on, but we’ll sort that out with the next project.

There’s a whole bunch of shit nobody tells you about when writing your own thing, and I am really quite proud that I managed to muster the bloody-mindedness to work through things like creating trailers and installers and driver issues and the Windows API. I’d not touched C++ since University either, so that was a big step up.

Have I mentioned that you can buy it on Steam? Because you totally can.

Single Player GOTY: Deathloop

Multiplayer GOTY: Also Deathloop

Arkane do it again; it’s not quite as good as Prey, but it’s given me some of my favourite gaming moments of the year. The single-player aspects of it are good enough to carry it- a plot to unravel, a world to explore- but the multiplayer is what elevates it to something really special. Like Dark Souls (almost exactly like Dark Souls) other players can invade your game and try and kill you.

Given that you’re trying to perform a certain sequence of actions in a certain order and do it perfectly in order to beat the game, when someone invades it means you have to drop all the plans you had and focus on the attacker. And the attacker can do all the things that you can, so you have to be ready for pretty much anything. They can go invisible and snipe you from a distance. They can make themselves near-invulnerable and run up to you with a shotgun. They can tie your fate to one of the NPC goons and shoot said goon in the face. They can sneak up behind you and stab you in the back. And if they manage to win, you have to start the day again.

Show some respect rookie

And so my favouite gaming moment of the year: getting invaded on the final map whilst going for my first perfect loop. Fifteen minutes of very tense stealth and spotting each other on distant rooftops, firing off a shot, and trying to get a better position finally ended when I managed to sneak up behind them on the roof of a castle and kick them into the sea. Enemy defeated, I cleaned up the rest of the targets, and rolled through to the ending with a big grin on my face.

Hindsight is 2021: Dyson Sphere Program

Some games have such complicated mechanics that they become almost entirely like programming a computer; Dyson Sphere Program is one of these games. The problem is, I do that for a living, and so if I’m going to do that for fun I’d rather work on my own projects. It’s obviously brilliant, and I have absolutely no excuse to play it.

Favourite Replay / Ongoing: Outer Wilds Echoes of the Eye

Best DLC of the year: Outer Wilds Echoes of the Eye

The Outer Wilds is a masterpiece, and they’ve managed to add DLC that’s just as good, AND that takes place in the same 22 minute time span as the original. It’s been long enough since I completed the main game that going back contains enough mystery, but working out how to get to the DLC and then still being surprised by it has been a real treat. It’ll be a while yet before I finish it, but finish it I will.

Backlog Award: Apex Legends

The best game I absolutely suck at.

Didn’t Click Award: Loop Hero

Do you like waiting for things to happen? Do you like having minimal control over a chaotic system that gives minimal rewards and punishes you with the feeling of wasted time? Well Loop Hero is the game for you! Or at least, Loop Hero is not the game for me. It requires just enough attention that you can’t leave it open on a separate screen, but not so much that anything really happens while you’re looking at it.

Most Forgettable Award: Metroid Dread

I played it. I enjoyed it. I even got 100% of the items! And then it completely cleared itself from my mind.

Unexpected Joy: Inscryption

The joy here is somewhat short lived: after completing the first ‘act’, the game reveals an entirely new section of itself that is similar but totally different to the first. Trouble is, after the initial elation, it turns out to be a bit of a miserable grind. The first part is sublime, but it never quite gets back to that level.

A big part of the game is the surprises, and without acts two and three they wouldn’t be able to cram as many in; but it would have been the better game if it had been a third of the length.

Best Music: Death’s Door

Don’t take my word for it though, just listen to the damn thing:

Now go and play the game.

Favourite Game Encounter: Ragnarock and the leaderboard reset

Ragnarock is the only VR rhythm music game that isn’t backed by ‘synthwave’ and / or fucking dubstep, and so is an immediate win in my book. You’re on a Viking longboat, banging the drums to make your crew row at the right speed… to a selection of absurd metal songs. There’s a few too many with bagpipes in, but there’s also a collection by a band called Wind Rose who seem to be entirely about writing songs about dwarves who like mining things. Check this shit out:

Anyway there’s this fucker by the name of Captain CLAWWW who is at the top of every single leaderboard for this game. There’s also an achievement you can unlock for posting the number one score. My highest genuine score puts me in the top 50. As such: good luck getting it without being a much, much better drummer than I am- and I’ve got a Grade 8 drumkit certification.

Luckily when they came out of Early Access they reset the leaderboards, and I was READY: straight in, found a track nobody was going to be playing- a mid tier one half-way down the list with zero bragging rights attached- and went for it, and got it. And now I have this, and you never will:

This is almost impossible

Most Accessible Game: The Jean-Paul Software Screen Explosion

Have I mentioned that screensavers don’t have complicated control schemes

“Waiting for Game-dot”: Pathologic 2

I’ve had this staring at me in my Steam library for ages. I really want to play it. For some reason I haven’t. I loved the first game before I gave up on it; it’s probably the feeling that exactly the same will happen here. I’ve also got too many New Years’ resolution candidates already, so I’ll just need to play it before it seems hopelessly dated.

Game that Made Me Think: Halo Infinite

Halo Infinite has the absolute worst dialogue I’ve heard in some time. The baddies are all scenery-chewing pantomime villians; your AI companion seems to have been written by an AI, trained on a combination of rejected Joss Whedon scripts and casual conversation with a start-up social media manager. The other Named Character is voiced by the actor who does Octane in Apex Legends, and has the same accent, except they’ve made him a whiny fuck who just wants to get home to his family and probably has some redemption character arc that I will never see because I gave up after an hour and a half.

Anyway, your AI companion, in addition to sounding like she’s doing one of those adverts you get on Instagram that are shot on a mobile phone and have an attractive young person talk straight to camera about this Amazing Thing they’ve just discovered, and that they’ve looked all over for but never quite found until now, is called…

The Weapon.

THE WEAPON

EVERYTHING in Halo has a name of the for ‘The X’; The Covenant, The Flood, The Banished, The Forerunners. I stopped playing when I found out the next mission was going to be at a place called The Conservatory. It made me realise: this naming scheme is everywhere, and I think this is the game that made me think about how much I hate it. Off the top of my head: Back 4 Blood has you up against The Ridden. Fallout 4 has The Institute, The Commonwealth, The Minutemen. I know for a fact there’s a lot more examples than that.

It’s lazy, it’s cheap, and it’s infuriating- but it’s particularly bad in Halo, a game set on a structure that’s been ripped entirely from one of Iain M. Banks’ amazing books. Iain M. Banks’ work is constantly surprising; Halo never is.

The new one has a nice grappling hook though, so that’s something.

Girlfriend Reviews Reward (your favorite game to watch playthroughs / streams of): Slay the Spire

I don’t have the brain for Slay the Spire. I am amazed by watching people who do. Perhaps they only upload the streams where everything goes right?

“Glad I stuck with it” Award: The Jean-Paul Software Screen Explosion

If you get it in the Winter sale, it’s 25% off!

Wildcard award: Psychonauts 2

I genuinely loved this game, even if it didn’t quite hit the highs of Deathloop. It’s wholesome without being cloying; weird without being “wacky”; it’s actually funny, and the fighing system doesn’t entirely suck.

So that’s it. I haven’t enabled comments on this website yet so please just complain into the ether.