Interaction patterns in Covert Bitops games by Cadaver ------------------------------------------------------ 0. Introduction This is a mostly unstructured rant that explores some common patterns related to game object (aka "actor") interaction and code optimization in Covert Bitops games. 1. Actor transformation This is already explored in the Escape From New York dissected rant. Actors in the games are for the most part interchangeable and it is legal for them to transform to another actor type during gameplay. A typical example would be an enemy transforming into an explosion when defeated. This could also be used to implement special-case sequences where the player actor transforms into something else, or becomes different in behavior. Particularly when combined with loadable code, it allows to keep the resident engine code footprint smaller, by keeping only the often-used behavior in the "base" player actor. For Hessian there was an experiment where the player would momentarily take control of a small tank-like enemy, using this mechanism. Unfortunately it had to be scrapped. 2. Actor spawning This is when an actor creates new actors during its lifetime. This can typically be used for "particle"-like effects such as smoke trails, or a larger explosion that consists of several explosions appearing in a timed sequence. Because the maximum number of actors onscreen in a C64 game is usually limited by using fixed-size arrays, some care needs to be taken to not disturb the important gameplay, such as the player being able to shoot more bullets during the effect. This can be achieved by reserving only some actor indices for the effects, or counting the number of actors already onscreen, and only proceeding if there's enough free. 3. Control override It's a good idea to keep the player in control of the player character for as much of the time as possible. However, for some short sequences it can be useful to be able to override the player controls. This can be as simple as feeding a virtual "joystick controls" value into the player actor update routine, instead of the actual joystick input. The simplest example is the conversations in Hessian and Steel Ranger: the game keeps running, but the player actor doesn't move, as zero is being fed to the joystick controls value. This is also how enemy AI is implemented from Metal Warrior 4 onward; the AI feeds joystick control values to the enemy update. It's also how the "tank sequence" described above would have worked, while keeping the controls familiar. 4. Update / affect another actor Another mechanism of control override is when some other actor takes over the player actor movement / physics either completely or partially. Metal Warrior 4 and Steel Ranger implement "lift platforms" in this manner: if the player actor (or some other actor) is not airborne and is colliding with the platform, the platform applies its own vertical velocity to the actor, giving the impression of riding along the lift. There was a late-stage bug that almost got left in Steel Ranger: initially the mines that the player could lay down in wheel mode would not be affected, and would stay hanging in the air. This was due to over-eager code optimization that only considered the player, enemies and items for riding on the lift. A different kind of control takeover happens in the "grapple rope" mechanic that will appear in MW ULTRA: When the rope connects, the player actor is placed in an inactive state ("sitting" at the end of the rope) and the rope hook actor handles all the movement, collision and controls, until detached again. 5. Data set reduction In a scrolling game, a typical problem is how to handle activation of actors as they scroll into the view, and deactivate them once they leave. Somewhat similar is also to determine if the player actor is close to an interactable environment object: there can be a large number of them in the complete level data, consuming much CPU to go through all of them. In Steel Ranger, whenever a new area is entered, the game checks which actors and objects of the level belong to the current area, and builds lists for them. These lists are then used for the per-frame activation and interaction checks. Another mechanism is to simply process Y amount of objects each frame from a total of X. This can however induce a noticeable delay, for example an actor seemingly appearing "out of thin air" by spawning late. It's also possible to build acceleration structures for these checks, however this can mean that the actors can not move freely, or at least, when an actor is deactivated, its exact last position can not be remembered. 6. Code-based actor render This does not really fit under "interactions" but is nevertheless somewhat of a game changer, first appearing in MW ULTRA / c64gameframework: Previous games had hardcoded mechanisms to handle rendering actors into sprites: either an actor consisting of N sprites that would animate as one piece (tables would be used to fetch the sprite frame(s) for each actor frame), or a second hardcoded path for humanoids, which could have separate lower and upper body animation, and then a weapon sprite. Now the engine just calls a routine which is supposed to produce sprites for the actor. That routine can then do whatever is necessary to achieve that. Using the previous "grapple rope" example: when called, the grapple hook's render code calculates the distance between itself and the player, calculates the angle (requires square root), and finally proceeds to draw a sufficient amount of rope sprites using the correctly-angled sprite frame.