Предисловие.
В этой статье вы научитесь создавать шкалу прогресса, а также разберем различные способы их создания?
Спрайтовая шкала прогресса
Самое простое что можно придумать, это сделать анимацию шкалы прогресса, и вручную менять кадр этой анимации (SPR_setFrame) в зависимости от значения шкалы.
Так, кстати, это реализовано в HAMOOPIG, движке файтинга под SGDK.
Шкала на слоях BG_A, BG_B
По сути, та же спрайтовая анимация, только отдельными кадрами. Каждый кадр это ресурс Image, который рисуется на слое и выбирается, в зависимости от значения шкалы. Такой способ тоже работает (хоть и медленно), но зачем он, когда есть..
Ручное рисование тайлов на слоях.
В данном способе, мы будем рисовать каждый тайл прогресс-бара вручную.
Скачайте SGDK проект с github.
Мы будем использовать тайлсет прогресс-бара из папки res/progressTileAnim.png

Теперь, откройте src/main.c
#include <genesis.h>
#include "resources.h"
Map *bga;
void drawProgressBar(u8 plane, u16 progressBarRootIndex, u8 pal, s16 x, s16 y, u16 value){
s16 remain = value;
u16 curTileX = 0;
while(1) {
if(remain >= 8){ //Если значение >= 8
//То понятно, что тайл полностью заполнен, поэтому делаем +8 к vram индексу
VDP_setTileMapXY(plane, TILE_ATTR_FULL(pal, 15, 0, 0, progressBarRootIndex+8), x+curTileX, y);
} else { //Если последний тайл прогресс-бара
//То рисуем соотвествующий тайл и заканчиваем работу
VDP_setTileMapXY(plane, TILE_ATTR_FULL(pal, 15, 0, 0, progressBarRootIndex+remain), x+curTileX, y);
return;
}
remain -= 8;
curTileX++;
}
}
int main()
{
//Подгружаем карту, тайлсет, и палитру
u16 vramIndex = TILE_USER_INDEX;
PAL_setPalette(PAL0, pal_img.data, CPU);
VDP_loadTileSet(&tileset_img, vramIndex, DMA_QUEUE);
bga = MAP_create(&map_img, BG_A, TILE_USER_INDEX);
vramIndex += tileset_img.numTile;
MAP_scrollTo(bga, 0, 0);
//Здесь, будет находится начальный индекс VRAM для делений прогресс-бара
u16 progressBarIndex = vramIndex;
//Грузим тайлсет прогресс-бара
VDP_loadTileSet(&ts_progressTile, progressBarIndex, DMA_QUEUE);
u16 curHp = 0;
while(1){
//Функция рисования прогресс-бара
drawProgressBar(BG_A, progressBarIndex, PAL0, 0,0, curHp);
curHp++;
if(curHp > 200){
//Если curHp>200, то сбрасываем curHp, и очищаем тайлы прогресс-бара
curHp = 0;
VDP_clearTextBG(BG_A, 0,0,25);
}
SYS_doVBlankProcess();
}
return (0);
}
Т.е. мы:
- Загрузили тайлсет прогресс-бара в VRAM по индексу progressBarIndex, и, т.к. все деления в тайлсете идут подряд, от пустого до заполненного тайла
- В функции drawProgressBar рисуем тайлы функцией VDP_setTileMapXY
- Если значение прогресс-бара >8, то рисуем полный тайл, если меньше, рисуем соответствующее деление, т.е. progressBarRootIndex+remain и заканчиваем рисование.
- Данную шкалу прогресса я зациклил, чтобы она выводила значения от 0 до 200.
Подробнее я объяснил в комментариях.
По итогу, получили следующее.

Ручное рисование тайлов на спрайтах.
Для следующего примера, потребуется сконвертировать тайлы в код, с помощью Python скрипта.
Создадим функцию drawProgressBarSprite:
const progressTilesets[] = {tileSet0,tileSet1,tileSet2,tileSet3,tileSet4,tileSet5,tileSet6,tileSet7,tileSet8};
s16 remain = value;
u16 curTileX = 0;
while(1) {
if(remain >= 8){
VDP_loadTileData(progressTilesets[8], (spr->attribut & TILE_INDEX_MASK)+curTileX, 1, CPU);
} else {
VDP_loadTileData(progressTilesets[remain], (spr->attribut & TILE_INDEX_MASK)+curTileX, 1, CPU);
return;
}
remain -= 8;
curTileX++;
}
Данный код мало чем отличается от drawProgressBar, подробнее про замену тайлов спрайта, я говорил здесь.
И создать функцию очистки тайлов спрайта.
void clearTilesSprite(Sprite* spr){
const u32 cleanTileset[8] =
{
// tile 0
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
for(u16 i=0;i<8;i++){
VDP_loadTileData(cleanTileset, (spr->attribut & TILE_INDEX_MASK)+i, 1, CPU);
}
}
Т.е. заполняем первые 8 тайлов тайлсета спрайта — пустыми тайлами.
И, функции main, делаем так:
int main()
{
SPR_init();
Sprite* progressSpr = SPR_addSprite(&spr_progressBar, 0, 16, TILE_ATTR(PAL0, 11, FALSE, FALSE));
PAL_setPalette(PAL0, pal_img.data, CPU);
u16 curHpSpr = 0;
while(1){
drawProgressBarSprite(progressSpr, curHpSpr);
curHpSpr++;
if(curHpSpr > 50){
clearTilesSprite(progressSpr);
curHpSpr = 0;
}
SPR_update();
SYS_doVBlankProcess();
}
return (0);
}
Итоговый результат.
