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

640 Кб должно хватить для любых задач. (c) Билл Гейтс

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

Опубликовано
Комментарии 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

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