Survive — Colisão de sprites I

survive-6_gotcha_2

No final das duas últimas publicações sobre o Survive eu toquei no tema da detecção de colisão e acabei não dando lá muitos detalhes a respeito.

Bem, ao menos não até agora. 🙂

Mais sobre o TMS9928

Sob o ponto de visa funcional o processador de vídeo do MSX opera de maneira “independente” do Z80, isto é, ele tem sua própria memória (a VRAM), seu conjunto de tarefas para executar e cuida delas sem que alguém precise “tomar conta”. Nos MSX de primeira geração a comunicação entre eles se faz através de duas portas de E/S. Uma para a transferência de dados (0x98) e a outra para controle (0x99). A porta de dados serve para ler da/escrever um valor na VRAM enquanto que a de comandos serve selecionar o endereço de memória onde se vai ler/escrever, alterar os valores dos oito registradores de modo e ler o registrador de status. Para não fugir muito do assunto vou tratar somente do registrador de status agora.

Registrador de status

Sua função é notificar à CPU — e consequentemente ao programa em execução — sobre eventos ocorridos dentro do VDP. No MSX ele pode ser consultado diretamente fazendo a leitura a porta de comando ou na variável de sistema STATFL — endereço de memória 0xf3e7 — que é cópia deste valor mantido atualizado pela BIOS.

Ele é organizado da seguinte maneira:

survive-6_registrador_status

7º bit = Interrupção (F)

O VDP está constantemente (re)desenhando a tela a partir do conteúdo da VRAM e daquilo que está configurado nos registradores de modo. No caso dos MSX brasileiros, coreanos e japoneses isto ocorre 60 vezes (60Hz) a cada segundo e 50 vezes (50Hz) nos demais.

Enquanto está desenhando a tela o valor deste bit é “0” e quando termina, e começa o desenho das bordas (inferior e depois a superior), este valor é colocado em “1” para indicar que ocorreu o término de um quadro (ou frame).

Na prática isto significa que quando este bit está ligado o VDP não está consultando a VRAM e que é o melhor momento para enviar coisas para ela — a BIOS sabe muito bem disto e rotinas como FILVRM, LDIRVM, WRTVRM etc esperam este momento acontecer. Este bit é utilizado para incrementar da variável de sistema JIFFY — endereço de memória 0xfc9e — usada pela função TIME do MSX-BASIC.

Na primeira versão do Flappy Bird não considerava este fato e nos MSX de 1ª geração ele produzia um efeito inesperado no deslocamento dos canos.

6º bit = Sinalização do 5º sprite (5S)

No TMS9128 penas quatro sprites podem ser exibidos simultaneamente em uma mesma linha. O 6º bit e os demais 5 bits menos significativos servem para alertar, respectivamente, o que um sprite foi parcialmente desenhado e quem foi ele.

Este programa ajuda a exemplificar como a sinalização ocorre:

Por padrão todos os bits referentes ao número do sprite que não foi desenhado ficam ligados mas este valor só é confiável quando o 6º bit está ligado, daí eles passam a conter o número (a camada) do sprite que não foi exibido.

survive-6_quinto_sprite

O número exibido abaixo é justamente o valor do registrador de status do VDP.

5º bit = Coincidência/Colisão (C)

Dentro do processador de vídeo, na parte¹ encarregada de desenhar os sprites na tela, quando um único pixel de um sprite sobrescreve o de outro há a sinalização que que ocorreu uma colisão (o datasheet chama de “coincidência”). Isto é feito colocando o 5º bit do registrador de status em “1”. Mas a parte chata é que ele somente avisa que ocorreu uma colisão mas, ao contrário da história do 5º sprite, não dá mais nenhuma informação a respeito.

(¹) Quase chamei de “rotina” mas isto aqui é hardware e não software.

Um exemplo de colisão

Começando com um exemplo bem simples, uma variação de um jogo que vi pela primeira vez em um livro de jogos em BASIC para ZX-81 e que desde então fiz dezenas de variações, o Gotcha. Nele você é uma “carinha sorridente” que começa no centro da tela e tudo o que tem de fazer é fugir da outra “carinha sorridente” que tem como único propósito alcançá-lo.

Você se movimenta duas vezes mais rápido que ele, mas não em diagonal e sabendo se esquivar conseguirá até manter uma certa distância dele. Mas claro que, tal qual na canção do Blondie, de um jeito ou de outro ele vai te pegar… 🙂

Apesar dos malabarismos que usei para garantir uma boa velocidade o programa é bem simples de compreender e em modelos de MSX operando a 50Hz é recomendável alterar o valor “3” por “2” nas linha 55 e 70. O laço principal do jogo está entre as linhas 30 a 55 e se encarrega de atualizar as coordenadas dos dois sprites.

Usando o controle de colisão entre sprites (o ON SPRITE GOSUB «linha» na linha 20) alterno² a execução do programa para a linha 60  caso os sprites se esbarrem e, como só tenho um caso para tratar, cuido do GAME OVER!

survive-6_gotcha_1

É público e notório o fato de que computadores são péssimos ganhadores. 🙂

(²) No MSX-BASIC existem outros seis tipos de eventos que permitem desvio da execução do programa para rotinas específicas — e você achando que o Visual BASIC foi o primeiro BASIC da Microsoft a trazer orientação por eventos em 1991, né?

E no Survive?

No caso específico do Survive não há um cenário único, o meu “herói” pode esbarrar em uma “caixa” que pode ser menor, igual ou maior a ele e portanto a rotina tem de ser bem mais inteligente do que a do exemplo anterior e considerar o tamanho de cada sprite e sua exata posição na tela antes de decidir se nosso “herói” deve viver ou morrer.

Mas isto fica para a próxima parte.

Anúncios

Um comentário sobre “Survive — Colisão de sprites I

  1. Pingback: Survive — Colisão de sprites II | giovannireisnunes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s