Godsend Programming #8: Fire Traps and Knockable Pillars

Fire Traps

This one is relatively short, as there’s nothing that special about it. A fire trap is kind of like a spike trap, but it switches on/off and it telegraphs its attack before executing it. Now this is a fine place to use an FSM, because all of the states are mutually exclusive and most of it is just managing animation and a state variable. So that’s what I did:

Fire_Trap

To know if the object should hurt the player, all I had to do was write an accessor function that checks if the current state is the active state.

Finally, we wanted to create interesting scenarios with this fire trap. A lot of games have “waves” of retractable spikes or fire walls. We figured we want something like that as well. To achieve asynchronous behaviour of a multitude of fire traps, I introduced a “start up delay”, so that the trap actually sleeps for a period of time when initialised and only then goes into its cycle of inactive-charging-active. This gave us asynchronous behaviour, but I also exposed the frequency at which the trap would switch states for the level designer. This is another way to make it asynchronous and the two could be combined to achieve the desired effect.

There’s nothing much to take away from this implementation, other than re-affirming that the best use case scenario of an FSM (in my opinion) is when the states are mutually exclusive to each other. If they’re not, there’s a lot of pitfalls, one of which was taught to me in my undergraduate degree – FSMs cause code branching, can be difficult to manage because of that and with a large number of states, it simply can become spaghetti code (https://en.wikipedia.org/wiki/Spaghetti_code). I know Alvaro experienced this pitfall when refactoring the player controller to be an FSM, so it’s something we should all watch out for when doing FSMs in the future – smallish number of states and mutual exclusivity of states (or at least let the states only manage the global state data, rather than the control flow of the program).

Knockable Pillars

A mechanic we decided to add to our game is a Knockable Pillar. This is an object that, when dashed into the player, falls over. The meaning of it was to give player choice – it’s a horizontal obstacle, it can open new paths, but it closes paths when knocked over as well, as it can serve as a higher platform for the player to jump on as well when not knocked over. Unfortunately, it didn’t get used a lot in the game, but the implementation of it was certainly interesting.

The base requirement for the mechanic is that it needs two “pivot” points: one at each lower corner. These are the points that it tips over on. I had to research how to do this, as none of our game objects really rotated. I ended up using rotation joints provided by Box2D:

Joint_Setup

But then again, one of these needs to be “inactive” and one needs to be active, otherwise the pillar won’t get knocked over. I solved this by setting one to be a dynamic body, depending on the side it has been dashed from. The dynamic body pivot would just move along with the whole knockable pillar, while the other one, being set to kinematic, would rotate the knockable pillar. Rotating sprites was not incorporated in the base framework, so I had to figure out how to sync the physics body rotation with the sprite rotation.

The first attempt was to derive the change in angle from the angular velocity of the physics body at each time step, but it was prone to floating point errors and the sprite/physics body would gradually get out of sync. Only after a while did I realise that I can extract the angle directly from a box2d body, and the matter then became a lot easier. I am always conscious of overthinking problems, but I missed this one and I should done more research on how to do it from the beginning. Then again, the fact that I still figured it out shows that I did think “there should be an easier way to do this” and finally got there, which is a good sign.

Finally, one last bit of poor implementation in this object is the way the joints are being initialised: at the first update frame at the level. For no good reason at all, it took us a while to figure out when exactly do physics bodies get initialised in the framework, as VOnResourceAcquire was too early – the physics shapes didn’t exist yet. VOnReset wasn’t good either. So I eventually found that it was actually VOnResurrected that created the physics body. A future improvement for this code would be to stick the initialisation to an overridden VOnResurrected function.

Related files

GCObjFireTrap.h – https://drive.google.com/open?id=0B_BnvnFZLH7mNkpSblExSFJZSjA

GCObjFireTrap.cpp – https://drive.google.com/open?id=0B_BnvnFZLH7mc3J1ejh0R0k1aFE

GCObjKnockablePillar.h – https://drive.google.com/open?id=0B_BnvnFZLH7mOFU0WHBLeDhrb28

GCObjKnockablePillar.cpp – https://drive.google.com/open?id=0B_BnvnFZLH7mMU1GY0ZVUUJSZ3M