Это 1 глава перевода оригинального руководства по Dream Maker от разработчиков.

Остальные главы руководства и статьи о программировании на коде BYOND от любителей на русском.

Оригинальная 1 глава руководства на английском языке

Глава 1: Встречайте Dream Maker

Первый шаг к мастерству в мире сна — это умение осознать то, что ты спишь, не пробудившись при этом. Первый шаг к мастерству в мире яви — это умение забыть о реальности, не погружаясь при этом в сон. — Книга Дел, часть первая.

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

Часто для описания, очень хорошо подходит терминология ролевых игр: персонажи, управляемые человеком называются PC’s (playing characters); персонажи, управляемые компьютером называются NPC’s (Non-player characters). Виртуальный вариант человека так же называют аватаром. Игровые правила пишутся на языке DM и строго контролируется компьютером. Правила определяют какое действие может совершить ваш аватар, над чем он может совершить действие и какой эффект это действие произведёт. Так же правила определяют многие другие возможные события происходящие с течением времени.

Для полного понимания механики системы, полезно знать несколько простых терминов. Компьютерные программы, работающие через сеть, часто делятся на два типа: на клиент и на сервер. Клиент (client) – это программа, через которую игрок посылает свои команды и наблюдает за результатом их выполнения. Другими словами, клиент обрабатывает входную и выходную информацию. Сервер (server) – это программа, которая запускает саму игру и выполняет правила написанные на языке DM. Создатель игры (game-designer) пишет эти правила в третьей программе называемой компилятором (compiler). Она читает DM-программу (по другому, исходный код программиста), проверяет на наличие грамматических ошибок, создаёт более компактный и удобный для компьютера файл, состоящий из байтов или двоичных кодов. Сервер, прочитав именно этот файл, понимает как запустить игру.

Таким образом, существуют три основные программы: клиент, сервер и компилятор. Мы называем их: Dream Seeker, Dream Daemon, Dream Maker, соответственно. В целом, мы объединяем их в пакет программного обеспечения под названием BYOND, что расшифровывается как «Создай свою виртуальную мечту» (Built Your Own Net Dream) – точное описание нашей цели и как далеко это зашло от наших первоначальных планов. Но это уже другая история!

Каждое введение в язык программирования должно начинаться с похожего примера. Назовите это судьбой, неизбежностью или чистой случайностью, но скорее это волшебство, что название универсального введения является “Hello world” (Здравствуй мир). Жутко, не так ли? Это именно то, что происходит в примере - мы говорим привет нашему миру.

На языке DM это будет выглядеть как:

mob
   Login()
      world << "Hello, world!"

Если у вас уже есть опыт программирования, то скорее всего последняя строка для вас выглядит не совсем понятной. Что такое mob и почему отступы каждой строчки выглядят как лестничные ступеньки. Всему своё время. Сейчас, достаточно просто понять, что mob обозначает в игре аватар человека. Когда человек входит, сервер получает команду выдать ему сообщение «Hello, world!».

Скомпилируйте и запустите эту программу (смотрите раздел 1.1). Если всё пойдёт по плану, вы должны увидеть надпись «Hello, world!», появившуюся, как будто, по волшебству на экране Dream Seeker. Вуаля! Вы создали свой первый мир.

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

Hello World!

Первый созданный мир служит не только для введения в язык программирования DM, но также и для знакомства с редактором и компилятором Dream Maker. К счастью, система была разработана таким образом, чтобы быть лёгкой в использовании. И с помощью нескольких шагов вы отправитесь по своему пути волшебства программирования BYOND.

Dream Maker хранит группу файлов, которые в своей совокупности составляют игровой мир. Когда вы создаете новый проект, появляется единственный файл, который будет выглядеть так: "[имя вашего мира].dme". Этот файл может содержать программный код, но в целом он будет состоять из автоматически-генерируемых ссылок на другие файлы проекта. Это лучше видно на практике, поэтому хватит говорить, давайте это напишем.

1. Создадим проект «Hello», выбором строчки New environment в пункте меню Filе. Это ведёт к созданию директорию, где будет размещаться ваш проект. Создадим новую диекторию, с названием “Hello”, где будет находится environment-файл “Hello.dme”. Обратите внимание, “hello.dme” так же появился в дереве файлов (file-tree) в левой части экрана. Все environment-файлы директории будут отображаться здесь.

