Neste domingo eu escrevi um código de exemplo para rodar na VM do Another World. É uma animação bem simples de uma imagem zigue-zagueando pela tela (rebatendo nos cantos da tela). Algo parecido com um jogo de PONG, que aliás seria uma ótima opção para um segundo exemplo de código um pouco mais complexo. No gif animado abaixo eu mostro o programinha rodando na VM dentro do MAME.
A colisão com a borda é detectada com o ponto central do objeto como referência. O vetor é desenhado ao redor daquele ponto. Por isso que o desenho sai um pouco da tela antes de rebater. O código de exemplo (escrito em assembly da VM) está disponível no github aqui: AnotherWorld_VMTools/example/bounce.asm at main · felipesanches/AnotherWorld_VMTools · GitHub
BALL_IMAGE EQU 0x031E ; This is the address of one of the code wheel symbols.
; These are the VM vars we'll use:
BALL_X EQU 0x00
BALL_Y EQU 0x01
BALL_ZOOM EQU 0x02
SPEED EQU 0x03
PAUSE_SLICES EQU 0xFF
; This programs uses a single VM thread and a single videopage.
init:
movConst [PAUSE_SLICES], 2 ; 2*20ms = 40ms per frame = 25 frames / sec
movConst [SPEED], 1
movConst [BALL_X], 160
movConst [BALL_Y], 100
movConst [BALL_ZOOM], 0x40
; The VX and VY vars are strictly positive values, so we treat
; zero as -SPEED,
; SPEED as zero
; 2*SPEED as +SPEED
mov [BALL_VX], [SPEED]
add [BALL_VX], [SPEED]
mov [BALL_VY], [SPEED]
add [BALL_VY], [SPEED]
setPalette 0x03 ; This is one the color palette used for that code wheel symbol.
selectVideoPage 0x00
mainloop:
; fill the whole page with a background color:
fillVideoPage 0x00, color:0x07
; draw the symbol:
video off=BALL_IMAGE x=[BALL_X] y=[BALL_Y] zoom:[BALL_ZOOM]
; and update the screen:
blitFramebuffer 0x00
; update the screen coordinates based on the current x and y velocities:
sub [BALL_X], [SPEED]
addConst [BALL_X], [BALL_VX]
sub [BALL_Y], [SPEED]
addConst [BALL_Y], [BALL_VY]
; mirror the velocities if the symbol collides with the borders:
jl [BALL_X], 320, _1
movConst [BALL_VX], 0
_1:
jg [BALL_X], 0, _2
movConst [BALL_VX], [SPEED]
add [BALL_VX], [SPEED]
_2:
jl [BALL_Y], 200, _3
movConst [BALL_VY], 0
_3:
jg [BALL_Y], 0, _4
movConst [BALL_VY], [SPEED]
add [BALL_VY], [SPEED]
_4:
jmp mainloop
Como eu ainda não tenho um assembler, eu tive que gerar o bytecode montando o código manualmente. Fui olhando a tabela de opcodes e transcrevendo a representação binária. Tem um outro arquivo no mesmo repo chamado bounce.asm.manual que tem a transcrição dos opcodes e operandos: AnotherWorld_VMTools/example/bounce.asm.manual at main · felipesanches/AnotherWorld_VMTools · GitHub
É meio chato de fazer isso manualmente, mas como o programa era pequeno, eu concluí que seria mais rápido do que escrever um assembler. Para programas maiores eu com certeza precisarei implementar o assembler. Como a linguagem é relativamente simples, estou ainda na dúvida se faço em python mesmo, ou se emprego lex e yacc (flex e bison)…
Depois de transcritos todos os valores numéricos das instruções (inclusive com o cálculo manual dos endereços de memória), usei um editor hexadecimal (eu uso o hexcurse) pra inserir os bytes em um arquivo binário que é carregado pela VM no MAME.
O desenho foi reutilizado do banco de polígonos do jogo. Tive só que descobrir qual o endereço de memória onde a estrutura de dados desse símbolo fica armazenada. Descobri esse endereço vendo o diretório de SVGs gerados pelo extrator e depois consultando o header gerado automaticamente pelo disassembler.