Dev Log Week 11 (kinda): FINISH!

This is it. I’m finally done.

A whole summer’s work is behind me, and I have a finished game. I’m not sure that I have too much I want to add. I could discuss the design of my final set of levels, but I also want to keep those a secret even for those who’ve read this blog start to finish (for some reason).

It’s funny – I actually feel really happy to not have to think about this game for a while. It’s not that I don’t like it – I poured so much of my heart into it that I’d have to at least like it – but it’s been a lot of surprisingly hard work. From drawing the last sprite to placing the last block, there really wasn’t an easy day in the whole process. I had to solve so many problems I wouldn’t even know would come up until I got to them. My brain is wore out, even with the vacation/wisdom teeth break.

I suppose thanks are in order. Thanks to my parents, who had at least enough faith in me to let me work on this crazy project instead of getting a proper summer job. Thanks to STEP for paying me for doing something I’ve always wanted to do, but couldn’t find the motivation to ever push towards. And thanks to you, reader, whyever you’re here. It often feels like I’m writing for no one in these posts, so if you’ve found your way here, I appreciate it.

Now play my game! It’s free!

Dev Log Week 10: Seeing Red

Red beam levels! Let’s go.

SPOILERS AHEAD. IF YOU ACTUALLY WANT TO PLAY MY GAME, PLAY IT FIRST AND COME BACK TO THIS LATER.

Alright, so the idea behind the red beams was baked into the game from about day 3 or 4. If the default beams could be walked on, it made a lot of sense to introduce a type that doesn’t allow for that. Levels could be far more controlled and platforming-focused, without requiring taking into consideration every possible angle the beam could be shot at and where that could allow the player to walk to. Plus, it allowed me to create a sort of “checkpoint” for the beam – if it started white and needed to be red to finish, the player would need to direct it to a white-in red-out diode before getting it to the finish. But as I was designing the levels, I came up with the coolest idea I’d had for the game in a long while.

What I could use two starting beams at once? The player could use the white beam as a platform to adjust the red beam!

There was a small problem to that – I, as a lazy coder, made a bunch of assumptions that revolved around there only being one starting beam object. I tried making these levels with a bunch of stacked diodes pointing at each other, but it just didn’t work right. I’d have to fix previous me’s errors.

*queue hacking montage*

By the way, try searching “hacker stock photo”. Try it. Really. Every single image is ridiculous.

Just one more, I promise:

Anyway, I made the changes I needed to make, which allowed the construction of this level:

Just looking at it, you can tell the design is vastly different from previous levels so far. This isn’t the first level with two beam sources in the game, but it is the second, and to have the two types side-by-side as they are helps call attention to them immediately. They signal that things are vastly different and more complicated now, and that the player is going to need to stretch their brain hard for these levels. Additionally, more mirrors are mounted on walls and ceilings than on the floor in this level. The player gets to figure out where their platforms need to be, while under the tight constraints of the existing mirrors. In many ways, it’s the epitome of the idea I had when I was just starting. See if you can figure out how to get from the first picture to the second, or the second to the exit:

I’ll be pausing development for a while after this – I’ll be going on a family vacation and getting my wisdom teeth out over the next couple weeks. By the time you see my next post, I’ll probably be completely done with the game. See you then.

Dev Log Week 9: Bouncy Mushrooms and Cutting Content

This week, the plant levels… kinda. I actually don’t want to show an example level as much as I want to talk about the history behind some of the objects used in the plant levels, as they went through several conceptual iterations before reaching their final state. Cool? Cool. If you saw my first screenshot of a testing level, you may have noticed some vines on the left side of the screen, and a couple mushrooms scattered throughout. The mushrooms ended up staying and making up the basis of my plant levels, while the vines were cut entirely.

(Just in case you haven’t seen them)

