Organisation des niveaux / salles dans un monde basé sur du texte de type MUD


12

Je pense à écrire un petit jeu d'aventure basé sur du texte, mais je ne sais pas trop comment concevoir le monde d'un point de vue technique.

Ma première pensée est de le faire en XML, conçu quelque chose comme ceci. Toutes mes excuses pour l'énorme pile de XML, mais j'ai pensé qu'il était important d'expliquer pleinement ce que je fais.

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

De toute évidence, il faudrait en faire plus que cela. L'interaction avec les gens et les ennemis ainsi que la mort et l'achèvement sont des ajouts nécessaires. Étant donné que le XML est assez difficile à travailler, je créerais probablement une sorte d'éditeur mondial.

Je voudrais savoir si cette méthode présente des inconvénients et s'il existe une méthode "meilleure" ou plus standard pour le faire.


3
Personnellement, je ne traiterais pas XML comme autre chose qu'un format de sérialisation. Si vous résumez la question "je vais lire et écrire ceci sur le disque" (en utilisant quelque chose comme XML, JSON, des tampons de protocole, un format binaire personnalisé, peu importe), alors la question devient "quelles données dois-je stocker ", auquel vous seul pouvez vraiment répondre en fonction des exigences de votre jeu.
Tetrad

Bon point. Cependant, j'ai déjà vu des jeux utiliser des styles comme celui-ci et ils se sont avérés vraiment restrictifs. Dans ce cas, cependant, le déroulement du jeu et la logique sont assez simples, donc cela pourrait bien fonctionner et m'éviter d'implémenter un moteur de script. Je suis principalement intéressé à savoir si une telle structure fixe (pièces séparées, portes, objets, variables dans un fichier de définition quelque part) est viable ou non.
Polynôme

Essayer de ne pas faire écho à Tetrad mais si vous envisagez de créer un éditeur mondial (ce que je suggérerais à moins que le jeu ne soit très court), votre format de fichier ne fait aucune différence puisque vous travaillerez avec lui dans l'éditeur, contre codage en dur des chambres.
Mike Cluck

Réponses:


13

Si vous n'êtes pas complètement lié à C #, alors la façon "plus standard" de le faire est d'utiliser l'un des nombreux outils de création d'aventure de texte qui existent déjà pour aider les gens à créer exactement ce genre de jeu. Ces outils vous offrent un analyseur déjà fonctionnel, la gestion de la mort, la sauvegarde / restauration / annulation, l'interaction avec les personnages et d'autres fonctionnalités standard similaires d'aventure de texte. À l'heure actuelle, les systèmes de création les plus populaires sont Inform et TADS (bien qu'il existe également une demi-douzaine d'autres)

Inform peut compiler dans la plupart des jeux d'instructions de machine virtuelle Z Machine utilisés par les jeux Infocom, ou dans les jeux d'instructions de machine virtuelle glulx les plus récents. TADS, d'autre part, compile dans son propre code de machine virtuelle.

Les deux types de binaires peuvent être exécutés par la plupart des interprètes de fiction interactifs modernes (dans le passé, vous aviez souvent besoin d'interprètes séparés pour les jeux TADS des jeux ZMachine des jeux glulx. Mais heureusement, ces jours sont fondamentalement terminés maintenant.) Les interprètes sont disponibles pour seulement sur n'importe quelle plate-forme que vous souhaitez; Mac / PC / Linux / BSD / iOS / Android / Kindle / navigateur / etc. Vous avez donc déjà bien pris en charge plusieurs plates-formes.

Pour la plupart des plates-formes, l'interprète actuellement recommandé est Gargoyle , mais il y en a beaucoup d'autres, alors n'hésitez pas à expérimenter.

Le codage dans Inform (en particulier la dernière version) prend un peu de temps pour s'y habituer, car il se commercialise davantage auprès des auteurs que des ingénieurs, et donc sa syntaxe semble étrange et presque conversationnelle. Dans la syntaxe d'Inform 7, votre exemple ressemblerait à ceci:

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

Alors que TADS ressemble plus à un langage de programmation traditionnel, et le même jeu dans TADS ressemble à ceci:

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

Les deux systèmes sont disponibles gratuitement, très fréquemment utilisés, et ont une abondante documentation de tutoriel (disponible à partir des liens que j'ai donnés ci-dessus), il vaut donc la peine de les vérifier tous les deux et de choisir celui que vous préférez.

Notez que les deux systèmes ont des comportements standard subtilement différents (bien que les deux puissent être modifiés). Voici une capture d'écran du jeu joué, compilée à partir de la source Inform:

Informer la capture d'écran

Et en voici un du jeu en cours (à l'intérieur d'un terminal - la typographie peut être beaucoup plus agréable que cela), telle que compilée à partir de la source Tads:

Capture d'écran de TADS3

Points intéressants à noter: TADS vous donne un affichage de score en haut à droite par défaut (mais vous pouvez le désactiver), contrairement à Inform (mais vous pouvez l'activer). Inform vous indiquera par défaut les états ouverts / fermés des éléments dans la description de la chambre, contrairement aux Tads. Tads a tendance à prendre automatiquement des mesures pour vous afin d'exécuter les commandes des joueurs (à moins que vous ne le lui disiez), où Inform a tendance à ne pas le faire (à moins que vous ne le lui disiez).

L'un ou l'autre peut être utilisé pour créer n'importe quel type de jeu (car ils sont tous deux hautement configurables), mais Inform est plus structuré vers la production de fiction interactive de style moderne (souvent avec des énigmes minimales et un style plus narratif), où TADS est plus structuré vers la production d'aventures de texte à l'ancienne (souvent fortement axées sur les puzzles et définissant rigoureusement les mécanismes du modèle mondial du jeu).


c'est très cool et instructif, mais imo ne répond pas à la question. J'allais essentiellement poser exactement la même question. Je voudrais en savoir plus sur si oui ou non ce XML est une approche valide ou s'il y a des pièges ou des faiblesses qu'il aurait.
DLeh

1
@DLeh La question était "J'aimerais savoir si cette méthode a des chutes, et s'il y a une" meilleure "ou une manière plus standard de le faire" Cette réponse fournit la meilleure et la plus faire .
Trevor Powell

Mais depuis que vous avez posé des questions sur les «pièges et faiblesses»: la mise en œuvre d'Inform comporte 19 lignes. L'exemple TADS comporte 40 lignes. L'implémentation XML nécessite 126 lignes (et serait encore plus longue si elle était encapsulée dans 80 colonnes et contenait des espaces pour la lisibilité, comme le font les implémentations Inform et TADS).
Trevor Powell

En plus d'être beaucoup plus courts, les exemples Inform et TADS prennent également en charge plus de fonctionnalités. Par exemple, dans les deux, vous pouvez mettre le couteau dans les placards, ce qui n'est pas du tout pris en charge dans la version XML.
Trevor Powell

1
Il convient également de noter que la version XML incorpore le contenu des armoires dans la description des armoires. Autrement dit, il y a un message codé en dur pour savoir quoi imprimer lors de l'ouverture ou de la visualisation des armoires (ouvertes), qui vous indique qu'il y a des piles à l'intérieur. Mais que faire si le joueur a déjà pris les piles? La version XML vous indiquera qu'il y a des piles à l'intérieur (car c'est la seule chaîne qu'elle a à afficher), tandis que les versions Inform et TADS vous diront que les armoires sont vides.
Trevor Powell
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.