КОТ++
Прикладное программирование
Системное программирование
Программирование микроконтроллеров

Если вы дадите человеку программу, то займете его на один день. Если вы научите человека программировать, то займете его на всю жизнь. (с) Васим Латиф

Поиск по тегам

Опубликовано
Комментарии 0

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

Почему я не взял готовый движок? Во-первых, NIH, я уже писал про это (там я и сказал пару слов о движке), во-вторых, желание разобраться в работе движков. Движок был назван изначально EEngine – Egor Engine, это название я придумал ещё до момента, когда был выработан концепт движка, после того как уже был готовый движок у меня появилась небольшая капля скромности и название мне перестало нравиться. Но я его не стал менять, просто первую букву E нужно расшифровывать как-то иначе.

Концепт движка заключается в следующем: EEngine отрисовывает графику через GPU – graphics processing unit, на мобилках это видеочип, на компах это видеокарта. GPU по сути работает с 3D графикой, но мой движок 2D, а 2D для GPU это тот же 3D только без манипуляций осью Z, представьте плоский куб, у которого толщина равна 0, на передней и единственной грани рендерится (отрисовывается) текстура – спрайт.

Отрисовка производится шейдерами. Шейдеры – это программы для рендеринга, которые скармливаются GPU, они сообщают видеочипу как отрисовывать каждый пиксель. Так как GPU манипулирует только треугольниками, то в шейдере в общих словах алгоритм таков: рисуем два треугольника, два треугольника это по сути прямоугольник, потом берём текстуру и натягиваем поверх нарисованного треугольника – так мы получим отрисованный 2D спрайт. То есть каждый графический объект является прямоугольником из двух треугольников, такая конструкция называется мешом, меш – набор треугольников определяющих форму графического объекта.

Работа движка осуществлена с помощью паттерна «Игровой цикл», в общем виде игровой цикл должен выглядеть так:

while (1)
{
	processInput(); //обработка пользовательского ввода
	update(); //обработка логики игры 
	render(); //отрисовка
}

В бесконечном цикле вызываются у корневой сцены методы processInput(), render() и update(). Общая суть паттерна игровой цикл в том, что есть бесконечный цикл, а в нём последовательно обрабатываются пользовательский ввод (processInput), отрисовка (render), просчёт логики игры (update) и просчёт физики (физику не разбираю в этой статье). О игровых паттернах очень хорошо рассказано в этой книге, как раз таки в ней я о них и узнал.

Все графические объекты являются нодой (узлом) связного списка, в итоге возможность ноды иметь дочерние объекты порождает дерево графических объектов, отрисовка выполняется обходом по дереву, у каждой ноды берётся текстура и отрисовывается по необходимым координатам шейдером. Аналогичным образом идёт вызов метода update() у объектов. И аналогичным образом реализованы сигналы и слоты у элементов UI, реализовал работу сигналов-слотов будучи вдохновлённым Qt. UI элементы это те же графические элементы, но расширены функционалом сигналов-слотов для работы с пользовательским вводом. У UI элемента достаточно подписаться на определённое событие, добавив слот. Потом когда движок породит сигнал, что событие произошло, то также через обход дерева найдётся объект, который был подписан на этот сигнал.


root – корневая нода, с неё начинается обход дерева

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

После я принялся за разработку физического движка, к сожалению работу над физическим движком я не завершил до конца. Если у меня дойдут руки, то выложу материал по физическому движку.

Технические подробности (новичкам можно пропустить абзац): движок был написан на AS3, использован для мобильных игр на Adobe AIR, например эта. Движок я не выполнил отдельной библиотекой, поэтому исходники смешаны с исходниками самой игры по ссылке, потому что разрабатывал его параллельно с написанием игры. Изначально игра была написана чисто на Flash без движков, но настал момент, что потребовалась оптимизация, для оптимизации я решил написать свой движок. Шейдеры были написаны на AGAL – Adobe Graphics Assembly Language, адобовский мини ассемблер. Бесконечный цикл у меня реализован не особо привычном образом, флеш генерирует событие ENTER_FRAME строго соотвествуя FPS и я подключил цикл к этому событию.

Теги , , , , ,
Автор

Опубликовано
Комментарии 0