At first, the vines were going to act as static spikes that would kill the player and reset the level, which would give some edge to platforming sections here and later in the game. There were two main problems with this philosophy, though – they weren’t very useful as a puzzle element, and I really didn’t want any obstacles between the player and the end door besides their own brain and jumps that could be quickly retried without slogging through most of a puzzle all over again. I tried to solve the first problem first by making them start out ungrown and harmless, and only growing in response to light, whereupon they would stay grown forever. I liked the idea of having something permanent in a level, in contrast to the easily changed light beam. But the fact that they killed the player was still too much, so I redid the graphics and turned them into simple walls, as you can see in the screenshot above. This was interesting, and allowed for a sort of “checkpoint” system where if the player could get light to one particular place, they would have something permanent (for the level) for their achievement. An early idea that was never fleshed out past the concept stage revolved around using the vines to grow higher and higher platforms until the door was reachable. It was almost ready to work.

But, at the same time, I was working on the mushroom objects as well. I decided that I wanted the mushrooms to be one-way platforms that couldn’t be fallen through or one-way walls, creating a unique way to wall off sections and force the player to traverse the level in more interesting ways. Two problems immediately came up – one of implementation and one of design. For the former, messing with the already clunky collision code wasn’t something I was looking forward to doing any time soon. As for the latter, it didn’t really make sense that the player could fall through the one way platforms but not these mushrooms. I solved both problems, however, by making the mushrooms bounce the player upward. By pushing the player back into the air instead of making it a dynamic piece of ground, the collision could be hacked together without diving back into the existing stuff. It also made players not even wonder why they couldn’t fall through, because the mushrooms weren’t platforms in the same way the rest of the ground was. And, on top of that, players just had fun bouncing off of mushrooms. The character’s jump height is pretty short for a standard platformer (six feet, or about 1/4 of Super Mario World’s version of Mario’s jump height), so being able to keep vertical momentum and sail through the level was extra dramatic.

As I was making levels, I couldn’t help but feel like the mushrooms did everything the vines did and more. So, I combined the two into one, making the mushroom only grow when light shined on it. After ensuring that puzzles could still be properly made with the new mushrooms, the vines were deleted from the game. I put a decent amount of work into them, but players don’t really care how much work it took as long as the end result is good.

Next week, I’ll be talking about levels with red beams, and how a late design change cracked open a new world of puzzles.

Dev Log Week 8: Splashing Around

Let’s get right into the design of a water levels. I’m going to use this level to talk a bit more about teaching mechanics to the player through gameplay, something I admire a whole lot about games like Portal and The Witness. Same warning as last time:

SPOILERS AHEAD. IF YOU ACTUALLY WANT TO PLAY MY GAME, PLAY IT FIRST AND COME BACK TO THIS LATER.

That said, this will be less bad to look at then some other ones, since I’m going to show how I introduce water to the player the first time, and one other detail of the water mechanics I bring up later. I will have more complex puzzles to show off, don’t worry. Here’s a screenshot of the level when starting, and one when completed.

(as always, click to make bigger)

To start the level, the player has to turn the first mirror farthest right. It is intentionally impossible to get to this mirror without falling into the water and learning that you can swim in it. Sounds simple enough to not need to teach, but plenty of games prevent your character from swimming at all, so I figured it was a good starting point. They immediately know that water will break your fall and not hurt you. So, the player moves on to the second mirror on the bottom, and may become a bit confused. The path between them is clearly blocked by tiles, and a straight shot won’t work. Here, the player is pretty likely to discover that the light beams bounce off water by accident, as they try to aim the beam down to get around the blocks. In playtesting, this actually happened to my sister between the first two mirrors, so she was able to learn it even quicker. Additionally, the player has to swim again to reach the third mirror, just to drive the point home that the water can be swam in and that doing so may be necessary. The rest of the level completes itself – point the beam at the top mirror, wall jump up, then point it at the diode and exit. The player now knows basically everything they need to know about water to effectively use it in puzzles.

…except that the water can move up and down. I don’t introduce that wrinkle until the third water level, though, and here’s how that level looks at the start:

The light beam, redirected from above, points at neither of the visible mirrors, and if the player explores a little, they’ll see that getting up there is impossible at the moment. A new object presents itself, however, near the middle of the screen. This is the object to control the height of the water, placed in such a spot that it can’t possibly be missed. It’s the only thing even worth interacting with at the start of the level, so of course the player is going to try it and discover its function.

