Моделируем игру с помощью Obsidian canvas
В этой статье я покажу, как мы в студии tezee.art используем в разработке бесконечные холсты Obsidian canvas. И что холсты годятся не только для обычного документирования чего-либо, а ещё и для моделирования. То есть полученный граф-документ используется как схема для дальнейшей интерпретации в коде (этот подход известен как Schema Source of Truth).
Почему Obsidian хорошо подходит для этого
- Он бесплатный и это хорошая IDE для текста. Даже без расширений и плагинов.
- С Obsidian вы сами выбираете, как хранить свою документацию, например в git. То есть облачное хранение в Obsidian это необязательная платная доп возможность.
- Умеет работать с markdown.
- А ещё имеет такой функционал, как canvas.
Контент, организованный карточками в виде графа на canvas, сильно выигрывает в наглядности по сравнению с обычными лонгридами типа wiki/confluence. Под наглядностью документации я подразумеваю её информативность и понятность, что является показателями качества. С качественной документацией мы тратим меньше усилий:
- на понимание кода других разработчиков;
- на решении проблем, связанных с ошибками;
- на передачу знаний новым членам команды.
Ванильный Obsidian уже обеспечивает комфортную работу, не требуя дополнительных настроек. Разве что можно выбрать тему: конкретно мне понравилась популярная тёмная тема obsidian_nord, с ней комфортней переключаться между IDE c кодом.
Делаем правила игры понятными для всей команды
Делать игровые проекты сложно. Настольная игра, которую мы выбрали как дебютный игровой проект, с первого взгляда не выглядит такой уж большой и сложной. Но всё же, как и любая система, требует понятной документации. Иначе разработка и поддержка игры может превратиться в хаос. И поэтому с самого начала мы были озадачены тем, как сделать хорошую документацию к игровому проекту. А конкретно, как описать правила игры и не запутаться потом в них.
В архитектуру настольной игры мы заложили простой принцип: у игры есть конечные состояния и переходы между ними. Что визуально соответствует ориентированному графу (это такой, где есть направления в виде стрелок). Именно такой мы можем изобразить на canvas. Этот принцип мы назвали мета-ребро, потому как мы используем отдельную карточку-ноду, чтобы описать «стрелку» на графе.
Чтобы лучше понять принцип моделирования, я приведу простой пример схемы для игры, в которой необходимо выбросить на кубике определяемое игрой число. Мы также можем добавить дополнительное описание для карточек, если это будет полезным. Раскрашивать и подписывать стрелки необязательно, но это может помочь в восприятии схемы.
Таким образом мы можем создавать графические схемы, которые помогают нам понимать сложные взаимосвязи между различными частями игры. То есть описание правил игры это большая композиция состояний и переходов. Нам просто остаётся моделировать граф… но есть нюансы.
Нюансы возникают, когда нам необходимо ветвление. Вот простой пример ветвления:
Если продолжать усложнять такие связи, допустим, хотим добавить переход C -edge→ B
, то мы также получим лишнюю связь, которая нами не задумывалась, это C -edge→ A
. Такие связи мешают корректному трактованию схемы.
Поэтому при моделировании графа необходимо быть внимательным при прокладывании связей. А такие ситуации разрешать через дублирование.
В этом репозитории вы найдете больше примеров и код парсера, который мы используем для проверки целостности схемы правил нашей настольной игры.
Как это работает
Файлы холста сохраняются с расширением *.canvas
, но на самом деле это обычный JSON файл, который описывает тип CanvasData
. Все типы для TypeScript
можно изучить в официальном репозитории Obsidian canvas.d.ts.
Для схемы нам достаточно будет карточки типа CanvasTextData
. А чтобы отличать карточку состояния от карточки перехода, мы просто раскрашиваем их в отличительные цвета по соглашению: цветом 1
мы раскрасили состояния, а цветом 2
раскрасили переходы. И также по соглашению будем именовать карточки markdown заголовком # Title
. Такие заголовки можно хорошо рассмотреть при масштабировании и навигации по холсту.
Следующим шагом собираем граф по идентификаторам fromNode
и toNode
, информация о которых находится в свойстве CanvasData['edges']
. Для удобного программного интерфейса мы используем библиотеку graphlib
. Это хороший готовый API для графовых структур, чтобы не выдумывать что-то своё. Но можете легко заменить это на что-нибудь другое.
Что в итоге получили 💎
Мы получили граф с программным интерфейсом, через который смогли контролировать разработку. Визуализация помогает увидеть конечное множество вещей, которое нам необходимо реализовать.
Теперь у нас есть понятная документация. Её же, как структуру данных, мы используем для дальнейших операций над кодом игры. Например, часть бойлерплейт кода мы генерировали через hygen.
Программная реализация согласована через документацию, и мы в этом уверены. Таким образом, мы можем создавать сложные схемы, которые помогают нам понимать игровую логику. Это особенно полезно для новичков в команде, которые могут использовать эти схемы для поиска информации о том, как работает игра.
Мы также получили общую концепцию моделирования систем, которая может быть использована вне зависимости от языка, платформы и других факторов. Мы будем продолжать использовать canvas для моделирования различных процессов, поскольку Obsidian обладает гибкостью для кастомизации.
Заключение
На следующем изображении представлен общий вид блоков схемы, который мы разработали для нашей настольной игры. Мы не можем раскрыть детали схемы, потому что они уже являются частью наших коровых процессов и интеллектуальной собственностью студии. Однако общий вид схемы демонстрирует эффективность использования schema-first design в создании игровых проектов. Надеемся, что наш опыт моделирования поможет вам в создании своих игр и приложений.
Читайте также
Более подробно про schema-first design рассказывает Кристофер Сандовал в этой статье: Using a Schema-First Design as your Single Source of Truth