Игра по мотивам ролика "MLP Goes 8-Bit — Save Equestria from Lord Tirek!!"

+131
в блоге Игры
Приветствую всех!

Недавно Hasbro выпустили ролик, посвященный 35-летию франшизе MLP стилизованный под 8-битную игру. И мне захотелось сделать из этого игру.

Коротко о том, что у меня получилось:

Подробнее под катом

На данный момент это по большей части демка, можно бегать, прыгать, собирать монетки и редактировать карту.

Управление
  • Стрелки — перемещение
  • Пробел — прыжок
  • ЛКМ — поставить блок на карту
  • ПКМ — Удалить блок
  • Клавиши 1-8 — выбор блока
  • s — сохранить карту
  • e — расширить карту
  • r — переместиться в стартовую позицию
  • Esc — выход


Ссылки на скачивание

С первопостом меня, yay!

45 комментариев

*пнул в ленту*
NFS_MONSTR
+1
Заочно ставлю плюс и пожимаю мужественную руку/копыто/крыло или что там у разработчика.
NTFS
+5
Спасибо. Надеюсь со временем получится не только реализовать всё то, что есть в видео, но и хотя бы сделать остальных персонажей играбельными
NFS_MONSTR
+1
Для начала неплохо бы музыку заиметь, а то как будто игра сломалась.
Vadiman98
+1
И смерть в яме.
Vadiman98
+1
И хотя бы невидимую стену на границе.
Vadiman98
+1
Звуки с музыкой конечно тоже будут, но геймплей и вырезание остальных спрайтов сейчас в большем приориете.
NFS_MONSTR
0
Ну ты и наркоман!
Продолжай...
Ginger_Strings
+3
Круто! Удачи с игрой!
Lyinx
+1
Сборки под GNU/Linux обе 32-разрядные.
MiniRoboDancer
+1
Упс. Не заметил, когда скрипт сборки всех версий писал. Исправил
NFS_MONSTR
0
Теперь сегфолтится.
MiniRoboDancer
+1
0_o Вот это уже реально странно. А в какой момент? Может каких-то библиотек не хватает? Я тестировал на ArchLinux x86_64
NFS_MONSTR
0
ldd гласит, что все библиотеки на месте. Падает вроде на загрузке Images/players/rd/rd_standing_0.cfg, но это не точно. Держи strace.
MiniRoboDancer
+1
Ну это правда странно. Этот файл он нормально загружает. Дальше происходит загрузка ещё пачки картинок
Кусочек strace
openat(AT_FDCWD, "Images/players/rd/rd_standing_0.cfg", O_RDONLY) = 26
read(26, "center_x=52\ncenter_y=65\nbottom_y"..., 8191) = 85
read(26, "", 8191)                      = 0
close(26)                               = 0
futex(0x7f33200bc060, FUTEX_WAKE_PRIVATE, 2147483647) = 0
openat(AT_FDCWD, "Images/players/rd/rd_standing_1.png", O_RDONLY) = 26
fstat(26, {st_mode=S_IFREG|0644, st_size=1206, ...}) = 0
lseek(26, 0, SEEK_CUR)                  = 0
lseek(26, 0, SEEK_SET)                  = 0
read(26, "\211PNG\r\n\32\n\0\0\0\rIHDR\0\0\0d\0\0\0d\10\6\0\0\0p\342\225"..., 4096) = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
lseek(26, 1206, SEEK_SET)               = 1206
close(26)     


