Совсем недавно я опубликовал пост о моем небольшом проекте tengine. Для меня довольно неожиданным было то, что многие проявили интерес к его идеям и наработкам. А раз есть интерес – это повод продолжить публикации.
Предлагаемая вам статья является туториалом по созданию небольшой игры. Необходимость в нем очевидна: идеологически, создать что-либо в tengine без редактора уровней (MapEditor3, далее me3) фактически невозможно. Именно с помощью него ресурсы привязываются к объектам игры, генерируются файлы с константами-идентификаторами, создается сцена, звуковые схемы и т.д. И самое главное – me3 генерирует готовые бинарные файлы уровней, необходимые для работы логики tengine: файл с общими данными (o-файл), файлы с данными по каждому уровню (l[0..n]-файлы) и файлы с текстовыми данными (t[0..n]-файлы)
Для начала создадим папку space_invaders и структуру папок внутри нее:
После запуска me3, следует настроить пути для работы с ресурсами: «Файл->Настройка путей» и устанавливаем путь к папке «rawres». Затем переходим в «Файл->Настройки редактора» и устанавливаем глобальные настройки: тип графических ресурсов. В текущей версии me3 есть возможность работы только c bmp или png форматами. Если bpp < 32, цвет 0xff00ff считается прозрачным, если bpp == 32, за прозрачность отвечает альфа-канал. Установим тип ресурсов в png.
После установки глобальных настроек можно приступать к созданию сцены: «Файл->Новый проект». Теперь создаем первую сцену (карту): «Проект->Создать карту». Появляется окно с установками новой карты:
Уровень 0 создан, но я хочу остановиться на одном важном моменте. Пока карта пустая, нужно задуматься – нужны ли нам такие мелкие фрагменты карты (8х8), при таком большом экране. Скорей всего нет. Потому упростим работу рендеру и увеличим их размеры, тем самым уменьшив их количество. Для этого перейдем в меню «Фон Игры->Настройка элементов фона», установим новую ширину и высоту фрагмента в 32 пикселя, ставим галочку на «Сохранить размер карты…» и жмем «Применить» (согласен, немного неудобно и не интуитивно). Проверить, все ли нормально с размерами можно, посмотрев настройки карты: «Проект->Настройка карты».
Немного дополнительно информации о картах (сценах): tengine умеет загружать несколько карт и рисовать их одновременно (один поверх второго) на указанную плоскость отрисовки (render plane). Загруженные карты в tengine называются логическими слоями (layers). Архитектурно поддерживается до 4 независимых плоскостей отрисовки (на каждой платформе реализация плоскости отрисовки своя). На одну плоскость отрисовки можно привязать теоретически бесконечное количество логических слоев, но только один из них может быть основным (primary layer) и может отрисовывать тайлы фона, иметь объекты с подгружаемой анимацией, проигрывать музыкальные схемы (вызовы описанных функционалов в неосновных слоях либо игнорируются, или выдают assert-ошибку). Кроме этих особенностей, логические слои никак не пересекаются логикой между собою. Пример использования нескольких слоев: слой игрового меню, слой игрового интерфейса и слой самой игры делает физически удобное разделение подсистем на независимые модули.
Для начала создадим фон. Для этого нужно перейти в режим фона: нажимаем F2 (или иконку на панели с изображением фона). Появляется окно-палитра объектов фона. Ассоциировать графикой пустые ячейки палитры можно несколькими способами: поэлементно (навести курсор на нужный элемент и нажать «Enter» или дважды кликнуть мышью) или функцией «разрезать готовую картинку». Воспользуемся более легким способом: ставим курсор на любой элемент палитры, который будет являться первым элементом разрезанной картинки, выбираем слой 0 миксера (Активный слой) и нажимаем иконку с ножницами. В появившемся меню выбираем нужную картинку и нажимаем «Применить». Как результат – видим группу ячеек, ассоциированных с графическим ресурсом.
Немного о слоях миксера. Фон может состоять из множества слоев, для этого нужно установить нужное количество слоев в настройках фона: «Фон игры->Настройка элементов фона». Слои рисуются в порядке возрастания, или, другими словами: слой 1 перекрывает слой 0. Таким образом, можно добиться более интересных комбинаций тайловой карты. Установка «Активный слой: все» рисует все слои, показывая, как они будут рисоваться на карте.
Итак, палитра объектов фона готова. Переносятся на карту они очень просто: выделяем мышкой нужную область объектов, копируем (ctrl+c), ставим курсор в нужное место карты и вставляем (ctrl+v). Более того, операция копирования-вставки работает и на самой палитре, вы можете копировать и вставлять объекты в любое место палитры, вы можете копировать и вставлять тайлы фона в любом месте карты. Есть еще одна полезная функция «размножить» (или «замостить»): копируем некую область объектов фона, выделяем другую область карты (или всю карту ctlr+a) и нажимаем ctrl+alt+v, как результат – вся выделенная область будет заполнена повторяющимся фрагментом скопированной области.
Немного дополнительной информации об элементах фона: объекту фона палитры можно задать некоторые свойства. Для этого нужно создать типы свойств фона в менеджере свойств фона (меню «Фон игры->Типы свойств фона»). В свойствах можно задать логическую «проходимость» элементов, а так же присвоить некий цифровой дополнительный параметр, который можно будет использовать в игровой логике. После создания типов свойств, в палитре объектов фона можно назначить свойства, нажав «Enter» или дважды кликнуть мышью по выделенному объекту и в появившемся окошке выбрать нужный тип (выпадающий список «Тип фрагмента»). С этого момента все тайлы карты этого типа будут иметь указанные свойства (проверяется нажатием ctrl+p на выделенном тайле под курсором мышки).
Единственное условие всех этих манипуляций: режим фона должен быть активный (иконка «Режим фона» в состоянии «нажата» на панели инструментов).
Для того чтобы в игре появились звуки, нужно создать звуковою схему. Выше уже было описано, что звуковые схемы следует создавать только на картах, которые станут основными слоями. Также следует учесть, что звуковые схемы принадлежат картам, а не игре в целом: каждый уровень требует свою звуковую схему, если вы планируете один набор звуков на всю игру – копируйте и вставляете одну звуковую схему между всеми картами, которые будут уровнями игры.
Сначала переключаемся в режим объектов: нажимаем F1 (или иконку на панели с изображением объектов). В нижнем окошке палитры объектов переключаемся на вкладку «Системные», хватаем объект «SOUND SCHEME» и бросаем в любое место карты. Затем заходим в свойства объекта на карте (ctrl+p или правой кнопкой мышки вызвать контекстное меню объекта и выбрать «Свойства»). В появившемся окне добавляем звуковые файлы, даем им имена-идентификаторы и устанавливаем им параметры SFX (эффект) или BGM (фоновая музыка).
Перед созданием игровых объектов нужно создать список типов анимации и состояний. Для начала запускаем менеджер типов анимации («Проект->Типы анимации») и добавим два типа, которых нам должно хватить для нашей небольшой игры: «ANIM_ACTIVE» и» ANIM_DAMAGED». Теперь создадим типы состояния объектов. Запускаем менеджер типов состояний («Проект->Состояния») и добавляем два состояния: «STATE_ACTIVE» (на которое завязываем анимацию «ANIM_ACTIVE») и «STATE_DAMAGED» (завязываем анимацию «ANIM_DAMAGED»).
Немного дополнительной информации о состояниях: вся логика игровых объектов завернута вокруг состояний. Именно состояния задают объекту логическое (логическое, так как названия «вверх», «вниз», «вправо» и «влево» введены только для разыменования четырех вариантов направлений) направление движения, особенно, когда объект прикреплен к путевым нодам, а также задают имя анимации, которое сейчас нужно проигрывать.
Вторыми по важности параметрами после состояний для объекта являются свойства. Они создаются в менеджере свойств в виде шаблона («Проект->шаблон свойств»). Добавим два важных свойства: «PRP_ENABLE» и «PRP_SPEED». Свойств объекту можно придумать сколько угодно, но только на эти два tengine реагирует внутренней логикой. Если «PRP_ENABLE» не равняется 1, объект не рисуется и не участвует в логике игрового процесса. Свойство «PRP_SPEED» задает скорость перемещения по путевым нодам. Если эти свойства не созданы, считается, что «PRP_ENABLE» == 1, «PRP_SPEED» == 0.
Также создадим одно событие, оно нам потребуется, для определения окончания анимации смерти космического пришельца, чтобы знать момент, когда можно убирать его из сцены. Для этого запускаем менеджер событий («Проект->Типы событий») и создаем тип события «EVENT_END_ANIM_DAMAGE_INVADER».
Важно знать: добавить или убрать типы анимации, состояний, событий или свойств можно в любое время на любой стадии разработки проекта.
Вот теперь можно создать наш первый тип игрового объекта. Сначала переключаемся в режим объектов: нажимаем F1 (или иконку на панели с изображением объектов). В нижнем окошке палитры объектов переключаемся на любую вкладку «Общие» (ее можно переименовать). Правой кнопкой мыши в окне вызываем контекстное меню и выбираем пункт «Добавить объект». Пусть первый объект у нас будет космическим пришельцем.
Окно создания игрового объекта состоит из двух основных вкладок: «Общие» и «Редактор анимации».
Вкладка «Общие» содержит настройки:
Назовем объект SPACE_INVADER, установим ему состояние по умолчанию STATE_ACTIVE и перейдем во вторую вкладку, где сможем создать анимацию.
Вкладка «Редактор анимации». Самое первое, что нужно сделать – это выбрать из списка нужное имя анимации, и создать первый кадр. Выбираем анимацию «ANIM_ACTIVE», спускаемся чуть ниже поля выбора анимации к окошку кадров, правой кнопкой мыши вызываем контекстное меню и выбираем пункт «Добавить пустой кадр». Мы создали первый кадр анимации. Теперь нужно нарезать графические элементы для графической составляющей кадра. Справа от пустого кадра мы видим вспомогательное окно. Убеждаемся, что в этом окне активная вкладка «Графика» содержит активную подвкладку «Стандартная». Правой кнопкой мыши по пока еще пустому окну-палитре графических элементов вызываем контекстное меню и выбираем «Редактировать». Появилось окно редактирования графического изображения объекта. Здесь создаются (вырезаются) графические элементы, из которых будут создаваться кадры анимации. Для начала создадим новую группу, в которую мы будем собирать элементы пришельцев. Для этого, правой кнопкой мыши по окну групп графических элементов (самое левое окошко с надписью «Общие») вызываем контекстное меню и выбираем «Создать группу». Называем группу «INVADERS». Теперь делаем активной эту группу (левая кнопка мыши) и правой кнопкой мыши вызываем в группе контекстное меню, в котором выбираем «Добавить» (или нажимаем кнопку Insert). В группе появилась пустая ячейка. Делаем ее активной. Переходим в окно «Файл-источник» и выбираем файл «characters.png». После этого, в появившейся картинке выделяем область изображения пришельца первой фазы анимации (для удобства, используйте клавиши-стрелки для перемещения выделенной области, а также комбинацию ctlr+стрелки для изменения размеров выделенной области, также используйте ползунки для изменения масштаба изображения). Добавляем еще один кадр в группу «INVADERS» и выделяем область изображения пришельца второй фазы анимации. Нажимаем «Применить». Мы снова в редакторе анимации. Теперь самое время создать кадры анимации пришельца. Выделяем в палитре графических элементов нужное изображение пришельца, ставим мышку на поле кадра, вызываем правой кнопкой контекстное меню и выбираем пункт «Поставить». По аналогии с первым кадром, добавляем еще один пустой кадр и ставим второй кадр пришельца. Давайте посмотрим, что у нас получилось. Нажимаем «Старт» проигрывателя и смотрим как работает наша первая анимация. Слишком быстро меняются кадры? Выставим время для каждого кадра. Нажимаем «Стоп». Переключаемся мышкой в окошке кадров по каждому кадру и выставляем в поле «Время кадра» группы «Текущий кадр» в 200 (ms). Проверяем снова. Теперь анимация работает как надо.
Пришло время добавить в кадр немного логической составляющей: коллижн-область (зона столкновения). Она будет нужна для определения зоны попадания пули в пришельца. Важно знать, что в tengine графика объекта не принимает участие в логике вычислений столкновений или зон «видимости». Для этих нужд введены два логических параметра (эти понятия условны, так как tengine никак не оперирует с этими зонами):
Есть еще один способ определения зоны столкновения: использование дополнительной растровой карты «столкновения». Подробнее о работе с этим функционалом описано в документации (prHasAlphaCollideMap() и prGetAlphaCollideMapValue() функции).
Выбираем первый кадр анимации. Переключаем вкладку вспомогательного окна с «Графика» на «Логика». Для удобства работы, изображение графики исчезает. В данном случае нам нужно видеть изображение, чтобы обрисовать его колижн-зоной. Ставим галочку на опции «Графика и логика» (нижняя часть окна создания анимации). В вспомогательном окне ставим галочку на свойствах «рабочая область объекта», активируя тем самым ее редактирование. Вводим параметры W = 40, H = 30, потом хватаем мышкой получившийся прямоугольник и ставим его так, чтобы «пришелец» оказался внутри него (для удобства перемещения объектов можно использовать ctrl+стрелки). Копируем выделенную область (если выделение пропало, кликаем мышкой по краю прямоугольника, тем самым выделяя его) с помощью комбинации клавиш ctrl+c, переключаемся на второй кадр и вставляем (ctrl+v) колижн-зону и для этого кадра. Таким образом мы получаем анимацию космического пришельца с колиж-зоной в каждом кадре. Осталась одна мелочь: создать иконку для палитры выбора объектов. Выбираем первый кадр, вызываем контекстное меню этого кадра и выбираем опцию «Создать иконку». Вот теперь все, можно нажимать «Применить». В палитре объектов появился наш первый объект.
Выстраиваем на карте пришельцев. Для этого хватаем объект мышкой и тащим его на карту. Так как у нас пришельцев будет много, можно использовать функцию контекстного меню объекта на карте «клонировать».
Для упрощения работы с объектами в редакторе есть менеджер объектов (ctrl+o). В нем удобнее следить за количеством объектов, менять их позицию в списке отрисовки, свойства и т.д.
По аналогии создаем для пришельца анимацию смерти («ANIM_DAMAGED»). Единственное, на последнем кадре анимации в поле «Событие» выбираем из выпадающего списка значение «EVENT_END_ANIM_DAMAGE_INVADER». Также создаем объекты пушку «TURRET», базу «BASE» и ракету «MISSILE». Ставим их на карту. Причем ракет на карту ставим несколько, устанавливаем им свойства PRP_ENABLE = 0, нам они понадобятся для пула.
Немного о пулах: идеология tengine запрещает порождать объекты. Поэтому все объекты, которые планируется «создавать» в процессе игры должны находиться на карте в достаточном количестве и иметь свойство PRP_ENABLE = 0. Также пишется дополнительная логика в логике игры для использования этого пула.
Немного дополнительной информации о работе с текстами в ме3:
Текстовые поля бывают динамические и статические. Текст динамических полей можно менять из кода приложения с помощью специальных функций. Текст статических полей не изменяем, на него назначен идентификатор строки, которая автоматически меняет свое значение в зависимости от выбранного текущего языка.
Создадим еще одну карту. Мы будем использовать ее для вывода текстовых сообщений. Это будет логический слой игрового меню. «Проект->Создать карту», ставим размеры 25х19 (800х608), размеры карты – 1х1 экран. Пускай в нашей игре будут доступны два языка: русский и английский. Переходим в «Файл->Настройки редактора», выбираем вкладку «Текстовый редактор». Нажимаем на кнопку «Редактировать» под окошком доступных языков и в появившемся окошке меняем язык «DEFAULT» на «LNG_ENG», «LNG_1» на «LNG_RUS». Тут я обнаружил досадную ошибку редактора, изначально в появившемся окошке менеджера нет выбора языков. Нужно ввести в окошке поиска любую букву и удалить ее, только тогда можно будет увидеть список. Это будет исправлено в следующей версии me3. После этого нажимаем «Применить» и отмечаем галочками наши языки «LNG_ENG» и «LNG_RUS». Снова нажимаем «Применить». Теперь нужно проверить, есть ли в проекте доступные для использования шрифты. Если в папке «rawres» нет файлов с расширением «*.fnt» — нужно создать шрифт.
Немного о шрифтах: все шрифты для работы с tengine и me3 создаются отдельной утилитой «Bitmap font generator». Она была выбрана ввиду своей бесплатности и легкости в освоении, находится в папке «tengine\tools\BMFont». Подробнее об утилите описано на сайте www.angelcode.com/products/bmfont, но вкратце, создание шрифта состоит из нескольких шагов:
Создадим текстовое сообщение «Игра окончена»: «Проект->Текстовый редактор», переключаемся на вкладку «LNG_ENG», нажимаем «Создать». Называем этот текст «TXT_GAMEOVER», устанавливаем нужный шрифт, пишем текст «GAME OVER», смотрим, как текст будет выглядеть в визуализаторе. Тут же, в редакторе, можно задать выравнивание, установить цвет и размер канвы для текущего сообщения. Закрываем окно текстового редактора, переключаемся на вкладку «LNG_RUS», видим, что тут текста еще нет, нажимаем «Редактировать», пишем «ИГРА ОКОНЧЕНА». Таким образом, мы локализовали сообщение «TXT_GAMEOVER» на два языка.
Теперь создаем текстовый объект на карте. Переходим на вкладку «Системные» палитры объектов, ставим на карту объект TEXTBOX. Это будет текстовое поле для статического текста TXT_GAMEOVER. Заходим в свойства этого объекта, выбираем «Статический текст», называем его TXTBOX_GAMEOVER, нажимаем кнопку «…», выбираем нужный текст и нажимаем «Применить». Объект наследует цвет и размеры канвы текстового сообщения, но его можно изменить индивидуально для каждого объекта предлагаемыми настройками.
Создадим еще один текстовый объект для вывода fps. Заходим в его свойства, даем ему имя TXTBOX_FPS, устанавливаем пункт «динамический текст», «строк» устанавливаем в 1, «букв на строку» — 10. Шрифт устанавливаем «system», далее устанавливаем цвет фона и размеры выводимой для текса области: 64х18
Изменить текущий язык можно в «Вид->Текущий язык».
Мы создали все, что нам понадобится в игре. Пришло время генерации карт и констант для tengine. Для начала, можно в «Проект->Информация о карте» посмотреть по каждой карте какие ресурсы используются и в каком количестве. Также, тут можно узнать предупреждения о потенциальных проблемах. После этого нужно сгенерировать *.h файл с константами. Для этого запускаем «Проект->Список переменных» и сохраняем константы в папку «game» как «constants.h». После этого запускаем «Файл->Сохранить карту(ы)» и указываем папку «assets\data». Теперь все готово для работы с tengine, осталось только сконвертировать ресурсы.
Создадим в корневом каталоге нашего проекта пустой файл «make_res_bmp.bat» с таким содержимым:
for %%i in (rawres\*.png) do ..\..\tools\bmpcvtr.exe %%i -5551 -2n -oassets/data
copy rawres\arial_28.fnt assets\data\
copy rawres\system.fnt assets\data\
copy rawres\*.wav assets\data\
pause
Мы конвертим все *.png файлы в формат r5g5b5a1, автоматически устанавливаем все размеры текстурам, кратные 2^n и копируем их в «assets/data» папку, затем копируем файлы шрифтов и звуков в ту же папку. Обратите внимание на то, что в 32bpp ресурсе (arial_28_0.png) при конвертации в формат 5551 создалась дополнительные данные с информацией о альфа-канале, таким образом, даже при 5551 формате полупрозрачность не теряется. Подробнее о параметрах утилиты «bmpcvtr.exe» можно узнать, запустив ее без входных параметров. Запускаем файл «make_res_bmp.bat».
Теперь осталось только написать логику игры и скомпилить проект. Смотрите исходники, дополнительная информация находится в «tengine\src\tengine\manual»
Все исходники данной статьи лежат в репозитории tengine tengine/samples/space_invaders
Бинарник готовой игры space_invaders_demo1.zip
Предлагаемая вам статья является туториалом по созданию небольшой игры. Необходимость в нем очевидна: идеологически, создать что-либо в tengine без редактора уровней (MapEditor3, далее me3) фактически невозможно. Именно с помощью него ресурсы привязываются к объектам игры, генерируются файлы с константами-идентификаторами, создается сцена, звуковые схемы и т.д. И самое главное – me3 генерирует готовые бинарные файлы уровней, необходимые для работы логики tengine: файл с общими данными (o-файл), файлы с данными по каждому уровню (l[0..n]-файлы) и файлы с текстовыми данными (t[0..n]-файлы)
Структура папок проекта:
Для начала создадим папку space_invaders и структуру папок внутри нее:
- _win32
В этой папке находятся файлы проекта для MS VS - assets
В этой папке хранятся подготовленные для tengine ресурсы: сконвертированные утилитой bmpcvtr.exe графические ресурсы, сгенерированные me3 данные и звуковые (*.wav) файлы - game
В этой папке находятся исходный код нашей игры - mapeditor
В этой папке находится файл проекта me3. Для удобства работы, на время создание игры, в эту папку переносится файл MapEditor3.exe из «tengine\tools\editor» - rawres
В этой папке находятся не сконвертированные графические ресурсы (*.bmp или *.png), звуки, файлы шрифтов т.д.
Начало работы с me3:
После запуска me3, следует настроить пути для работы с ресурсами: «Файл->Настройка путей» и устанавливаем путь к папке «rawres». Затем переходим в «Файл->Настройки редактора» и устанавливаем глобальные настройки: тип графических ресурсов. В текущей версии me3 есть возможность работы только c bmp или png форматами. Если bpp < 32, цвет 0xff00ff считается прозрачным, если bpp == 32, за прозрачность отвечает альфа-канал. Установим тип ресурсов в png.
После установки глобальных настроек можно приступать к созданию сцены: «Файл->Новый проект». Теперь создаем первую сцену (карту): «Проект->Создать карту». Появляется окно с установками новой карты:
- Размеры экрана (в единицах фрагментов карты)
Здесь мы настраиваем размеры экрана. Величина эта абстрактная: для скроллера величина экрана большой роли не играет, но для игр-одноэкранок это важный параметр. Идея разделить карту на количество экранов была внедрена после запроса дизайнера, ему так было проще ориентироваться, создавая области игрового мира. Экраны в редакторе разделяются сеткой, но ее можно отключить («Вид->Сетка»). Фрагмент карты по умолчанию равняется 8х8 пикселей. Устанавливаем высоту 38 и ширину 50, пусть у нас игровой экран будет 800х600. - Размеры карты (в экранах)
Игра у нас планируется на один экран, но я хочу показать для демонстрации еще и функционал скроллинга карты, звезды заднего фона будут двигаться, посему карту устанавливаем: 2 экрана в высоту и один в ширину. - Количество зон
Эта настройка используется для больших карт, у которых можно включать-выключать игровые зоны. Что это такое я описал в документации tengine. У нас зоны использоваться не будут, вернее будет только одна зона.
Уровень 0 создан, но я хочу остановиться на одном важном моменте. Пока карта пустая, нужно задуматься – нужны ли нам такие мелкие фрагменты карты (8х8), при таком большом экране. Скорей всего нет. Потому упростим работу рендеру и увеличим их размеры, тем самым уменьшив их количество. Для этого перейдем в меню «Фон Игры->Настройка элементов фона», установим новую ширину и высоту фрагмента в 32 пикселя, ставим галочку на «Сохранить размер карты…» и жмем «Применить» (согласен, немного неудобно и не интуитивно). Проверить, все ли нормально с размерами можно, посмотрев настройки карты: «Проект->Настройка карты».
Немного дополнительно информации о картах (сценах): tengine умеет загружать несколько карт и рисовать их одновременно (один поверх второго) на указанную плоскость отрисовки (render plane). Загруженные карты в tengine называются логическими слоями (layers). Архитектурно поддерживается до 4 независимых плоскостей отрисовки (на каждой платформе реализация плоскости отрисовки своя). На одну плоскость отрисовки можно привязать теоретически бесконечное количество логических слоев, но только один из них может быть основным (primary layer) и может отрисовывать тайлы фона, иметь объекты с подгружаемой анимацией, проигрывать музыкальные схемы (вызовы описанных функционалов в неосновных слоях либо игнорируются, или выдают assert-ошибку). Кроме этих особенностей, логические слои никак не пересекаются логикой между собою. Пример использования нескольких слоев: слой игрового меню, слой игрового интерфейса и слой самой игры делает физически удобное разделение подсистем на независимые модули.
Работа с фоном
Для начала создадим фон. Для этого нужно перейти в режим фона: нажимаем F2 (или иконку на панели с изображением фона). Появляется окно-палитра объектов фона. Ассоциировать графикой пустые ячейки палитры можно несколькими способами: поэлементно (навести курсор на нужный элемент и нажать «Enter» или дважды кликнуть мышью) или функцией «разрезать готовую картинку». Воспользуемся более легким способом: ставим курсор на любой элемент палитры, который будет являться первым элементом разрезанной картинки, выбираем слой 0 миксера (Активный слой) и нажимаем иконку с ножницами. В появившемся меню выбираем нужную картинку и нажимаем «Применить». Как результат – видим группу ячеек, ассоциированных с графическим ресурсом.
Немного о слоях миксера. Фон может состоять из множества слоев, для этого нужно установить нужное количество слоев в настройках фона: «Фон игры->Настройка элементов фона». Слои рисуются в порядке возрастания, или, другими словами: слой 1 перекрывает слой 0. Таким образом, можно добиться более интересных комбинаций тайловой карты. Установка «Активный слой: все» рисует все слои, показывая, как они будут рисоваться на карте.
Итак, палитра объектов фона готова. Переносятся на карту они очень просто: выделяем мышкой нужную область объектов, копируем (ctrl+c), ставим курсор в нужное место карты и вставляем (ctrl+v). Более того, операция копирования-вставки работает и на самой палитре, вы можете копировать и вставлять объекты в любое место палитры, вы можете копировать и вставлять тайлы фона в любом месте карты. Есть еще одна полезная функция «размножить» (или «замостить»): копируем некую область объектов фона, выделяем другую область карты (или всю карту ctlr+a) и нажимаем ctrl+alt+v, как результат – вся выделенная область будет заполнена повторяющимся фрагментом скопированной области.
Немного дополнительной информации об элементах фона: объекту фона палитры можно задать некоторые свойства. Для этого нужно создать типы свойств фона в менеджере свойств фона (меню «Фон игры->Типы свойств фона»). В свойствах можно задать логическую «проходимость» элементов, а так же присвоить некий цифровой дополнительный параметр, который можно будет использовать в игровой логике. После создания типов свойств, в палитре объектов фона можно назначить свойства, нажав «Enter» или дважды кликнуть мышью по выделенному объекту и в появившемся окошке выбрать нужный тип (выпадающий список «Тип фрагмента»). С этого момента все тайлы карты этого типа будут иметь указанные свойства (проверяется нажатием ctrl+p на выделенном тайле под курсором мышки).
Единственное условие всех этих манипуляций: режим фона должен быть активный (иконка «Режим фона» в состоянии «нажата» на панели инструментов).
Создание звуковой схемы
Для того чтобы в игре появились звуки, нужно создать звуковою схему. Выше уже было описано, что звуковые схемы следует создавать только на картах, которые станут основными слоями. Также следует учесть, что звуковые схемы принадлежат картам, а не игре в целом: каждый уровень требует свою звуковую схему, если вы планируете один набор звуков на всю игру – копируйте и вставляете одну звуковую схему между всеми картами, которые будут уровнями игры.
Сначала переключаемся в режим объектов: нажимаем F1 (или иконку на панели с изображением объектов). В нижнем окошке палитры объектов переключаемся на вкладку «Системные», хватаем объект «SOUND SCHEME» и бросаем в любое место карты. Затем заходим в свойства объекта на карте (ctrl+p или правой кнопкой мышки вызвать контекстное меню объекта и выбрать «Свойства»). В появившемся окне добавляем звуковые файлы, даем им имена-идентификаторы и устанавливаем им параметры SFX (эффект) или BGM (фоновая музыка).
Создание игровых объектов
Перед созданием игровых объектов нужно создать список типов анимации и состояний. Для начала запускаем менеджер типов анимации («Проект->Типы анимации») и добавим два типа, которых нам должно хватить для нашей небольшой игры: «ANIM_ACTIVE» и» ANIM_DAMAGED». Теперь создадим типы состояния объектов. Запускаем менеджер типов состояний («Проект->Состояния») и добавляем два состояния: «STATE_ACTIVE» (на которое завязываем анимацию «ANIM_ACTIVE») и «STATE_DAMAGED» (завязываем анимацию «ANIM_DAMAGED»).
Немного дополнительной информации о состояниях: вся логика игровых объектов завернута вокруг состояний. Именно состояния задают объекту логическое (логическое, так как названия «вверх», «вниз», «вправо» и «влево» введены только для разыменования четырех вариантов направлений) направление движения, особенно, когда объект прикреплен к путевым нодам, а также задают имя анимации, которое сейчас нужно проигрывать.
Вторыми по важности параметрами после состояний для объекта являются свойства. Они создаются в менеджере свойств в виде шаблона («Проект->шаблон свойств»). Добавим два важных свойства: «PRP_ENABLE» и «PRP_SPEED». Свойств объекту можно придумать сколько угодно, но только на эти два tengine реагирует внутренней логикой. Если «PRP_ENABLE» не равняется 1, объект не рисуется и не участвует в логике игрового процесса. Свойство «PRP_SPEED» задает скорость перемещения по путевым нодам. Если эти свойства не созданы, считается, что «PRP_ENABLE» == 1, «PRP_SPEED» == 0.
Также создадим одно событие, оно нам потребуется, для определения окончания анимации смерти космического пришельца, чтобы знать момент, когда можно убирать его из сцены. Для этого запускаем менеджер событий («Проект->Типы событий») и создаем тип события «EVENT_END_ANIM_DAMAGE_INVADER».
Важно знать: добавить или убрать типы анимации, состояний, событий или свойств можно в любое время на любой стадии разработки проекта.
Вот теперь можно создать наш первый тип игрового объекта. Сначала переключаемся в режим объектов: нажимаем F1 (или иконку на панели с изображением объектов). В нижнем окошке палитры объектов переключаемся на любую вкладку «Общие» (ее можно переименовать). Правой кнопкой мыши в окне вызываем контекстное меню и выбираем пункт «Добавить объект». Пусть первый объект у нас будет космическим пришельцем.
Окно создания игрового объекта состоит из двух основных вкладок: «Общие» и «Редактор анимации».
Вкладка «Общие» содержит настройки:
- Поле ввода имени объекта
- Будет ли объект декорацией. Если да, то какого типа: переднего плана (рисуется всегда перед игровыми объектами игры) или заднего плана (рисуется всегда за объектами игры). Декорации не имеют свойств и не принимают участие в игровой логике.
- Использовать ли графику для этого объекта. Иногда объект нужен только для некоторой логики игрового процесса (например, только для колижн-области) и не нуждается в графическом отображении
- Игнорировать ли графические ресурсы, используемые объектом, если на карте нет ни одного экземпляра данного типа объектов. По умолчанию, при генерации данных карты, включена оптимизация, которая добавляет в список загружаемых ресурсов только ресурсы тех объектов, экземпляры которых находятся на карте. Данная опция позволяет отключить оптимизацию для определенной группы объектов.
- Редактирование значений свойств по умолчанию объектов этого типа. Каждый экземпляр объекта этого типа при установке на карту получает значения, установлены в этом шаблоне. Важно: изменение значений свойств по умолчанию не влияет на свойства объектов-экземпляров данного типа уже поставленных на карту, для принудительного изменения значений есть дополнительный функционал в выпадающем списке контекстного меню палитры объектов.
- Состояние по умолчанию устанавливает состояние, которое устанавливается экземпляру объекта, поставленному на карту.
Назовем объект SPACE_INVADER, установим ему состояние по умолчанию STATE_ACTIVE и перейдем во вторую вкладку, где сможем создать анимацию.
Вкладка «Редактор анимации». Самое первое, что нужно сделать – это выбрать из списка нужное имя анимации, и создать первый кадр. Выбираем анимацию «ANIM_ACTIVE», спускаемся чуть ниже поля выбора анимации к окошку кадров, правой кнопкой мыши вызываем контекстное меню и выбираем пункт «Добавить пустой кадр». Мы создали первый кадр анимации. Теперь нужно нарезать графические элементы для графической составляющей кадра. Справа от пустого кадра мы видим вспомогательное окно. Убеждаемся, что в этом окне активная вкладка «Графика» содержит активную подвкладку «Стандартная». Правой кнопкой мыши по пока еще пустому окну-палитре графических элементов вызываем контекстное меню и выбираем «Редактировать». Появилось окно редактирования графического изображения объекта. Здесь создаются (вырезаются) графические элементы, из которых будут создаваться кадры анимации. Для начала создадим новую группу, в которую мы будем собирать элементы пришельцев. Для этого, правой кнопкой мыши по окну групп графических элементов (самое левое окошко с надписью «Общие») вызываем контекстное меню и выбираем «Создать группу». Называем группу «INVADERS». Теперь делаем активной эту группу (левая кнопка мыши) и правой кнопкой мыши вызываем в группе контекстное меню, в котором выбираем «Добавить» (или нажимаем кнопку Insert). В группе появилась пустая ячейка. Делаем ее активной. Переходим в окно «Файл-источник» и выбираем файл «characters.png». После этого, в появившейся картинке выделяем область изображения пришельца первой фазы анимации (для удобства, используйте клавиши-стрелки для перемещения выделенной области, а также комбинацию ctlr+стрелки для изменения размеров выделенной области, также используйте ползунки для изменения масштаба изображения). Добавляем еще один кадр в группу «INVADERS» и выделяем область изображения пришельца второй фазы анимации. Нажимаем «Применить». Мы снова в редакторе анимации. Теперь самое время создать кадры анимации пришельца. Выделяем в палитре графических элементов нужное изображение пришельца, ставим мышку на поле кадра, вызываем правой кнопкой контекстное меню и выбираем пункт «Поставить». По аналогии с первым кадром, добавляем еще один пустой кадр и ставим второй кадр пришельца. Давайте посмотрим, что у нас получилось. Нажимаем «Старт» проигрывателя и смотрим как работает наша первая анимация. Слишком быстро меняются кадры? Выставим время для каждого кадра. Нажимаем «Стоп». Переключаемся мышкой в окошке кадров по каждому кадру и выставляем в поле «Время кадра» группы «Текущий кадр» в 200 (ms). Проверяем снова. Теперь анимация работает как надо.
Пришло время добавить в кадр немного логической составляющей: коллижн-область (зона столкновения). Она будет нужна для определения зоны попадания пули в пришельца. Важно знать, что в tengine графика объекта не принимает участие в логике вычислений столкновений или зон «видимости». Для этих нужд введены два логических параметра (эти понятия условны, так как tengine никак не оперирует с этими зонами):
- Рабочая зона объекта. Предполагается, что «рабочая зона объекта» будет служить в игровом процессе как зона столкновений, размеры этой области задаются в каждом кадре анимации отдельно.
- Зона видимости объекта. Предполагается, что «зона видимости объекта» принимает участие в логике взаимодействий объектов или является размерами кадра анимации. Размеры этой зоны один для всех кадров анимации.
Есть еще один способ определения зоны столкновения: использование дополнительной растровой карты «столкновения». Подробнее о работе с этим функционалом описано в документации (prHasAlphaCollideMap() и prGetAlphaCollideMapValue() функции).
Выбираем первый кадр анимации. Переключаем вкладку вспомогательного окна с «Графика» на «Логика». Для удобства работы, изображение графики исчезает. В данном случае нам нужно видеть изображение, чтобы обрисовать его колижн-зоной. Ставим галочку на опции «Графика и логика» (нижняя часть окна создания анимации). В вспомогательном окне ставим галочку на свойствах «рабочая область объекта», активируя тем самым ее редактирование. Вводим параметры W = 40, H = 30, потом хватаем мышкой получившийся прямоугольник и ставим его так, чтобы «пришелец» оказался внутри него (для удобства перемещения объектов можно использовать ctrl+стрелки). Копируем выделенную область (если выделение пропало, кликаем мышкой по краю прямоугольника, тем самым выделяя его) с помощью комбинации клавиш ctrl+c, переключаемся на второй кадр и вставляем (ctrl+v) колижн-зону и для этого кадра. Таким образом мы получаем анимацию космического пришельца с колиж-зоной в каждом кадре. Осталась одна мелочь: создать иконку для палитры выбора объектов. Выбираем первый кадр, вызываем контекстное меню этого кадра и выбираем опцию «Создать иконку». Вот теперь все, можно нажимать «Применить». В палитре объектов появился наш первый объект.
Выстраиваем на карте пришельцев. Для этого хватаем объект мышкой и тащим его на карту. Так как у нас пришельцев будет много, можно использовать функцию контекстного меню объекта на карте «клонировать».
Для упрощения работы с объектами в редакторе есть менеджер объектов (ctrl+o). В нем удобнее следить за количеством объектов, менять их позицию в списке отрисовки, свойства и т.д.
По аналогии создаем для пришельца анимацию смерти («ANIM_DAMAGED»). Единственное, на последнем кадре анимации в поле «Событие» выбираем из выпадающего списка значение «EVENT_END_ANIM_DAMAGE_INVADER». Также создаем объекты пушку «TURRET», базу «BASE» и ракету «MISSILE». Ставим их на карту. Причем ракет на карту ставим несколько, устанавливаем им свойства PRP_ENABLE = 0, нам они понадобятся для пула.
Немного о пулах: идеология tengine запрещает порождать объекты. Поэтому все объекты, которые планируется «создавать» в процессе игры должны находиться на карте в достаточном количестве и иметь свойство PRP_ENABLE = 0. Также пишется дополнительная логика в логике игры для использования этого пула.
Текстовые поля и создание шрифтов
Немного дополнительной информации о работе с текстами в ме3:
- Поддержка до 8 языков. Установить, сколько языков будет использоваться в приложении можно в вкладке настройках «Файл->Настройка редактора->вкладка Текстовый редактор». Здесь можно переименовать языки («LNG_0..n») в более удобные названия и отметить галочками какие языки принимают участие в текущем проекте. Ширина и высота выводимой области – размеры окна текстового окна по умолчанию
- Поддержка шрифтов (о создании шрифтом будет рассказано немного позже)
- Отдельная подсистема-редактор для создания текстовых сообщений
Текстовые поля бывают динамические и статические. Текст динамических полей можно менять из кода приложения с помощью специальных функций. Текст статических полей не изменяем, на него назначен идентификатор строки, которая автоматически меняет свое значение в зависимости от выбранного текущего языка.
Создадим еще одну карту. Мы будем использовать ее для вывода текстовых сообщений. Это будет логический слой игрового меню. «Проект->Создать карту», ставим размеры 25х19 (800х608), размеры карты – 1х1 экран. Пускай в нашей игре будут доступны два языка: русский и английский. Переходим в «Файл->Настройки редактора», выбираем вкладку «Текстовый редактор». Нажимаем на кнопку «Редактировать» под окошком доступных языков и в появившемся окошке меняем язык «DEFAULT» на «LNG_ENG», «LNG_1» на «LNG_RUS». Тут я обнаружил досадную ошибку редактора, изначально в появившемся окошке менеджера нет выбора языков. Нужно ввести в окошке поиска любую букву и удалить ее, только тогда можно будет увидеть список. Это будет исправлено в следующей версии me3. После этого нажимаем «Применить» и отмечаем галочками наши языки «LNG_ENG» и «LNG_RUS». Снова нажимаем «Применить». Теперь нужно проверить, есть ли в проекте доступные для использования шрифты. Если в папке «rawres» нет файлов с расширением «*.fnt» — нужно создать шрифт.
Немного о шрифтах: все шрифты для работы с tengine и me3 создаются отдельной утилитой «Bitmap font generator». Она была выбрана ввиду своей бесплатности и легкости в освоении, находится в папке «tengine\tools\BMFont». Подробнее об утилите описано на сайте www.angelcode.com/products/bmfont, но вкратце, создание шрифта состоит из нескольких шагов:
- «Options->Font settings», выбрать нужный шрифт, определить набор символов: ANSI или Unicode, установить размер. Больше никаких значений в окне настроек не менять.
- В основном окне приложения нужно отметить мышкой символы, которые будут участвовать в конечном шрифте (не забудьте символ «пробел»). Если в настройках был выбран Unicode, используйте переключение между наборов символов в правом окне. Помните, чем больше символом – тем больше будет финальный атлас с растровыми изображениями символов.
- Зайти в настройки и установить размер генерируемой текстуры, битность, предустановку альфа канала и тип данных формата fnt. Значения «Spacing» для большей оптимизации можно установить в 0, 0. Размер текстуры должен быть достаточно большой: если символы не помещаются в одну текстуру, их генерируется несколько. В свою очередь, tengine и me3 умеют работать только с одной текстурой на один шрифт, потому нужно следить за тем, чтобы все символы поместились в одну текстуру, если при генерации создается более чем одна текстура, нужно увеличить размеры. Проверить, помещаются ли символы в текстуру можно с помощью «Options->Visualize». Битность глубины цвета можно использовать как 8, так и 32. В случае 8 бит, нужно будет в любом графическом редакторе залить все пространство, которое должно быть прозрачным 0xff00ff цветом. В случае 32 битности, нужно выбрать в предустановках («Presets») установку «Outlined text with alpha». Формат данных нужно установить только в «Binary». Тип текстуры — png (внимание: если в настройках me3 выбран формат графических ресурсов «BMP», следует сконвертировать текстуру в bmp формат (32bpp) любым графическим конвертером)
- Генерация шрифта происходит вызовом «Options->Save bitmap font as..». После генерации в указанной папке должно появиться два файла: имя.fnt и имя.png.
- Опционально, для уменьшения размера графического ресурса, можно открыть сгенерированную текстуру в любом графическом редакторе и удалить пустое пространство.
Создадим текстовое сообщение «Игра окончена»: «Проект->Текстовый редактор», переключаемся на вкладку «LNG_ENG», нажимаем «Создать». Называем этот текст «TXT_GAMEOVER», устанавливаем нужный шрифт, пишем текст «GAME OVER», смотрим, как текст будет выглядеть в визуализаторе. Тут же, в редакторе, можно задать выравнивание, установить цвет и размер канвы для текущего сообщения. Закрываем окно текстового редактора, переключаемся на вкладку «LNG_RUS», видим, что тут текста еще нет, нажимаем «Редактировать», пишем «ИГРА ОКОНЧЕНА». Таким образом, мы локализовали сообщение «TXT_GAMEOVER» на два языка.
Теперь создаем текстовый объект на карте. Переходим на вкладку «Системные» палитры объектов, ставим на карту объект TEXTBOX. Это будет текстовое поле для статического текста TXT_GAMEOVER. Заходим в свойства этого объекта, выбираем «Статический текст», называем его TXTBOX_GAMEOVER, нажимаем кнопку «…», выбираем нужный текст и нажимаем «Применить». Объект наследует цвет и размеры канвы текстового сообщения, но его можно изменить индивидуально для каждого объекта предлагаемыми настройками.
Создадим еще один текстовый объект для вывода fps. Заходим в его свойства, даем ему имя TXTBOX_FPS, устанавливаем пункт «динамический текст», «строк» устанавливаем в 1, «букв на строку» — 10. Шрифт устанавливаем «system», далее устанавливаем цвет фона и размеры выводимой для текса области: 64х18
Изменить текущий язык можно в «Вид->Текущий язык».
Генерация карт игры и констант для использования в tengine
Мы создали все, что нам понадобится в игре. Пришло время генерации карт и констант для tengine. Для начала, можно в «Проект->Информация о карте» посмотреть по каждой карте какие ресурсы используются и в каком количестве. Также, тут можно узнать предупреждения о потенциальных проблемах. После этого нужно сгенерировать *.h файл с константами. Для этого запускаем «Проект->Список переменных» и сохраняем константы в папку «game» как «constants.h». После этого запускаем «Файл->Сохранить карту(ы)» и указываем папку «assets\data». Теперь все готово для работы с tengine, осталось только сконвертировать ресурсы.
Конвертация ресурсов
Создадим в корневом каталоге нашего проекта пустой файл «make_res_bmp.bat» с таким содержимым:
for %%i in (rawres\*.png) do ..\..\tools\bmpcvtr.exe %%i -5551 -2n -oassets/data
copy rawres\arial_28.fnt assets\data\
copy rawres\system.fnt assets\data\
copy rawres\*.wav assets\data\
pause
Мы конвертим все *.png файлы в формат r5g5b5a1, автоматически устанавливаем все размеры текстурам, кратные 2^n и копируем их в «assets/data» папку, затем копируем файлы шрифтов и звуков в ту же папку. Обратите внимание на то, что в 32bpp ресурсе (arial_28_0.png) при конвертации в формат 5551 создалась дополнительные данные с информацией о альфа-канале, таким образом, даже при 5551 формате полупрозрачность не теряется. Подробнее о параметрах утилиты «bmpcvtr.exe» можно узнать, запустив ее без входных параметров. Запускаем файл «make_res_bmp.bat».
Написание кода игры
Теперь осталось только написать логику игры и скомпилить проект. Смотрите исходники, дополнительная информация находится в «tengine\src\tengine\manual»
Все исходники данной статьи лежат в репозитории tengine tengine/samples/space_invaders
Бинарник готовой игры space_invaders_demo1.zip