2. Давайте поместим код этого проекта в отдельный файл. Выберите New file из пункта меню File. Выберите Code file как тип для создаваемого файла и назовите его “Hello”. Создастся новый файл под названием “Hello.dm” В директории проекта и соответствующей пункт в дереве файлов. Флажок рядом с ним указывает, что код в “Hello.dm” будет включён в проект.

3. Теперь “Hello.dm” готов к редактировании. Введите следующий код. Убедитесь, что первая строка без отступа, вторая с отступом, а третья с двумя отступами. Для этой цели используйте клавишу Tab или пробелы.

mob
   Login()
      world << "Hello, world!" 

4. Скомпилируйте код, нажав Compile в пункте меню Build. Если есть проблемы, они будут указаны в окне, внизу экрана. Но если вы поставили отступы правильно, всё должно пройти гладко.

5. Запустите скомпилированный мир выбрав Run из пункта меню Build. Запуститься Dream Seeker, который должен поприветствовать Мир!

Рассмотрим пример “Hello World” снова. DM код говорит, что когда игрок входит в систему, должно быть показано сообщение. Мы можем сделать нечто похожее и с другими типами действий. К примеру, если игрок напечатает команду, сообщение отобразится на экране.

В языке DM, команды называются verbs. Пример команды показан в следующем примере:

mob
   verb
      smile()
         world << "[usr] grins."

Обратите внимание, отступы снова похожи на ступеньки лестницы. Зачем это сделано, будет пояснено немного позже. Сейчас же, прочтите пример сверху вниз. Снова мы определяем свойство mob (аватара игрока), однако в этом случае мы добавили verb, действие которое игрок может поручить аватару выполнить. Имя verb – “smile”. Последняя линия показывает сообщение, отображающееся, когда аватар смеётся. Обратите внимание на [usr] в сообщении, как вы могли догадаться, эта часть не будет буквально отображаться на экране, а заменится логином игрока, который инициировал команду.

Запустите этот пример. После того как вы вошли в систему, попытайтесь напечатать команду smile и нажмите Enter. Вы должны увидеть сообщение, где сказано, что ваш логин смеётся. Невероятно! Фантастика! Но играть в бога это серьезное занятие. Не позволяйте никому увидеть улыбку на вашем лице.

Для разнообразия вы можете добавить несколько команд. Вот некоторые из них:

mob
   verb
      smile()
         world << "[usr] grins."
      giggle()
         world << "[usr] giggles."
      cry()
         world << "[usr] cries \his heart out."

Теперь мы видим, что порядок ступенчатой лестницы нарушен, потому что все три команды smile, giggle, и cry имеют одинаковые отступы. В DM, отступы в начале строки служат для объединения нескольких вещей в группы. Так smile, giggle, и cry объединены в одну группу, принадлежащей mob. Каждая из этих команд имеет свое содержание с отступом под ними.

Обратите внимание на использование \his в команде cry. Этот макрос будет заменяться на соответствующее местоимение. Это может быть his, her, its или their, в зависимости от пола. DM предоставляет множество других полезных макросов, для облегчения процесса.

До сих пор ничего не было сказано о пустых скобках после команд в предыдущих примерах. Они так же были и в первом примере после Login. Это отметки определения операции. Verbs и Login это примеры процедур, которые показывают инструкции, по которым они будут исполняться. В предыдущих примерах каждая процедура состояла лишь из одной строки – указания вывести на экран сообщение. Конечно они могут быть намного сложнее.

Существуют две основные категории процедур: те что отображают действия игрока и другие. Они называются verbs и procs соответственно. К примеру, Hello World относился к процедуре proc.

Скобки после имени процедуры выполняют не только декоративную функцию. Они используются для определения параметров процедуры. Это предоставляет процедуре больше информации. Эта информация хранится в переменой, т.е. на участке памяти с именем. Для усложнения понимания, программист будет называть переменные, служащие для определения параметров процедур – аргументами. Зачем? Просто, так.

Вот вам пример процедуры с параметром, которая будет транслировать короткое сообщение на весь Мир.

mob
   verb
      say(msg as text)
         world << "[usr] says, [msg]"

В этих нескольких строках основы всемирного общения. Пользователи могут войти и начать болтать между собой, используя команду say. Попробуйте. Это будет выглядеть примерно так:

say "hello world!"
Dan says, hello world!

Самое интересное место в коде DM, где в скобках определяется переменная msg. Впрочем, она может быть названа по другому, имя переменной произвольно. Определяется она строчкой "as text", показывающим что в переменной будет храниться короткое сообщение пользователя. Это сообщение будет вставлено в финальный результат, вместо указанного выражения [msg].

До сих пор я поверхностно охватил только mobs, verbs, procs и arguments. Настало время для формального утомительно-захватывающего описания синтаксиса DM. Это займёт всего несколько сложных предложений, поэтому не волнуйтесь.

DM имеет структуру дерева. Верхняя часть называется root (корень). Различные типы виртуальных объектов (таких как mobs) являются ответвлениями от корней и в свою очередь тоже могут иметь дополнительные ответвления.

Если вы ещё не заметили, терминология дерева для кода перевёрнута с ног на голову. Конечно же как ваша файловая система на жестком диске и любые другие существующие информационные деревья. Вполне возможно, что большинство IT-специалистов никогда не видели настоящее дерево. На самом деле смысл "перевернутого" дерева заключается в том, что вы всегда можете нажать справа на стрелку вверх и оказаться в корне. Или это просто часть стандартного запутывания программистов. Вот почему я это делаю.

Пришло время для примера. Вот один интересный тип виртуальных объектов turf. Это строительный блок, для постройки карт, по которым могут ходить игроки. Предположим, вы бы хотели сделать лабиринт. Для этого потребуется два вида turf’а: floors (полы) и walls (стены). Вот как бы вы их определили:

turf
   floor
   wall

Всё что мы сделали, это сделали два новых типа объектов, являющимися ответвление от корневого turf. Терминология дерева часто используется для описания отношений между определяемыми объектами. Turf является родителем floor и wall. Двое потомков являются братьями и сёстрами друг другу. Ребёнок наследует все свойства родителя и добавляет некоторые из своих, для различия между своими братьями и сестрами. Оба, и floor и wall являются строительными блоками turf, потому что являются его производными.

Для создания лабиринта, мы должны добавить несколько свойств для floor и wall: как они будут выглядеть и можно ли пройти сквозь них. Пока мы заговорили об этом, как выглядит игрок тоже должно быть определенно. Вот как это делается:

turf
   floor
      icon = 'floor.dmi'
   wall
      icon = 'wall.dmi'
      density = 1
mob
   icon = 'player.dmi'

Несколько свойств были добавлены. Имя свойство пишется в левой части, а значение, которое оно принимает, в правой. В случае с картинками (icons), значением является имя файла записанное в одинарных кавычках. В случае с плотностью (density), значение должно быть 0 либо 1. При значение 1, объект не позволит через себя пройти другим объектам с свойством density равным 1.

Захватывающее создание карты

Для большинство программ, добавление графической поддержки, это тяжёлый труд. Однако возможности Dream Maker, делают эту задачу значительно проще. В нашем примере, мы просто нарисуем пару иконок и разместим их на карте.

1. Создайте новый проект “maze” через пункт меню New environment.

2. Создайте основной файл “maze .dm” и внесите туда код:

turf
   floor
      icon = 'floor.dmi' 
   wall
      icon = 'wall.dmi'
      density = 1
mob
   icon = 'player.dmi'

3. Создайте “floor.dmi”, выбрав пункт меню New file и в выпадающем меню нажмите Icon File. Откроется новое окно для создания пиксельных, анимационных или направленных картинок. Выберите New Pixmap из меню Graphic и используя всё своё умение художника нарисуйте картинку пола. Повторите эти шаги для wall.dmi и player.dmi.

4. С тремя нашими картинками, проект должен скомпилироваться. Проверим, нажав пункт Compile. Если все прошло гладко, вы должны увидеть свои иконки в дереве объектов в левом окне экрана. Это дерево показывает определённые объекты в вашем Мире.

5. Вы можете запустить ваш Мир, но не сможете увидеть никакую из картинок потому что мы ещё их пока не разместили на карте. Для постройки карты, снова нажмите New File и выберите Map file. Назовите как посчитаете нужным. К имени добавиться .dmm указывая что этот файл - карта.

