Pull to refresh

Comments 30

Поймал себя на мысли, что не понимаю, нужно ли в реальной жизни такое обобщение. Скорее всего борьба с таким «движком» будет стоить больше сил, чем если бы ты начинал с чистого листа.
До определённого момента это верно, но посмотрите на тот же ZoG. 2300 игр, не считая тех, что идут в поставке! Все писать с чистого листа? Можно конечно, но придётся раз за разом делать одно и то же с лёгкими (а иногда и не очень лёгкими) вариациями. Да, разработчик может использовать свои прежние наработки, но в том то и дело, что эти две тысячи с лишним игр писали не разработчики! Эти люди не имели доступа к исходному коду ZoG, пользуясь лишь его DSL. В общем, подход жизнеспособен, хоть и ориентирован, в большей степени на гиков. Такие проекты следует рассматривать не как коллекции игр, а как возможность разработки новых, людьми не имеющими доступа к исходникам. Нужно ли это? Не знаю. Я занимаюсь этим для себя.
а почему не сделать внутренний DSL?
Насколько я понимаю, это именно то, что предлагается в данной статье. Сам я, по ряду соображений, решил (пока) делать внешний DSL.
По существующим продуктам: ZoG — внешний DSL, Axiom — можно сказать внутренний.
В данной статье — внешний

embedded (or internal) domain-specific languages, implemented as libraries which exploit the syntax of their host general purpose language or a subset thereof, while adding domain-specific language elements (data types, routines, methods, macros etc.).
В личной переписке, Vitter предлагал мне использовать внутренний DSL на основе Хаскеля
В этом и состоит мудрость — обеспечить баланс желаний и возможностей.
Монстры игровых движков, такие как Unreal Engine 4 и Cocos2d — это всего лишь визуализаторы (+ физика объектов).
Всю логику вы пишите сами.
Единственное, эти движки предназначены для реал-таймовых игр, поэтому большое внимание уделяется событиям.
И этими движками пользуются.
UFO just landed and posted this here
я когда увидел Майнкрафт, подумал — «кому это интересно?»
А люди там компьютер (размером с небоскрёб) создают средствами самой игры: из камней и лавы ))))
Нотч уже миллионер.

И вы помните, какую следующую игру хотел сделать Нотч?
0x10c
Там планировлось создать «компьютер» внутри игры, так, что основой игры стало бы программирование космических кораблей.
Да, прототипирование новых настольных игр — это, пожалуй, самое важное применение таких проектов. Иногда даже автоматизация разработки концепций новых игр. И да, эта деятельность никогда не будет массовой и вряд ли принесёт доход.

