Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm thinking of writing a small text-based adventure game, but I'm not particularly sure how I should design the world from a technical standpoint.

My first thought is to do it in XML, designed something like the following. Apologies for the huge pile of XML, but I felt it important to fully explain what I'm doing.

<level>
    <start>
        <!-- start in kitchen with empty inventory -->
        <room>Kitchen</room>
        <inventory></inventory>
    </start>
    <rooms>
        <room>
            <name>Kitchen</name>
            <description>A small kitchen that looks like it hasn't been used in a while. It has a table in the middle, and there are some cupboards. There is a door to the north, which leads to the garden.</description>
            <!-- IDs of the objects the room contains -->
            <objects>
                <object>Cupboards</object>
                <object>Knife</object>
                <object>Batteries</object>
            </objects>
            </room>
        <room>
            <name>Garden</name>
            <description>The garden is wild and full of prickly bushes. To the north there is a path, which leads into the trees. To the south there is a house.</description>
            <objects>
            </objects>
        </room>
        <room>
            <name>Woods</name>
            <description>The woods are quite dark, with little light bleeding in from the garden. It is eerily quiet.</description>
            <objects>
                <object>Trees01</object>
            </objects>
        </room>
    </rooms>
    <doors>
        <!--
            a door isn't necessarily a door.
            each door has a type, i.e. "There is a <type> leading to..."
            from and to are references the rooms that this door joins.
            direction specifies the direction (N,S,E,W,Up,Down) from <from> to <to>
        -->
        <door>
            <type>door</type>
            <direction>N</direction>
            <from>Kitchen</from>
            <to>Garden</to>
        </door>
        <door>
            <type>path</type>
            <direction>N</direction>
            <from>Garden</type>
            <to>Woods</type>
        </door>
    </doors>
    <variables>
        <!-- variables set by actions -->
        <variable name="cupboard_open">0</variable>
    </variables>
    <objects>
        <!-- definitions for objects -->
        <object>
            <name>Trees01</name>
            <displayName>Trees</displayName>
            <actions>
                <!-- any actions not defined will show the default failure message -->
                <action>
                    <command>EXAMINE</command>
                    <message>The trees are tall and thick. There aren't any low branches, so it'd be difficult to climb them.</message>
                </action>
            </actions>
        </object>
        <object>
            <name>Cupboards</name>
            <displayName>Cupboards</displayName>
            <actions>
                <action>
                    <!-- requirements make the command only work when they are met -->
                    <requirements>
                        <!-- equivilent of "if(cupboard_open == 1)" -->
                        <require operation="equal" value="1">cupboard_open</require>
                    </requirements>
                    <command>EXAMINE</command>
                    <!-- fail message is the message displayed when the requirements aren't met -->
                    <failMessage>The cupboard is closed.</failMessage>
                    <message>The cupboard contains some batteires.</message>
                </action>
                <action>
                    <requirements>
                        <require operation="equal" value="0">cupboard_open</require>
                    </requirements>
                    <command>OPEN</command>
                    <failMessage>The cupboard is already open.</failMessage>
                    <message>You open the cupboard. It contains some batteries.</message>
                    <!-- assigns is a list of operations performed on variables when the action succeeds -->
                    <assigns>
                        <assign operation="set" value="1">cupboard_open</assign>
                    </assigns>
                </action>
                <action>
                    <requirements>
                        <require operation="equal" value="1">cupboard_open</require>
                    </requirements>
                    <command>CLOSE</command>
                    <failMessage>The cupboard is already closed.</failMessage>
                    <message>You closed the cupboard./message>
                    <assigns>
                        <assign operation="set" value="0">cupboard_open</assign>
                    </assigns>
                </action>
            </actions>
        </object>
        <object>
            <name>Batteries</name>
            <displayName>Batteries</displayName>
            <!-- by setting inventory to non-zero, we can put it in our bag -->
            <inventory>1</inventory>
            <actions>
                <action>
                    <requirements>
                        <require operation="equal" value="1">cupboard_open</require>
                    </requirements>
                    <command>GET</command>
                    <!-- failMessage isn't required here, it'll just show the usual "You can't see any <blank>." message -->
                    <message>You picked up the batteries.</message>
                </action>
            </actions>
        </object>
    </objects>