Small design decisions like these allow me to get away with as little immersion-breaking tutorial text as possible. In the first couple rooms, I give pop-ups for controls, but beyond those and the designed-but-yet-to-be-programmed title screen, no other text is used in game. It was always a design goal for me to allow the player to dig in and think for themselves, and setups like these let me get out of the way as much as possible.

Next week, I’ll be talking about a level with plants in it, and about how the plants function, including a success of lazy design.

Dev Log Week 7: The First Real Puzzle

Hello again! Let’s talk about level design, and what goes into making the first real puzzle of the game both satisfying to solve while not creating a huge difficulty spike.

WARNING: SPOILERS AHEAD. IF YOU ACTUALLY WANT TO PLAY MY GAME, PLAY IT FIRST AND COME BACK TO THIS LATER.

Cool? Cool. With that out of the way, let’s look at a screenshot of the critical moment of the puzzle.

Up to this point, the levels haven’t really been puzzles. The player has mostly just pointed the beam at the only mirror they can reach, walked/jumped/wall jumped their way to it, then turned it to the next one. Here, the player runs into an issue. They can’t reach that top mirror or the diode above it, which will open the door (hidden by lighting) and allow them to progress. They look around and only see one more mirror, far below. That mirror can’t even direct the beam to the mirror or the diode. How do they progress? Hint: “walked/jumped/wall jumped”

Got it yet? The player needs to point the beam at the bottom mirror, turn it so they can wall jump their way up to the top-right mirror, adjust that mirror so that the beam coming from the left will hit the diode, then point the light back in the configuration shown, but this time, the beam will hit the diode. Pictures will probably help here:

(as always, click to make larger)

So, how can I be so sure that this isn’t a huge difficulty spike? For one, playtesting. I grabbed my sister and had her play through the chunk of levels I had created. Some did turn out to be too hard, but she was able to solve this one after a bit of thinking. But how can I ensure that from a design standpoint, instead of making my sister play everything multiple times? The answer is more an art than a science (I’d call it one of the key artistic decisions of game making), but I take the approach of reducing as many variables as possible for the first puzzle. Once you get to the critical point, there are exactly two mirrors to work with. The player is unlikely to get overwhelmed by options, or follow an incorrect line of reasoning for too long, simply because there’s not too far to follow it before the player runs out of space. I also suggest at the solution a tiny bit graphically – the overhang of the island above is meant to call a bit of attention to itself, and lead to the beam being pointed there.

Despite all these measure to ease on the difficulty, however, the puzzle still feels like a real puzzle. if the entire level were just the right side, it’s likely that the player would feel like the level was too simple. Having a small bit of filler on the left side allows the solution to feel much more like a real puzzle solution without adding any complexity. Additionally, I had once experimented with adding a differently-colored block near where the beam should be pointed to allow wall jumping up, but that felt unsatisfying. Part of what I’m trying to teach in this level is that beams don’t necessarily need to be pointed where it looks like they should be pointed (mirrors, etc.), and giving too obvious a hint would break that lesson and make the level feel like it was already solved when you walked in.

Thanks for reading, again. Next week, the trend continues as I talk about the addition of water, and what that means for design.

Dev Log Week 6: Sound Ideas

If you’ve been following the blog so far (why?), you’ll know I promised a whole lot of counting to 4 for this post. My idea was to talk about a dynamic music system, where various instruments could be swapped out or change between simple and complex versions of their melody. As the musicians may know, this would mean keeping track of beats, measures, etc., which are usually in groups of 4. There were two problems with this approach:

  1. Music is hard, to put it bluntly. I was a pretty good percussionist in my high school band, and I can drop some “sick beats,” as the kids say, but those skills did not transfer to composing anything complex. I’ve tried working with some chiptune stuff before, and since chiptune is basically the pixel art of sound, I was able to hack something together, but it’s much harder to make something sound good when you can pick whatever instrument you want.
  2. Failing to make music myself, I started looking up songs that I thought might fit underneath the game. I didn’t really like any of them, to cut to the point. I thought they were always too busy and melodic for a relatively simple, atmospheric puzzle game. The closest I got was a track from Super Metroid (go to 17:37 if the timestamp doesn’t work), and while I quite liked its feel, I’m still not good enough at music to replicate what I liked about it in my own song.

