SGDK. Создаем шкалу прогресса.

Предисловие.

В этой статье вы научитесь создавать шкалу прогресса, а также разберем различные способы их создания?

Спрайтовая шкала прогресса

Самое простое что можно придумать, это сделать анимацию шкалы прогресса, и вручную менять кадр этой анимации (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);
}

Итоговый результат.

Пожалуйста отключи блокировщик рекламы, или внеси сайт в белый список!

Please disable your adblocker or whitelist this site!