Mengatur level / kamar dalam dunia berbasis teks MUD

12

Saya sedang berpikir untuk menulis game petualangan berbasis teks kecil, tapi saya tidak terlalu yakin bagaimana saya harus merancang dunia dari sudut pandang teknis.

Pikiran pertama saya adalah melakukannya dalam XML, mendesain sesuatu seperti berikut ini. Permintaan maaf untuk tumpukan besar XML, tapi saya merasa penting untuk sepenuhnya menjelaskan apa yang saya lakukan.

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

Jelas perlu lebih dari ini. Interaksi dengan orang dan musuh serta kematian dan penyelesaian adalah tambahan yang diperlukan. Karena XML cukup sulit untuk dikerjakan, saya mungkin akan membuat semacam editor dunia.

Saya ingin tahu apakah metode ini memiliki kelemahan, dan apakah ada cara "lebih baik" atau lebih standar untuk melakukannya.

Polinomial
sumber
3
Secara pribadi saya tidak akan memperlakukan XML lebih dari format serialisasi. Jika Anda mengabstraksi pertanyaan "entah bagaimana saya akan membaca dan menulis ini ke disk" (menggunakan sesuatu seperti XML, JSON, buffer protokol, format biner kustom, apa pun), maka pertanyaannya menjadi "data apa yang perlu saya simpan ", yang hanya dapat Anda jawab tergantung pada persyaratan permainan Anda.
Tetrad
Poin yang bagus. Namun, saya telah melihat game menggunakan gaya seperti ini sebelumnya dan mereka ternyata sangat membatasi. Dalam hal ini, alur permainan dan logika cukup sederhana, sehingga mungkin bekerja dengan baik dan menyelamatkan saya dari penerapan mesin scripting. Saya terutama tertarik pada apakah struktur tetap seperti itu (ruang, pintu, objek, variabel dalam file definisi yang terpisah) layak atau tidak.
Polinomial
Mencoba untuk tidak menggema Tetrad tetapi jika Anda berencana membuat editor dunia (yang saya sarankan kecuali gimnya akan sangat singkat) maka format file Anda tidak ada bedanya karena Anda akan bekerja dengannya dalam editor, dibandingkan dengan pengodean ruang yang sulit.
Mike Cluck

Jawaban:

13

Jika Anda tidak sepenuhnya terikat dengan C #, maka cara "lebih standar" untuk melakukan ini adalah dengan menggunakan salah satu dari banyak alat penciptaan petualangan teks yang sudah ada untuk membantu orang membuat game seperti ini. Alat-alat ini memberi Anda parser yang sudah berfungsi, menangani kematian, menyimpan / mengembalikan / membatalkan, interaksi karakter, dan bit standar fungsionalitas teks petualangan serupa lainnya. Saat ini, sistem penulisan yang paling populer adalah Inform , dan TADS (walaupun ada setengah lusin lainnya juga tersedia)

Inform dapat mengkompilasi ke dalam sebagian besar set instruksi mesin virtual Z Machine yang digunakan oleh game Infocom, atau ke set instruksi mesin virtual glulx yang lebih baru. TADS, di sisi lain, mengkompilasi ke dalam kode mesin virtualnya sendiri.

Kedua jenis biner dapat dijalankan oleh sebagian besar penerjemah fiksi interaktif modern (di masa lalu, Anda sering membutuhkan penerjemah terpisah untuk game TADS dari game ZMachine dari game glulx. Tapi untungnya, hari-hari itu pada dasarnya sudah lewat sekarang.) Penerjemah tersedia hanya untuk saat ini. tentang platform apa pun yang Anda inginkan; Mac / PC / Linux / BSD / iOS / Android / Kindle / browser / dll. Jadi Anda sudah memiliki cross-platform dengan baik dan benar-benar diurus.

Untuk sebagian besar platform, juru bahasa yang saat ini direkomendasikan adalah Gargoyle , tetapi ada banyak yang lain, jadi jangan ragu untuk bereksperimen.