Вот бинарник, добавил сюда немного отладочного вывода и убрал пару std::move на всякий случай
Так получится лучше локализовать место падения
NFS_MONSTR
0
Ну то же самое
Loading texture Images/bg_level_01-01.png
Loading texture successful Images/bg_level_01-01.png
Loading texture Images/start_screen_0.png
Loading texture successful Images/start_screen_0.png
Loading texture Images/start_screen_1.png
Loading texture successful Images/start_screen_1.png
Loading texture Images/player_selector_bg.png
Loading texture successful Images/player_selector_bg.png
Loading texture Images/selected_player_0.png
Loading texture successful Images/selected_player_0.png
Loading texture Images/selected_player_1.png
Loading texture successful Images/selected_player_1.png
Loading texture Images/selected_player_2.png
Loading texture successful Images/selected_player_2.png
Loading texture Images/selected_player_3.png
Loading texture successful Images/selected_player_3.png
Loading texture Images/selected_player_4.png
Loading texture successful Images/selected_player_4.png
Loading texture Images/selected_player_5.png
Loading texture successful Images/selected_player_5.png
Loading texture Images/level_intro_0.png
Loading texture successful Images/level_intro_0.png
Loading texture Images/level_intro_1.png
Loading texture successful Images/level_intro_1.png
Loading texture Images/level_intro_2.png
Loading texture successful Images/level_intro_2.png
Loading Images/players/rd/rd_standing_0.png
Creating sprite Images/players/rd/rd_standing_0.png
Loading texture Images/players/rd/rd_standing_0.png
Loading texture successful Images/players/rd/rd_standing_0.png
Loading config Images/players/rd/rd_standing_0.cfg
Ошибка сегментирования
MiniRoboDancer
+1
Не совсем. Теперь понятно что падает оно вот на этом участке кода
Спойлер
    std::cout << "Loading config " << configPath << std::endl;
    Config config;
    config.load(std::move(configPath));
    if (config.isExist("center_x") && config.isInt("center_x"))
        center.x = config.getInt("center_x");
    if (config.isExist("center_y") && config.isInt("center_y"))
        center.y = config.getInt("center_y");
    if (config.isExist("width") && config.isInt("width"))
        mWidth = config.getInt("width");
    if (config.isExist("height") && config.isInt("height"))
        mHeight = config.getInt("height");
    if (config.isInt("top_x"))
        hitbox.x = config.getInt("top_x");
    if (config.isInt("top_y"))
        hitbox.y = config.getInt("top_y");
    if (config.isInt("bottom_x"))
        hitbox.w = config.getInt("bottom_x");
    if (config.isInt("bottom_y"))
        hitbox.h = config.getInt("bottom_y");
    if (config.isInt("stand_left"))
        mStandLeft = config.getInt("stand_left");
    if (config.isInt("stand_right"))
        mStandRight = config.getInt("stand_right");
    if (config.isInt("solid"))
        mSolid = config.getInt("solid")!=0;
    std::cout << "Loading config successful " << configPath << std::endl;