Кокос на момент написания статьи не поддерживает из коробки Dragon Bones спрайты. Поэтому сначала нужно подружить кокос и драгон бонс. Для этого нужно скачать исходники Dragon Bones C++ Runtime. Нам понадобятся из этого репозитория директории: DragonBones/src/dragonBones/dragonBones, Cocos2DX_3.x/src/dragonBones/cocos2dx, 3rdParty/rapidjson. В проекте должна быть такая структура:

Ваш проект
    |-- Classes
        |-- rapidjson
            |-- ...
        |-- dragonBones
            |-- animation
            |-- armature
            |-- ...
            |-- cocos2dx
            |-- ...
    |-- Resources
        |-- ...

Далее, если проект win32, то остаётся добавить все эти файлы в проект через Добавить->Существующий элемент…

Использовать Dragon Bones спрайты в коде не сложно, допустим ваш Dragon Bones проект называется man, тогда вы должны кинуть в папку Resources файлы: man_ske.json, man_tex.json, man_tex.png (эти файлы получаются через экспорт из программы Dragon Bones).
Подгрузит анимацию и добавит её на сцену следующий код:

#include "cocos2d.h"
#include "dragonBones/cocos2dx/CCDragonBonesHeaders.h"
...
auto factory = dragonBones::CCFactory::getFactory();
factory->loadDragonBonesData("man_ske.json");
factory->loadTextureAtlasData("man_tex.json");
auto armatureDisplay = factory->buildArmatureDisplay("Armature", "man");
scene->addChild(armatureDisplay);

Проиграть анимации по названию поможет следующий код:

armatureDisplay->getAnimation()->play("idle"); //зацикленно
armatureDisplay->getAnimation()->play("hit", 1); //один раз

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

Важно: для прорисовки всех объектов в анимации в игре – каждый объект должен иметь кость. Если у какого-то объекта не будет кости, то в игре этот объект не прорисуется, хотя сама программа Dragon Bones будет отображать.

Также в используемых c++ исходниках Dragon Bones существует проблема прорисовки спрайтов, если спрайт находится на границе видимой области сцены. Эта проблема фиксится в файле CCArmatureDisplay.cpp в методе DBCCSprite::_checkVisibility. Я подробно не разбирался в алгоритме работы этого метода, только в общих чертах, мне помогло увеличение рамки у прямоугольника visiableRect, исправленный фрагмент кода из метода _checkVisibility:

visiableRect.origin.x -= wshw * 4;
visiableRect.origin.y -= wshh;
visiableRect.size.width += wshw * 8;
visiableRect.size.height += wshh * 2;

В заключение хочу сказать, что очень хорошо чувствуется бесплатность Cocos2d и Dragon Bones, в них присутствуют различные проблемы, которых вероятно нет в платных аналогах. Но что кокос, что драгон бонс не стоят на месте, развиваются, а данная публикация должна помочь разобрать некоторые проблемы, связанные с этими инструментами.

Теги , , ,
Автор

Опубликовано
Комментарии 0

Недавно достаточное количество времени промучался с собиранием кокосовского проекта под android. И так небольшое количество туториалов, статей и видео зарубежных коллег, да и эти не точны, а вероятно относятся к старым версиям, поэтому и не работают. А на русском инструкций практически нет, а которые есть в основном бесполезны. Так как проблему сборки я решил, то хочу поделиться решением. Для особо внимательных – да да я снова занимаюсь разработкой игры.

И так, я предполагаю, что проект cocos2d-x у вас уже создан и вы уже посмотрели как выглядит этот проект на windows, к слову сборка именно под windows очень простая, достаточно открыть win32 проект в Visual Studio и скомпилить. Под android не так просто, нам понадобится Android Studio. Устанавливаем через Android Studio одну из актуальных Android SDK, и ещё ставим NDK, все эти действия легко делаются в Tools->Android->SDK Manager. Добавляем в переменную среды Path путь до cmake, cmake находится в папке с Android SDK %LocalAppData%\Android\sdk\cmake\3.10.2.4988404\bin (название папки с версией вероятно у вас может быть другое, сами посмотрите какое у вас). JDK нам устанавливать не нужно, в пакете Android Studio оно уже есть.

Выбираем NDK (если возникнут какие-то проблемы, то вероятно нужны ещё другие компоненты что на скрине, но у меня они уже были установлены)

Ставим путь до cmake

