Back in January, I implemented a half-hearted underwater state for the player. The reason for doing so was to experiment with conditionally inverting the player’s gravity, depending on if a shot has been fully charged or not. No charge = float up, full charge = sink down. This didn’t pan out, so I left it untouched for a while. Recently, I found that I needed more kinds of environmental transitions, so I came back and wrote up a proper underwater state.
There are a few common ways to do underwater movement in 2D platformers. I’ve opted for just modifying the physics a bit to move slower, and converting the jump button to swim up when held. You can go a lot fancier, but I don’t want to substantially change the central hold -> charge -> shoot mechanic. I probably won’t include drowning just to keep things simple.
I’ve had difficulty making level content lately, so I took a step back and reevaluated the game’s premise and storyline. These are things that don’t really matter a lot for the finished game (this is a no-frills action platformer with no dialogue), but at the same time, it sets the tone for the whole project, and serves as a guide during the process of development when the majority of the game is still vaporous.
I changed the structure and flow of the levels (or more accurately, what I imagine the levels will be like, since I still don’t have a single completed level at this point, ugh), making them more episodic and less interconnected. Having to worry about the end of one level being the beginning of the next level is making me stall. One level -> one self-contained location.
This helped a lot, and my protagonist now has a better motivation for traveling and fighting, and some sort of end goal and resolution, even if they’re pretty simple and predictable.
Level Planning Method
With the revised plot in mind, I worked through a plan for the first level consisting of a room-by-room summary and a pixel art storyboard. The written summary assigns each room a tag and nickname, and describes what should happen, and how the player gets to the next part. In the storyboard, 480×270 screens are reduced down to 28×16 rectangles, and rooms are tagged (“a”, “b”, “c”…) to match the written summary. This provides just enough resolution to roughly lay out enemy positions and terrain and level structure, and is easier to copy and rearrange than working directly in a tilemap editor or with graph paper.
I have a pile of stage gag ideas and various creature mockups which are piling up. Going through the level over and over in this fashion reveals opportunities for using those unattached gags, and helps with identifying new ideas as well. It also forces me to think about the physical structure of the level, how it can be traversed, and how situations can develop across multiple areas.
In 2016, I had plans for a sidescroller somewhat similar to this game. It never got past displaying a tilemap and a few test animations in Kivy and then LOVE, but I started using a similar walkthrough + pixel storyboard method to step through the game, pretending that the mouse cursor is the player (wow this is embarrassing to write.) Later parts were pretty vague, but it did help me arrive at a solid picture of how the first two-and-a-half levels could be structured.
Here is part of my old 2016 project’s pixel map plan. Every 16×16 region would be roughly one screen. This was intended to be a linear action game, but with a “global” interconnected map for every stage.
Back to Bolero 2. This is my (very unfinished) level 3 plan. There’s barely anything in it, but even just thinking about the shapes of rooms and how they connect is helpful.
Control Consoles, Vehicles
I considered adding weapons to the game which could be equipped by both the player and opponents. This would be good for adding some variety at times, but besides being complicated to implement and test, I couldn’t figure out a way to comfortably fit ‘equip’ and ‘drop’ actions into the existing control scheme without conflicting with other actions.
I backed out, but thinking it over did lead to some ideas which might be a better fit for the existing control scheme. The player could jump into small containers that house control panels with levers and buttons, and the user’s up/down/left/right/attack button inputs could be forwarded to other actors as a way to control machinery in the environment. To exit the container, jump out of it. The endpoint could be a platform, a vehicle, a security turret, another Bot, etc.
As a test, I made a simple vehicle built out of multiple linked actors: a body, a wheel, and a control panel. The body is anchored to the wheel and the control panel anchored to the body. The control panel and body have port_out and port_in strings which point the control panel’s input to the body.
I want to go a bit further with this vehicle and give it two visible wheels, and maybe some kind of suspension. This is all slapped together and won’t scale well with many different kinds of machines, though, and I need to think more about how to implement multi-actor entities in a cleaner and less bug-prone fashion. Before I can do that, I need to make a comprehensive list of all the kinds of devices I want to have in the game.
I had about a week or so without access to my main desktop PC, so while working from a Windows laptop, I tried to come up with some modules to pack and compress map data. LOVE 11.x has compression and packing functions, but the build system for this game doesn’t have access to the LOVE API, and I’d like to leave open the future possibility of unpacking a map incrementally over multiple frames.
Maps are already compressed as part of the project being zipped into a .love file. What’s wanted in this case is to reduce the memory footprint of areas that are in RAM but not currently active. The existing solution was to run-length encode the layer data for each map. With the present set of 22 test maps (53 map layers), this reduces size to about 6%. I didn’t get literal runs working at the time, so there was a risk of unique tile runs undoing or even expanding the array size if they appear more often than duplicate runs. A frequently-used checkerboard or vertical stripe tile pattern could potentially expand the total layer size.
Lua doubles can hold 52-bit integers without introducing floating point errors, and I’m never going to produce even half that number of tiles by hand (67108864), so I got the idea to pack every two tiles into one Lua double, and then run-length encode the pairs. This would roughly halve the memory usage of dormant maps, and applying the RLE on tile-pairs instead of single tiles could catch repeating patterns like “1, 2, 1, 2, 1, 2” instead of treating that as a literal run.
Once I got back to my PC, I updated the RLE routine to support literal runs and added the twinned-tile routine. Usage is about 5% now (from 6%.) Oops, I wasted my time. Truth be told, my current maps aren’t really all that detailed either, so I have no idea if this is going to be beneficial with the finished maps or if it’s going to backfire.
I just reread my last devlog. I forgot how intense that month was. For all of the dubious changes I made to the engine, it’s at least been very helpful to have multiple tilesets per map.
I don’t have much to show this month besides the test vehicle and swimming, but I did work a lot on design stuff and sketch -> pixel art mockups. With the plot revision and storyboarding, I feel like I’m on the right track again.