SGDK. Последовательно печатаем текст на экране.

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

По просьбе англо-говорящего читателя Relde, выкладываю свой старый скрипт который печатает текст последовательно.

Разбираем код.

Скачайте проект с github.

Откройте main.c, там разберем функцию printMessageBase которая отвечает за печать текста.

printMessageBase(char* str, Image* img_msg_sign, u8 msg_sign_pal) 

Она принимает:

  • текст, который будем последовательно печатать
  • изображение плитки
  • палитру плитки.

Первым делом, включили WINDOW слой, и сказали что он будет отнимать 10 тайлов сверху от BG_A

VDP_setWindowVPos(FALSE, 10);

И нарисовали картинку плитки на этом слое.

VDP_setWindowVPos(FALSE, 10);
VDP_drawImageEx(WINDOW, img_msg_sign, TILE_ATTR_FULL(msg_sign_pal, 255, FALSE, FALSE, VDPTilesFilled), 0, 0, FALSE, FALSE);

Далее:

u32 str_len = strlen(str); //Получаем длину строки
char str_char[1]; //Создаем буффер для текущего символа
	
char str_line[35]; //Создаем буффер для текущей строки
u8 start_pos_x = 10; //Задаем смещение позиции 1-ой строки
u8 start_pos_y = 2;

bool skip = FALSE;
	
u8 cur_y = 0; //Позиция текущего символа текущая и максимальная
u8 max_y = 6;
u8 cur_x = 0;
u8 max_x = 27;
//К текущей позиции прибавляется смещение cur_x+start_pos_x
u8 max_x_line = max_x;

Если кнопка пропуска была нажата до выполнения печати, то игнорируем пропуск. Это сделано для того, чтобы при последовательном запуске printMessageBase, строка не пропускалась автоматически если зажата кнопка.

if (joy_value & BUTTON_A || joy_value & BUTTON_B || joy_value & BUTTON_C || joy_value & BUTTON_START) {
  can_skip = FALSE;
}

Копируем часть строки в буффер str_line

strncpy(&str_line, 0, max_x);

Проходящимся по всем символам текста, проверяем нажатие кнопки пропуска

for(u32 i=0;i<str_len;i++) {
	strncpy(&str_char, str+i, 1);
		
		
	joy_value = JOY_readJoypad(JOY_1);
	if (joy_value & BUTTON_A || joy_value & BUTTON_B || joy_value & BUTTON_C || joy_value & BUTTON_START)  {
		joy_pressed = TRUE;
		if(joy_pressed && !prev_joy_pressed && can_skip) {
			skip = TRUE;
		} else {
			joy_pressed = FALSE;
		}
	} else {
		can_skip = TRUE;
	}

Если символ дошел до конца строки, то переходим на следующую строку

if(i != 0 && (cur_x > max_x_line)) {
	cur_x = 0;
	cur_y += 2;

Если это последняя строка, то ждем нажатия кнопки действия, чтобы перейти на следующую страницу.

if(cur_y >= max_y) { //if text doesn't fit in the rectangle, then
	while(1) {
		joy_value = JOY_readJoypad(JOY_1);
		SYS_doVBlankProcess();
		//waiting for just_pressed action from player
		if (joy_value & BUTTON_A || joy_value & BUTTON_B || joy_value & BUTTON_C || joy_value & BUTTON_START) 
		{
						
			joy_pressed = TRUE;
			if(joy_pressed && !prev_joy_pressed) {
				cur_x = 0;
				cur_y = 0;
				skip = FALSE;
				can_skip = FALSE;
				VDP_drawImageEx(WINDOW, &img_message_sign, TILE_ATTR_FULL(msg_sign_pal, 255, FALSE, FALSE, VDPTilesFilled), 0, 0, FALSE, FALSE);
				break;
			}
		} else {
			joy_pressed = FALSE;
		}
		prev_joy_pressed = joy_pressed;
	}
}

Печатаем текущий символ со смещением по координатам.

VDP_drawTextBG(WINDOW, str_char, start_pos_x+cur_x, start_pos_y+cur_y);

Если, это начало текущей строки, то

if(cur_x == 0) {
        //Обновляем буфер текущей строки и её длину
	strncpy(&str_line, str+i, max_x);
	u8 str_line_len = strlen(str_line);
        //Если оставшийся текст влезает в стоку для печати, то максимальное_кол_символов_в_строке = осталось_символов
	if(str_line_len < max_x) {
		max_x_line = max_x;
	}
	else {
                //Иначе, ищем последний символ пробела и по нему делим строку.
		for(u8 j=0; j<max_x; j++)
		{
			if(str_line[j] == ' '){
				max_x_line = j;
			}	
		}
	}
	
	strncpy(&str_line, str+i, max_x_line);
	KDebug_Alert(str_line);
}

Если не пропуск ( skip), то ждем после печати каждого символа.

if (!skip) {	
	waitMs(20);
	SYS_doVBlankProcess();
}

И, в конце, ждем нажатия кнопки действия, чтобы выйти из диалога.

//waiting for last press
while(1) {
	joy_value = JOY_readJoypad(JOY_1);
	if (joy_value & BUTTON_A || joy_value & BUTTON_B || joy_value & BUTTON_C || joy_value & BUTTON_START)  {
		joy_pressed = TRUE;
		if(joy_pressed && !prev_joy_pressed) {
			break;
		}
	} else {
		joy_pressed = FALSE;
	}
	prev_joy_pressed = joy_pressed;
	SYS_doVBlankProcess();	
}

И выходим из WINDOW режима.

VDP_setWindowVPos(FALSE, 0);

Теперь, скомпилируйте и запустите rom.

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

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

Please disable your adblocker or whitelist this site!