Теперь нам надо исправить следующие файлы: CMakeLists.txt (лежит в корне кокос проекта) и Android.mk (лежит в proj.android/app/jni). Если у вас HelloWorld проект и больше не добавляли никаких классов, то можно пропустить этот шаг. Суть в том, что нужно добавить недостающие пути к исходникам в эти файлы. В CMakeLists.txt нужно добавить и .cpp и .h файлы. В Android.mk добавить только все .cpp файлы, а также прописать все директории в которых есть .h файлы.

Пример исправлений в файле CMakeLists.txt:

<...> - тут остальная часть файла, которую менять не надо
list(APPEND GAME_SOURCE
     Classes/AbstractGameObject.cpp     
     Classes/AppDelegate.cpp     
     Classes/ChoiceMenu.cpp     
     Classes/Contestant.cpp     
     Classes/dragonBones/animation/Animation.cpp     
     Classes/dragonBones/animation/AnimationState.cpp     
     Classes/dragonBones/animation/BaseTimelineState.cpp     
     Classes/dragonBones/animation/TimelineState.cpp     
     Classes/dragonBones/animation/WorldClock.cpp     
     Classes/dragonBones/armature/Armature.cpp     
     Classes/dragonBones/armature/Bone.cpp     
     Classes/dragonBones/armature/Constraint.cpp     
     Classes/dragonBones/armature/DeformVertices.cpp     
     Classes/dragonBones/armature/Slot.cpp     
     Classes/dragonBones/armature/TransformObject.cpp  
     <...> - тут ещё куча файлов .cpp
     )
list(APPEND GAME_HEADER
     Classes/AbstractGameObject.h
     Classes/AppDelegate.h
     Classes/ChoiceMenu.h
     Classes/Contestant.h
     Classes/dragonBones/animation/Animation.h
     Classes/dragonBones/animation/AnimationState.h
     Classes/dragonBones/animation/BaseTimelineState.h
     Classes/dragonBones/animation/IAnimatable.h
     Classes/dragonBones/animation/TimelineState.h
     Classes/dragonBones/animation/WorldClock.h
     Classes/dragonBones/armature/Armature.h
     Classes/dragonBones/armature/Bone.h
     Classes/dragonBones/armature/Constraint.h
     Classes/dragonBones/armature/DeformVertices.h
     Classes/dragonBones/armature/IArmatureProxy.h
     Classes/dragonBones/armature/Slot.h
     Classes/dragonBones/armature/TransformObject.h
     <...> - тут ещё куча файлов .h
     )
<...> - остальная часть файла, которую менять не надо

Пример исправлений в файле Android.mk:

<…> – тут остальная часть файла, которую менять не надо
LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../../Classes/AbstractGameObject.cpp \ ../../../Classes/AppDelegate.cpp \ ../../../Classes/ChoiceMenu.cpp \ ../../../Classes/Contestant.cpp \ ../../../Classes/dragonBones/animation/Animation.cpp \ ../../../Classes/dragonBones/animation/AnimationState.cpp \ ../../../Classes/dragonBones/animation/BaseTimelineState.cpp \ ../../../Classes/dragonBones/animation/TimelineState.cpp \ ../../../Classes/dragonBones/animation/WorldClock.cpp \ ../../../Classes/dragonBones/armature/Armature.cpp \ ../../../Classes/dragonBones/armature/Bone.cpp \ ../../../Classes/dragonBones/armature/Constraint.cpp \ ../../../Classes/dragonBones/armature/DeformVertices.cpp \ ../../../Classes/dragonBones/armature/Slot.cpp \ ../../../Classes/dragonBones/armature/TransformObject.cpp \ <…> – тут ещё куча файлов .cpp

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes \ $(LOCAL_PATH)/../../../dragonBones/ \ $(LOCAL_PATH)/../../../dragonBones/animation \ $(LOCAL_PATH)/../../../dragonBones/armature \ $(LOCAL_PATH)/../../../dragonBones/core \ $(LOCAL_PATH)/../../../dragonBones/events \ $(LOCAL_PATH)/../../../dragonBones/factories \ $(LOCAL_PATH)/../../../dragonBones/geom \ $(LOCAL_PATH)/../../../dragonBones/model \ $(LOCAL_PATH)/../../../dragonBones/parsers \ $(LOCAL_PATH)/../../../dragonBones/cocos2dx \ $(LOCAL_PATH)/../../../dragonBones/textures \ $(LOCAL_PATH)/../../../Classes/rapidjson \ $(LOCAL_PATH)/../../../Classes/rapidjson/error \ $(LOCAL_PATH)/../../../Classes/rapidjson/internal \ $(LOCAL_PATH)/../../../Classes/rapidjson/msinttypes \ <…> – тут ещё остальные директории
<…> – остальная часть файла, которую менять не надо

