Some miscellaneous room prototyping.
I made some good progress on high-level design this month, but didn’t get much done that’s tangible or playable. I’m narrowing the project’s scope a bit to help stay focused.
I’ve finally given this project a proper name: BALLEG. The core codebase is still Bolero, but it’s nice to have something to call the game part of the project other than “Bolero 2 Project”.
Bolero 1 Stuff
I pushed an update to Hibernator, bringing it up to v1.04. This is the first game I released as part of Project Bolero. It was also my first Lua program larger than a couple hundred lines, so its codebase is really bad, with global variables used all over the place. The game itself is OK, but pretty sparse. I designed it to be something that I could finish and get out the door in a reasonable timeframe, and it fulfilled that purpose. As the devlog I linked above notes, I’d like to eventually convert it to the Bolero 2 codebase, maybe remake it, but that won’t be for a while.
Hibernator 1.04, sporting a slightly different pause menu.
Opponent Hit Response
I expanded how the player’s shot reacts when it hits an opponent. Before, any non-fatal hit would destroy the shot on contact, and any fatal hit would have the shot pass through, with velocity slightly reduced. So an enemy with 3 HP would destroy the first two shots, while the third shot would pass through as its defeat animation plays.
When I added multi-hit enemies to the game (back in January), I made the non-fatal shots self-destruct instead of bounce back because the player could hurt themselves with their own projectiles. I think I was also struggling with how to deal with ambiguous collisions where the shot hit a corner of an opponent’s hitbox, which would also exacerbate the problem of hazardous rebounds.
The new system lets you set an enemy’s response mode for fatal and non-fatal hits independently. The responses are:
- pass: The shot goes through the actor with no modifications.
- impede: The shot goes through the actor, with some minor changes to velocity to simulate an impact. The default for fatal hits.
- bounce: The shot ricochets off the actor, with some minor changes to velocity. The default for non-fatal hits.
- break: The shot self-destructs upon impact.
The bounce response does a few checks to determine how the shot should react. Direct collisions away from any corners bounce back as you’d expect:
Corners get special handling based on the X position and velocity of the shot. If the shot’s center X coordinate is beyond the opponent hitbox bounds, and it’s also moving towards the opponent’s center X coordinate, then it counts as a side hit, not a top hit. But if the shot is past the opponent’s center X, then collisions on the “far” corner count as a top hit.
I’m doing this to prevent situations where the player lands a hit on the “far” corner and the opponent is configured to do a knock-back behavior, which would backfire and make the enemy lurch towards the player.
If the shot’s X velocity is zero or close to it, then hitting the corners is treated like a side hit. When hitting the top side dead-on with little to no X velocity, the shot is given a minimum X velocity in order to prevent it from just bopping the opponent in place over and over.
I should note that this system does not (and is not intended to) fully resolve collisions between the opponent and the shot. It negates the shot’s velocity on one axis, and enforces a minimum rebound speed using math.min() / math.max(), but if a shot were spawned within the same area as the opponent, it will continuously damage them as it gets slowly pushed out to the side.
This should add some much-needed variety to the combat. Tougher opponents always breaking shots was getting tiresome, as you’d have to burn time waiting for new shots to fully charge up. Now you can throw a shot, grab it after the rebound, and repeat that action. Meanwhile, special-case fortified enemies can still destroy the shot on impact. I also added a separate knockback rule, so that some enemies can get bumped back a bit when it makes sense in context.
Made an additional, more severe damage response for the player, and created some new animation frames and a modified sound effect to go with it.
The player following a severe hit.
More Tilemapped Hazards
Taking damage from a hazardous floor tile.
I’ve been putting this off, but finally sat down and implemented tilemapped terrain which is both solid and hazardous along one or multiple sides. It’s a little more complex to deal with than non-obstacle hazard tiles, but I need them to eliminate some platforming exploits such as safely standing on ledges next to spikes:
This is harmless but looks so silly.
I also added some green toxic liquid tiles, which damage the player while they swim in it. I’m not sure how much this will be used, but I could see substituting in toxic water depending on the level’s context, and maybe the difficulty setting.
I had a tough time getting started this month, but in the final week or so I had some ideas on how to move forward with design:
- Up to this point, my level plans and my actual prototype fragments weren’t matching up. I was stressing about making each level take place in a distinct area, and giving each region a strong physical identity. But I have to concede that I don’t have the manpower to accomplish this while also handling other aspects of the project.
- Solution: All levels take place in the same sci-fi fortress structure, and use the same blocky tileset as the basis for their art design, with color changes and custom extensions where necessary. Regions are abstract and do not need to be “believable”.
- Having the two enemy groups fight each other when the player isn’t nearby is a fun idea, but with the way things are going in the prototype content, instances of this are going to be rare. The code to make enemies select targets other than the player also makes development more difficult while contributing little to the core action.
- Solution: The two enemy groups are now on the same team.
- Bolero 2 can arrange multiple tilemapped rooms within the same scene, and I plan to use this so that the player travels through many areas seamlessly without hard cuts. However, I have no visual editor for setting up these room relationships, and assigning them in code is a tedious job where I need a good idea of the layout in advance (ie sketched out on paper.)
- Solution: For now, just link rooms together with warp-doors. Set up a proper room node graph later on.
In a nutshell: I’m narrowing the game’s scope and putting more trust in the prototype fragment content defining the gameplay. I may renege on this in the future, but it’s what I need right now. The player’s idiosyncratic method of attack is really messing up anything I try to plan out in advance.
That’s all I’ve got! I feel I didn’t make the most of this month, so I’ll try and do better with December.
I should probably come up with some different stats for 2021 which are more interesting, as things like mapping have no impact at all on LOC, while copying and pasting boilerplate actor setup code has a disproportionate impact.
Codebase issue tickets:
Project lines of code: