In the last devlog, I mentioned how I wrapped up the penultimate area of the game and worked on the main menu.
However, my work on that main menu was not quite done yet. I did not feel satisfied with how the transition into the game looked, and some people did point out how that one felt a bit rushed. For a refresher, it was this one:
I needed to rethink it while keeping in mind that eventually, I’d have to implement a difficulty selection menu if the player selected an empty save slot.
During a somewhat lengthy session of brainstorming, I came up with the idea of wrapping the different moving lines around the lozenge in a circle. If the difficulty of the slot was already set, it would simply shrink then grow back into the game; but if it wasn’t, the menu would appear inside the slot.
After spending forever fine-tuning the speed and delay values of each element, I got to a satisfactory result:
Moving on to the difficulty menu. At first, I wanted to make the slot act like a window that would move around the background to reveal the different difficulty options. That was because I was afraid the translations for the difficulties would be too long and wouldn’t all fit inside the slot at once (notably the French and German ones).
But that approach was very complicated to pull off with the setup I had, so I dropped it and just tinkered with the font sizes and the slot size to make it so everything fit together.
The appearance of the main menu was handled with a shiny diagonal bar revealing it, and the slot gently pulsating. Indeed, had it not pulsated, the shine bar’s movement would’ve been too quick for the eye due to its speed and width.
The menu in itself is quite basic, the background too. I originally wanted to make a custom particular scenery, but figured a simple animated logo will do (for now?). The extra touch is that it slightly changes colours when selecting the different options.
There is a problem I didn’t mention though. The saving system I had treated the difficulty setting as a global option for the whole game. I could’ve simply modified it so it would be custom for each slot, but I took that opportunity to completely remake the system.
Indeed, all the Game Maker big boys use JSON nowadays. It was time to follow the gurus.
Using JSON offers the advantage of being able to save very complex data structures in only one .json file (but because I wanted to be cooler, I used my own .tawbs files instead)
I only needed to save some global settings, then a couple stats and info for each save slot. This is how I organized the data:
With json_encode, I can simply transform the wrapper (containing all of the data) into a human-readable string, then save it on the save file. But before doing that, I encoded the string once more in base64 so that the players couldn’t easily cheat by modifying it (unless they’re really persistent and use a converter).
As I said at the beginning of the devlog, I had just finished the penultimate area of the game last summer. Naturally, I moved on to the last area of the game, which is the cave levels. The premise of those levels is that the player navigates in the dark, the only light sources being itself, the enemies, and some special light objects.
I started by making a lighting system that would allow for several light sources, of different colours, that could cast shadows (just because that’d be prettier).
In order to draw the lights, I wrote a script that built a gradient circle out of many vertexes. However, it turned out to be quite performance heavy. I could’ve drawn the gradient circle only once to a surface, then used that surface instead; but I went for the more simple and straightforward solution of drawing a pre-rendered sprite.
The shadowing was made with basic ray-casting techniques: the shadows are mere black polygons going from each wall/caster corner to somewhere further:
However, the number of shadows that have to be drawn increases rapidly as more individual objects get juxtaposed, which isn’t optimal.
For example, this simple structure made out of 5 different wall objects (their corners are coloured differently) has a total of 20 points, which represents 20 shadows (left image). To avoid this, I got rid of duplicate/unnecessary points. In this example, it decreased down to 11 shadows, which is fine for now (right image).
To put everything together, each light source’s surface is composed of a coloured gradient circle, and the shadows cast from nearby instances on top of it. Then the lights are drawn together on another surface with an additive blend mode. That surface is then drawn on top of the game with a multiply blend mode, meaning black spots will be opaque (x*0 = 0), but lighter colours will be transparent-ish (x*1 = x)
With the lighting engine being done, I went onto designing more little aesthetic elements. I wanted the caves to feel like an abandoned facility, so I decided to display blinking LEDs on the borders of some walls.
A fun fact about them is that they can display custom Morse code messages. I can either manually enter a message for each set of LEDs or let the blinking pattern be random. This way, I can add in extra lore information just for the heck of it.
It’s one of those features that aren’t necessary nor likely to be noticed at all, but still very neat for those who discover them.
While brainstorming on other different visual elements, the idea of floating chains popped up. I think it was because I was envisioning these levels to be surreal, in a way. Indeed, it’s intentionally odd that the chains float as if they were in water while everything else behaves as if under normal circumstances.
The way I made them was by drawing several link sprites back to back, with the angle of each link varying with the same speed and amplitude, but with an offset proportional to their position in the chain:
Then came the moment I had to create a new design for the deathly traps of the area. In the second area, there were the sawblades. In the third one, the cogs. For this one, I started by drawing a mix of both:
However, somehow seeing that shape reminded me of motifs I had seen in Persona5:
So I decided to ditch what I had made to recreate something similar: a spike ball.
Yet again, it looks much less chaotic than in P5, because each individual spike moves with a smooth sine function. I did want to spice it up when the player touched it though, and I did that by using a clausen function instead of a sine function.
That formula might not look like much, but the graph representing that function immediately makes it clear why it’s so interesting in this scenario: instead of smoothly going up and down (blue), it rapidly bursts up then slowly goes back down (red).
Coding the function in Game Maker wasn’t complicated, as it’s literally just a matter of adding up numbers. Instead of going to infinity, I noticed that 15 sums were good enough for the eye.
After mixing in some screen-shake, pulses, and rotating circles, I successfully managed to make those spike balls go berserk when the player touched them. Finally, I attached them to those chains I mentioned previously.
Lastly, I wanted to make holes in the walls to emphasize the ruin aspect of the area. I originally created them by literally not putting walls at certain spots. This was very tedious as I had to manually place, scale and rotate walls around a hole – and it prevented me of simply placing big blocks of walls.
After realizing how terrible that approach was, I decided to make a white object overlapping the walls that I would place on top of them. Even still, I had to manually place, scale and rotate those white objects to make the hole – and it was still tedious.
After realizing how also terrible that approach was, I decided to make an object which would draw those holes based on coordinates I would put in first. Even still, I had to manually enter the coordinates for each hole – and guess what, it was still tedious.
After realizing how inconvenient that approach was, I decided to make a tool allowing me to draw the shapes of the holes then generate a list of the coordinates. The problem was, I couldn’t just give in the list of the coordinates to the hole drawer: the shapes of the holes were often convex, which cannot be drawn by just drawing each vertex back to back.
Instead of looking for a way to arrange the coordinates in a processable manner, I gave up and made a hole shape generator. It simply:
1) takes in a big square
2) removes little squares of various sizes around the corners of the big square
Of course, this was very restrictive in terms of variations. But it was good enough for the type of shapes I wanted to make anyway (plus they’re always centred).
And then, an idea hit me out of nowhere. What if the holes… looked like this!
And so they did (after a couple technical hassles). Now, not only they visually conveyed the idea of ruin, but also the idea of an abandoned facility I was trying to get with the LEDs (since it looks electric-ish).
What is a cave… without dust? This essential question got me started on making foreground floating dust particles. This was my first time not using Game Maker’s built-in particle system. Instead, I opted for a custom grid-based system which consisted of a grid storing the [x, y, time, life duration, size, direction, speed with their respective variation values] of one given particle. All I had to do was manipulate the attributes, periodically create particles, and iterate through the grid to draw them on the screen.
That was all I needed for the aesthetics of the cave levels. Only the gameplay elements remained to be done…
Without going too much into the story and why the player ends up in the caves, this area is supposed to convey a feeling of uneasiness, insecurity, and speculation – hence the darkness. The spike balls do not cast light, so the player mustn’t rush forward and has to move somewhat slowly, creating a state of hesitation matching the narrative of the levels.
However, the player still has a large radius of light around him, which gives a certain sense of security. This is the reason why I decided to switch it up with… light switches!
As you can see, light switches act as regular switches that can trigger doors or other objects like conveyor belts. The player has to cast its laser on it to turn it on. When that happens, the player loses its light: instead, deadly hazards such as spike balls light up.
This configuration creates a bigger feeling of uncertainty, as the player now depends on dangerous elements (enemies and spike balls) in order to see and traverse through the level. Even better, as he has to kill the enemies, he’s doomed to loose light sources and thus visibility. Naturally, the only viable way to proceed forward is to get dangerously close to the spike balls (in order to see in their light), then kill the enemies around. Pink enemies, who follow the player, can also be used as moving light sources – but again, it’s a risky and uncomfortable situation.
To turn the player’s light back on, I created a similar looking object. But instead of igniting it with the laser, the player just steps on the button to smother the fire – it seemed like a more intuitive approach.
I haven’t gotten to design many layouts with this gameplay in mind, but I’ll make sure to show them off in the next devlog!
Other than that, many little tweaks and bug fixes have been made throughout the levels. The most notable features are the cyan enemies finally having a death animation, and the camera zooming-out whenever the player enters a new level.
The latter was done because some people seemed to be confused, when seeing a video of the game, as to where the player was. With the camera zooming out of the player at the start of a level, its position is made clearer. And it looks kinda cool.
In other news, I released an OST video in September! I spent an obnoxious amount of time manually animating and syncing the hand crafted visuals with the song, but in the end, it was worth it. The song, “More Killable Squares” (by ThaPredator, the composer) is going to be used in the hidden bonus levels:
That’s all for this devlog!
This one was quite overdue as I did not anticipate college to be so time and energy consuming. I am still very happy I’ve made this much progress while also being focused on my studies. I don’t expect to consistently pull that off throughout the next five years though, but I’ll do my best!
Very many thanks for reading this through; if you enjoyed it, don’t hesitate to follow me on twitter or share my work around!