Лайфхак как добавить исходные файлы если у вас их очень много. Зайдите в cmd в папку с исходниками, наберите:

dir /B /s | find ".cpp"

Выведет список всех .cpp в проекте, осталось только подкорректировать текст автозаменой и добавить пути в CMakeLists.txt и в Android.mk.

Почти готово, теперь открываем папку proj.android в Android Studio как проект. Главное иметь достаточно места на диске, сборка съест около 2-3 гигов. Нажимаем Build->Build APK в Android Studio, ждём минут 15, после можем радоваться собранному APK. В итоге всё достаточно просто если есть инструкция.

Теги , , , ,
Автор

Опубликовано
Комментарии 0

Splinter Jump – вторая игра моего авторства. Вдохновлённый игрой Doodle Jump, а она была очень популярная почти 8 лет назад, я решил сделать свою игру с похожей механикой. Кроме паскаля я тогда ничего не знал, соответственно, и эта игра была написана на паскале, в среде PascalABC.NET. Суть игры заключается в том, чтобы прыгать по платформам и добраться до верха и найти телевизор. На уровне разбросаны сыр и напитки. Сыр нужно собирать для зарабатывания очков, напитки дают улучшенный прыжок на ограниченное время. Игра полностью завершённая, в ней реализованы все задуманные уровни, в игре 10 уровней, в некоторых уровнях присутствуют боссы. Персонаж игры может атаковать, соответственно механика не ограничена только прыжками по платформам.

Через пару лет, когда изучил flash, то я решил переписать эту же игру на нём и загрузить её во ВК. Но к сожалению, ВК больше не поддерживают flash игры и они отключили мою игру. Первые четыре скрина – версия для windows, написанная на pascal, последние четыре скрина – flash версия для ВК, написанная в среде FlashDevelop, как видно по скрину была добавлена возможность поставить игру на паузу.

Исходный код pascal версии: https://bitbucket.org/Eg0r/splinter-jump




Теги , , , ,
Автор

Опубликовано
Комментарии 0

TMNT Nightmare Dreams – самая первая игра, которую я сделал, была написана ещё в школьные годы, а это примерно 8 лет назад с момента написания поста. Игра написана в среде PascalABC.NET. Для вывода графики использовались стандартные PascalABC и .NET Framework наборы классов. Для проигрывания аудио была использована библиотека Bass.NET. Именно в процессе работы над этой игрой я узнал и освоил ООП.
Игра содержит всего два уровня, 4 персонажа, 3 вида врагов, 3 удара, прыжки. Жанр игры – beat em up. До конца доделана она не была, я лишь написал основной функционал.




Теги , , ,
Автор

Опубликовано
Комментарии 0

EE Level Editor – тайловый редактор уровней. Написан на C#. Редактор был написан специально для моего 2D движка – EE.



Можно создавать и сохранять уровень в файл. Есть возможность прилипания тайлов друг к другу для удобного группирования тайлов мышкой. Вытягивание тайлов в стороны (быстрое размножение одинаковых блоков). Выделение и объединение нескольких тайлов. Показ границ объектов. Увеличение и уменьшение масштаба просмотра для удобного редактирования. Добавление тайлов в программу с помощью кнопки «Добавить тайл».

Теги , ,
Автор

Опубликовано
Комментарии 0



В этом посте хочу рассказать про одну из игр написанных мной. Игру я делал при участии в команде разработчиков VilPig. Суть игры в том, что пользователю предстоит управлять горячим Джиходом, захватывать нефтяные вышки и уничтожать вражеских для него солдат. В игре присутствует широкий арсенал оружия, а также большое разнообразие врагов. Геймплей в игре бесконечный.

Приложение разработано под Андроид с использованием технологий Adobe Air. Также в игра построена на базе моего движка, о котором можно прочитать тут. Все аспекты этого «секретного» движка можно будет узнать в следующих статьях.

Ссылка: https://play.google.com/store/apps/details?id=air.com.varvar.jihod

Теги , , ,
Автор