6. Теперь самая весёлая часть! Создайте свою карту, размещая картинки из вашего дерева объектов в произвольном порядке. К примеру, постройте ряд стен, выбрав функцию Add на панели кнопок, нажмите на Wall в дереве объектов (Wall располагается в выпадающем дереве Turf), и разместите их на карте , просто нажимая левой кнопкой по ней. Для удаления используйте правую кнопку. Редактор карт имеет много возможностей, изучить из вы можете прочитав прилагающуюся документацию.

7. Скомпилируйте новый, уже графический проект и запустите в Dream Seeker. Если всё было сделано правильно, вы увидите свой проект на экране. Ваш аватар может ходить по этому полу и ударяться головой об эти стены. Не так плохо для нескольких минут работы!

Причина по которой мы не убрали floor в свойствах плотность ("density = 0"), в том что turf уже имеет по умолчанию "density = 0". Так как floor является потомком turf, он наследует все свойства родителя. Этот вид наследования свойств один из главных элементов объектно-ориентированных языков, к которым относится DM. В конечном счёте, это просто компактный способ описания связей между родственными объектами.

Перед тем как рассматривать пример, вы должны нарисовать иконки и построить из них лабиринт.

После завершения постройки карты, вы сможете скомпилировать и протестировать Мир. Когда вы зайдёте в систему, вы сможете пройтись по вашему лабиринту используя клавиши стрелок. Невероятно!

Конечно же осталась одна небольшая деталь, о которой пока никто не думал. Где же всё таки начало лабиринта? Мы никогда не задумывались, а игрок просто появляется на карте в первой возможной точке. Вот пример, как это можно исправить:

turf
   floor
      icon = 'floor.dmi'
   start
      icon = 'start.dmi'
   wall
      icon = 'wall.dmi'
      density = 1
mob
   icon = 'player.dmi'
   Login()
      loc = locate(/turf/start)

Теперь вам необходимо нарисовать ещё одну иконку start и разместить её в начале вашего лабиринта.

Команда loc, которая производит размещение игроков (mobs), входит в группу procs. Она указывает начальное местоположение mob на блоке start. Это достигается использование инструкции location(), одной из множества встроенных процедур в DM. Оно вычисляет начальное положение некоторого объекта (в данном случае на блоке start).

Обратите внимание как был указан объект /turf/start. Такая запись называется type path, из-за способа указания пути (начиная с корневого объекта, в нашем случае turf) до необходимого объекта.

Теперь представим что вы забыли разместить объект Start на карте. Что произойдёт? Инструкция locate() станет ошибочной, и игрок не будет размещен на карту и следовательно не сможет увидеть лабиринт когда зайдёт в систему. Это станет катастрофой! Было бы не плохо, вернуться на пару шагов назад и разместить где-нибудь mob на карте? Другими словами, мы должны запустить процесс входа Login по умолчанию и так же созданный нами для объекта start, на всякий случай. Вот как это сделать:

mob
   Login()
      loc = locate(/turf/start)
      ..()

Всю работу выполняет последняя строка. Запускается процедура со странным именем: две точки. Это имя DM использует для описания процедур по умолчанию, более известная как родительская или суперпроцедура. То есть процедура Login проверяет наличие на карте mob, если его нет, то размещает его на любое доступное место. Это именно то что мы хотели получить.

Теперь вы можете ощутить общее впечатление от программирование на DM. Есть ряд событий (Login один из них), которые обрабатываются процедурами. В необходимости вы можете заменить процедуру по умолчанию на свою собственную, чтобы всё работало именно как вы хотели.

Это ещё один важный момент объектно-ориентированного программирования. Каждый тип объекта может реагировать на события по разному. Так он может реагировать как его родитель по умолчанию, либо добавить дополнительные меры по необходимости.

Это введение только поверхностно охватывает DM. Теперь вы можете видеть открывшиеся для вас возможности. И в тоже время, у вас появилось множество вопросов. Держите их при себе, они станут проводником для вас к более подробному изучению языка DM.

Помощь в пути!

Ни один из языков программирования не обходится без справки. Dream Maker предоставляет её в виде поиска разделов и прилагающейся документации на английском языке. Получить доступ вы можете, нажав клавишу F1 или на пункт меню Help. Если курсор находится над словом (к примеру locate), справка автоматически найдёт раздел таким именем.