Убрал и этот std::move и добавил в этот участок ещё больше вывода
бинарник
NFS_MONSTR
0
Спойлер
Line parsed ;menus
Line parsed and
Line parsed ui
Line parsed intro=Images/intro.gif
Line parsed bg_level_01-01=Images/bg_level_01-01.png
Line parsed level_intro_0=Images/level_intro_0.png
Line parsed level_intro_1=Images/level_intro_1.png
Line parsed level_intro_2=Images/level_intro_2.png
Line parsed player_selector_bg=Images/player_selector_bg.png
Line parsed selected_player_0=Images/selected_player_0.png
Line parsed selected_player_1=Images/selected_player_1.png
Line parsed selected_player_2=Images/selected_player_2.png
Line parsed selected_player_3=Images/selected_player_3.png
Line parsed selected_player_4=Images/selected_player_4.png
Line parsed selected_player_5=Images/selected_player_5.png
Line parsed start_screen_0=Images/start_screen_0.png
Line parsed start_screen_1=Images/start_screen_1.png
Line parsed ;
Line parsed ;entities
Line parsed coin_0=coin_0.png
Line parsed coin_1=coin_1.png
Line parsed coin_2=coin_2.png
Line parsed coin_3=coin_3.png
Line parsed coin_4=coin_4.png
Line parsed coin_5=coin_5.png
Line parsed ;
Line parsed ;players
Line parsed rd_jumping_0=Images/players/rd/rd_jumping_0.png
Line parsed rd_jumping_1=Images/players/rd/rd_jumping_1.png
Line parsed rd_jumping_2=Images/players/rd/rd_jumping_2.png
Line parsed rd_standing_0=Images/players/rd/rd_standing_0.png
Line parsed rd_standing_1=Images/players/rd/rd_standing_1.png
Line parsed rd_standing_2=Images/players/rd/rd_standing_2.png
Line parsed rd_walking_0=Images/players/rd/rd_walking_0.png
Line parsed rd_walking_1=Images/players/rd/rd_walking_1.png
Line parsed rd_walking_2=Images/players/rd/rd_walking_2.png
Line parsed rd_walking_3=Images/players/rd/rd_walking_3.png
Line parsed rd_walking_4=Images/players/rd/rd_walking_4.png
Line parsed ;
Line parsed ;blocks
Line parsed block_0=Images/blocks/block_0.png
Line parsed block_1=Images/blocks/block_1.png
Line parsed block_2=Images/blocks/block_2.png
Line parsed block_3=Images/blocks/block_3.png
Line parsed block_4=Images/blocks/block_4.png
Line parsed block_5=Images/blocks/block_5.png
Line parsed block_6=Images/blocks/block_6.png
Line parsed block_7=Images/blocks/block_7.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_8=Images/blocks/block_8.png
Line parsed block_9=Images/blocks/block_9.png
Line parsed useSoftware=0
Loading texture Images/bg_level_01-01.png
Loading texture successful Images/bg_level_01-01.png
Loading texture Images/start_screen_0.png
Loading texture successful Images/start_screen_0.png
Loading texture Images/start_screen_1.png
Loading texture successful Images/start_screen_1.png
Loading texture Images/player_selector_bg.png
Loading texture successful Images/player_selector_bg.png
Loading texture Images/selected_player_0.png
Loading texture successful Images/selected_player_0.png
Loading texture Images/selected_player_1.png
Loading texture successful Images/selected_player_1.png
Loading texture Images/selected_player_2.png
Loading texture successful Images/selected_player_2.png
Loading texture Images/selected_player_3.png
Loading texture successful Images/selected_player_3.png
Loading texture Images/selected_player_4.png
Loading texture successful Images/selected_player_4.png
Loading texture Images/selected_player_5.png
Loading texture successful Images/selected_player_5.png
Loading texture Images/level_intro_0.png
Loading texture successful Images/level_intro_0.png
Loading texture Images/level_intro_1.png
Loading texture successful Images/level_intro_1.png
Loading texture Images/level_intro_2.png
Loading texture successful Images/level_intro_2.png
Loading Images/players/rd/rd_standing_0.png
Creating sprite Images/players/rd/rd_standing_0.png
Loading texture Images/players/rd/rd_standing_0.png
Loading texture successful Images/players/rd/rd_standing_0.png
Loading config Images/players/rd/rd_standing_0.cfg
Config object created
Line parsed center_x=52
Line parsed center_y=65
Line parsed bottom_y=97
Line parsed top_x=6
Line parsed bottom_x=96
Line parsed stand_left=27
Line parsed stand_right=78
Config object loaded
center_x checked
center_y checked
width checked
height checked
top_x checked
Ошибка сегментирования
MiniRoboDancer
+1
Кажется понял в чём проблема
Исправленый бинарник
NFS_MONSTR
0
MiniRoboDancer
+1
Ну общими усилиями вычислили)
Скорее всего такая ситуация возникла из-за разных версий реализации стандартной библиотеки
Пойду обновлять в посте версии)
NFS_MONSTR
0
values.find(key)->second

Эхх, придётся эту вкусняшку распиливать. Ну чому в плюсах нету
?.
? Или уже есть?
MiniRoboDancer Изменён автором
0
Честно говоря я не настолько опытен в c++, до этого в основном писал на Free Pascal(после него и std::vector кажется манной небесной) и Java
NFS_MONSTR
0
Free Pascal

Да, отсутствие шаблонных методов и коллекций во FreePascal — один из самых больших минусов. Так-то он хорош, но необходимость каждый раз приводить коллекцию к типу — утомляет. Впрочем, в последних версиях (3.0 и выше) — что-то сделали, но как-то криво вышло. Посмотри, может, разберешься.
NTFS Изменён автором
+1
Да, я видел. Но проблема в том, что сейчас я пользуюсь им в основном на олимпиадах или чём-то таком и там нужно сдавать исходник, а компилируют там в лучшем случае под 2.6.4. Приходится выкручиваться)
А так, да язык хорош
NFS_MONSTR
0
guest@slax:~/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37$ gdb ./8bit_SaveEq
GNU gdb (GDB) 7.11.1
Copyright © 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-slackware-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./8bit_SaveEq...done.
(gdb) run
Starting program: /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/8bit_SaveEq
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
[New Thread 0xf78f7b40 (LWP 8594)]
[New Thread 0xf270db40 (LWP 8597)]
[New Thread 0xf1d54b40 (LWP 8598)]

