Організація рівнів / номерів у світі, заснованому на текстовому стилі 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, буфери протоколів, нестандартний бінарний формат, будь-який інший), тоді питання стає "які дані мені потрібно зберігати ", що є чимось, на що ви справді можете відповісти, залежно від ваших вимог до гри.
Тетрад

Гарна думка. Однак я бачив ігри, як раніше використовувались такі стилі, і вони виявились дуже обмежуючими. У цьому випадку потік і логіка гри досить прості, тому це може спрацювати добре і врятує мене від впровадження сценарію. Мене насамперед цікавить, чи є така фіксована структура (окремі кімнати, двері, предмети, змінні десь у файлі визначення) життєздатною чи ні.
Поліном

Намагаючись не повторювати Tetrad, але якщо ви плануєте зробити світового редактора (що я б запропонував, якщо гра буде дуже короткою), то ваш формат файлу не має ніякої різниці, оскільки ви будете працювати з ним у редактор проти жорсткого кодування номерів.
Майк Клук

Відповіді:


13

Якщо ви не повністю вподобані C #, то "більш стандартний" спосіб цього - використовувати один із багатьох інструментів створення текстових пригод, які вже існують, щоб допомогти людям зробити саме таку гру. Ці інструменти дають вам вже функціонуючий аналізатор, поводження зі смертю, збереження / відновлення / скасування, взаємодію символів та інші подібні стандартні біти функцій текстових пригод. На даний момент найпопулярнішими авторськими системами є Inform та TADS (хоча є й півдесятка інших)

Інформація може збиратись у більшу частину наборів інструкцій віртуальної машини 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 за замовчуванням відображає показник "оцінка" у верхньому правому куті (але ви можете вимкнути його), тоді як Інформувати - ні (але ви можете увімкнути його). Інфо буде за замовчуванням повідомляти вам про відкриті / закриті стани предметів в описі кімнати, Tads не буде. Tads, як правило, автоматично виконує дії для вас, щоб виконувати команди гравця (якщо ви не скажете цього не робити), де Inform прагне не робити (якщо ви цього не скажете).

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


це дуже круто і інформативно, але imo не відповідає на питання. Я збирався в основному задати це саме те саме питання. Я хотів би дізнатися більше про те, чи є цей XML правильним підходом чи чи є якісь підводні камені чи слабкі місця.
DLeh

1
@DLeh Питання було: "Я хотів би знати, чи є у цього методу падіння, і чи є" кращий "або більш стандартний спосіб зробити це" Ця відповідь дає кращі та стандартні способи робити-це .
Тревор Пауелл

Але оскільки ви запитували про «підводні камені та слабкі місця»: Реалізація Inform триває 19 рядків. Приклад TADS - 40 рядків. Реалізація XML вимагає 126 рядків (і була б навіть довшою, якби вона була оброблена словами у 80 стовпцях і містила пробіл для розбірливості, як це роблять реалізації Inform та TADS).
Тревор Пауелл

Окрім того, що вони значно коротші, приклади Inform та TADS також підтримують більше функцій. Наприклад, в обох ви можете помістити ніж у шафи, що зовсім не підтримується у версії XML.
Тревор Пауелл

1
Варто також зазначити, що версія XML випікає вміст шаф в опис шаф. Тобто, є твердо кодоване повідомлення про те, що друкувати, коли відкриваєте чи дивитесь на (відкриті) шафи, що говорить про те, що всередині є батареї. Але що робити, якщо плеєр вже взяв акумулятори? Версія XML скаже вам, що всередині є батареї (адже це єдина струна, яку вона має для відображення), тоді як версії Inform та TADS скажуть вам, що шафи порожні.
Тревор Пауелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.