Porting SDL C++ Game to HTML5 (Emscripten)

[Translation may be some day]

За последний год я написал простейший движок Flame Steel Engine и набор классов для игровой разработки Flame Steel Engine Game Toolkit. В данной статье я опишу как производил портирование движка и SDL игры Bad Robots на HTML 5, с использованием компилятора Emscripten.

Установка Hello World – Emscripten

Для начала нужно установить Emscripten. Простейшим вариантом оказалось использование скрипта emsdk для Linux. На официальном сайте данный тип установки называется как “Portable Emscripten SDK for Linux and OS X“. Внутри архива есть инструкция по установке с использованием скрипта. Я производил установку в директорию ~/emsdk/emsdk_portable.

После установки emscripten нужно проверить корректность работы компилятора, для этого создаем простейший hello_world.cpp и собираем его в hello_world.html с помощью команд:

source ~/emsdk/emsdk_portable/emsdk_env.sh
emcc hello_world.cpp -o hello_world.html

После компиляции в папке появится hello_world.html и вспомогательные файлы, откройте его в лучшем браузере Firefox, проверьте что все работает корректно.

Портирование кода игры

В javascript нежелательно вызывать бесконечный цикл – это приводит к зависанию браузера. На данный момент корректная стратегия – запрашивать один шаг цикла у браузера с помощью вызова window.requestAnimationFrame(callback)

В Emscripten данное обстоятельство решено с помощью вызова:

emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop);

Таким образом, нужно изменить код игры для корректного вызова метода emscripten. Для этого я сделал глобальный метод GLOBAL_fsegt_emscripten_gameLoop, в котором вызываю шаг цикла игрового контроллера. Главный игровой контроллер также вынесен в глобальную видимость:

#ifdef __EMSCRIPTEN__

void GLOBAL_fsegt_emscripten_gameLoop() {

GLOBAL_fsegt_emscripten_gameController->gameLoop();

}
#endif

Также для обработки специфических для Emscripten моментов, нужно использовать макрос __EMSCRIPTEN__.

Ресурсы и оптимизация

Emscripten поддерживает ресурсы и сборку с оптимизацией.

Для добавления изображений, музыки и прочего, положите все файлы в одну папку, например data. Далее в скрипт сборки добавьте:

emcc <файлы для сборки> –use-preload-plugins –preload-file data

Флаг –use-preload-plugins включает красивый прелоадер в углу экрана, –preload-file добавляет указанный ресурс в файл <имя проекта>.data
Код постоянно останавливался с ошибками доступа к ресурсам, пока я не включил оба этих флага. Также стоит заметить что для корректного доступа к ресурсам, желательно запускать игру на https (возможно и http) сервере, или отключить защиту локального доступа к файлам в вашем браузере.

Для включения оптимизации добавьте флаги:

-s TOTAL_MEMORY=67108864 -O3 -ffast-math

TOTAL_MEMORY – оперативная память в байтах(?) необходимая для корректной работы игры. Вы можете использовать флаг для динамического выделения памяти, но тогда часть оптимизаций работать не будет.

Производительность

Код javascript из C++ работает гораздо медленнее, даже со включенными оптимизациями. Поэтому если ваша цель это разработка для HTML5, то приготовьтесь к ручной оптимизации алгоритмов игры, паралелльному тестированию, также к написанию javascript кода вручную в особо узких местах. Для написания javascript кода используется макрос EM_ASM. Во время реализации рейкастера на emscripten, мне удалось добиться повышения fps с 2-4 до 30 с помощью прямого использования методов canvas.drawImage, в обход обертки SDL->Canvas, что почти приравнялось к написанию всего на javascript.

Поддержка SDL

На данный момент почти не работает SDL_TTF, поэтому отрисовка шрифта для Game Score в BadRobots очень проста. SDL_Image, SDL_Mixer работают корректно, в mixer я проверил только проигрывание музыки.

Исходный код Flame Steel Engine, Flame Steel Engine Game Toolkit, игры Bad Robots:

https://github.com/demensdeum/BadRobots
https://github.com/demensdeum/FlameSteelEngine
https://github.com/demensdeum/FlameSteelEngineGameToolkit

Статья на эту тему:

https://hacks.mozilla.org/2012/04/porting-me-my-shadow-to-the-web-c-to-javascriptcanvas-via-emscripten/

You can’t fly because of your lack of wings component

Entity Component System – what the hell is that thing? It has entity, It has component, and system. But what the hell is that?

200_sCats are funny

I am developing game right now, it’s called Call Of The Death Mask, and about month ago I had a headache. Reason of my headache was the question “How I can make zombies fly?”
What to do if your game designer want to make all treasures chests in game to have teeth and attack player character? And if you ask him “Dude are you crazy?” he will replies to you with magic word “Mimic”
Mimics are fictional living creatures, that looks like ordinary things, but they can attack you.


Mimic by BenWootten on DeviantArt

At this point you probably have class called Chest and it can’t attack anyone, because it’s not belongs to enemy class hierarchy. Damn what to do?
Entity Component System gives good approach that works ideally for games. You create class called Entity, and construct every object in game by filling Enitity with Components. Component is just some property of Entity. For example in my game all zombies have:

  1. Position component (x, y, z – Vector)
  2. Sprite component (Zombie.png – image)
  3. Rotation angle component (x, y, z – Vector)
  4. Zombie AI component (to behave like zombie)

