GBA ASM - День 13: Эффекты со спрайтами — Архив WASM.RU
Какие именно эффекты со спрайтами?
Мы рассмотрим следующие: вертикальный и горизонтальный кувырок (flip), мозаику, вращение и масштабирование. Тем не менее, относительно вращения, я не буду рассказывать о SIN() и COS(), поэтому мы тольо обсудим что и где поместить в данных для поворота/масштабирования, а остальное вам придётся додумать самим. Я мог бы обсудить создание таблицы значений для массива вращения, но это не слишком вписывается в тему данного Дня.
Флаги кувырка
Это настолько просто, что я даже не буду давать полный пример. Флаг вертикального кувырка - это бит #12 в атрибуте 0. Необходимые константы уже содержатся в sprites.h:
- VERTICAL_FLIP
- HORIZONTAL_FLIPФлаг горизонтального кувырка - это бит #13 в атрибуте 0. Чтобы включить флаг кувырка, вам нужно поместить содержимое первых 32-х битов OAM-элемента спрайта в регистр и поEORить (то же самое, что и поXORить) его с VERTICAL_FLIP или HORIZONTAL_FLIP. Ок, вот немного кода:
Код (Text):
ldr r2,=OAM ldr r3,[r2] ; загружаем r3 из памяти ; вышеприведённое загрузить r3 атрибутом 0 и атрибутом 1, т.к. регистр ; 32-х битный, а OAM-атрибуты 16-ти битные. eor r3,r3,VERTICAL_FLIP ; XORим r3 с VERTICAL_FLIP и помещаем значение в r3. ; EOR и XOR - это одно и то же, главное помните, что инструкция называется EOR. str r3,[r2] ; сохраняем модифицированные атрибуты обратно в OAM.Этот код включает флаг вертикального кувырка. Я думаю, вы поняли идею, и сможете включить флаг горизонтального кувырка самостоятельно.
Мозаика
Регистр мозаики находится по адресу 0x400004C. Регистр 16-ти битный, биты #15-12 - это вертикальная мозаика, а #11-8 - горизонтальная. Другие биты предназначются для бэкграунда. Кроме инициализации REG_MOSAIC, нам также понадобится установить флаг мозаики в атрибуте 0. Его можно включить, заменив в коде выше VERTICAL FLIP на MOSAIC. Обратите внимание, что вы можете сORить их с помощью символа '|'. Вот изменённый пример:
Код (Text):
; иницилизируем регистр мозаики ldr r4,=REG_MOSAIC ldr r3,=0x1200 ; 1 для горизонтальной, 2 для вертикальной, ничего для ; бэкграунда str r3,[r4] ; сохраняем его ldr r2,=OAM ldr r3,[r2] ; загружаем r3 из памяти ; вышеприведённое загрузить r3 атрибутом 0 и атрибутом 1, т.к. регистр ; 32-х битный, а OAM-атрибуты 16-ти битные. eor r3,r3,MOSAIC ; XORим r3 с MOSAIC и помещаем значение в r3. ; EOR и XOR - это одно и то же, главное помните, что инструкция называется EOR. str r3,[r2] ; сохраняем модифицированные атрибуты обратно в OAM.И вуаля! У вас есть мозаичный спрайт.
Вращение
Я надеюсь, что вы прочитали День 3 C-туториала на ThePernProject.COM, потому что если нет, всё это будет достаточно нелегко. Идите, и прочитайте его.
...
...
Прочитайте ещё раз .
...
...Думаете, что вы его поняли? Если нет, то неважно, так как я всё равно собираюсь объяснить это сам.
Чтобы с чего-то начать, скажу, что есть нечто под названием "данные вращения" (Rotation Data), в каждом элементе которых есть 4 16-ти битных "пятна". Поняли? Хорошо.
Данные вращения находятся в OAM. Как, спросите вы, разве в OAM не атрибуты спрайтов? Я отвечу: да. Помните, что случилось с атрибутом 3? Мы никогда его не использовали, в то время, как этот атрибут 3 и является данным вращения. Вот маленькая диаграма, показывающая отображение OAM на элементы вращения данных и pa, pb, pc, pd, о которых рассказывается в Дне 3 на ThePernProject:
Код (Text):
Sprite 0 Att#0 Sprite 0 Att#1 Sprite 0 Att#2 Sprite 0 Att#3 - Элемент данных вращения #0 - 16bit "spot"#1 - pa Sprite 1 Att#0 Sprite 1 Att#1 Sprite 1 Att#2 Sprite 1 Att#3 - Элемент данных вращения #0 - 16bit "spot"#2 - pb Sprite 2 Att#0 Sprite 2 Att#1 Sprite 2 Att#2 Sprite 2 Att#3 - Элемент данных вращения #0 - 16bit "spot"#3 - pc Sprite 3 Att#0 Sprite 3 Att#1 Sprite 3 Att#2 Sprite 3 Att#3 - Элемент данных вращения #0 - 16bit "spot"#4 - pd Sprite 4 Att#0 Sprite 4 Att#1 Sprite 4 Att#2 Sprite 4 Att#3 - Элемент данных вращения #1 - 16bit "spot"#1 - pa Sprite 5 Att#0 Sprite 5 Att#1 Sprite 5 Att#2 Sprite 5 Att#3 - Элемент данных вращения #1 - 16bit "spot"#2 - pb Sprite 6 Att#0 Sprite 6 Att#1 Sprite 6 Att#2 Sprite 6 Att#3 - Элемент данных вращения #1 - 16bit "spot"#3 - pc Sprite 7 Att#0 Sprite 7 Att#1 Sprite 7 Att#2 Sprite 7 Att#3 - Элемент данных вращения #1 - 16bit "spot"#4 - pd ---- И в таком духе продолжается дальше по всему OAM ----Я поинмаю, что эта диаграмма получилось довольно большой, но я надеюсь, что она хорошо иллюстрирует расположение данных вращения. Обратите, что любой спрайт может использовать любой элемент данных вращения. Есть 32 элемента, то есть 32 спрайта могут вращаться/масштабироваться.
Тогда что нам нужно поместить в каждое из 16-ти битных "пятен" (pa, pb, pc, pd)? Ок, ThePernProject даёт нам несколько очень неплохих уравнений:
Код (Text):
spot 1 - pa needs to be the COSine of the angle. spot 2 - pb needs to be the SINe of the angle. spot 3 - pc needs to be the NEGATIVE SINe of the angle. spot 4 - pd needs to be the COSine of the angle.Здесь есть ещё кое-что, но оно относится к вращению, которое мы рассмотрим в другой раз.
Обратите внимание, что "пятно" 3 должно быть отрицательным синусом угла, и это то, что делает вращение таким сложным (по крайней мере для меня). Чтобы инициализировать "пятна", нужно получить атрибуты 2 и 3 какого-либо спрайта, очистить атрибут 3 и "пятно" с помощью AND, а затем установить новое значение с помощью OR. Помните, это 16-ти битные числа, поэтому если мы просто инициализируем атрибут 3 нужным значением, мы можем случайно обнулить атрибут 2.
Чтобы облегчить эту задачу, я сделал несколько (на самом деле, довольно много) новых define'ов в sprites.h. Они предназначаются для данных вращения и выглядят как PA_0, PB_0, PC_0, PD_0. Замените '0' номером элемента данных вращения, который вы хотите использовате. Держите в уме, что в sprites.h они определены до PD_19 включительно.
Также, чтобы сделать все это проще, так нам нужно только изучить, как вращать спрайты, мы не будем контролировать обнуление атрибута 2 (мне следует написать соответствующий день о байтовых масках). Вместо этого, мы просто используем спрайт #0 и элемент данных вращения #0. Таким образом, мы можем безболезненно обнулять атрибут 2, так как он и так должен быть равен 0.
Начнём кодирование!
Я надеюсь, что у вас ещё остался sprit.asm из Дня 5. Держите его и дальше, потому что он понадобится в будущем ещё не раз. Давайте глянем на код!
Код (Text):
;;--- НАЧАЛО КОДА ---;; @include screen.h @include dma.h @include keypad.h @include <a href="/archive/pub/26/files/sprites.h">sprites.h</a> b start @include sprit.asm start ldr r1,=REG_DISPCNT ldr r2,=(MODE_1|BG2_ENABLE|OBJ_ENABLE|OBJ_MAP_1D) str r2,[r1] ldr r1,=REG_DMA3SAD ldr r2,=pallete str r2,[r1] ldr r1,=REG_DMA3DAD ldr r2,=OBJPAL str r2,[r1] ldr r1,=REG_DMA3CNT ldr r2,=(128|DMA_32NOW) str r2,[r1] ldr r1,=REG_DMA3SAD ldr r2,=obj str r2,[r1] ldr r1,=REG_DMA3DAD ldr r2,=CHARMEM str r2,[r1] ldr r1,=REG_DMA3CNT ldr r2,=(512|DMA_32NOW) str r2,[r1] ;;--- СТОП КОПИРОВАНИЕ ---;;Полагаю, вы должны понять, что здесь происходит.
Код (Text):
;;--- ПРОДОЛЖЕНИЕ КОДА ---;; ldr r1,=OAM ldr r2,=((SQUARE|COLOR_256|30))|((SIZE_32|(0<<9)|10)<<16) str r2,[r1] ;;--- СТОП КОПИРОВАНИЕ ---;;Здесь есть кое-что новенькое. Количество данных вращения сдвигается на 9, чтобы оказаться в правильном "пятне". Мы используем элемент данных вращения #0.
Код (Text):
;;--- ПРОДОЛЖЕНИЕ КОДА ---;; ldr r1,=PA_0 ; сохранение будет происходить в PA. ldr r2,=70<<16 ; COS(45 градусов) = 0.70, в первом байте регистра, который str r2,[r1] ; работает с числами с фиксированной запятой в данных вращения. ldr r1,=PB_0 ; сохранение будет происходить в PB ldr r2,=70<<16 ; SIN(45 градусов) = 0.70. так же как и в предыдущем случае. str r2,[r1] ldr r1,=PC_0 ; сохранение будет происходить в PC ldr r2,=0 ; Отрицательный SIN(45 degrees) = -0.70 sub r2,r2,70 ; вычитаем 70 от 0, чтобы получить отрицательное значение, и mov r2,r2,lsl 16 ; сдвигаем, чтобы получить только необходимые 16 бит. str r2,[r1] ldr r1,=PD_0 ; сохранение будет происходить в PD ldr r2,=70<<16 ; COS(45 градусов) = 0.70 снова. str r2,[r1] ; сохраняем в атрибуты #2&3 спрайта 3. ;;--- СТОП КОПИРОВАНИЕ ---;;Обратите внимание, что мы работаем с 16-ти битными числами с фиксированной запятой, поэтом нам нужны эти 3 сдвига на 16 бит не только для того, чтобы получить значение в нужной части регистра, но также и потому, что 70 - это 0.70 и должно находиться в дробной части числа.
Код (Text):
;;--- ПРОДОЛЖЕНИЕ КОДА ---;; infin ldr r1,=KEYS ; первые 3 строки проверяют, нажата ли клавиша A. ldr r1,[r1] ; эти строки включают флаг вращения ands r1,r1,#KEY_A ; и флаг двойного размера. ldreq r1,=OAM ; однократное нажатие включает эти два флага. ldreq r2,[r1] ; получаем атрибуты 0 & 1 спрайта. eoreq r2,r2,#(ROTATION_FLAG|SIZE_DOUBLE) ; устанавливаем биты флагов с помощью ; инструкции EOR (аналог XOR). streq r2,[r1] ; Обратите внимание, что последние 4 строки выполняются только, если нажата ; клавиша A. b infin ;;--- КОНЕЦ КОДА ---;;Компилируйте и запускайте! Я надеюсь, что вам всё понятно.
Обзор этого дня
Я рад, что доделал этот День, было весело. Да, 13 - счастливое число, вы знаете? Хе-хе. Пока. © Mike H, пер. Aquila
GBA ASM - День 13: Эффекты со спрайтами
Дата публикации 10 авг 2006