Meeting Variables

A Way To Think About Combining Things

Combat in Videogames - Numbers

The starting point for this is re-thinking combat in videogames. Why, in videogames, do we always seem to have the same basic interaction: hit something, shoot something? There are a hundred valid reasons, but the overriding ones seem always to be: we know how it works, and it's expected. So the entire idea of combat has to me felt for a long time like a heavy and very limiting weight of tradition. It would be nice to supercede this, somehow.

Looking just at RPGs, a central problem with them (as they are usually formulated) is how to deal with scaling numbers. If the player has twice as many hit points at level 5 than they do at level 1, but a monster at level 5 deals twice as much damage, nothing has changed since it's just the same number of hits, the same interactions exactly. (There can, though, be a see-sawing balance of power, as well as a steady increasing in real difficulty, both of which are interesting.)

A truly open-world RPG has an additional problem that the player may tackle the combat challenges that the game presents in any order they choose. A few solutions are possible, for instance I noticed that Ultima VI (having just played it) seems to deal with this by setting combat difficulty to be overall quite low, and having the player become powerful quite quickly. The side effect of this is that most interesting combat challenges are early on in the game, and other later areas can be tedious. Skyrim approaches this problem by adjusting the levels of monsters (and treasure) when you enter each dungeon, based on your own level. One problem with this approach is that the player could become aware that things are being tweaked in this way, and may stop feeling that the world is a thing to explore and learn about that is separate from them. If the rules are changing to accomodate you, you may (paradoxically) feel cheated, because your effort to learn things about it has been an illusion.

Something More Interesting - Mechanics

Rather than rely on scaling numbers, open-world RPGs (or any game, really) could solve this problem by creating areas which require (or at least encourage) genuinely different approaches to complete them. A few thoughts on this.

As a base approach, we could create new mechanics for each area. Zelda games tend to do this; for instance requiring changing of water levels in the water temple (Link to the Past, among others), or the double-hookshot in the Sky City (Twilight Princess.) Good designers can find interesting puzzles by laying these elements out differently, but this approach is still immensely problematic from an implementation standpoint: it is just a lot of work to implement drastically different mechanics.

Worse, it can fall flat if we feel like certain abilities or items are only useful within the limited context they were created for. (An example would be the spinning top item in Twilight Princess, which does not usually feel useful outside the dungeon you find it in, yet has quite an elaborate control scheme.) The novelty of a new ability will wear off quickly for the player unless they can apply it across a variety of situations. The word "gimmick" is sometimes applied disparagingly toward these kind of mechanics. A pretty disappointing outcome considering the work involved in implementation!

So, it seems obvious what we would like to create: new mechanics which can be applied across a variety of situations.

Aside: A Simple Trick

Ideally any new mechanics that the player acquires should be applicable not only going forward but especially to previously-encountered situations. A hammer should not just whack things in that we are going to encounter after getting the hammer, but we should also get to go back and whack things from before we got it, too.

This is an easy win for a game designer: to take a situation that the player may feel frustrated with, for instance a challenging enemy, and introduce an item later on that reduces this frustration. This creates a sense of empowerment with gaining the new ability since they already apprciate what it's like to not have it, first.

Along these same lines, gameplay situations that are awkward are sometimes an opportunity to create a useful special item. Rather than increase running speed per se, it might be more satisfying to have higher running speed be a reward for exploring and area or beating a boss. (Running speed in particular is thorny for a number of reasons, however.)

Hit Points

Systems like hit points are really a way to combine different mechanics together in a convenient way. A sword swipe can deal 10 points of damage; an arrow deals 5. They work differently (one swipes at close range, one flies through the air) but interact with other objects in the same way-- by subtracting their damage from their target's hit points.

Damage systems can be expanded to include damage types, armour types, and more-- features which can all interact. Again, these are to make it convenient to combine things: objects might respond to "piercing" versus "slashing" damage, but they don't have to know that it was an arrow or a spear producing the piercing damage.

The Combining Things Principle

A central organizing principle of the universe is the combining things principle.

Let's say we have the budget to create 9 things, whether they are special items, or obstacles that the player can use them on (an obstacle could be an enemy, a switch, or something else.) We could create 1 special item and 8 types of obstacles to use it on (for instance, a sword, and 8 types of enemies.) Or, we could create 8 special items and 1 type of obstacle. In either case, we've created 1 × 8 = 8 experiences.

If we create one more special items, 2, then we can create 7 obstacles (or vice versa, 7 special items and 2 obstacles.) This would be 14 experiences-- much better, for (theoretically) the same budget!

Continuing this pattern, we can write out the sequence like this: 8, 14, 18, 20, 20, 18, 14, 8. It peaks in the middle, at 20, which is 4 × 5 or 5 × 4. So to produce the largest number of experiences, we ought to create 4 items and 5 types of obstacles, or vice-versa.

(Note: we can weight these "things" with different costs, for instance stipulating that one item is worth two types of obstacle, so adding an item to the budget means we must subtract two obstacles; starting with 1 item and 8 obstacles, our sequence would be 8, 12, 12, 8.)

Many games tend to ignore this rule, and combine things in ratios more like 8:1. This is the hidden problem with relying on scaling numbers-- we create many special items (weapons) but they can only interact in one way (causing damage.) Assume for a moment that the enemies don't behave very differently; then they are in a sense all the same thing-- just a collection of hit points to reduce to 0. As a result, if we create 8 weapons, the player has 8 × 1 = 8 experiences to have. (This is an even bigger problem if one of those 8 weapons tends to dominate; for instance if ranged weapons dominate because enemy behaviour doesn't cope with them very well.)

