I’ve been asked a few times now how the new height system in ProtoDungeon/The Waking Cloak works, and I think it’s a good time now to write it out!
This system was something I’d been tossing around for a while, but I wanted the boots (the jump item) to be able to go up and down cliffs properly. Alundra(a great Zeldalike PS1 game with lots of jumping around) inspired me and convinced me that it could be done.
If you’re familiar with the x and y axis in 2D games, you may also know about the z axis for 3D games. Since PD/TWC are 2D games, we will have to fake the z axis…
I picked up where I left off in August: wrapping up the tileset for the episode. Water details, beach details, waterfalls, spikes, cracked floors, etc. Lots of work, especially since I haven’t done a lot of art recently. I’m really proud of the improvement here though.
Next I started on another big task: enemies! I’ve done these before in The Waking Cloak, so there’s a decent framework. Definitely still a big deal, though, given how much I’ve already done on this episode.
I have two enemy types planned, one of which I’m (creatively) calling a hopper (not the official name but probably what it will be called in code forever). In terms of gameplay it’s like a cross between a goomba with butt spikes and a tektite. Will this be annoying to deal with? Maybe! Hopefully not too much. That’s what testing is for.
Anyway, to give you an idea of what went into this single enemy:
AI - fairly simple, just runs every step and has a chance to trigger the jump state
States - idle, jump, death
Art - sprites for all states, facing both east and west each
Hitbox logic - hopper hurts player with spikes, player hurts hopper without spikes
Jumping - tweaking this to feel right without being too fast or too often definitely took some time, as well as flipping the spikes orientation
Player impact - tricky to get that little bounce without feeling mushy
Confining to a single area - will be useful for all enemies
Work out bugs with pushing the player on hurt - will also be useful for all enemies
Enemy manager - keeps track of enemies, deaths, etc.(I ended up putting this on the backburner for another episode; will be mostly useful when I have multiple rooms)
The other enemy? I want to keep it a surprise.
I took a break from enemy design to update the save/load functionality. Ever since I added saving and loading in Episode II, whenever the game had updates, there was a high likelihood that a save file from the old version of the game would break in the updated version.
The reasons for this are numerous and complicated, but the fix is to add save file versioning. With this, I save a version number to the save file, say, 1.2.0. When I make changes to the game, I will also update this number in the game itself.
For example, say a player saves and quits their game in a certain location. Then say I move that entrance to a room in version 1.3.8. If the player updates and they will not be able to load in the proper location and instead might load inside of a tree or a wall and be unable to escape. Thus the fix: the conversion script would check the save file version (1.2.0) against the game version (1.3.8). It would run a line of code to check whether the player is in that position, and if so, move them to the new room entrance.
I wrapped up the hopper, then did a quick bugfix for the cliffs. There was a case where if you jumped at a cliff and hit the ledge just right, you could do sort of a glitchy jump where you weren’t falling or getting up on the cliff. It didn’t hurt anything, but it didn’t look good. I actually got frustrated trying to replicate the bug after fixing it which… uh… I guess means I fixed it.
Then I circled back around to ramps. Westward-facing ramps had incorrect height calculations, meaning they act just like eastward-facing ramps, so I fixed that.
Some more attempts at ramp collision made me question whether I wanted to still do them or not. Of course I’d still have north-facing stairs, but collision is much simpler on those. Since I only had one east/west ramp in the level design, I removed it and decided to only do north-facing ramps.
NEXT… the fun part! The culmination of all my plans for the dungeon, creating the map in Tiled, painstakingly building the new mechanics, and so on: actually creating the dungeon room.
Of course, I’ve changed the functionality of the boots since I last planned the dungeon. This has been a pattern starting back in Episode I, and it’s a result of taking theory and putting it into practice. For the boots, here’s what changed from my initial design notes:
Lv1 - Jump height has been reduced from 16px to 12px. I decided partway through level design that not only could you jump over pits, but you could jump up cliffs. But jumping up the standard height of 16px breaks a lot of design; cliffs would have to be very tall to serve as blockers, and various other obstacles break too. 12px jumps let you go up 8px cliffs without jumping over various obstacles. However, the map design did not yet account for 8px cliffs.
Lv2 - Diving has been added. Not sure how I overlooked this, but here we are. Diving below the surface is great for ducking under projectiles and maybe finding some secret stuff.
Lv3 - The dash no longer serves as a “long jump.” This solves a handful of redundancy issues (mainly jumping/swapping), but it did require a map update. Instead, dashing only acts as temporary invincibility and a faster roll. This will still let you dash through attacks and so on, but not over pits, and I plan to use this in Episode III.
So I made quite a lot of changes, all told, from the Tiled draft to the room in GameMaker.
I broke one of the cardinal rules of programming: instead of making small changes and testing often, I got lazy(?) and made a BUNCH of changes and didn’t test for days. I figured adding collision tiles and water tiles and cliffs wouldn’t cause too much trouble.
Well. They mostly worked. But the first foray into the dungeon was pretty janky with loads of bugs. It was honestly pretty discouraging, and I wanted to just stop and give up for a while. But I started breaking down the problems into more manageable chunks. That was enough to keep me going. Here are the bugs I tackled this month:
Made tile collision respect z-height.
Fixed an issue with the east area border snapping the player back.
Prevented jump in midair
Fixed camera dip when diving
Fixed cliff sprite generation drawing invisible layers (usually leading to garbled, neon-colored cliffs)
Prevented teleporters (stairs, cave entrances, etc.) from triggering when submerged.
Fixed camera movement issue when loading the game that started the player in the wrong room (sometimes within a wall).
Fixed issue with being able to jump into tile walls and get stuck.
Fixed cliff collision box calculations (I messed this up earlier this week when messing with tides interacting with cliffs).
Made one high cliff at the bottom of one of the areas shorter, thus fixing a bad collision issue.
Rigged up a way to allow high tide to smoothly allow you to walk onto floors at both 0 and 16 (the secret is to lower all adjacent cliffs by 16 at high tide).
Fixed invisible daytime tiles when loading a daytime save file.
I also rigged up a way for “tides” to work, meaning tiles and collision changes depending based on day or night.
Near the end of the month, I took one more swing at (north-facing) ramps. This ended up being a whole thing. I couldn’t use my stair object like before because the player actually has to change z-height. I temporarily forgot how triangles worked.
It’s hard to see here, but the player needs to make it up to a z-height of 48. However, she’s only getting up to about 37. This completely baffled me for about an hour. I tried changing the calculation, the collider, and so on, with no results.
Well. As it turns out, I was trying to force the hypotenuse of the triangle (the ramp) to be the same size as the sides (the ground and the cliff). This isn’t physically possible, lol. When you’re only factoring in two dimensions, this isn’t an issue, but when you add the z axis (even if it’s faked), you have to obey the laws of geometry.
(still some work to do here; ramp movement is very fast and the shadow is all over the place, but it does work).
After that, the bugs were getting me down again, so I decided to switch gears. I added the boots, chapel keys, regular keys, and some rocks! This doesn’t sound like a lot, but it goes a long way towards making it a real, functional game.
And lastly: October is going to be fun! I’m doing Devtober! I effectively do this anyway–a little bit of game development every day–but it’ll be good to join everyone again. My goal is to have everything playable by the end of the month from start to finish (but not necessarily bug free). Wish me luck!
I spent the first week of August cleaning up cliff and z-object stuff. Not very glamorous! I was definitely ready to move on, but it had to be done. Everything I mentioned at the end of the July newsletter? I tackled it.
Falling off ledges now works properly. This was surprisingly difficult.
Tile animations on z objects is now handled…
Building cliffs is much less painstaking now. The objects automatically resize themselves for proper collision, and the sprites are all color- and number-coded.
And more: lots and lots of weird cases and stuff fixed. Cliffs at a “negative z” (below sea-level, essentially) were a whole ‘nother animal. They’re still a little janky, and I’ll have to do more manual intervention for these.
Also, area transitions were only based on x and y, so throwing z into the mix messed those up hardcore.
Once I got past all that, I decided to tackle swimming!
Talk about a switch. Cliffs took me a few months. Swimming took me, like, a couple days. Even the stuff I thought would be hard (falling off waterfalls, slippery momentum, etc.) ended up being more or less built in to the systems I have, lol, so I basically just wrote a line or two of new code for those. Diving took an extra few days on top of that, mostly just because I went back and forth on how to modify the z.
Next came rolling. (You might say we’re on a roll.) This was the first bit I’d copied over from The Waking Cloak project in ages. The Waking Cloak will eventually be built afresh on the ProtoDungeon foundation, but I guess the old code does still have some useful stuff in there!
I did spend an evening converting my mess of move speed/direction/vectors to create a Vector2 struct in 2.3. Structs are a nice breath of Object-Oriented Programming in GameMaker. :) Then I leveraged this so I could easily modify the direction of rolling, jumping, etc. I could have done all this without, but it makes it easier.
“Rolling” in the water will be a dash. Unfortunately, in doing all this, I broke the “slippery” friction on water, which for some reason took me a few days to fix.
Roll cleanup from there involved allowing jumping into a roll and rolling into a jump. For gameplay purposes, these don’t let you jump further or anything, but it adds some usability. Without this, if you press the “roll key” right before landing, nothing happens, and it feels clunky. With this, if you press the roll key while jumping, the character will roll immediately when they hit the ground. It feels really good!
I updated the controls to match the new rolling. Space and shift now both trigger rolls for keyboard, and the left face button does so on the gamepad. This also meant I had to update the control remapping settings (which needs a UX overhaul, I’m breaking a couple guidelines here, but no time for that now lol).
And then I rounded out the month by updating various tiles and sprites. It was pretty tough to get back into the swing of things, art-wise. Thanks to the Studio Spacefarer Discord server, though, I’m pretty happy with the direction things went.
Oh, also, on the penultimate day of the month, I felt like taking a quick break from all of everything to install rt-shell, a plugin that lets you do debug commands. My previous debug method was a list of hotkeys. It was pretty limited! The new one is extensible (I can write my own scripts), so it’s gonna be really helpful.
Well, month two of this newsletter! We’re still doing this thing!
This gif isn’t really related to anything in this newsletter, but I wanted to share this because 1) there will be a few paragraphs without images and I want to provide you with some interesting content, 2) I’m sort of possibly doing more camera rework which you may hear about next month… who knows, and 3) it’s hilarious.
So anyway, yeah, I got a lot done this month. I installed the GameMaker Studio 2.3 beta, created the ProtoDungeon 3 project, and put together the git repository. Of course, I ran into a fair few bugs when transitioning to the 2.3 beta. Namely, the player would always just slide to the right…
After quite a lot of debugging (is my input library working? is there an object on the player pushing the player? are there two players pushing each other?), I discovered that the player was pushing herself. Some stuff had changed behind the scenes that messed with one of my collision checks. Easy to fix though!
Then I fixed up some ancient camera issues that have been around since the dawn of time. The camera was originally created to follow the player with lerp (short for “linear interpolation;” this is what makes the camera move smoothly). This lerp caused all kinds of little visual quirks if I wanted to instantly move the camera anywhere because it was trying to “smooth out” that movement. And it was inflexible too. Well, now I have more control over it; stuff most people probably won’t notice, but it makes things much easier on my end and does actually get rid of those quirks.
As sort of another giant rabbit trail (bear trail?) from starting actual work on Episode 3, I implemented the new floating HUD. I thought I had a ton of code that would be impossible to untangle due to the way the camera compensated for the HUD being at the bottom… but this was surprisingly easy. Now, there’s some rooms that aren’t big enough causing problems, and I’ll have to go through and resize all of them (most of Episode I will be this way). Anyway, super pleased with the new direction on the HUD here.
Before:
After:
And then the main feature: I worked on the new boots! The boots have a lot of different functions, but I’m trying to get the main one: jumping! This also went much faster than expected. I do have a lot of polish to apply still, but it does work.
Fun fact: it’s the same sprite as the ring spell object, and it ends up kinda looking like the Mario jump. I dunno if it’s gonna stay that way… but it’s not bad?
Lastly, I ran into a tile collision tutorial, so I (perhaps unwisely) chose to convert my collision system to that. It’s much more performant and way easier to change in the workflow, but it will require me to fix a few collision issues I’ve sort of been masking until now. Will this pan out? Who knows.
I’m pretty excited at my current pace of development. Of course, I’m not over-optimistic enough to say this episode will be done soon, though. :)
I hope it’s is a good one for all of you. Here’s to another year of community, friendship, and gamedev. :)
So… it seems like a good way to start off the year is with a big ol’ update for ProtoDungeon: Episode I! Not only have I made a TON of changes thanks to developments from Episode II, but now available for the first time is…
(drumroll please)
PROTODUNGEON ON MAC!!!
But even if you’re not a macOS kind of human, don’t fear. As mentioned, this update contains quite a lot of updates for both PC and macOS versions thanks to Episode II. Here’s the full changelog:
From Episode II:
Lighting (reorganized the the torches in the level, as the new lighting draws emphasis to specific places; some places did not need to be emphasized, while I was able to take advantage of the lighting to draw attention to other locations).
Menu system (including a new Episode I title card).
Updated logo.
Saving/loading (all things considered, this dropped in surprisingly well; I did have to add a few extra cases to fix, such as falling through a pit to the level below).
Graphics settings.
Audio settings.
Updated to the Wandersong audio engine (also updated all audio container names to use constants instead of writing out the strings every time… there were way more of these than I expected).
Key remapping (new default keys as well to match the updated defaults from Episode II).
Ability to jump off all cliffs (had to rearrange some stuff to prevent softlocks and other issues).
Other improvements:
Repaired swap mechanic–this had broken after changing some of the underlying code for another mostly-unrelated system.
Updated the tiles for the pits that lead to floors below–these should be more distinguishable from the normal hazard death pits now.
Updated the swap spell item descriptions to be lore-based for consistency.
Simplified the lv1 swap spell puzzle, as it was trying to teach too much all at once and MANY players found this confusing (this was one area that the new lighting came in handy too).
Updated the lv2 swap spell puzzle, as it never actually taught the player how to USE the lv2 spell–this was the trickiest change, but adding a new room underneath both gives space for a lvl2 teaching puzzle and makes the punishment for falling a lot less brutal.
Fixed a collider in the outside room transition.
Updated the object activation/deactivation manager to account for falling to the floor below.
Updated the player “fall to target” state so modifying the target coordinates elsewhere won’t interfere with this state (“targetX” and “targetY” are variable names used for a handful of different states).
Tweaked the top of the teleporter collider so you can’t accidentally miss it.
Fun stuff today: writing! It’s a bit of work, but it’s a blast and makes the world feel more alive. And now you can read the gravekeeper’s ledger in the basement, just like you’ve always wanted.
Fixed the pit room puzzle in the catacombs–a previous fix (which I made so the player couldn’t get stuck) made it so that the apparent solution was actually a really long and tedious process. That tedious solution worked, but I don’t want to leave that in to annoy the player when the real solution takes a bit more thought and is more fun.
Saved the current music blend so that the correct track will play on load.
Balanced some of the audio (tall grass was obnoxiously loud in particular).
Created some new sound effects for the ring blocks and a few other things.