Organisation von Ebenen / Räumen in einer textbasierten Welt im MUD-Stil

12

Ich denke darüber nach, ein kleines textbasiertes Abenteuerspiel zu schreiben, bin mir aber nicht ganz sicher, wie ich die Welt technisch gestalten soll.

Mein erster Gedanke ist, dies in XML zu tun, das ungefähr wie folgt aufgebaut ist. Entschuldigung für den riesigen Haufen von XML, aber ich fand es wichtig zu erklären, was ich tue.

<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>

Offensichtlich müsste mehr dran sein. Die Interaktion mit Menschen und Feinden sowie Tod und Vervollständigung sind notwendige Ergänzungen. Da es ziemlich schwierig ist, mit XML zu arbeiten, würde ich wahrscheinlich eine Art Welteditor erstellen.

Ich würde gerne wissen, ob diese Methode Nachteile hat und ob es eine "bessere" oder üblichere Methode gibt.

Polynom
quelle
3
Persönlich würde ich XML nicht als etwas anderes als ein Serialisierungsformat behandeln. Wenn Sie die Frage "Irgendwie werde ich das lesen und auf die Festplatte schreiben" (mit etwas wie XML, JSON, Protokollpuffern, benutzerdefiniertem Binärformat usw.) abstrahieren, lautet die Frage "Welche Daten muss ich speichern?" ", was nur Sie wirklich beantworten können, je nachdem, welche Spielanforderungen Sie haben.
Tetrad
Guter Punkt. Ich habe jedoch gesehen, dass Spiele Stile wie diesen verwenden, und sie haben sich als sehr restriktiv erwiesen. In diesem Fall sind der Ablauf und die Logik des Spiels jedoch recht einfach, sodass es möglicherweise gut funktioniert und mich davon abhält, eine Skript-Engine zu implementieren. Mich interessiert in erster Linie, ob eine solche feste Struktur (getrennte Räume, Türen, Objekte, Variablen in einer Definitionsdatei irgendwo) realisierbar ist oder nicht.
Polynom
Der Versuch, Tetrad nicht wiederzugeben, aber wenn Sie vorhaben, einen Welt-Editor zu erstellen (was ich vorschlagen würde, wenn das Spiel nicht sehr kurz ist), spielt Ihr Dateiformat keine Rolle, da Sie damit arbeiten werden der Herausgeber, versus harte Kodierung der Räume.
Mike Cluck

Antworten:

13

Wenn Sie nicht vollständig mit C # verbunden sind, besteht die "üblichere" Methode darin, eines der vielen Tools zum Erstellen von Textabenteuern zu verwenden, die bereits vorhanden sind, um den Benutzern zu helfen, genau diese Art von Spiel zu erstellen. Diese Tools bieten Ihnen einen bereits funktionierenden Parser, der sich mit Todesfällen, Speichern / Wiederherstellen / Rückgängigmachen, Zeicheninteraktion und anderen ähnlichen Standardfunktionen für Textabenteuer befasst. Derzeit sind Inform und TADS die beliebtesten Autorensysteme (obwohl auch ein halbes Dutzend andere verfügbar sind).

Inform kann in die meisten von Infocom-Spielen verwendeten Befehlssätze für virtuelle Maschinen von Z Machine oder in die neueren Befehlssätze für virtuelle Maschinen von glulx kompiliert werden. TADS hingegen kompiliert sich in seinen eigenen Code für virtuelle Maschinen.

Beide Arten von Binärdateien können von den meisten modernen interaktiven Fiktionsinterpreten ausgeführt werden (früher brauchten Sie oft separate Interpreter für TADS-Spiele von ZMachine-Spielen von Glulx-Spielen. Aber zum Glück sind diese Tage im Grunde jetzt vorbei.) über jede Plattform, die Sie möchten; Mac / PC / Linux / BSD / iOS / Android / Kindle / Browser / etc. Sie haben sich also bereits gut und wirklich um plattformübergreifend gekümmert.

Für die meisten Plattformen ist Gargoyle der derzeit empfohlene Dolmetscher , aber es gibt viele andere. Sie können also gerne experimentieren.

Das Codieren in Inform (insbesondere in der neuesten Version) ist etwas gewöhnungsbedürftig, da es sich eher an Autoren als an Ingenieure richtet und die Syntax daher seltsam und beinahe gesprächig aussieht. In der Inform 7-Syntax sieht Ihr Beispiel folgendermaßen aus:

"My Game" by Polynomial

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."

In the Kitchen is a knife and some cupboards.  The cupboards are fixed in 
place and closed and openable.  In the cupboards are some batteries.

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."

Woods is north of Garden.  "The woods are quite dark, with little light bleeding 
in from the garden. It is eerily quiet."  

Trees are scenery in the Woods.  "The trees are tall and thick. There aren't any 
low branches, so it'd be difficult to climb them."

