Организация уровней / комнат в текстовом мире в стиле MUD

12

Я думаю о написании небольшой текстовой приключенческой игры, но я не совсем уверен, как я должен проектировать мир с технической точки зрения.

Моя первая мысль - сделать это в XML, разработав что-то вроде следующего. Извиняюсь за огромную кучу XML, но я чувствовал, что важно полностью объяснить, что я делаю.

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

Очевидно, должно быть что-то большее, чем это. Взаимодействие с людьми и врагами, а также смерть и завершение являются необходимыми дополнениями. Поскольку с XML довольно сложно работать, я бы, вероятно, создал какой-то мировой редактор.

Я хотел бы знать, есть ли у этого метода какие-либо недостатки, и есть ли «лучший» или более стандартный способ сделать это.

многочлен
источник
3
Лично я бы не рассматривал XML как нечто большее, чем формат сериализации. Если вы абстрагируете вопрос «каким-то образом я собираюсь прочитать и записать это на диск» (используя что-то вроде XML, JSON, буферов протокола, пользовательского двоичного формата и т. Д.), То возникает вопрос «какие данные мне нужно хранить? «Это то, на что только вы можете ответить, в зависимости от ваших требований к игре.
Тетрад
Хорошая точка зрения. Тем не менее, я видел игры, использующие стили, подобные этому, и они оказались действительно ограничительными. В этом случае, однако, игровой процесс и логика довольно просты, поэтому он может работать хорошо и избавить меня от реализации скриптового движка. Меня прежде всего интересует, жизнеспособна ли такая фиксированная структура (отдельные комнаты, двери, объекты, переменные в файле определения).
Полином
Стараясь не повторять Тетрада, но если вы планируете сделать редактор мира (что я бы посоветовал, если игра не будет очень короткой), тогда формат вашего файла не имеет значения, так как вы будете работать с ним в редактор, в отличие от жесткого кодирования комнат.
Майк Клак

Ответы:

13

Если вы не полностью привязаны к C #, то «более стандартный» способ сделать это - использовать один из множества существующих инструментов для создания текстовых приключений, чтобы помочь людям создать именно такую ​​игру. Эти инструменты дают вам уже функционирующий парсер, обрабатывающий на предмет смерти, сохранения / восстановления / отмены, взаимодействия с персонажами и других аналогичных стандартных функций текстового приключения. В настоящее время наиболее популярными системами авторинга являются Inform и TADS (хотя есть и полдюжины других доступных)

Inform может компилироваться в большинство наборов инструкций виртуальной машины Z Machine, используемых в играх Infocom, или в более поздние наборы инструкций виртуальной машины glulx. С другой стороны, TADS компилируется в собственный код виртуальной машины.

Любой тип двоичного кода может быть запущен большинством современных интерактивных игровых интерпретаторов (в старые времена вам часто требовались отдельные переводчики для игр TADS от игр ZMachine от игр glulx. Но, к счастью, те дни в основном закончились.) Переводчики доступны только для о любой платформе, которую вы хотите; Mac / PC / Linux / BSD / IOS / Android / Kindle / браузер / и т.д.. Итак, вы уже хорошо кроссплатформенны и по-настоящему заботитесь о них.

Для большинства платформ в настоящее время рекомендуется использовать интерпретатор Gargoyle , но есть множество других, поэтому не стесняйтесь экспериментировать.

К кодированию в Inform (особенно в последней версии) требуется немного времени, чтобы привыкнуть, так как он больше ориентирован на авторов, чем на инженеров, и поэтому его синтаксис выглядит странно и почти разговорно. В синтаксисе Inform 7 ваш пример будет выглядеть так:

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

Принимая во внимание, что TADS больше похож на традиционный язык программирования, и та же самая игра в TADS выглядит так:

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

Обе системы находятся в свободном доступе, очень часто используются и имеют большое количество учебной документации (доступно по ссылкам, которые я дал выше), поэтому стоит проверить обе из них и выбрать ту, которая вам больше нравится.

Обратите внимание, что две системы имеют слегка различающиеся стандартные поведения (хотя обе могут быть изменены). Вот снимок экрана с игрой, собранной из источника Inform:

Сообщить скриншот

И вот одна из игр, в которые играют (внутри терминала - типографика может быть намного лучше, чем эта), собранная из источника Tads:

Скриншот TADS3

Интересные моменты, на которые следует обратить внимание: TADS по умолчанию отображает «счет» в правом верхнем углу (но вы можете отключить его), а Inform - нет (но вы можете включить его). По умолчанию Inform сообщит вам открытые / закрытые состояния предметов в описании комнаты, а Tads - нет. Тэдс склонен автоматически предпринимать действия для вас, чтобы выполнять команды игрока (если вы не говорите, что нет), в то время как Информ не склонен (если вы не говорите это).

Любой из них может быть использован для создания игр любого типа (поскольку они оба легко настраиваются), но Inform более ориентирован на создание интерактивной художественной литературы в современном стиле (часто с минимальными головоломками и большим количеством повествовательных стилей), где TADS более структурирован. к созданию текстовых приключений в старом стиле (часто сильно сосредоточенных на головоломках и строгом определении механики модели мира игры).

Тревор Пауэлл
источник
это очень круто и информативно, но ИМО не отвечает на вопрос. Я собирался задать в основном этот же вопрос. Я хотел бы узнать больше о том, является ли этот XML допустимым подходом или есть ли какие-либо подводные камни или недостатки, которые он может иметь.
DLeh
1
@DLeh Вопрос был: «Я хотел бы знать, есть ли у этого метода какие-либо недостатки, и есть ли« лучший »или более стандартный способ сделать это». Этот ответ обеспечивает лучший и более стандартный способ делаю это .
Тревор Пауэлл
Но так как вы спросили о «подводных камнях и слабостях»: реализация Inform состоит из 19 строк. Пример TADS имеет длину 40 строк. Реализация XML требует 126 строк (и была бы еще длиннее, если бы она была завернута в слова в 80 столбцах и содержала пробел для удобочитаемости, как это делают реализации Inform и TADS).
Тревор Пауэлл
В дополнение к тому, что примеры Inform и TADS намного короче, они поддерживают больше функций. Например, в обоих из них вы можете положить нож в шкафы, что вообще не поддерживается в версии XML.
Тревор Пауэлл
1
Стоит также отметить, что в версии XML содержимое шкафов включается в описание шкафов. То есть есть жестко закодированное сообщение о том, что печатать при открытии или просмотре (открытых) шкафов, которое сообщает вам, что внутри есть батарейки. Но что, если плеер уже забрал батарейки? Версия XML скажет вам, что внутри есть батареи (потому что это единственная строка, доступная для отображения), а версии Inform и TADS сообщат, что шкафы пусты.
Тревор Пауэлл