When I first launched the (at its time) cutting edge "UnrealEd" to make my very first UT level (which sucked), I was pretty surprised to be told that levels are, in fact, a huge solid cube of material from which I carve away my rooms. I thought it would be the other way around: That there would be some sort of data void, some "nothing-ness", and I would just "place rooms" in it.
But most editors that deal with 3D environment allow you to either "build" something (by placing shapes) or to "carve" something (by removing a shape from an already existing block). And that's very, very convenient: Sometimes it is easier to just "carve out a block", sometimes I need to "place a statue". Sometimes I go with what is there, sometimes I need to create something new.
What's that to do with adventure games? Am I going to make an Unreal Tournament adventure game? Is there an UnrealEd plugin for AGS now? Can AGS characters now have Bouncy Boob Physics?
The answers, in order: "A lot, as this post will show", "No, no way", "Possibly not" and "I'm still desperately hoping for that".
Today I want to compare two methods to create an adventure game, and to do so, I will compare AGS with Inform. This may need some explaining, depending on your background, so read on to get a summary. If you're familiar with the toolkits, skip the next bit.
AGS is a toolkit for making graphic adventures, and it mostly works by giving the user a few types of "building blocks": Rooms, Hotspots, Objects, Characters, Inventory Items are the most important ones. These building blocks are then handled by the AGS runtime engine, which ensures that animations and scripts attached to the objects are executed in the right order. Just creating a room or a character will not make a lot happen: You must assign graphics, views, and scripts to give an AGS object any functionality (not really true, but more on that later).
Inform is a programming language for Interactive Fiction (or "text adventures"), the forerunner of the graphic adventure. Inform works by defining a huge set of rules that create a "world model", and giving the user a few types of building blocks, all of which are instantly subject to all rules. Functionality that goes beyond the basic rules are defined by the user, either by assigning different rules, or by replacing reaction to the rules.
(Skippers, read on!)
Technically a fresh AGS project is a "void". What AGS knows is that some things must be there (you can't start a game that has no rooms), and some functionality is given from the start (like mouse clicks being read, and so on). To fill the void, the user then creates rooms and characters and so on. And each of these needs some set-up before anythig can happen with it. Creating an object and giving it the sprite of an apple, for example, just makes the sprite of an apple appear in a room, because that's what AGS knows about objects: "If an object has a sprite, draw it". To make the object a bit more interesting, the user can write a script that is executed with the player "picks up" the apple: The object is made invisible, and the player says "Hmm, tasty!". Or an inventory item is given to the player, with the same apple sprite: Then the player has picked the apple up.
What you do mostly in AGS is creating individual elements with very individual events attached to them. There isn't such a thing as an "object which can be picked up by the player"- there's just AGS's knowledge about a cursor mode called "pick up", and most classes in AGS can react to it (objects, hotspots and characters as well as inventory items). Each time you want an object to be "gettable", you must write an event to do just that.
Inform, on the other hand, is mostly about rules, and there are many of them. Some are there to sort out the structure of the game: the player, for example, must always be in a room, and things the player throws will drop to the ground, and without light the player cannot see a thing, and so on. Everything the player creates (mostly rooms, objects and characters) is instantly subject to all the rules. In combination with the non-graphical nature of IF, this means that you can just write "The apple is on the table." to create an apple- and the player can instantly do a lot of things with the apple, like picking it up, offering it to a character, putting it into a box and so on. The apple is a generic object, though, and Inform rules say that objects cannot be eaten.
However, just by writing "The apple is edible", this is fixed- Inform knows about the "eat" command, and once we make the apple subject to that rule, we're good.
And even more, since Inform IS technically just rules, we can also say:
"A food is a kind of thing that is edible." From then on, we can have edible stuff everywhere by writing "The banana is a food on the table."
AGS is about creating objects and giving them individual rules. Inform is about creating exeptions and extensions to a ruleset and creating objects accordingly. You could say that AGS has no idea at all how objects should react to whatever the player tries to do with them, and each object needs all the basics covered over and over again. Inform has a rather clear idea about how a "basic object" must behave, and functionality is created by tailoring the rules. AGS makes you BUILD stuff. Inform makes you work with what's already there.
Now, a lot of that is only possible because IF does play quite a bit different from your basic graphic adventure. Our AGS apple needs stuff no Inform apple ever has to worry about- it needs a sprite, an x/y position on the screen, it must draw itself, and if we want to go all the way, we even need stuff not at all part of the apple (like a player animation for eating it). The Inform apple just needs a bit of text like "After eating the apple, say 'You even gulp down the core, it's just so juicy!'". That's it.
The AGS system offers a great deal of flexibility, though, because all objecs are technically only different in terms of their abilities. In AGS, the apple can be a hotspot, an object, or even a character- we can always make the player pick it up! (But as a hotspot we can't make the original apple disappear, and as a character, we do not win anything because the apple neither talks, nor does he have an inventory) If we made the apple a character, as it is, the player wouldn't notice... because it still looks like an apple. A savy AGS user who notices the same apple appearing in different rooms MAY think: Oh, crafty Ghost used a character for that apple so that it can change rooms. But that's about it.
AGS has no "world model"- everything you create is unique. The only exeption to the rule is, by default, the "unhandled_event" bit in the global script, where users can define reactions to, well, events that have no scripts. As soon as you create the function and define something like: "picking up a character makes the player say 'I prefer blondes'", you technically have made a "world rule". Every character who has no script for being picked up will trigger that response.
I am not sure if a more elaborate model world would be a cool thing to have in AGS, but I think it wouldn't be too hard to implement some basic rules- using properties and checks in repeatedly_execute. For example, if my player character has a camera, and must photograph a rare bird in the woods, it would be quite useful to have a "world rule" that everything can be photographed, but only the bird will make me win the game. As it is now, AGS requires me to have every object in the game have its own reaction to the "use camera on me" event- it would be more sensible for the camera to check if the thing it was used on was the bird.
Well, that's something to talk about, isn't it? First post gets a free unhandled_event!
2 comments:
That's a very interesting topic for me, especially since I'm building a completely different kind of interface for my next AGS game and an easy methodology for setting up global rules would be invaluable.
As it is, I'm mostly relying on super-complex functions that I have call in every event for the interface to work properly. For example:
function oHammer_Interact
{
InterfaceDoYourThing("It's too heavy", 1, 4, 5);
}
That's possibly not the smartest way to do it, so I'm open to advice.
Where's my free unhandled_event!?
Post a Comment