Предисловие.
За то время что я работал в SGDK, я повстречал немало багов, и, многие меня скорее поймут. Фикс багов — самая разочаровывающая часть программирования. В этой статье я рассмотрю пару не-очевидных багов и их решение.
Какой эмулятор использовать?
Используйте BlastEm эмулятор, т.к. у него лучшая эмуляция железа сеги, среди доступных.
Я изменил структуру и теперь игра сломана.
Удалите папку out в своем SGDK проекте, и скомпилируйте заново.
Ошибка ILLEGAL INSTRUCTION !

Данная ошибка в 99% случаев связана с выходом за границы массива.
Допустим, у нас есть структура EntityMerged:
typedef struct {
bool alive;
u16 entityType;
} EntityMerged;
где, entityType хранит индекс в массиве.
Вы выделяете память под массив структуры EntityMerged, таким образом.
EntityMerged_arr = MEM_alloc(sizeof(EntityMerged)*20);
Массив EntityMerged_arr хранит мусор, поэтому нужно убедится что, до тех пор пока данный массив не заполнят нормальными данными, он не будет использоваться.
for(u16 i=0; i < 20; i++){
EntityMerged_arr[i].alive = FALSE;
EntityMerged_arr[i].entityType = 0;
}
Проблема решена.
У меня черный экран.
Причины могут быть следующими:
- Вы вошли в бесконечный цикл.
- Не хватает оперативной памяти (RAM)
что-бы узнать количество RAM, используйте эту комманду:
KLog_U1("FreeMem: ", MEM_getFree());
Утечка памяти.
Проверяйте количество RAM, с помощью комманды
KLog_U1("FreeMem: ", MEM_getFree());
Если видите что количество RAM стремительно уменьшается, то двигаемся дальше.
Высвобождайте память указателей, с помощью этой комманды:
MEM_free(curLocalVariables);
Порядок тоже важен, например в этом случае:
MEM_free(curEntityAll->EntityMerged_arr);
MEM_free(curEntityAll);
Здесь, EntityMerged_arr находится внутри curEntityAll, поэтому, нужно сначала высвободить все вложенное (EntityMerged_arr), а уже затем, избавиться от тела (curEntityAll).
И в заключение используйте:
MEM_pack();
MEM_pack — уменьшает фрагментацию памяти. На практике, вы получите больше оперативной памяти в игре.
Пример функции деаллокации:
void deallocLevel(){
//Deallocate prev entityData to avoid memory leak
MEM_free(curLocalVariables);
MEM_free(curEntityAll->EntityBulletMerged_arr);
MEM_free(curEntityAll->EntityMerged_arr);
MEM_free(curEntityAll->Trigger_arr);
MEM_free(curEntityAll);
MEM_free(bga);
MEM_free(bgb);
MEM_pack();
}
Аллокация и деаллокация во время игры — плохая идея.
Сильно, не рекомендую аллоцировать и деаллоцировать память во время игры (кроме спрайтов), единственное место где это оправдано, это загрузка уровня. Создайте лучше переменную, которая будет постоянно сидеть в RAM, а лучше, аллоцируйте её во время загрузки уровня, тогда проблем не будет.
ForceRedraw и мусорные тайлы
При использовании MAP_scrollToEx в режиме forceRedraw
if(bga) MAP_scrollToEx(bga, cameraPosition.x, cameraPosition.y, TRUE);
if(bgb) MAP_scrollToEx(bgb, cameraPosition.x, cameraPosition.y, TRUE);
Чаще используйте SYS_doVBlankProcess(), иначе получите мусорные тайлы.

Вот так, данная сцена выглядит после фикса.

SYS_doVBlankProcess();
if(bga) MAP_scrollToEx(bga, cameraPosition.x, cameraPosition.y, TRUE);
SYS_doVBlankProcess();
if(bgb) MAP_scrollToEx(bgb, cameraPosition.x, cameraPosition.y, TRUE);
SYS_doVBlankProcess();
На картинке мусорные тайлы.
Может быть, в вашей картинке слишком много уникальных тайлов, из-за чего, в VRAM сеги попросту не хватает места. Измените картинку и попробуйте заново.
Левая колонка при скролле, ведет себя странно.

Данный баг связан с режимом скролла.
VDP_setScrollingMode(HSCROLL_TILE, VSCROLL_2TILE);
Лучше, данный режим скролла не использовать, т.к. это баг самой приставки.
Заключение.
Данной статьей я хотел вас предостеречь от огромных трат по времени на поиск ошибок в коде. Надеюсь, данная информация вам окажется полезной.
Итоговый результат.