In the end, I took an open-source ambiance track, put it under my other open-source sound effects, and almost called it a day from frustration then and there. While I’m bringing it up, I might as well talk about sound effect design. I was continuing to take cues from the SNES for my sound effects, which meant doing a bit of processing to the effects I took to make them sound a bit worse. Specifically, they had to sound worse in two ways – reduced sample rate and bit crushing – although those are really two sides of the same complex, not really worth getting into coin. Suffice to say that the SNES didn’t have enough memory to store sound in the quality we’re used to, so developers had to compromise. What the SNES could do, though, is pitch-bend the crap out of any sample you put in, so I experimented with doing the same. Some sound effects in the game are actually being played at half speed and pitch from their original sample. Gamemaker also allowed me to dynamically pitch-bend samples I put in, which is useful for getting good footstep effects that don’t sound repetitive. Minecraft, for example, has 3-4 footstep sound effects for each type of material, but by never playing the same effect twice in a row and randomly pitch bending the one you’re currently playing, it can create the feeling of constant, slightly different footsteps. I take a similar approach.

Anyway, after I had the version with the ambiance (which is decidedly un-SNES sounding, but whatever), I still felt like something was missing. I didn’t have a sound effect representing the beam itself, since I figured it was going to be a long, droning sound that would get masked by any music. I decided to take a cue from Portal 2 and add the barest hint of a melody under the guise of the beam sound effect. I decided to make 5 different pitches the beam sound effect can play at, and made sure they were in the same musical key and didn’t clash too badly if any pair were played together. Then, I added the sound effect in, where it was just loud enough to be audible. When the beam reflects off of something new, it changes the pitch and makes the effect louder for a second or so. Standing on the beam also makes it louder, and if a second beam object is in the game, both of them play their sound effect to create a chord.

Sorry for no pictures this time – not like they can help too much when talking about sound. Next week, though, I get to finally start showing off some level design! I plan on essentially spoiling 1 level every week, talking about its design process, any cool objects that went into it, and so on.

Dev Log Week 5: The Lights! The Colors!

Hello! I’m going to ignore whatever happened last week and say that I’m excited because I can actually give proper screenshots now! Plus, I can actually use them to demonstrate a point – namely, the non-intuitive way my lighting system has to work.

(Oooh. Aaah. Click to make larger.)

The first screenshot is what you might see at the start of a level, and the second would be closer to the end. I’ll be focusing on the second one in my explanations, just because it demonstrates most of what I want to talk about.

When I came up with the idea for the lighting system, I knew that I wanted to implement it without causing anything to leave the 216 color pallete I mentioned way back in week 1. Those colors are called the “Web-Safe Color Palette,” and they were more useful in the early days of computing, when a web designer could only expect computers to be able to display 256 colors. But to explain what was so special about the web-safe color palette, I’ll need to go a little bit into how colors are made on your screen.

Every pixel on your computer screen is actually made up of a red, a green, and a blue LED. Those LEDs can be displayed at any intensity to simulate other colors; purple, for example, is just a mix of the red and blue lights. All colors can be described this way by setting a number equal to the brightness of each LED – usually in red, green, blue order. (0, 0, 0) means no lights are on, so black is displayed, and white is displayed when all the lights are at maximum brightness, almost always (255, 255, 255).

In the web-safe color palette, these numbers are restricted to only have one of 6 values: 0, 51, 102, 153, 204, and 255. Note that these are evenly spaced in multiples of 51. Therefore, in order to stay within the color palette, colors can only move in jumps of 51 in each component. That will be important in a minute.

