Morbidware and Headup Games have graced us with the following tech blog on their latest game 'The Textorcist: The Story of Ray Bibbia' and the design that went into creating the wild bullet patterns and weapons.
When I started working on The Textorcist I wanted to be able to create complex and visually impressive bullet patterns. To achieve this I needed a very light game engine that would allow hundreds of bullets on screen at the same time and each one following different update behaviors. GameMaker was the perfect choice for what I needed. In this article, I’ll give you an overview of the process behind bullets, weapons, and patterns. There’s a lot to go through featuring Objects that are more complex than what they seem, but I’ll try to simplify things so we can focus on the relevant code. This means that we won’t go in-depth on the animation code or the special effects added to certain events. Instead, we’ll try to get a grasp of the workflow that gave us enough flexibility to easily implement every solution that came to our minds.
Let’s start with the Bullets. The most basic structure of a bullet has the following properties: x, y, direction, speed, the radius for collisions. Every other bullet in the game is a child of
obj_bullet and as time passed, I found myself adding many more variables to let these bullets achieve a variety of different tasks.
Let’s take a look at
obj_bullet Create Event where we define all properties:
As you can see here we have the base properties plus a number of properties for waving, generating other bullets, orbiting and so on. Usually, shmups are flat, but our game features a top-down view. Therefore we had to perform some visual trickery so that collisions would happen with bodies like in all shmups and elements would be sorted and placed with a projected shadow underneath.
Since bosses shoot from various fire points (hands, horns, etc…) and they vary in size, certain bullets generated by bigger or taller bosses would spawn at a certain height and should briefly reach the right height to hit the player character (which is between 0 and 12 pixels above the ground): that’s why we have also the altitude property and it can also be manipulated manually depending on the bullets needs.
All bullets in the Step Event adjust their altitude, update positions and check for collisions with walls.
The easiest bullet is the pistol bullet used by the tutorial boss. It’s just a straight bullet that reiterates the speed in every Step. Every bullet has its own code in the Step Event to update direction and speed and other properties as needed. The biggest part of the code is in the
obj_bulletStep Event, so we can focus on the custom code for our children. Let’s see how the
obj_bullet Step Event looks like:
Now that we have our bullets in place we need something to properly shoot them in every way we want. To shoot bullets we need a weapon. An
obj_weapon can be loaded with any bullet and has other useful properties like capacity and rate of fire among others. Let’s take a look at the Create Event of the
When a weapon is activated and starts entering the Step Event it will update its state and it will shoot bullets with the specified timings. The direction for the bullets is determined by the weapon itself. Let’s take a look at the Step Event of the
obj_weapon to understand how all timers interact.
Now I’d like to take a look at some more complex weapons taken from the Cardinal, the most difficult boss so far.
The fourwaver shoots straight bullets and swings the weapon direction to create this nice and deadly effect.
The Penta is a weapon drawing a pentagram around the enemy that stays in that shape for a while and then shatters. Since it has a single bullet we use the ammo property as a timer to define how long it stays in shape. In fact, we leave the Shoot Event empty and do our magic in the Step Event. In the video below you see two Penta together.
ds_listto hold the five tips of the star. If the
ds_listis empty we create the five tips. Then we make the radius of the shape grow and shoot a specific kind of bullet that has a starting point and ending point and both of them are linked to other bullets to define the shape. When the timer reaches 0 we give speed and random direction to every bullet belonging to the shape.
Last but not least, let’s take a look now at the Crystal, the final weapon in the final stage of the Baphomet Fight. It’s one of the first weapons designed for this game and I really like it.
obj_bullet_generatoris a simple straight bullet that spawns two bullets at regular intervals.
obj_bullet_slow_bigis the giant bullet that looks like a skull.
Now that we explained the structure of how we get bullets and weapons let’s have a recap before proceeding: we have
obj_bullet as an ancestor of every other bullet. Bullets have different values in the Create Event and different update routines in the Step Event. To shoot bullets we have
obj_weapon as an ancestor of every other weapon. Weapons have different values in the Create Event and various shooting routines in the Step Event. Weapons shoot Bullets, ok, but who uses Weapons? Weapons are used by Demons (Duh!) as children of
Let’s take a look at the Create Event of
Enemies have phases (lives), a
ds_list holding other
ds_lists for the patterns, a
ds_list holding other
ds_lists for the spells, timers, a list of firepoints, points in space that match the positions that the enemy can take during attacks. During the Step Event, every enemy cycles through the various weapons defined in the list and activates one weapon at a time. It’s important to note that “waiting” and “changing stance” are weapons too. About the “waiting”, the ammo represents the number of frames that the enemy will stand still: for example, an
obj_weapon_wait loaded with starting ammo of 30 will keep the enemy still for 30 frames. As for the stances, the ammo represents the stance to take for the next attack: this means that the same defined weapon can shoot from different positions depending on the current stance of the enemy, weapons can be stacked to shoot at the same time from different firepoints so the possibilities are endless. Now let’s take a look at the Step Event for the enemy:
As you can see we are simply moving from one timer to another and changing animations and all other elements involved accordingly. When everything is ready, the next weapon is activated and depending on the weapon type the enemy will either wait or start the attack animations before shooting.
This short essay is exemplifying of the management of a Boss inside a shmup. There’s so much that we didn’t cover but I tried to parse the basic relations between enemies, weapons, and bullets hopefully in the most understandable and concise way. I hope you have a better understanding of the subject or a different take on a problem you may be facing; I also hope you enjoyed this short ride and have fun with (possibly) tons of bullets! AMEN!