My Content Workflow For Sanguinite
I recently added a new enemy to Sanguinite called the Aegis Drone, and I thought it might be interesting to document the process. Sanguinite is being built in the Godot engine which uses a node-tree system that makes it easy to piece together new content with existing parts (if you set things up correctly… see my last post to read about my struggle with that).
This isn’t a tutorial or anything– many specifics and details are glossed over (maybe tutorials will come in the future, if there is demand). This is more of an overview or showcase of what adding content to Sanguinite looks like for me.
Inception
Having a decently firm idea for what you are going to add is important. I knew I wanted another “drone” type enemy similar to the Sentinel Drone that is already in the game, but larger and more challenging. I had been wanting to add a segmented “bubble shield” mechanic into the game for a while, so I decided this was a good opportunity to go ahead and do that. I also wanted to make the way it attacked distinctive and synergize with the shield mechanic, so I settled on a slow sweeping beam weapon that would discourage players from staying still and shooting the same shield segment too long. The resulting concept was a slower and more bulky defensive drone that was a bit tougher to take on and had a unique fight cadence.
Making Art
The first thing I personally like to do is get some art done. Art is probably one of the last things most people make a serious effort on, but it helps me get into a good head space to start with a visual. Lately I’ve been using Pyxel Edit pretty much exclusively.
I made art for the bubble shield first, since it was simple and easy to get warmed up on. I knew I wanted a projectile-blocking shield made of eight segments where each segment had its own health. I decided to break each segment into three parts to make it easier to visually inform the player how damaged a segment is when we put it together in Godot.
I also decided to make separate “orthogonal” and “diagonal” sprites. With pixel art you want to avoid rotating the sprite in the engine if you can get away with it, and having two sprites let me form a circle of segments with simple sprite flips.
I wanted the drone to be similar to the previously added Sentinel Drone, but also be distinct. It should look like they are built in the same factory but have different purposes.
I kept a reference image of the Sentinel Drone open while I worked. I started with a simple circle a bit bigger than the Sentinel Drone, added the eye, then cut out a more interesting shape trying to make it distinctive from the Sentinel. I had a vague idea that I wanted some sparky tesla coil things to match the bubble shield.
Building The Scene
Godot (somewhat confusingly) calls a tree of nodes a “scene”, which is similar to a prefab in Unity but more generic. Scenes can be nodes inside other scenes as well. In this case, the Aegis Drone will be its own scene, or a tree of nodes that make up all the parts of this enemy.
I named the root node of this scene “AegisDrone” and set it to be a RigidBody2D, the basic 2D physics node for Godot. Next I threw in some basic nodes to start to compose this enemy: the sprite (which uses the texture I drew earlier), and the collision shape that tells the physics engine what shape this object is.
Next I throw in some behavior nodes that I had already cooked up for other enemies. This is where a component-based system really shines; I haven’t touched any code yet, and the way this enemy behaves is already nearly defined. These nodes can be made to have adjustable parameters exposed as well, like the values shown in the above image that “PatrolDroneBehavior” exposes to fine-tune the behavior.
Mind you, these behavior nodes took a bit of scripting (not shown here) to set up the first time, but after that you can just slap them into any scene and run with it. Nice.
Also notice the “PupilSprite” node under the “DroneEyeBehavior” (which reuses the pupil texture from the Sentinel Drone). I built the eye behavior node to treat any sprite node children as the pupil graphic, making it pretty flexible.
Slapping on a few more components, and the enemy really begins to take shape. An “AcquisitionArea” takes care of searching for and acquiring targets, a “LootDropper” can be set up to drop goodies when this dude dies, a couple of particle effect nodes add some ion-exhaust pizazz, and of course the BubbleShield gets slapped on which I created earlier.
Now the Aegis Drone is well on its way to becoming fully functional. Other components need to be added, like a node that handles particle effects when the enemy gets hit with a projectile, an effects node that handles death animations, and some 2D spacial audio nodes for various sound effects. Then it all needs to be tied together in a simple script. Since these are all either engine nodes or nodes I’ve already built and are in use elsewhere, it’s basically as easy as slapping them in. In my opinion, this is where Godot really flexes.
The Beam Scene
Thankfully, Past Wheffle already built out a fairly flexible beam weapon scene that can be inherited from and tweaked to quickly create a new beam weapon.
The generic beam is red with red square particles. By simply adjusting a few parameters, it’s easy to shape the beam into something else. In this case I widened it quite a bit from the base width (making sure to widen the hit box with it), changed its color to blue, and swapped the texture of the particles with an animated electricity texture that I had lying around. Done! Nice.
After this was completed, it was a simple matter of dragging-and-dropping the beam scene into an exposed parameter in the Aegis Drone’s script.
Registering With The Spawn System
Lastly, the new enemy needs to be added to Sanguinite’s spawn system with some metadata that tells it when and where this guy can spawn. This is done by adding a new child node to a global spawn system scene that exposes parameters that can be tweaked.
The Aegis Drone is a Relic enemy, is worth 1.5 “standard” enemies, can only spawn in missions of hazard level 2 and above, spawns underground, is eligible as a reinforcement “swarm” unit, and can spawn as a miniboss that guards a loot pile. There’s also support for adding more variants of this enemy that can spawn intstead if I decide to make some in the future.
The End Product
And there you have it. From concept to art to nodes and code, the Aegis Drone comes to life and tries to kill you. One of the most satisfying moments in game development is watching your creations spring to life.
Obviously a lot of steps were glossed over or skipped here (I used LabChirp to create a couple new sound effects for the beam, a free sound effects tool that I highly recommend for retro game audio development). Much of the process stood on the shoulders of previously created nodes, but I feel like I’ve got a decent groove going (especially compared to some of my past projects where adding content became a terrible chore). By breaking out as many pieces as possible into generic components with one responsibility, you’ll save a lot of time later by avoiding reinventing the wheel and making it easy to pivot your designs without much fuss.
Hopefully this was interesting or maybe even helpful. I almost know for a fact that I’ll be referencing this myself to remind my ADHD brain where to start next time I want to add a new enemy. Happy coding!