My lighting system is subtractive. This means that if you were to disable the lighting entirely, everything would look like it was in the brightest light possible – in my case, the inside light of the white beam. If things aren’t in that brightest light, then the numbers that make up their original colors are subtracted from to make them darker. For example, the outer ring of light from the white beam subtracts 102 from each component. See where I’m going with this? Let’s take the light grey from the background rock texture. It has color values of (153, 153, 153). When that color is in the outer ring of light from the white beam, 102 is subtracted from each value, making it display as (51, 51, 51), which is also a color in the web-safe color palette! That means that I can remain faithful to my arbitrary goal of using only those 216 colors!

…hey, where are you going? I still haven’t even talked about how overlapping lights are dealt with! Come back!

No? Guess it’s just you and me then. Look back at the second screenshot above. It’s kind of odd how the yellow torch-light just kind of replaces the light from the red beams, right? And the white would replace both of them. This does have reasoning behind it: one, I think keeping the clean, geometric shapes looks nice, and two, it means I can stay within the 216 color palette. The logic behind what gets drawn over what is actually pretty simple – the brighter, the better. The bright white light shows up over the bright red light because the red light is adjusting the color by (0, -51, -51). I can only subtract in the lighting system, not add, so to make the light look red, I have to subtract from green and blue. Meanwhile, the white light isn’t subtracting at all, so it’s light is brighter, meaning it goes on top. The players torch adjusts by (0, 0, -51), so it goes on top of the red but behind the white, etc.

There’s only one exception to this rule, and it comes with the vines and mushrooms you can see in the second screenshot. They have their own ring of faint light around them – purple for the mushrooms, green for the vines – to help them stand out. I wanted to keep these lights distinct and circular even if they would normally be drawn over by torch or beam light. So, no matter what, their light is shown instead of any faint light that would normally be in that area. If a bright light passes through, however, it will appear over the faint light, as you would expect.

Quite the explanation this week, but for an awesome effect. I didn’t even get to touch on the water effect, which I’ll get to when I talk about designing levels with water in them. Next week, expect a discussion on sound, music, and (just maybe) a whole lot of counting to 4.

Dev Log Week 3: Beams, Mirrors, and Good Enough

Last week, I touched on how I had to make the player able to walk on the light beams they created, but I didn’t discuss the beam’s main mechanic – reflecting off mirrors and interacting with other objects it pointed at. I’ll be expanding on more specific objects as I talk about level design in the future, but we’ll focus on the mirror and some higher-level beam concepts for now.

The mirror is simple in concept, at least. Point light at it, and it reflects. But how do you know exactly where to stop the light beam when it’s hitting the mirror? What about if it’s hitting a mirror at all? Thanks to the tile-based collision I wrote instead of using default Gamemaker code, I also had to determine if the beam was hitting a tile-based wall myself. As I like to think about it, there’s a correct way and an easy way to do it, and I’ve drawn them out in this image below to help explain.

(As a side note, I use pen-and-paper a lot more than you’d expect for doing something as digital as video game design. To me, at least, things feel much more fluid and easy to change on paper or whiteboard than on the harsh glow of a screen. I should post some of my pages of notes. They make me look like a madman.)

The most precise and efficient way to check if a line has hit a tile is to check the transition points along the grid lines where changes are possible, as you see on the left. This has several advantages – no redundant checks are made, and the final point that hits a tile will be exactly on the border of the wall. It’s primary disadvantage is being hard to code, and after a few days of trying my hardest to get it right, I gave up and moved on to the easy version on the right. On the right, you simply check after a set distance along the line, and once you get a point that’s within a solid tile, you stop. Depending on how big the gap between checks is, this is either inefficient (taking hundreds of checks where 10 would suffice) or imprecise (going too far into blocks or possibly going through a corner that should have blocked it).

Ultimately, a bit of imprecision was okay for me to accept. For one, I actually wanted the line to go a bit into the tiles if I could help it. I was making the beam appear on screen with a simple draw_line_width() function, and that function ended the lines abruptly, at 90 degree angles. If the beam ended exactly at the line, then I would still need to push it farther in anyway to make it look right to the player. Secondly, I didn’t really care if the beam cut a corner occasionally. This is something I like to call a “beneficial bug” – it’s something that’s not intended, but it’s existence actually makes the game a bit less frustrating than if it was more harshly correct. It’s not hard to imagine the player trying to line up an awkwardly angled beam and getting frustrated at it being cut off on the sides.

