Over the past few months, we’ve been trying to address all the little bits of weirdness in frogatto’s gameplay. We’ve had a whole bunch of little corner cases in our gameplay that are each kind of minor in themselves, but taken as a whole, can make the game frustrating enough to ruin the fun for some people. Why we waited so long to fix them came down to cost/benefits being really poor for each of them, individually. Each of these was a tiny problem, but fixing it was a huge, sweeping overhaul, so we ended up working on other, more important stuff earlier on.
Some of the examples include:
- when you spit out an enemy, it was not possible to grab the enemy again whilst it’s in the air – or for some enemy shots like acorns or the thrown metal balls, to ever grab them again after spitting them. Now you can.
- there were odd situations in which enemies would “cancel out” of certain states; where behavior from one state of a multi-state object would “leak” into another state by the object running into some trigger that almost never got called in normal circumstances, but could very rarely ‘derail’ the object into some other state. For example, a flier bumping into ground might start walking, or might get stuck. A swimmer might fly if for whatever reason it escaped from the water. A frequent one was thrown enemies canceling their stun early.
- related to thrown stuff, it was possible at times for enemies to fail to set their team correctly, resulting in an enemy becoming permanently harmless; or sometimes resulting in frogatto being hurt by his own projectile. The fix for both these and the state issues is described further on in this post, under “States:”.
- frogatto couldn’t jump on top of enemies during his post-hit invincibility; he was completely intangible the whole time. Now, he’s intangible only until he’s outside of the enemy’s solid-area.
- when thrown enemies, or enemies in general, landed in awkward spots (such as slightly overlapping the player, or enemies getting stuck), we usually did a cop-out where they just died. We’ve come up with a few “escape systems” which try to find some way to shove/bounce them out of that situation without having to kill them. Quite a number of these “just kill it” cop-outs were so common that they were exploitable as a way to predictably kill the enemy.
- frogatto’s tongue tip had to directly touch an enemy to grab it, which is fine for anything that stays still, vertically speaking, but for bouncing projectiles (acorns, metal balls), it was insanely hard to catch them, and there are a number of new enemies we’ve been working on that were also similarly hard to grab. It was just no fun, and we needed it to be much more forgiving – now it is.
- rare situations could trigger two additive effects that made frogatto go up, both frogatto jumping, and frogatto bouncing at the same time. Other situations could result in a jump being robbed of almost all it’s upward velocity. We found what caused this and fixed it.
- Frogatto’s tongue now can attack in all 8 cardinal + diagonal directions. More importantly, it now extends in all of them with upgradeable length. The reason this took a while was that it wasn’t until recently that we had support for non-vertical/horizontal objects that could stretch like ropes. Our code to draw the tongue, as it was before, only functioned horizontally; the up-attack was just a hand-drawn animation, baked into frogatto’s sprite – it wasn’t something with a stretchable part.
- We removed the one instance we knew of where frogatto’s attack was “locking”. Locking is an annoyance seen in some videogames where you begin to perform an action, and whilst the action plays, you’re unable to perform other actions. In frogatto, whilst you attacked, you were unable to walk forward – if you were in the midst of walking, it stopped you and pinned you there until the move ended (technically, a few actions like jumping or walking the other way could escape this, but they had a different problem).
- Said different problem has also been fixed, at a graphical cost that we’ll work to correct: if you jumped or turned, your tongue disappeared – this was a bad thing if you did it a frame too soon, before the tongue touched some oncoming enemy. Attacks in games often act like a “parry”, you launch an attack, and expect it to nullify some oncoming threat. For example, if frogatto’s tongue just disappears halfways to an oncoming ant, suddenly that ant isn’t going to get removed, and suddenly, you’re going to take damage you thought you’d protected yourself from. This felt especially wrong in frogatto, because, sure, we had a reason why we didn’t do it (the tongue, facing in the now-opposite direction, would need to complete its course and retract, which might look odd), but in any shooter game, this is never a problem. Shots would leave the main character’s gun, and the main character would neither be locked in place to fire them, nor would they ever have to worry about the shot randomly disappearing and leaving them vulnerable to something incoming. Frogatto’s tongue feels like it should follow the same rules; now it does.
The graphical problem we get out of this is that we now do frogatto’s head, modularly (sometimes). Under circumstances of quickly changing animations, you’ll sometimes see it persist a frame or so longer than it should; it looks a little like a motion blur, so it really doesn’t look too bad, and we think it’s a problem worth introducing to get the gameplay right. We’ll see what we can do about fixing it, though.
On the subject of locking, I’ve noticed two games that were at the opposite ends of the spectrum in this regard – the original price of persia, from the 80s, had almost every animation/action in the game be locking; if you entered a walk animation, you were stuck until it finished – I found it incredibly stiff and frustrating. On the flip side, because it has almost no real player-animations to speak of (a 2-frame walk cycle, and just some directional aiming-frames), the famous “cave story” features almost no locking whatsoever – I think this is one of the bigger factors in how appealing its controls were; the player-character always responded when you pressed the controls. Period. You never felt like the game had unfairly trapped your character when you tried to dodge something.
Fear of graphical-interpolation issues were, I think, the source of Prince-of-Persia’s design flaw. They didn’t have interpolations between every possible state, and because their animations were slow and long, interrupting them and snapping into a different one looked ugly enough that they decided not to allow it. This also solved the “disappearing attack” problem mentioned above. I imagine the reason they didn’t do interpolation was that having full interpolations between every possible animation in a game with large sprites is not just a lot of work to draw the graphics, but to write the logic, it’s a combinatorial nightmare.
The state issues were a big strategic change, because most of these were done with variables; when you entered a state, you set a variable, and when you exited the state, you had to clear it. What was bad about this was that these variables sometimes wouldn’t get set at all, and then mismatched the appearance of the game. For example, if something doesn’t get set at the right time, one of frogatto’s projectiles could end up being completely harmless to an enemy. This breaks the absolute basics of videogaming – gamers form a mental model of what the rules are supposed to be in your game, and this makes out like the rules randomly don’t apply sometimes. No reason for it, no predictability, just “hey, that didn’t deal damage when I spat that enemy out… what the heck?”
The problem we had is that we’re a physics-based game, and by design, we’ve got more code-paths than we could ever anticipate. The player can execute moves largely in whatever sequence they want – usually the more freedom, the better. They can bump into things, do all sorts of crazy combinations of stuff we could never foresee. Now, we could try to play “whack a mole” and slap these variable-changers on each and every possible switch between modes, but it’s a bad idea because it takes a ton of time and effort to nail every last one, and the moment we change anything or add any new moves, there’s breakage because we’ve just added new paths.
Instead, it’d be ideal if we didn’t need to track those paths at all. If we didn’t have to set “state-tracking-variables”. It occurred to us: “hey, if we’re establishing a contract with the player where certain appearances are supposed to indicate certain states… why don’t we directly check the appearance?” So for a lot of things now, rather than storing our states, we try to make every state in the game “derived”, and we treat the appearance itself as the storage (or in some cases, the underlying physics; like what velocity something has). We do this now for what team something is on (who they’re able to hurt, that is), how much damage they deal, etc. It rocks, because it doesn’t matter how you get into, or leave a state; if you’re in it, you get the right settings during it.
Leaking behavior, such as “random ways stuff could get out of a stun early” was another big problem. We fixed these with a new system where objects change type during certain states. Changing type means swapping out the object’s entire bank of logic to remove all the stuff we don’t want to happen. In the past, for example, an object like the “water beetle” had all of it’s “land mode” and “water mode” code in the same file. All of those “behavior patterns” for the land-mode were sitting there just waiting to be triggered by some weird thing we didn’t anticipate, and thus didn’t turn off, underwater. Now, those are in two separate sets. Once something is underwater, all those little logic/behavior hooks from when it was a walker, are just gone. There’s no way they can trigger by accident.
The most frequent time when objects currently change type is for their thrown state. Walking objects tend to have tons of hooks in them that return them to their walk animation, and it was extremely common for enemies to escape a stun early by just having some other enemy bump into them, or something.
Another primary motivation of all this was to cut out any instances of code duplication, and to set up our damage system so that all of the different parts of dealing damage (the knockback, the cooldown, the amount of damage dealt, the named ‘type’ of the damage, the graphical effects from it, etc) were all split into separate functions, so that each of these could be overridden (a bit like subclassing) individually without clobbering all the rest. This keeps all our monster behavior more consistent (we had about 3-5 inconsistent implementations of things like flashing-after-getting-hit, for example, because every time we overrode one thing, we had to override everything), but it also paves the way for future additions. One thing we have in mind is a much more interesting powerup system; but we couldn’t do it without a clean framework to build off of.
We’ve still got a bunch of little bits we’re not so happy with.
- frogatto’s tongue should grab the acquirable goodies, like coins and such. One of many easy things we haven’t gotten around to.
- some enemy projectiles that are slow when fired by the enemy (because otherwise they’d be unfair) are strange to remain slow when frogatto spits them. Acorns and metal balls come to mind. Should be an easy fix.
- the general mechanics (especially the vertical limitation that keeps you from climbing without a column to bounce back and forth in) of the walljump are as we want, but there are a few things we don’t like about it. Far and away the worst, I think, is how it breaks the flow by “reflecting” horizontal movement if you miss a jump, and hit a wall. This is especially bad if you just barely miss the lip of a ledge. Because of our controls, you usually leap in the opposite direction. I don’t know how we want to address this.
- the walljump’s downward slide is also a little frustrating, and I’m not sure it needs to be present at all.
- frogatto’s enhanced spit power changes the trajectory in ways that make previously easy shots hard. Upgrading the spit power seems like an easy idea on paper, but in practice, I’m not sure it’s a good idea to have the upgrade at all. (We’d probably consider replacing it with something equally rewarding, but less awkward, such as something that increases how much damage spat enemies deal.)
Is there anything in the gameplay that currently bugs you, but we haven’t mentioned? Anything we have mentioned, and you also are dying to see? Please leave a comment!