- PVSM.RU - https://www.pvsm.ru -
Совсем недавно я опубликовал пост о моем небольшом проекте tengine [1]. Для меня довольно неожиданным было то, что многие проявили интерес к его идеям и наработкам. А раз есть интерес – это повод продолжить публикации.
Предлагаемая вам статься является туториалом по созданию небольшой игры. Необходимость в нем очевидна: идеологически, создать что-либо в 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». Она была выбрана ввиду своей бесплатности и легкости в освоении, находится в папке «tenginetoolsBMFont». Подробнее об утилите описано на сайте www.angelcode.com/products/bmfont [2], но вкратце, создание шрифта состоит из нескольких шагов:
Создадим текстовое сообщение «Игра окончена»: «Проект->Текстовый редактор», переключаемся на вкладку «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». После этого запускаем «Файл->Сохранить карту(ы)» и указываем папку «assetsdata». Теперь все готово для работы с tengine, осталось только сконвертировать ресурсы.
Создадим в корневом каталоге нашего проекта пустой файл «make_res_bmp.bat» с таким содержимым:
for %%i in (rawres*.png) do ....toolsbmpcvtr.exe %%i -5551 -2n -oassets/data
copy rawresarial_28.fnt assetsdata
copy rawressystem.fnt assetsdata
copy rawres*.wav assetsdata
pause
Мы конвертим все *.png файлы в формат r5g5b5a1, автоматически устанавливаем все размеры текстурам, кратные 2^n и копируем их в «assets/data» папку, затем копируем файлы шрифтов и звуков в ту же папку. Обратите внимание на то, что в 32bpp ресурсе (arial_28_0.png) при конвертации в формат 5551 создалась дополнительные данные с информацией о альфа-канале, таким образом, даже при 5551 формате полупрозрачность не теряется. Подробнее о параметрах утилиты «bmpcvtr.exe» можно узнать, запустив ее без входных параметров. Запускаем файл «make_res_bmp.bat».
Теперь осталось только написать логику игры и скомпилить проект. Смотрите исходники, дополнительная информация находится в «tenginesrctenginemanual»
Все исходники данной статьи лежат в репозитории tengine [3] tengine/samples/space_invaders [4]
Бинарник готовой игры space_invaders_demo1.zip [5]
Автор: pascualle
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/34818
Ссылки в тексте:
[1] tengine: http://habrahabr.ru/post/179839/
[2] www.angelcode.com/products/bmfont: http://www.angelcode.com/products/bmfont
[3] репозитории tengine: https://bitbucket.org/pascualle/tengine
[4] tengine/samples/space_invaders: https://bitbucket.org/pascualle/tengine/src/9bdb4821cbfcfa73e3777d9bfddf99caa465d77a/samples/space_invaders?at=master
[5] space_invaders_demo1.zip: https://bitbucket.org/pascualle/tengine/downloads/space_invaders_demo1.zip
[6] Источник: http://habrahabr.ru/post/180443/
Нажмите здесь для печати.