Кстати, игры на ZRF писали даже дети, не знакомые с другими языками программирования.
Очень востребованный. Ибо среди «игроделов» (который в резюме называют себя game designer'ами) достаточно много людей которые могут придумывать правила игры и гораздо меньше тех, кто готов эти правила воплощать в законченную разработку. Им нужен внятный интерфейс с разработчиками-программистами, которые будут превращать это всё в готовый продукт (при поддержке художников и иже с ними).
Мне кажется что подобный скриптовый язык практически идеально годится на роль этой прослойки. Игроделы будут писать внутреннюю логику игры, а программисты — движок визуализации, клиент-серверный обмен и т.д.
Хочу напомнить, что речь идёт о довольно узком классе игр. Например для реализации арканоида или RTS такой движок вряд-ли подойдёт.
Хотя, надо отдать должное ZoG. На ней было реализовано, например вот это.
С одной стороны — довольно узкий. С другой — это могут быть всякие мини-игры, встроенные в большие проекты. Вспомните, например, игру на взлом компьютера из SystemShock2. Я не уверен полностью, т.к. наблюдаю GameDev со стороны, но мне кажется что удобный движок мог бы увеличить количество подоных мини-игр, которые, на мой взгляд, сущетсвенно добавляют антуража.
Дам ряд своих комментариев к статье:

1. Полностью согласен с тем, что термины «досочные игры» или даже «настольные игры» неудачны. Речь скорее идёт о «дискретных» играх
2. Не всегда «в один момент времени ходит один игрок». Есть игры с «кооперативным» ходом (например «Камень-ножницы-бумага»), впрочем, пока, у меня и в мыслях нет как такое можно было бы реализовать в DSL, спасибо за наводку
3. То что, в этой статье, называется «движок» я называю генератором хода. Помимо него есть описание доски (также stateless) и игровое состояние (например текущее расположение фигур), всё это вместе — «движок» в моём понимании и уже поверх него навешиваются AI и визуализаторы
4. Динамическое изменение доски — это довольно сложное решение (поскольку хочется иметь stateless описание). В ZoG поступили проще: на «убитые» поля выставляются нейтральные фигуры, препятствующие движению игроков, но возможно полноценная динамика потребуется.
5. Parsec — просто замечательная иллюстрация DSL!
6. Идея шаблонов игр интересна, спасибо
Стесняюсь спросить, слышали ли вы о GDL ( en.wikipedia.org/wiki/Game_Description_Language )?
Кроме того, ваши требования к языку довольно утопичны: <<чтобы можно было легко писать ботов и ИИ>>. Писать ботов для игры по её формальному описанию — целая наука (см., например, курс General Game Playing на Coursera). Или вы не это имели в виду?
GDL упоминался здесь, но я как то не догадался поискать на Wiki.
Спасибо за ссылку. По поводу утопичности — не обязательно писать ботов по описанию игры, достаточно, чтобы бот имел доступ к API генератора ходов и состоянию. Бот запрашивает список ходов и выбирает наилучший (для реализации минимакса придется хранить иерархию состояний).
Ну дык, сгенерировать список ходов по описанию обычно не сложно. Вот выбрать наилучший — это как раз и есть целая наука. Ведь, как правило, выбрать совсем наилучший вычислительно невозможно, тут и возникает проблема выбора стратегий, «хороших» ходов и так далее.
ZoG с этим справляется (правда не так чтобы очень хорошо). Axiom — только при наличии оценочной функции или engine на ForthScript-е (в противном случае, пытается выполнить полный поиск до цели). В общем, и та и другая работают как раз в этом ключе, но не идеально.
Есть ещё графический язык для моделирования гемплея — www.jorisdormans.nl/machinations/
Посмотрите, может оттуда ещё вдохновение почерпнёте.
Очень грамотная декомпозиция задачи, не ожидал увидеть настолько действенный подход. Спасибо за интересную статью.
Уже давно пишу игры (www.buho21.com). Разработал более-менее универсальную платформу с плагинной архитектурой, позволяющую интегрировать игры. Предложенная идея в основном правильная, хотя и не нуждается в отдельном скриптовом языке. При помощи обычного языка программирования (в моем случае Java), правильно организованного API и ООП можно достичь желаемого результата.

С точки зрения реализации игры всегда будут три компонента: GUI, модель и контроллер. Модель полностью описывает текущее состояние игры. Контроллер принимает действие пользователя, проверяет валидность, и меняет состояние игры. GUI соответственно отображает состояние и визуализирует ходы. Модель хорошо масштабируется для сети: каждый клиент всегда хранит копию текущего состояния игры, ходы передаются всем игрокам партии, контроллер каждого клиента одинаковым образом актуализирует у себя состояние игры.

Проблема начинается, когда модель игры плохо состыковывается с моделью GUI. Например, в шахматах состояние доски логично хранить ввиде матрицы клеток, где фигуры — значения в клетках. GUI использует обратную модель: обычно список визуальных компонентов фигур, которые хранят внутри свои координаты на доске. Необходимо писать достаточно нетривиальный код, связывающий эти две модели. Хороший способ избежать этого — сразу использовать модель, схожую с GUI. Например для карточных игр универсальная модель — это хранить список из всех карт колоды, с указанием, где она находится в данный момент (в колоде, на руках у пользователя, в «бите», на столе в такой то позиции, etc). Для визуализации хода достаточно лишь вычислить координаты позиции для карты и анимировать соответствующий компонент.

Скелет для контроллера настольных игр достаточно прост в первом приближении. Лучший способ описания контроллера и всей логики игры — конечный автомат (finite state machine). Есть куча библиотек на этот счет, я разработал свою. Но потом оказывается, то GUI для визуального отображения ходов (обычно с анимацией) необходима расширенная информация от контроллера о последнем изменении состояния. Например в случае шахмат — это не просто действие пользователя (какая фигура куда сходила), а был ли ход шахом, рокировкой, съеданием. Поэтому частично логику GUI контроллер частично управляет логикой GUI посредством генерации событий после изменения состояния. В других играх ход игрока может генерировать целый каскад событий. Например в игре в покер ситуация, где игрок пошел all-in (одно единственное событие игрока), открываются карты обоих игроков, затем последовательно все карты флопа, затем производится сравнение комбинаций, затем распределяется выигрыш и после этого дилится новый кон.

В следующем приближении обнаружится, что для многих игр, особенно карточных, состояние игры не одинаково для всех игроков — каждый игрок должен видеть только свои карты и карты на столе. И требуется один особый «серверный» контроллер, которому доступно состояние всех карт (если держать полное состояние на клиенте — моментально сломают). Модель игры становится асимметричной, появляются исключительно «серверные» ходы: сдать карту, бросить кубик, etc. Логика должна уметь синхронизировать состояние серверой модели с состояниеми моделей игроков.

По мере написания игр всплывает еще куча дополнительных нюансов. Обнаруживается, что многие игры помимо основного геймплея имеют раунды и таблицу очков, и хотелось бы иметь некий общий шаблон для этого. В онлайн играх очень актуально решить что делать, если пользователь отконнектился: завершить игру, продолжать играть за него машине, продолжить игру с меньшим числом игроков, etc. Также неплохо внедрить логику таймаута на ход: например делать машиной случайный ход. Для этого контроллер должен уметь гененировать всевозможные ходы для данной позиции (которые также можно использовать для валидации хода пользователя). И еще куча нюансов.

Вобщем, что я хотел сказать. Задача написания универсального движка для игр не сводится к созданию языка для описания игровой логики, а к созданию иерархии шаблонов общим функционалом. И написаны они могут быть написаны на любом языке. Для этого нужно проанализировать большое количество игр, разбить на классы (карточные, досочные, настольные). Для каждого из компонентов (GUI, контроллер и модель) выделить абстрактный функционал и написать расширяемые шаблоны. Тем не менее, для любой игры 80% времени всегда будет занимать создание GUI.
>> Вобщем, что я хотел сказать. Задача написания универсального движка для игр не сводится к созданию языка для описания игровой логики, а к созданию иерархии шаблонов общим функционалом. И написаны они могут быть написаны на любом языке.

Это только до тех пор пока в вашей игре мало логики. В своё время, давным давно, передо мной такой вопрос встал, когда я кодил французскую карточную игру Таро, примерно похоже на преферанс играемый всегда «в закрытую», тобишь «стоя». Сами по себе правила уже весьма не короткие. А когда встал вопрос о примитивном AI который хотя бы мог соблюдать простейшие правила, «Под игрока с Симака», «со второго короля не ходят, если он не марьяж». Быстро выяснилось, что написание простейшего Пролог-подобного языка на котором все эти правила задаются в декларативной форме и потом кодинг уже на нём в разы быстрее, чем пытаться что-то придумать в рамках более традиционного программирования.
Я написал несколько игр с испанской колодой. При правильном шаблонизировании описание новой игры достаточно простое, даже изменения в GUI минимальны. Также программировал покер, несколько вариантов шашек, и очень много занимался шахматами. На мой взгляд, лучший способ — это разделить логику правил и геймплей. Например, логика покера — это поиск комбинаций и операции с банком. Логику можно описывать на любом языке, хоть на хаскеле, хоть на джаваскрипте. Геймплей — это общий граф состояний игры, описывающий передачу хода между пользователями, завершение раунда, завершения игры, промежуточные состояния, etc, и обычно сильно связанный с визуализацией в GUI. Описывать его лучше через конечный автомат — в декларативной форме на порядок усложнится отладка.

AI-это отдельная тема. Любой AI состоит из функции генерации ходов и оценочной функции. Генерация ходов не представляет собой проблемы, если описан конечный автомат. А вот оценка позиции и хода представляет собой отдельную задачу, которая не имеет ничего общего с описательной частью игры. Она программируется совершенно отдельно, напр. минимаксным алгоритмом. Более того, во многих случаях для AI приходится генерировать отдельно упрощенный граф состояний (для которого не важны промежуточные состояния GUI), а иногда использовать и другую и модель данных.
Ну да, отладка требует написания своих необычных логеров, действительно было сложнее, чем в хорошем обычном коде, но проще, чем в лапшекоде, с которым часто приходится работать. Но зато типичные шаблонные ситуации, которые нужно распознать как при оценке позиции так и просто при проверке соблюдения правил, пишутся, и что важно, читаются сильно проще и быстрее. Надо будет тоже когда-нибудь статью про тот мой движок статью написать, когда время будет.

Не у всех, как у нас с вами, был случай повозиться с логическими играми. В наше время клепание интерфейсиков больше времени занимает.
Когда я играл в Дурака в детстве, то можно было и подкидывать одновременно и бить на выбор и т.п., т.е. утверждение «В один момент времени всегда ходит 1 игрок» для такого Дурака — не верно.
Конечно же, реализовать такую игру гораздо сложнее, особенно если добавить режим мультиплеера. Там уже задачи из разряда синхронизации сразу нескольких процессов, разделенные ресурсы и подобное.
При игре в «Дурака» весь этот сложный ход можно разбить на последовательность более элементарных ходов. Порядок передачи ходов будет довольно сложным, но ни одна пара элементарных ходов не будет выполняться одновременно (в отличии от игры «Камень-ножницы-бумага», в которой одновременность хода двух игроков принципиальна).
Данный конкретный пример я рассмотрел в статье.
По правилам — любой игрок может подкинуть карту.
Это можно эмулировать тем, что после каждого отбивания карты, все остальные игроки случайным образом спрашиваются — подкинуть или нет.
Качество эмуляции близко к 99%.
Но тут я согласен с тем, о чём я и говорил — любые ограничения захочется обойти. Чем их меньше, тем лучше.
Точно, если спрашивать игроков случайным образом, будет близко к живому оригиналу.
Вместо «кто первый, тот и успел» будет выбор игрока случайным образом, по-прежнему сохранится элемент такой себе хаотичности и все также можно позволить подкидывать больше положенного, чтобы потом бить на выбор.

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

Я попробовал практически все варианты Дурака из App Store, везде на данный момент реализован простой подход, когда игроки подкидывают строго по часовой стрелке.

Посмотрите на https://github.com/Ludeme/Ludii — недавно выложенный на Гитхабе исходный код активного проекта по теме с довольно длинной историей.

Sign up to leave a comment.

Articles