So, instead of having only one major system (damage-dealing) on the other side of the equation, we could perhaps have two or more. One obvious thing would be physical-movement effects; so shooting an arrow at a switch could activate it. Another might be material effects, for instance weapons could have sharpness which affects their ability to cut things. We could then use a sword or an arrow to cut a rope, or if sharp enough, a steel cable. We could use a binary material property like "is it metal" to create sparks when the weapon strikes something metal, with the idea that sparks could ignite flammable things.

Meeting Variables

My own goal as a designer is to move from the idea of a weapon to a tool, and from the idea of combat to more general systems of interacting with things. Ideally, rather than just weapons that deal damage I'd like to have a variety of tools that interact with a variety of objects in different ways.

The problem is that a typical implemention along these lines is either 1 × N (for instance, a fishing road catches a number of kinds of fish) or, it's M × N but where we need to implement and consider M × N interactions. In the first case, the tool has limited uses for all our work; you can fish and that's it. In the second case, we have a very large amount of work ahead of us: Will the fishing road work as a weapon? That might be reasonable. Will it work on curtains, allowing us to hook them and pull them down? That could be a lot of work for a one-off effect.

The key really is that we can think of things like damage-dealing systems (hit points) as a central point for different objects to interact with each other. Let's call them meeting variables. Then, rather than just create things on one side of the equation (i.e., create a lot of tools which each have completely unique effects) we can try to expend that same energy creating multiple meeting variables, such as sharpness, cuttability, or "is it metal", described above.

Meeting Variables - N + M cost, N × M value

Each meeting variable will typically represent a high implementation cost. The advantage is that multiple tools (and objects) can make use of them. In the case above, curtains could have an is_hookable variable (together with necessary functionality to make this meaningful). Fishing rods will interact with the is_hookable (and it's associated functionality) without knowing they are curtains. Likewise, arrows could do the same thing.

The point isn't that this is easy, but that it's worth doing.

In the case of arrows and with fishing rods, we have to implement 2 × 1 things, since arrows will likely interact a bit differently with is_hookable than fishing rods will. Likewise, curtains will have to implement is_hookable one way, while fish will have to implement it another.

So in general, if we have M tools and N objects that all interact with is_hookable, we'll implement M × 1 + N × 1 = M + N things. However, from the perspective of the player, the net effect will be M × N experiences, because is_hookable is hidden from view. We can now shoot arrows at fish as well as at curtains, which doesn't feel like the same experience. What's more, different tools will interact with a different set of meeting variables, so shooting an arrow at a fish where it interacts with is_hookable is not the same as shooting it at a monster where it would interact with is_damagable. Likewise different objects will implement different meeting variables, so curtains might be is_flammable while fish are not.

The players' experiences, from the designer's perspective, "meet" at the is_hookable variable.

Meeting Variables vs. "Good Abstraction"

Normally, this aspect of design is somewhat glossed-over as "good abstraction." And definitely, meeting variables are a kind of good abstraction. But meeting variables per se are a specific mental model for seeing where we can abstract things in the first place.

This way, when we implement new mecahnics, we can expand on our intuition of and experience with hit points and damage systems, rather than falling into the trap of implementing too many special purpose tools.

Practical Experience

I've been using this concept fairly well in Paradise Never. All objects have a collection of traits which can be queried. I can use a trait to indicate that an object has a certain meeting variable. So, for instance, objects which can be burned have their is_flammable trait set to true. As often as possible, I try to not write code that looks for objects of a certain type, but that looks for objects with certain traits. So for example, when spreading fire, we look for all objects with is_flammable set to true.

The trait just signals that the object interacts in this way, of course; most of the meeting variables I find myself implementing are a combination of a trait like is_something together with methods like something_effect (...). It's rare to include actual numeric counters (ala hit points) but this can happen, for instance when I implemented burnable objects they are consumed by a certain number of "points" each time fire_consume () is called (it's up to the object to interpret these points.)

Boolean traits on their own are rarely very useful, however; normally a meeting variable will also necessitate some special functionality. Perhaps it's useful to think of boolean (or even numeric) traits that we can only query as being a very limited case of meeting variables, but I prefer to think of meeting variables as requiring an associated interface in order to support a certain interaction.

Interfaces, Implementation, Conclusion

Again, meeting variables are just a rough mental model, a way of starting from "how do I get away from hit points and damage" and ending up with a concrete idea for an abstract system.

There's a lot of ways to put that abstract system in place; really what I'm doing by using a trait system together with some added functionality is just creating an interface that is only implemented by some objects. Perhaps a "classic-C++" approach would be to use multiple inheritance (so an object could inherit "Burnable", "Throwable", etc.) or something like that. (I think multiple inheritance is mostly abandoned, now, though, thankfully.) What I do in Lua though is more along the lines of simple inheritance, where the base object class implements the trait system (so I can select ones that interact in a certain way) and also has all meeting variables' interfaces, but for each type of object only some of these might be implemented. It works well in practice.

Hopefully there are some interesting ideas here. I'd love to hear your thoughts on this, please email me calvin@kittylambda or tweet me @psysal. Especially if you have a different way of thinking about this, I'd love to hear it!

November 6, 2016
938 views


◀ Back