Pengkodean dalam Inform (terutama versi terbaru) membutuhkan sedikit waktu untuk membiasakan diri, karena pemasaran itu sendiri lebih ke arah penulis daripada ke insinyur, sehingga sintaksnya terlihat aneh dan hampir bercakap-cakap. Di sintaks Inform 7, contoh Anda akan terlihat seperti ini:

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

Sedangkan TADS lebih mirip bahasa pemrograman tradisional, dan gim yang sama di TADS terlihat seperti ini:

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

Kedua sistem tersedia secara bebas, sangat sering digunakan, dan memiliki banyak dokumentasi tutorial (tersedia dari tautan yang saya berikan di atas), jadi ada baiknya memeriksa keduanya dan memilih yang Anda inginkan.

Perhatikan bahwa kedua sistem memiliki perilaku standar yang agak berbeda (walaupun keduanya dapat dimodifikasi). Berikut adalah screenshot dari permainan yang sedang dimainkan, seperti yang dikompilasi dari sumber Inform:

Informasikan tangkapan layar

Dan ini satu dari permainan yang sedang dimainkan (di dalam terminal - tipografi bisa jauh lebih bagus dari ini), seperti yang dikompilasi dari sumber Tads:

Tangkapan layar TADS3

Poin menarik untuk diperhatikan: TADS memberi Anda tampilan 'skor' di kanan atas secara default (tetapi Anda dapat mematikannya), sedangkan Inform tidak (tetapi Anda dapat menyalakannya). Menginformasikan akan secara default memberitahu Anda membuka / menutup keadaan item dalam deskripsi kamar, Tads tidak akan. Tads cenderung untuk secara otomatis mengambil tindakan bagi Anda untuk melaksanakan perintah pemain (kecuali jika Anda tidak memberi tahu), di mana Inform cenderung untuk tidak (kecuali Anda memberi tahu).

Salah satu dapat digunakan untuk membuat game apa pun (karena keduanya sangat dapat dikonfigurasi), tetapi Inform lebih terstruktur untuk menghasilkan fiksi interaktif gaya modern (seringkali dengan teka-teki minimal dan gaya naratif lebih banyak), di mana TADS lebih terstruktur. menuju memproduksi petualangan teks gaya lama (sering sangat berfokus pada teka-teki dan dengan keras mendefinisikan mekanisme model dunia gim).

Trevor Powell
sumber
ini sangat keren dan informatif, tetapi imo tidak menjawab pertanyaan. Saya pada dasarnya akan menanyakan pertanyaan yang sama persis ini. Saya ingin tahu lebih banyak tentang apakah XML ini merupakan pendekatan yang valid atau apakah ada jebakan atau kelemahan yang dimiliki.
DLeh
1
@DLeh Pertanyaannya adalah "Saya ingin tahu apakah metode ini memiliki kejatuhan, dan apakah ada cara" lebih baik "atau lebih standar untuk melakukannya" Jawaban ini memberikan cara yang lebih baik dan lebih standar cara melakukannya .
Trevor Powell
Tetapi karena Anda bertanya tentang "perangkap dan kelemahan": Implementasi Inform adalah 19 baris. Contoh TADS adalah 40 baris. Implementasi XML membutuhkan 126 baris (dan akan lebih lama jika terbungkus kata pada 80 kolom dan berisi spasi putih untuk keterbacaan, seperti yang dilakukan oleh implementasi Inform dan TADS).
Trevor Powell
Selain lebih pendek, contoh Inform dan TADS juga mendukung lebih banyak fitur. Misalnya, di keduanya Anda dapat memasukkan pisau ke dalam lemari, yang sama sekali tidak didukung dalam versi XML.
Trevor Powell
1
Perlu juga dicatat bahwa versi XML memanggang isi lemari ke dalam deskripsi lemari. Yaitu, ada pesan dalam bentuk kode untuk apa yang akan dicetak saat membuka atau melihat lemari (terbuka), yang memberitahu Anda bahwa ada baterai di dalamnya. Tetapi bagaimana jika pemain sudah mengambil baterai? Versi XML akan memberi tahu Anda bahwa ada baterai di dalam (karena hanya string yang tersedia untuk ditampilkan), sedangkan versi Inform dan TADS akan memberi tahu Anda bahwa lemari kosong.
Trevor Powell