</level>

Obviously there'd need to be more to it than this. Interaction with people and enemies as well as death and completion are necessary additions. Since the XML is quite difficult to work with, I'd probably create some sort of world editor.

I'd like to know if this method has any downfalls, and if there's a "better" or more standard way of doing it.

share|improve this question
3  
Personally I wouldn't treat XML as anything more than a serialization format. If you abstract out the "somehow I'm going to read and write this to disk" question (using something like XML, JSON, protocol buffers, custom binary format, whatever), then the question becomes "what data do I need to store", which is something only you can really answer depending on what your game requirements are. –  Tetrad Nov 24 '11 at 17:34
    
Good point. However, I've seen games use styles like this before and they've turned out to be really restrictive. In this case, though, the game flow and logic is quite simple, so it might work well and save me from implementing a scripting engine. I'm primarily interested in whether such a fixed structure (separate rooms, doors, objects, variables in a definition file somewhere) is viable or not. –  Polynomial Nov 24 '11 at 17:39
    
Trying not to echo Tetrad but if you're planning on making a world editor (which I would suggest unless the game is going to be very short) then your file format doesn't make any difference since you'll be working with it in the editor, versus hard coding the rooms. –  Mike C Nov 24 '11 at 18:44
add comment

1 Answer

If you're not completely wedded to C#, then the "more standard" way of doing this is to use one of the many text adventure creation tools which already exist to help people make exactly this kind of game. These tools give you an already-functioning parser, handling for death, save/restore/undo, character interaction, and other similar standard bits of text adventure functionality. Right now, the most popular authoring systems are Inform, and TADS (though there are a half dozen others available as well)

Inform can compile down into most of the Z Machine virtual machine instruction sets used by Infocom games, or into the more recent glulx virtual machine instruction sets. TADS, on the other hand, compiles down into its own virtual machine code.

Either type of binary can be run by most modern interactive fiction interpreters (in the old days, you often needed separate interpreters for TADS games from ZMachine games from glulx games. But thankfully, those days are basically over now.) Interpreters are available for just about any platform you'd want; Mac/PC/Linux/BSD/iOS/Android/Kindle/browser/etc. So you've already got cross-platform well and truly taken care of.

For most platforms, the currently-recommended interpreter is Gargoyle, but there are plenty of others, so do feel free to experiment.

Coding in Inform (especially the latest version) takes a little bit to get used to, since it's marketing itself more toward authors than toward engineers, and so its syntax looks weird and almost conversational. In Inform 7's syntax, a part of your example would look like this:

Kitchen is a room. "A small kitchen that looks like it hasn't been used in a 
while. It has a table in the middle, and there are some cupboards. There is a 
door to the north, which leads to the garden."

An openable container called cabinet is here.  In the cabinet is a battery.  
A battery is a kind of thing.

Garden is north of Kitchen. "The garden is wild and full of prickly bushes. 
To the north there is a path, which leads into the trees. To the south there 
is a house."

Whereas TADS looks more like a traditional programming language, and looks like this:

startroom: Room                  /* we could call this anything we liked */ 
    roomName = 'Kitchen'         /* the displayed "name" of the room */ 
    desc = "A small kitchen that looks like it hasn't been used 
            in a while. It has a table in the middle, and there 
            are some cupboards. There is a door to the north, 
            which leads to the garden." 
    north = garden         /* where 'north' will take us */ 
; 
cupboards: Container
    vocabWords = 'cupboard/cupboards' 
    name = 'cupboards' 
    location = startroom 
; 
battery: Thing
    name = 'battery'
    location = cupboards
;
garden: Room                  
    roomName = 'Garden'
    desc = "The garden is wild and full of prickly bushes. To the 
            north there is a path, which leads into the trees. To 
            the south there is a house." 
    south = startroom        
; 

Both systems are freely available, very frequently used, and have copious amounts of tutorial documentation (available from the links I gave above), so it's worth checking out both of them and picking the one you prefer.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.