Während TADS eher wie eine traditionelle Programmiersprache aussieht und dasselbe Spiel in TADS wie folgt aussieht:

#charset "us-ascii"
#include <adv3.h>
gameMain: GameMainDef
    initialPlayerChar = me
;
versionInfo: GameID
    name = 'My Game'
    byline = 'by Polynomial'
;
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 */ 
; 

+me: Actor
; 

cupboards: OpenableContainer
    vocabWords = 'cupboard/cupboards' 
    name = 'cupboards' 
    isPlural = true
    location = startroom 
; 
battery: Thing
    name = 'battery'
    location = cupboards
;
knife: Thing
    name = 'knife'
    location = startroom
;
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." 
    north = woods
    south = startroom
; 
woods: Room
    roomName = 'Woods'
    desc = "The woods are quite dark, with little light bleeding 
            in from the garden. It is eerily quiet."
    south = garden
;
trees: Decoration
    desc = "The trees are tall and thick. There aren't any low 
            branches, so it'd be difficult to climb them."
    location = woods
;

Beide Systeme sind frei verfügbar, werden sehr häufig verwendet und verfügen über zahlreiche Lernprogramme (die über die oben angegebenen Links verfügbar sind). Es lohnt sich daher, beide auszuprobieren und das von Ihnen bevorzugte auszuwählen.

Beachten Sie, dass die beiden Systeme ein geringfügig unterschiedliches Standardverhalten aufweisen (obwohl beide möglicherweise geändert werden). Hier ist ein Screenshot des gespielten Spiels, zusammengestellt aus der Inform-Quelle:

Screenshot informieren

Und hier ist eines aus dem Spiel, das gerade gespielt wird (in einem Terminal - Typografie kann viel schöner sein als dieses), wie es aus der Tads-Quelle zusammengestellt wurde:

TADS3-Screenshot

Interessante Punkte zu beachten: Mit TADS erhalten Sie standardmäßig oben rechts eine „Punktzahl“ -Anzeige (Sie können sie jedoch deaktivieren), mit Inform dagegen nicht (Sie können sie aktivieren). Inform informiert Sie standardmäßig über den Status "Offen" / "Geschlossen" von Elementen in der Raumbeschreibung, Tads nicht. Tads neigt dazu, automatisch Aktionen für Sie auszuführen, um Spielerbefehle auszuführen (es sei denn, Sie sagen es nicht), während Inform dazu neigt, dies nicht zu tun (es sei denn, Sie sagen es).

Beide können für jede Art von Spiel verwendet werden (da beide in hohem Maße konfigurierbar sind), aber Inform ist strukturierter, um interaktive Fiktionen im modernen Stil zu produzieren (oft mit minimalen Rätseln und einem narrativeren Stil), bei denen TADS strukturierter ist auf das Produzieren von Textabenteuern im alten Stil (oft stark auf Rätsel fokussiert und die Mechanik des Weltmodells des Spiels rigoros definierend).

Trevor Powell
quelle
das ist sehr cool und informativ, aber imo beantwortet die frage nicht. Ich würde im Grunde genau dieselbe Frage stellen. Ich würde gerne mehr darüber erfahren, ob dieses XML ein gültiger Ansatz ist oder ob es Fallstricke oder Schwächen gibt.
1.
1
@DLeh Die Frage war: "Ich würde gerne wissen, ob diese Methode irgendwelche Nachteile hat und ob es eine" bessere "oder standardisiertere Methode gibt." Diese Antwort bietet die bessere und standardisiertere Methode. mach es .
Trevor Powell
Aber da Sie nach "Fallstricken und Schwächen" gefragt haben: Die Inform-Implementierung ist 19 Zeilen lang. Das TADS-Beispiel ist 40 Zeilen lang. Die XML-Implementierung erfordert 126 Zeilen (und wäre sogar noch länger, wenn sie in 80 Spalten umbrochen wäre und Leerzeichen für die Lesbarkeit enthält, wie dies bei der Inform- und der TADS-Implementierung der Fall ist).
Trevor Powell
Die Inform- und TADS-Beispiele sind nicht nur viel kürzer, sondern unterstützen auch mehr Funktionen. In beiden Fällen können Sie beispielsweise das Messer in die Schränke stecken, was in der XML-Version überhaupt nicht unterstützt wird.
Trevor Powell
1
Es ist auch erwähnenswert, dass die XML-Version den Inhalt der Schränke in die Beschreibung der Schränke einbrennt. Das heißt, beim Öffnen oder Betrachten der (geöffneten) Schränke wird eine fest codierte Meldung angezeigt, die besagt, dass sich Batterien im Inneren befinden. Aber was ist, wenn der Player die Batterien bereits entnommen hat? In der XML-Version wird angezeigt, dass sich Batterien im Inneren befinden (da dies die einzige Zeichenfolge ist, die angezeigt werden kann), während in der Inform- und der TADS-Version angegeben wird, dass die Schränke leer sind.
Trevor Powell