Thread 1 "8bit_SaveEq" received signal SIGSEGV, Segmentation fault.
0x08055b9a in LWZReadByte ()
(gdb) bt full
#0  0x08055b9a in LWZReadByte ()
No symbol table info available.
#1  0x08055dc2 in ReadImage ()
No symbol table info available.
#2  0x08055226 in AG_LoadGIF_RW ()
No symbol table info available.
#3  0x08054924 in AG_LoadGIF ()
No symbol table info available.
#4  0x0805724d in GameGifIntro::setGif(std::string) ()
No symbol table info available.
#5  0x080571f7 in GameGifIntro::GameGifIntro(SDL_Renderer*, std::string) ()
No symbol table info available.
#6  0x0804beae in main ()
No symbol table info available.


Даже с патчем сегфолтится :/
+ я залез редактором в Coin.cpp и добавил туда #include , иначе не собиралось (обоснование: stackoverflow.com/questions/16518210/sqrt-is-not-a-member-of-std )
Andrew-R
+2
sorry, now with debug build:
<br />
Starting program: /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/8bit_SaveEq
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
[New Thread 0xf78f7b40 (LWP 13709)]
[New Thread 0xf270db40 (LWP 13711)]
[New Thread 0xf1d54b40 (LWP 13712)]

Thread 1 "8bit_SaveEq" received signal SIGSEGV, Segmentation fault.
0x0805574f in GetCode (gd=0x81b0570, code_size=12, flag=0) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:560
560                     ret |= ((gd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
(gdb) bt full
#0  0x0805574f in GetCode (gd=0x81b0570, code_size=12, flag=0) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:560
        i = 860928
        j = 4
        ret = 0
        count = -1
#1  0x08055d0b in LWZReadByte (gd=0x81b0570, flag=0, input_code_size=8) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:614
        i = 4096
        code = 4096
        incode = 0
#2  0x08055dc2 in ReadImage (gd=0x81b0570, len=764, height=720, cmapSize=256, cmap=0x81b057c, interlace=0, ignore=1)
    at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:719
        image = 0xf7eabab1
        c = 8 '\b'
        i = 135683480
        v = -11784
        xpos = 0
        ypos = 0
        pass = 0
#3  0x08055226 in AG_LoadGIF_RW (src=0x8178e20, frames=0x0, maxFrames=0) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:392
        start = 0
        buf = "\000\000\000\000ь\002Р\002\000\062\006\b\000\060щч"
        c = 44 ','
        useGlobalColormap = 1
        bitPixel = 2
        iFrame = 23
        version = "89a"
        imageSurf = 0x0
        gd = 0x81b0570
#4  0x08054924 in AG_LoadGIF (file=0x8063234 "Images/intro.gif", frames=0x0, size=0) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Lib/SDL_anigif.c:151
        n = 0
        src = 0x8178e20
#5  0x0805724d in GameGifIntro::setGif (this=0xffffd290, path=...) at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Menus/GameGifIntro.cpp:14
No locals.
#6  0x080571f7 in GameGifIntro::GameGifIntro (this=0xffffd290, renderer=0x80d17c8, path=...)
    at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/Menus/GameGifIntro.cpp:10
No locals.
#7  0x0804beae in main () at /home/guest/botva/src/NFS_MONSTR-8bit_saveeq/NFS_MONSTR-8bit_saveeq-ab3d3efc2a37/main.cpp:166
        gifIntro = {<Menu> = {_vptr.Menu = 0x8058008 <vtable for GameGifIntro+8>, stop = false, exitStatus = Menu_Ok, renderer = 0x80d17c8}, frames = 0x0, framesCount = 0, lastFrameUpdate = 0,
          animationOffset = 0, renderQuad = {x = 0, y = 0, w = 0, h = 0}, texture = 0x0}
        startScreen = {<AnimationMenu> = {<Menu> = {_vptr.Menu = 0x1, stop = 188, exitStatus = (unknown: 4158677888), renderer = 0xf7e4c568}, animation = 0x8060000, animationOffset = 134576499,
            lastAnimChange = 134576464}, <No data fields>}
        selectPlayer = {<Menu> = {_vptr.Menu = 0x80602e0 <level>, stop = 196, exitStatus = (Menu_Quit | unknown: 134541394), renderer = 0x8049f60 <std::ios_base::Init::~Init()@plt>},
          images = 0x8060335 <_ZStL8__ioinit>, selected_player = -136002164, currenti = 0, currentj = -11372, players = {{134610524, -11512, 134529280}, {1, 65535, -11432}}}
        levelIntro = warning: can't find linker symbol for virtual table for `LevelIntro' value
{<AnimationMenu> = {<Menu> = {_vptr.Menu = 0xf7ba538d <__cxa_atexit+29>, stop = 142, exitStatus = (unknown: 4160683472), renderer = 0xffffd318},
            animation = 0x80579ed <__do_global_ctors_aux+29>, animationOffset = -136035416, lastAnimChange = 134610944}, <No data fields>}
<br />
Andrew-R
+1
отбой тревоги, у меня просто gif неправильно развернулся, не до конца.
Andrew-R
+1
Упс, долго страницу не обновлял)
Но за #include <cmath> спасибо
NFS_MONSTR Изменён автором
+1
Судя по бектрейсу, сегфолт в SDL_anigif.c. Это довольно старая библиотека она используется только для гифки в интро и скорее всего я потом откажусь от неё и реализую это иначе

Я думаю на данный момент проще всего будет отключить загрузку gif в интро например вот так
NFS_MONSTR
0
Ссылка на исходник не рабочая :(
demso
0
Заработала через прокси… Интересно…
demso
0
Роскомнадзор!
demso Изменён автором
0
Вау, ты реально крут! Удачи в начинании и с отличным первопостом.
Когда игру закончишь, спрайты в свободный доступ выложишь?
KaskeT
+2
По-сути спрайты уже в свободном доступе)
Всё лежит открыто в папке с игрой
NFS_MONSTR
0
И вправду, здорово. Просто привык, что ресурсы скрыты или перекодированы. Ещё раз спасибо =D
KaskeT
+1
Хм. Прикольно!

Только просто так бегать не очень интересно…
Бонусов нет.
Делать особо нечего…
Sergey_Gris
0
А как собрать исходник? Я просто без IDE редко работаю.
Использовать make?
NTFS
0
ccmake .
в директории с исходниками (туда же закинуть Images и map.bin, window.cfg из вин-релиза — их cmake попросит
make
запускать можно прямо из директории, где собиралось.
Andrew-R
+1
Нет у меня в Windows команды ccmake. Студия есть, QtCreator есть, даже MinGW есть, а ccmake нет :-)
Ладно, попробую в CodeBlocks запустить, создав проект.
NTFS
0
Или вместо ccmake просто cmake, на мой взгляд удобнее и проще в данном случае
NFS_MONSTR
0
да, я так и делал сначала, потом смотрю — бинарник собирается без дебаг-информации — полез это дело через меню ccmake править.
Andrew-R
0
Вопрос с ЛОРа:
Мне понравилась архитектура проекта, автор, если не секрет, ты сам до этого додумался или все же есть какие то общеизвестные шаблоны про которые можно где то прочитать?
MiniRoboDancer
0
Я бы посмотрел в сторону паттернов проектирования(хотя сам я ещё толком до них не добрался). Я начинал изучать ООП по книге Д. И. Аргова по ООП(в сети скорее всего её нет), там предлагалось сделать что-то вроде интерфейсной оболочки под MS-DOS на Turbo Pascal. Многие архитектурные решения позаимствованы оттуда.
NFS_MONSTR
0
Кек, думал, чего спам-фильтр стриггерился — а оно уже запостилось, оказывается.
MiniRoboDancer Изменён автором
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
Скрыто Показать