Я играл с gbdk/zgb, изучал разработку на C и Game Boy, а также пробовал писать несколько крутых демонстраций и прототипов игр.
Одной из первых вещей, которых я хотел добиться, было создание эффектов построчной прокрутки на плитках в V(ideo)RAM, чтобы я мог создавать круто выглядящие плитки с водой, не сохраняя несколько кадров для анимации. Затем я также использовал это для анимации листвы на тайловой карте, используя псевдосинусоиду, созданную с помощью простых операторов switch.
для этого я написал эти функции:
wrap_vram_byte()
void wrap_vram_byte(uintptr_t *address, int shift) { for ( int x = 0; x < abs(shift); x++ ) { if (shift < 0) { uint8_t vram_line = get_vram_byte( address ); vram_line = (vram_line >> 7 ) + (vram_line << 1); set_vram_byte( address, vram_line); } else if (shift > 0) { uint8_t vram_line = get_vram_byte( address ); vram_line = (vram_line << 7 ) + (vram_line >> 1); set_vram_byte( address, vram_line); } } }
эта функция прокручивает содержимое всей строки шириной 8 пикселей в конкретном тайле (или, скорее, оборачивает его шестнадцатеричные значения посредством битового сдвига и добавления)… или она бы так и делала, если бы данные для каждого тайла не хранились в двух последовательных байтов, а не один — в конце концов, Game Boy использует графику 2bpp. Для получения дополнительной информации об этом посетите эту классную страницу!
чтобы на самом деле прокрутить всю строку, мне нужно запустить эту функцию для каждого из ее двухбайтовых адресов. для этого я создал эту функцию:
wrap_vram_line
void wrap_vram_line(int address, int shift) { wrap_vram_byte( (uintptr_t *) address, shift ); wrap_vram_byte( (uintptr_t *) ( (int) address + 1 ), shift ); }
Таким образом, чтобы использовать эту функцию и прокрутить строку пикселей в конкретном тайле, вам нужно только указать адрес в VRAM, а затем указать, на сколько пикселей их нужно сдвинуть. отрицательные значения прокручивают его влево, положительные значения прокручивают его вправо.
например, чтобы прокрутить первую строку плитки, начинающуюся с адреса $9000, влево, я бы использовал такую функцию:
wrap_vram_line( (int) 0x9000, -1 );
это будет «прокручивать» (т.е. оборачивать) как байт в $9000, так и байт в $9001 влево. затем вы можете сделать это для каждой строки от 9002 до 900 долларов США, одновременно или с разной скоростью в любом направлении, чтобы добиться всевозможных эффектов на плитке, от постоянной прокрутки всей плитки в одном направлении до чего-то более причудливого. как качание травы на ветру.
теперь две оговорки:
- я очень новичок в C, и я уже точно уверен, что это можно было бы сделать намного быстрее, просто написав целую функцию на ассемблере. и я держу пари, что даже просто используя C, есть менее подробные способы сделать это, чем мои неуклюжие функции, поэтому, если вы это знаете и не возражаете против людей, использующих ваш код, пожалуйста, ответьте, что вы думаете об этом!
- я не совсем уверен, насколько эта манипуляция с VRAM повлияет на производительность всей игры, построенной вокруг нее. я узнаю, только если я действительно использую эту функцию в реальной полной игре. я отредактирую этот пост с любыми обновлениями по этому поводу.
в любом случае, не стесняйтесь использовать этот код так, как хотите! -м.