(Left: the issue with skipping corners, illustrated and exaggerated a bit. I check more frequently than depicted. Right: How the beam would look if it was placed exactly on the edge of the wall, since it’s collision line is in the center. Ultimately, the pixel art style would mask the issue well enough, but it’s something I would have noticed.)

During this process, I decided to avoid looking for mirrors entirely. It’s highly likely that they could fit in-between each checking point, and Gamemaker gives a simple way to see if an object is along a line you already have – a function called collision_line(). The issue with collision_line(), though, is that it won’t tell you what the line hit FIRST. Maybe there were two mirrors in a line – how do you know which one you hit? You don’t. Where is the mirror in the level? No idea. I was able to solve this issue, though, with a common algorithm called Binary Search.

In a binary search, you effectively start in the middle, and become more precise as you move on, taking out a half of the line with each check. For example, I would start by checking if there was a mirror along the first half of the line. Let’s say I don’t find one. That means there are no mirrors along that first half, so I only need to check the second half. I’ll start in the middle of the second half (so the 3/4 point). Oh, this time I found a mirror! Cool. But I only know it’s somewhere between the 1/2 and 3/4 points. I need to keep looking, so let’s look at the halfway point between those, at 5/8. This continues until we find the pixel where the mirror should be stopping the beam, and can stop it there.

(My bad attempt at drawing out Binary Search)

Whew, that was a lot. Join me next week as I talk about my lighting system, and the week after that where I mention sound design, probably.

Dev Log, Week 2: Collision, Tiles, and Not-So-Simple Geometry

Hi! Today, an explanation of collision detection in games. Less pictures this time, I’m afraid, since I’m mostly talking about code and concepts instead of showing off graphics.

Drawing any random 2d series of hills and valleys and expecting the player to be able to move over them has several problems. First, figuring out how to keep the player out of the ground becomes both complicated to code and computationally expensive. Second, storing a unique set of graphics for each level fills up space incredibly quickly. To avoid both of these issues, games often use something called “tiles” – a pre-determined series of small, square graphic elements that can be repeated (tiled) at will across levels. This not only saves storage space, but means that the player will only ever be colliding with purely vertical or horizontal walls. In turn, that makes keeping the player out of those walls easy and efficient.

Take, for example, this screenshot of Super Mario Bros 3. Each square set of bricks that Mario is standing on is a tile, clearly, but even the pipe and ground are made of tiles carefully designed to blend together naturally. If you already know the basics behind tiles and are looking for a tutorial to implement something like it in a game you’re making, this video explains things far better than I could, and it helped me implement this system in Solid Light.

Of course, sometimes you don’t want purely horizontal or vertical walls – slopes aren’t necessarily bad things, after all. In Solid Light, complications come two-fold: Not only does the player need to be able to either walk on or be pushed off of any arbitrary beam at any arbitrary angle, it also needs to work in only one direction. I want to stop the player from trapping themselves into a corner with light beams, so I decided to only let them push upward and act as a floor, not as a ceiling. Additionally, the player is only one button press away from being able to drop through those floors, so they won’t get stuck.

In order to keep the player out of slopes, I use linear projection to move them out at a right angle to the slope. Previously, I tried snapping only on the x/y axis for performance reasons, but too many edge cases and bugs were introduced to make it worth keeping around. For example, say you keep the player out of slopes by pushing them up vertically until they’re not in the slope. What if the slope leads up to a ceiling, and the player would be pushed into that ceiling by the slope? The ideal behavior would be to stop the horizontal movement of the player, but if the game is only adjusting vertically, the player will end up either inside the ceiling or below the slope – neither of which are acceptable.

Next week, I’ll be talking about the final implementation of the beam in more detail, and probably lighting effects after that.