The world of Abyssals
Abyssals is set in a world where players must fight against the darkness to survive. The art style is very Dark Souls-esque, because the artists on the team love the look and enjoy making badass swords. That, or they just wanted to make me test horrifying spiders all day.
Light plays a large role in the game mechanics. It allows adventurers to see their surroundings to explore and find treasures. At the centre of the world it is safe and light. At the edges it is pitch black. It is a constant battle between the adventurers pushing light outwards, and the creatures of the darkness pushing back.
Creating players and spiders
Abyssals is built on SpatialOS, using Unity for the game clients and for physics simulation. SpatialOS is not a game engine, but it’s straightforward to build an online game on it.
Everything in the world is an entity. This includes adventurers, spiders, equipment, and environment objects. Entities are made of components, which define different facets of what an entity is, and behaviours, which describe how these components change as the entities interact with each other.
Components and behaviours can be reused by many different entity types. For example, the spider and the adventurer share almost all of their code; the torch and the bonfire share almost all of theirs (except a bonfire can’t be put in a player’s inventory). This cuts down on code, which is especially useful when you only have a single game programmer!
These components are independent from each other, so they can be combined in interesting ways. For example, both adventurers and spiders use the Health component, but spiders don’t have the Armor component. They are terrifying enough without extra protection!
The component definitions are here.
Behaviours are pieces of code that determine how the entities, well, behave. This can be anything from spider AI to the logic of dying when health reaches zero; that is, anything you would call “game logic”.
In Abyssals, both the spider and the adventurer use the Attackee component. The associated AttackerBehaviour lets an entity receive commands to attack and send damage to another entity. The AttackedBehaviour entity will receive damage messages and change its health accordingly. In fact, the spider and player share almost the exact same code. The only difference is that the spider has an AI controlling it, and it can detect light sources.
At one point a dead spider body was following me around, which was super creepy. The bug was that the AI wasn’t listening for isDead to change.
The game logic is here.
I built the client on Unity. Most of the client code deals with visualising the simulation; for example, turning lights on and off, smoothly changing the size of things, drawing health bars, controlling the camera, and so on. The client also reads player inputs and sends them back to the simulation.
Some players after taking down a giant spider.
The client code is here.
Multiplayer by default
Players aren’t special in any way; they are entities, just like the spiders and the torches. The only difference is that they get commands from a game client, and the spiders get them from an AI behaviour. Making a game this way means it can be multiplayer by default.
There can be thousands of players and spiders in the world, but SpatialOS sends each client updates only for the entities that the player can see, and only the components relevant to the visualisation. For example, the client gets the position and rotation of the spiders, but not their AI state, since that is used by the AI code that runs in a logic worker in the simulation layer.
All of this happens behind the scenes. There is no networking code in Abyssals; it was essentially coded as a single player game on my own machine, and then deployed to the cloud, making it instantly playable for anyone on the Internet.
Once the game is running in the cloud, you can use the SpatialOS web interface to look after it. You have logs, monitoring dashboards and alerts to make sure it is healthy. You can use the world viewer to inspect the internal state of the game world:
I wanted to see how many players I could connect at the same time. I created a bot client, which connects to the game just like the Unity clients do.
I started a thousand of them:
A thousand simultaneous players
This worked just fine, and it required no optimization work on my part. These aren’t bots running on the simulation, but actual clients that connect and use a simple AI to generate player inputs, instead of reading them from a real mouse and keyboard.
One world, three ways to play
A thousand players running around killing giant spiders is fun, but I wanted to add more ways to interact with the world of Abyssals:
- Adventurer: Most players are adventurers. They explore the world and try to survive.
- Dev: The dev is able to monitor the state of the world, and fix problems as they occur without interrupting the game.
- Storyteller: A small number of trusted players are storytellers. A storyteller is able to build and shape the world around the adventurers. They are similar to the storyteller in a tabletop RPG.
Each of these is just a different view into the game world, with different visualisation and controls.
Adding a spectator player would be as simple as cloning the Unity scene, changing the camera controls, and having the client visualiser spawn a non-physical prefab in the world. This game client could run on PC, mobile, console, or even use a VR headset.
The dev is another game client type, that only very trusted people are given access to. In the dev view, the player can change the attributes of game entities in real time. For example, they can make a single spider gigantic and powerful!
That’s one big spider!
The dev can also see all the currently logged-in players including adventurers, storytellers, and other devs. The dev is all-powerful.
The storyteller has the ability to shape the adventurers’ world around them on the fly. They are a game master, but with limitations. They work within the rules of the game, so the players have a fighting chance against them. Think something like Dungeon Keeper or Evil Genius. It’s their job to make the game as fun as possible by injecting a human element in addition to the AI.
If the storyteller wants to create 200 spiders around a player, they can. SpatialOS will automatically spin up new physics and AI workers to handle higher load—this is invisible to the game developer and the players, and has no impact on game performance (see this article for more details).
The storyteller view after dropping a ton of spiders on some unsuspecting players.
In this simple prototype the storyteller can only create and modify spiders. However, the system has been designed to be easily extendable with new content, so giving storytellers the ability to create quests or mess with players in other ways would take just a few more days of coding.
SpatialOS is not a game engine, but it can be used together with Unity (or any other game engine) to make online games. While Abyssals is a work in progress, I built it in two weeks, and I didn’t have to write a single line of networking code.
But couple the power SpatialOS gives programmers with a dedicated team of designers and artists, and suddenly you can lay the groundwork for a massive, multi-client, production-ready online game that supports thousands of simultaneous players, in a matter of weeks.