Ok, so how to make all treasure chests into mimics at some point of level. Treasure Chest will have those components in my engine:

  1. Position component (x, y, z – Vector)
  2. Sprite component (Chest.png – image)
  3. Rotation angle component (x, y, z – Vector)
  4. Item component (to give that item to player, when he will open it)

And now we just add Mimic AI component to Treasure Chest at runtime, and he will attack player at right moment. And if some magic spell can make Mimics into Treasure Chests, then we just need to remove Mimic AI component at game runtime for that Treasure Chest, or for all of them (for cool spells that applies to all game map)
What stands for System at this pattern? System handles components for every entity. For example if player character have weapon component, then UI System must get weapon component and render it on screen.

screenshot_2016-09-24_14-33-43

Weapon component must have necessary data for UI System. In my game every weapon have two components:

  1. On map sprite component (it shows if weapon dropped to the ground)
  2. Iron sight component (it shows when player get weapon)

Shotgun weapon component at map, and another in player’s character hands, one rendered by scene renderer, another by ui renderer.

Links about ECS pattern:
https://en.wikipedia.org/wiki/Entity_component_system
https://www.youtube.com/watch?v=NTWSeQtHZ9M

Flame Steel Engine Game Toolkit

Today I want to show you Flame Steel Engine Game Toolkit architecture.
Flame Steel Engine Game Toolkit allows you to create games on Flame Steel Engine platform:
flamesteelgametoolkitschematics

All classes in Flame Steel Engine is starts with FSE prefix (Flame Steel Engine), and FSEGT (Flame Steel Engine Game Toolkit) for toolkit.
Game scene, objects and game map, ui, everything is FSEObject subclass and must be placed inside FSEGTGameData class. Every FSEObject subclass must conforms to FSESerialize interface (subclass), that allows to save/load the game data with all objects.
FSEController class that allows to work with FSEObjects data. Game toolkit have basic game scene controller – FSEGTGameSceneController, you must subclass it to use your custom game scene logic.
IOSystem is instance of FSEGTIOSystem interface (subclass), that interface contains FSEGTRenderer, FSEGTInputController, FSEGTUIRenderer.
FSEGTIOSystem must implement renderer, input handling and ui rendering, based on some IO system available for current platform.
At this moment game toolkit contains SDL-based renderer, keyboard handler inside FSEGTIOSDLSystem class.

Flame Steel Engine Raycaster Demo
Flame Steel Engine Raycaster Demo

In the future plans – to create OpenGL-based io system, it will be called FSEGTIOGLSystem. If you want to create your own io system for the game toolkit, you must subclass FSEGTIOSystem and implement FSEGTRenderer, FSEGTInputController for that system.

Source code of Flame Steel Engine, toolkit, and game:
https://github.com/demensdeum/FlameSteelCallOfTheDeathMask

How to run Wasteland 2 Director’s Cut On Linux (Ubuntu)

I am proud Wasteland 2 backer. So i tried to run Wasteland 2 Director’s Cut on Ubuntu 16.04, and I want to share experience with you. There is several problems with Unity on Ubuntu, I found error in Player.log file:

Could not open file /home/demensdeum/.local/share/Steam/steamapps/common/Wasteland 2 Director's Cut/Linux/WL2_Data/resources.assets for read

Player.log shows runtime errors, this file located here:

~/.config/unity3d/inXile\ Entertainment/Wasteland\ 2\:\ Director\'s\ Cut/Player.log

To start Wasteland 2 you need to run those commands, and run game directly without Steam:

ulimit -Sn 65536
~/.local/share/Steam/steamapps/common/Wasteland\ 2\ Director\'s\ Cut/Linux/WL2

Based on support forum:
https://forums.inxile-entertainment.com/viewtopic.php?t=15505

My Retro 16-bit Experience

Sorry for Runglish.
One day I got email, with something like this text:
“Hey! we are going to start retro game jam – bitbitjam3!!! You need to create game for some retro platform (8-16 bit)!!!”
Wow! It was my childhood dream – to create game for my favourite 16-bit console – Sega Genesis.
So I tried to create game for #bitbitjam3 game-jam, and I created something:
rqr
This thing called – “Red Queen Rampage”. Story of this game “Red Queen has been captured inside deadly maze, she is going to kill everything on her way to freedom.”
You can walk, you can attack green thing with red eyes, you can open treasure chest, and you can move from scene to scene.
This is actually hello-world level project in sega genesis world. I used SGDK toolset – GCC-based Motorola 68K compiler, and sega genesis specific hardware libraries.
Now I understood that it was really tough business to make games 20-30 years ago. For example – graphics (tiles) must be splitted into 8×8 pixels pieces, and then drawed together one-by-one. Every tiles must have its own pallete, only 16 color available! Damn its very easy to be gamedev at present time.
And like in nowadays – you need to create game engine, sound engine, graphics engine for game.
You can look at playable prototype of Red Queen Rampage by using Sega Genesis emulator with this ROM:
http://demensdeum.com/games/redQueenRampageSegaGenesis/RedQueenRampage.zip
If you interested in source code:
http://demensdeum.com/games/redQueenRampageSegaGenesis/RedQueenRampageSource.zip