|
Genre Definition Language, Part II: Templates |
In the previous article, I show you have you can use sets as a way to randomly combine nouns (base components like a sword or a piece of heavy armor) with adjectives (modifiers like sharp or elite). Using sets, you can control the randomization considerably. For instance, you can decide that you want a type of sword which can have any elemental adjective attached to it, but nothing else. You can even create a variety of swords, like an elemental sword, a magic sword, and a frightening sword, and put them into a set to pick one of them randomly.
This was all done through four basic objects: nouns, adjectives, sets of nouns, and sets of adjectives. The distinction between the sets is important, because you need to be sure that when you want a noun from a set, you get a noun. Adjectives can be attached to nouns, such that a noun definition could be something like hairy short sword.
If you'll recall, you could define nouns by randomly selecting values from a set:
magicSword = [elementalEnchantment, darknessEnchantment] sword
Technically, you are not creating a noun. Instead, you are creating a temple that creates a noun. As it is, magicSword represents every potential sword that can be procedurally generated from its definition. It is a genre of swords, albeit a small one.
It does not create a single sword, but a new sword every time it is asked. As such, the template is saved in potential form, from which many swords can be instantiated. This is not done in the genre definition itself, but by the game. It might call something like magicSword.create(). Even when there is no randomness at all, such as when the noun and adjectives are explicitly defined and unchanging, it is still considered a template, rather than a new noun.
I've already covered a template as a way to procedurally generate adjectives and a noun via sets. We'll call this the "base definition", since everything else will come out of that. Templates have two other functions: modification and composition.
Let's start with modification. Like adjectives, it can override something from the base definition object, though unlike adjectives, you explicitly define what and how it is changed. These changes are applied to the base object AFTER all adjectives are first applied.
Think of a healing potion from a typical fantasy game. Usually, these come in different sizes, which represent relative healing capability. Using the current genre definition rules using just nouns and adjectives, an appropriate solution does not present itself. We can create unique nouns for each type of potion, but that approach could lead to most of the game objects being done in code rather than data. We could create capacity adjectives, like small, large, and bigGulp, but the code would still have to interpret what that means (and what does a large troll mean?).
With templates, we can take a base object and modify variables on easily. For example:
noun potion with variable capacity.
smallPotion = potion
icon: "smallPotion.png"
capacity: 10
;
largePotion = potion
icon: "largePotion.png"
capacity: 20
;
Aha! Brilliant! But it gets better! Since templates represent potential objects and are not actually instantiated until requested, we can represent data as potential values as well. For example:
smallPotion = potion
icon: ["smallPotion.png", "smallPotion2.png"]
capacity: [10..20]
;
It's a weird example, but bear with me. As you can see, the icon, rather than being a single static value, is assigned to a set of potential values. When the smallPotion template is instantiated, one of those values is selected. Thus every smallPotion created will randomly have one of two different icons. Likewise, we can do the same thing with the capacity. Every smallPotion will have a random capacity between 10 and 20.
Again, template values are applied after the base component is fully formed, so any adjectives there are put first. For instance, if the base definition was a shiny potion which included a unique icon, that would be overwritten by the template's icon definition. The easy way around this is to define your objects more carefully.
Finally, templates can only affect values on the noun itself. Adjectives don't actually add new values (other than adding keywords, and that doesn't count) so it's really kind of a moot point there. However, I just wanted to bring it up so that I could mention that nouns, themselves, have boundaries for each variable, as well as a default value. Any variable that is modified to have a value that is out of bounds will be ignored. If a variable is untouched or if all attempts to change it fail, it will use the default value.
And hey, if you were thinking that it would be really easy to define adjectives as templates, you're right. The same requirements would apply (type keywords, what the adj applies to) but the body of an adjective could be created with the same syntax, making adjectives a slightly more purposeful template.
The third thing a template can do, beside defining new objects and modifying variables on them, is to compose complex objects out of several simpler ones. The classic example is an enemy, who gets not only a body, but also equips weapons and armor, and likely carries items and the like. Other containers are things like chests or even dungeons or the world itself.
At the simplest level, this just means having attributes that can hold objects or sets of objects. For instance:
orcArcher = weak orc
weapon: [ orcBow:90, rareOrcBow:10 ]
armor: leatherArmor
;
An important note is that sets are similar to templates in that they exist in a non-instantiated state. When the orcArcher is created, that object may attempt to create a weapon from the weapon attribute. It is not done automatically, and every time the orcArcher tries to instance from weapon, it will create a new weapon according to the set provided.
To the set, I'd like to add a slightly different data type, the list. A list is similar to a set - and in fact, can be used as a set if needed. There are two differences. The first is that a list is ordered, as in it has a first, second, third, etc object. The second is that a set is instantiated with the object. Though the definition may contain sets of sets of sets, when the object is created, it creates a single list of concrete objects and polling that attribute will return the same list, not a new one.
The purpose of a list is largely for dungeon creation, where you can keep each floor of the dungeon as an element in an ordered list. For example:
randomFloor = dungeonFloorplan
numRooms = [4..12]
enemies = setOfAllOrcs
treasures = setOfAllTreasures
;
bossFloor = dungeonBossFloorplan
arenaType = openArena
boss = [orcBoss1, orcBoss2]
treasures = setOfHealingTreasure OR setOfGoldTreasure
;
myDungeon = castleDungeon
floors = (dungeonFloor, dungeonFloor, [dungeonFloor:50, nil:50], bossFloor)
;
This has been an attempt at creating a definition language with which one can define many aspects of a game in terms of its components and their variations. It has a particular focus toward sets as a mechanism for randomization and categorization, which I believe creates a very simple, though very broad and powerful, way of organizing entire games. Templates, too, are a fundamental aspect of this language, since it creates a recursive way to generate lots of content differently every time.
Simply by changing a few sets here or there, you can make a game engine create a science fiction or fantasy setting. You can add steampunk to the fantasy genre simply by adding in firearm sets. You can have a fantasy game with nothing but dwarves, no dwarves at all, or dwarves as simply one of many different races. More importantly, if this system is given the player (perhaps with an appropriate metaphor, like collectible cards), they can create their own genres of games, like worlds of cross dressing orcs or a game where the humans are the bad guys.
One final note is that perhaps adjectives aren't strictly needed, as their functionality can be done exclusively through templates. My original thoughts were that adjectives can make it easier to modify nouns in small ways - mutators, if you will. Rather than defining a new orc for every permutation, you can just slap an adjective or two on him and bam, new unit type. However, they do appear to be optional and it might be easier to implement this definition language without them.
|