Sprites em Assembly
Você está em: MarMSX >> Cursos >> Assembly Z80
A criação e manipulação de sprites em Assembly é feita diretamente nas tabelas de padrão e atributos dos sprites.
A tabela de padrões dos sprites
A tabela de padrões define 256 padrões para sprites no modo 8x8 e 64 padrões para o modo 16x16. O padrão do sprite é definido por 8 bytes no modo 8x8 e por 32 bytes no modo 16x16.
Exemplo de padrão para um sprite 8x8 (valores em binário):
00111000 - Byte 0
01111100 - Byte 1
11111110 - Byte 2
11111110 - Byte 3
11111110 - Byte 4
01111100 - Byte 5
00111000 - Byte 6
00000000 - Byte 7
No MSX 1, essa tabela se localiza no endereço de 14336 (3800H) a 16383 (3FFFH) da VRAM, onde a cada 8 bytes temos um padrão de sprite para o modo 8x8 ou a cada 32 bytes temos um padrão de sprite para o modo 16x6:
Modo 8x8 Modo 16x16
3800H ┌────────────┐ 3800H ┌────────────┐
│ Padrão 0 │ │ Padrão 0 │
3808H ├────────────┤ 3820H ├────────────┤
│ Padrão 1 │ │ Padrão 1 │
3810H ├────────────┤ 3840H ├────────────┤
│ ... │ │ ... │
3FF8H ├────────────┤ 3FE0H ├────────────┤
│ Padrão 255 │ │ Padrão 63 │
3FFFH └────────────┘ 3FFFH └────────────┘
No modo 16x16, o desenho na tela de 16x16 pixels é formado pelos 32 bytes consecutivos da seguinte forma:
byte 0 | byte 16
byte 1 | byte 17
byte 2 | byte 18
byte 3 | byte 19
byte 4 | byte 20
byte 5 | byte 21
byte 6 | byte 22
byte 7 | byte 23
--------+--------
byte 8 | byte 24
byte 9 | byte 25
byte 10 | byte 26
byte 11 | byte 27
byte 12 | byte 28
byte 13 | byte 29
byte 14 | byte 30
byte 15 | byte 31
A tabela de atributos dos sprites
A tabela de atributos do sprite define 32 sprites. Cada sprite ocupa 4 bytes nessa tabela, onde possui suas coordenadas na tela e cor. Quanto menor o índice do sprite nessa tabela, ele terá prioridade sobre os outros sprites (nível) quando houver superposição.
Os atributos de cada sprite são definidos por 4 bytes, onde:
Byte 0 - Coordenada Y (topo da tela = 255, Y=Y+1)
Byte 1 - Coordenada X
Byte 2 - Número do padrão (qual padrão usar)
Byte 3 - | EC | 0 | 0 | 0 | Código da cor |
EC - Se 1, desloca o sprite 32 pontos à esquerda de X.
No MSX 1, essa tabela se localiza no endereço de 6912 (1B00H) a 7039 (1B7FH) da VRAM, onde a cada 4 bytes temos um sprite em qualquer modo:
1B00H ┌────────────┐
│ Sprite 0 │
1B04H ├────────────┤
│ Sprite 1 │
1B08H ├────────────┤
│ ... │
1B7CH ├────────────┤
│ Sprite 31 │
1B7FH └────────────┘
Exemplo em Basic de como criar 2 sprites
O programa a seguir cria um padrão de uma "bola", cria dois sprites que utilizam esse padrão de desenho e coloca os sprites na tela.
10 SCREEN 2
15 '
20 ' Tabela de padrões dos sprites
25 '
30 P=0 : EP=&H3800 : E=EP+P*8
40 VPOKE E ,&B00111000
50 VPOKE E+1,&B01111100
60 VPOKE E+2,&B11111110
70 VPOKE E+3,&B11111110
80 VPOKE E+4,&B11111110
90 VPOKE E+5,&B01111100
100 VPOKE E+6,&B00111000
110 VPOKE E+7,&B00000000
115 '
120 ' Tabela de atributos dos sprites
125 '
127 EA=&H1B00
130 S=0 : E=EA+S*4 : ' Sprite 0
140 VPOKE E,100 : ' Y=100+1
150 VPOKE E+1,100 : ' X=100
160 VPOKE E+2,0 : ' Usar padrão 0 da Tab. Pad.
170 VPOKE E+3,4 : ' Cor = 4
180 S=1 : E=EA+S*4 : ' Sprite 1
190 VPOKE E,100 : ' Y=100+1
200 VPOKE E+1,105 : ' X=105
210 VPOKE E+2,0 : ' Usar padrão 0 da Tab. Pad.
220 VPOKE E+3,14 : ' Cor = 14
230 GOTO 230
Observe que o sprite 0 (azul) tem prioridade sobre o sprite 1 (cinza).
Podemos movimentar os sprites alterando constantemente os valores das coordenadas na tabela. Acrescente as seguintes linhas ao código anterior.
224 FOR X=0 TO 255
225 VPOKE 6913,X
226 VPOKE 6917,255-X
Para inibir a vizualização de um sprite, defina a cor dele como sendo 0 (transparente).
Exemplo em Assembly de como criar e movimentar 1 sprite
O programa a seguir cria um sprite em Assembly e o desenha na screen 2.
End. Código Mnemônicos
5 CHGMOD: EQU &H5F
6 CHGET: EQU &H9F
7 LDIRVM: EQU &H5C
8 ; ----------------------
C000 10 ORG &HC000
C000 3E 02 20 LD A,2
C002 CD 5F 00 30 CALL CHGMOD ; Screen 2
C005 01 08 00 40 LD BC,8
C008 11 00 38 50 LD DE,&H3800
C00B 21 25 C0 60 LD HL,PAT
C00E CD 5C 00 70 CALL LDIRVM ; Copia padrão para tabela
C011 01 04 00 80 LD BC,4
C014 11 00 1B 90 LD DE,&H1B00
C017 21 2D C0 100 LD HL,SPR
C01A CD 5C 00 110 CALL LDIRVM ; Copia sprite para tabela
C01D CD 9F 00 120 CALL CHGET
C020 AF 130 XOR A
C021 CD 5F 00 140 CALL CHGMOD
C024 C9 150 RET
190 ; ----------------------
C025 38 7C FE 200 PAT: DEFB &H38,&H7C,&HFE,&HFE,&HFE,&H7C,&H38,&H00
FE FE 7C
38 00
C02D 00 64 00 210 SPR: DEFB 0,100,0,8
08
Esse outro exemplo irá criar um sprite e movimentá-lo pela tela.
End. Código Mnemônicos
4 WRTVRM: EQU &H4D
5 CHGMOD: EQU &H5F
6 CHGET: EQU &H9F
7 LDIRVM: EQU &H5C
8 ; ----------------------
C000 10 ORG &HC000
C000 3E 02 20 LD A,2
C002 CD 5F 00 30 CALL CHGMOD ; Screen 2
C005 01 08 00 40 LD BC,8
C008 11 00 38 50 LD DE,&H3800
C00B 21 31 C0 60 LD HL,PAT
C00E CD 5C 00 70 CALL LDIRVM ; Copia padrão para tabela
C011 01 04 00 80 LD BC,4
C014 11 00 1B 90 LD DE,&H1B00
C017 21 39 C0 100 LD HL,SPR
C01A CD 5C 00 110 CALL LDIRVM ; Copia sprite para tabela
C01D AF 120 XOR A
C01E 21 01 1B 130 LD HL,6913
C021 06 00 140 LD B,0
C023 CD 4D 00 150 LOOP: CALL WRTVRM
C026 3C 160 INC A
C027 10 FA 170 DJNZ LOOP
C029 CD 9F 00 180 CALL CHGET
C02C AF 190 XOR A
C02D CD 5F 00 200 CALL CHGMOD
C030 C9 210 RET
290 ; ----------------------
C031 38 7C FE 300 PAT: DEFB &H38,&H7C,&HFE,&HFE,&HFE,&H7C,&H38,&H00
FE FE 7C
38 00
C039 64 00 00 310 SPR: DEFB 100,0,0,8
08
Alguém anotou a placa do caminhão? A movimentação de sprites em Assembly é extremamente rápida!
Vamos acrescentar um retardo em cada iteração, de modo a tornar o movimento do sprite mais lento.
205 PUSH BC
206 LD B,0
207 WAIT: DJNZ WAIT
208 POP BC
Como alterar o tamanho e a magnitude dos sprites
O tamanho e a magnitude dos sprites pode ser definida alterando-se 2 bits do registrador #1 do VDP:
bit 7 - Tipo do VDP: 0-4KB / 1-16KB
bit 6 - Exibe tela: 0-Não / 1-Sim
bit 5 - Interrupção do VDP: 0-Não / 1-Sim
bit 4 - M1
bit 3 - M2
bit 2 - 0
bit 1 - Tamanho do sprite: 0-8x8 / 1-16x16
bit 0 - Magnitude do sprite: 0-Normal / 1-Dobro
Entretanto, esse registrador contém outras informações que deverão ser preservardas. Dessa forma, teremos que ler esse registrador e alterar somente os bits 0 e/ou 1.
Os registradores de modo do MSX não podem ser lidos, mas somente gravados. Apesar disso, a variável de sistema RG1SAV (F3E0H) contém uma cópia do conteúdo do registrador #1.
A instrução da BIOS WRTVDP escreve em um dos registradores do VDP:
Ponteiro: 0047H
Endereço: 057FH
Entrada: B=Byte de dado, C=Número do registro de modo do VDP
Saída: Nada
Modifica: AF, B, EI
O exemplo a seguir mostra como ler o registrador #1 e ajustar o tamanho dos sprites para 16x16 (bit 1=1):
LD A,(&HF3E0) ; Lê Reg#1
OR &B00000010 ; Seta bit 1
LD B,A ; Dado p/ Reg#1
LD C,1 ; Define Reg=1
CALL &H47 ; Escreve
O programa a seguir desenha um sprite de 16x16 pixels.
End. Código Mnemônicos
4 WRTVDP: EQU &H47
5 CHGMOD: EQU &H5F
6 CHGET: EQU &H9F
7 LDIRVM: EQU &H5C
8 ; ----------------------
C000 10 ORG &HC000
C000 3E 02 20 LD A,2
C002 CD 5F 00 30 CALL CHGMOD ; Screen 2
C005 3A E0 F3 31 LD A,(&HF3E0)
C008 F6 02 32 OR &B00000010
C00A 47 33 LD B,A
C00B 0E 01 34 LD C,1
C00D CD 47 00 35 CALL WRTVDP ; Seta sprite modo 16x16
C010 01 20 00 40 LD BC,32
C013 11 00 38 50 LD DE,&H3800
C016 21 30 C0 60 LD HL,PAT
C019 CD 5C 00 70 CALL LDIRVM ; Copia padrão para tabela
C01C 01 04 00 80 LD BC,4
C01F 11 00 1B 90 LD DE,&H1B00
C022 21 50 C0 100 LD HL,SPR
C025 CD 5C 00 110 CALL LDIRVM ; Copia sprite para tabela
C028 CD 9F 00 120 CALL CHGET
C02B AF 130 XOR A
C02C CD 5F 00 140 CALL CHGMOD
C02F C9 150 RET
190 ; ----------------------
C030 00 03 03 200 PAT: DEFB &H00,&H03,&H03,&H03,&H03,&H03,&H03,&H02
03 03 03
03 02
C038 06 06 07 210 DEFB &H06,&H06,&H07,&H4F,&H79,&H75,&H44,&H00
4F 79 75
44 00
C040 00 80 80 220 DEFB &H00,&H80,&H80,&H80,&H80,&H80,&H80,&H80
80 80 80
80 80
C048 C0 C0 C0 220 DEFB &HC0,&HC0,&HC0,&HE4,&H3C,&H5C,&H44,&H00
E4 3C 5C
44 00
C050 64 64 00 240 SPR: DEFB 100,100,0,8
08
Para testar em Basic:
10 E=&HC000
20 READ A$
30 IF A$="M" THEN 70
40 POKE E,VAL("&H"+A$)
50 E=E+1
60 GOTO 20
70 DEFUSR=&HC000:X=USR(0)
100 DATA 3E,02,CD,5F,00,3A,E0,F3,F6,02,47,0E,01,CD,47,00
110 DATA 01,20,00,11,00,38,21,30,C0,CD,5C,00,01,04,00,11
120 DATA 00,1B,21,50,C0,CD,5C,00,CD,9F,00,AF,CD,5F,00,C9
130 DATA 00,03,03,03,03,03,03,02,06,06,07,4F,79,75,44,00
140 DATA 00,80,80,80,80,80,80,80,C0,C0,C0,E4,3C,5C,44,00
150 DATA 64,64,00,08,M
Sprites modo 2 - MSX 2
Os sprites do modo 2 não diferem muito em termo de organização em memória dos sprites modo 1. A diferença está na localização da memória de vídeo das tabelas de atributo e padrões dos sprites, além de possuir uma tabela extra para definir as cores de cada linha do sprite. A partir da screen 4, os sprites funcionam como modo 2.
As tabelas de atributo e padrões dos sprites na screen 4 possuem os mesmos endereços que a screen 2. Entretanto, da screen 5 até a screen 8, as tabelas se localizam em um endereço ao final da página ativa (SET PAGE) do modo de tela em questão.
A organização da VRAM para as screen 5 e 6 do MSX 2 é a seguinte:
Página 0
0000H +------+ -
| |
| |
| | Padrões
| |
| |
6A00H +------+ -
| |
7400H +------+ - Cores dos sprites
7600H +------+ - Atributos dos sprites
7800H +------+ -
| | Padrões dos sprites
7FFFH +------+ -
Para as páginas:
1 - Some 8000H aos endereços
2 - Some 10000H aos endereços
3 - Some 18000H aos endereços
A tabela de cores das linhas dos sprites se localiza sempre 512 bytes antes da tabela de atributos.
A organização da VRAM para as screen 7 e 8 do MSX 2 é a seguinte:
Página 0
0000H +------+ -
| |
| |
| | Padrões
| |
| |
D400H +------+ -
| |
F000H +------+ - Padrões dos sprites
| |
F800H +------+ - Cores dos sprites
FA00H +------+ - Atributos dos sprites
FFFFH +------+
Para as página:
1 - Some 10000H aos endereços
Podemos obter o endereço de cada tabela no Basic através da instrução BASE(n).
Tabela de padrões: BASE(20 + (SCREEN - 4)*5)
Tabela de atributos dos sprites: BASE(23 + (SCREEN - 4)*5)
Tabela de padrões dos sprites: BASE(24 + (SCREEN - 4)*5)
Onde SCREEN é o número da screen de 4 a 8.
A tabela de atributos nos sprites modo 2 se difere por não possuir mais o byte relativo à cor. O espaço continua existindo, mas sem função.
Byte 0 - Coordenada Y (topo da tela = 255, Y=Y+1)
Byte 1 - Coordenada X
Byte 2 - Número do padrão (qual padrão usar)
Byte 3 - Sem função
Isso porque agora a cor de cada linha é controlada individualmente na nova tabela de cores dos sprites. Mesmo quando um sprite é criado como se fosse no modo 1 nas screens 4-8, o que ele faz e preencher todas as 16 linhas referentes ao sprite nessa nova tabela.
A tabela de cores de sprites possui 16 bytes, onde cada byte controla uma linha, mesmo para os sprites 8x8. Cada byte (linha) dessa tabela é configurada da seguinte maneira:
+----+----+----+----+----+----+----+----+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Bit
+----+----+----+----+----+----+----+----+
| EC | CC | IC | 00 | Código da cor | Configuração
+----+----+----+----+----+----+----+----+
Onde:
- EC - Se 1, desloca a linha do sprite 32 pontos à esquerda de X.
- CC - Se 1, combina a cor com outro sprite sobreposto de mesma prioridade usando a operação lógica OR.
- IC - Se 1, desabilita a linha para teste de colisão.
- Código da cor - valor de 0 a 15 (cor indexada).
Programa em Basic para alterar uma linha do sprite de branco para vermelho.
10 SCREEN 5
20 FOR T=1 TO 8
30 READ A$:S$=S$+CHR$(VAL("&B"+A$))
40 NEXT T
50 SPRITE$(0)=S$
60 PUT SPRITE 0,(128,95),15,0
70 VPOKE &H7402,8 ' Altera uma linha do sprite
80 GOTO 80
100 DATA 00111100
110 DATA 01111110
120 DATA 11111111
130 DATA 11111111
140 DATA 11111111
150 DATA 11111111
160 DATA 01111110
170 DATA 00111100
Referências:
[1] - MSX2 Technical Handbook, ASCII Corporation, 1987.
[2] - MSX Top Secret 2, Edison Moraes, 2004.