domingo, 6 de maio de 2007

Ocupando as Duas Telas

Tudo até agora foi programado usando apenas a tela de baixo, a tela 0. Mas este jogo deve ocupar as duas telas do DS. O nosso tanque tem que ficar só na tela de baixo, mas os tiros devem alcançar a tela de cima. Uma maneira de resolver isso seria bastante complexa, colocando os mesmos desenhos dos sprites de baixo nos sprites de cima e ficar controlando para ocultar um sprite em baixo quando ele passa a aparecer em cima.
Outra opção seria usar a própria PAlib para fazer esse controle. É o que nós faremos. Todos os comandos de sprites possuem um irmão "Dual", que não precisa especificar qual a tela ele será colocado, o valor de y é que definirá isso. A altura padrão de tela passa a ser 432 pixels (192 pixels da tela de baixo, mais 192 pixels da tela de cima, mais 48 pixels que não mostram imagem porque são o espaço entre as duas telas). O espaço entre as duas tela pode ser alterado pela função PA_SetScreenSpace mas nós continuaremos a usar os 48 pixels pois isso dá uma continuidade bem legal ao tiro.
Ah, sim. Faltou falar que os comandos para trabalhar com as duas telas como se fossem uma, são os mesmos comandos de gerenciamento de sprites, somente com a palavra "Dual" na frente (logo após o "PA_") e sem o parâmetro do número da tela.
Também iremos colocar os fundos das telas. O fundo set_bg_1.gif vai na tela de baixo e o set_bg_2.gif vai na tela de cima.
No programa, as alterações não são muito radicais:
  • trocar os comandos de sprites para os dual
  • tratar o tanque na tela de baixo, ou seja, y+240
  • permitir que o tiro ande por todos os 432 pixels
  • não desenhar mais o fundo de 16 bits amarelo sujo
  • colocar os dois tiled backgrounds

Fonte do programa:

// Includes
#include <PA9.h> // Include for PA_Lib
#include "gfx/all_gfx.c"
#include "gfx/all_gfx.h"

// Variaveis Globais
s16 angulo_body=0;
s16 angulo_turret=0;
s16 velocidade=1;
s16 x=111;
s16 y=79+192+48;
s16 angulo_tiro=0;
s32 x_tiro=-8<<8;
s32 y_tiro=-8<<8;
s16 vel_tiro=4;
s8 atirando=0;

void giraturret() {
  if (Stylus.Held) {
    angulo_turret=PA_GetAngle(x+16,y+16-240,Stylus.X,Stylus.Y);
    PA_DualSetRotsetNoZoom(0,angulo_turret);
  }
}

void movetanque() {
  if ((Pad.Held.Left && Pad.Held.A) || (Pad.Held.Right && Pad.Held.Y) || (Pad.Held.Up && Pad.Held.B) || (Pad.Held.Down && Pad.Held.X) || (Pad.Held.X && Pad.Held.B) || (Pad.Held.Y && Pad.Held.A)) {
   //o usuário está sacaneando, não executa nada
  } else if (!(Pad.Held.Up || Pad.Held.Down || Pad.Held.Left || Pad.Held.Right || Pad.Held.A || Pad.Held.B || Pad.Held.X || Pad.Held.Y)) {
   //nenhuma direção foi pressionada
  } else {
    if ((Pad.Held.Left || Pad.Held.Y || Pad.Held.Right || Pad.Held.A) && !(Pad.Held.Up || Pad.Held.X || Pad.Held.Down || Pad.Held.B)) {
      angulo_body=256*(Pad.Held.Left || Pad.Held.Y);
      x+=velocidade*(Pad.Held.Right || Pad.Held.A)-velocidade*(Pad.Held.Left || Pad.Held.Y);
    } else if (!(Pad.Held.Left || Pad.Held.Y || Pad.Held.Right || Pad.Held.A) && (Pad.Held.Up || Pad.Held.X || Pad.Held.Down || Pad.Held.B)) {
      angulo_body=128*(Pad.Held.Up || Pad.Held.X)+384*(Pad.Held.Down || Pad.Held.B);
      y+=velocidade*(Pad.Held.Down || Pad.Held.B)-velocidade*(Pad.Held.Up || Pad.Held.X);
    } else {
      angulo_body=256*(Pad.Held.Left || Pad.Held.Y);
      x+=velocidade*(Pad.Held.Right || Pad.Held.A)-velocidade*(Pad.Held.Left || Pad.Held.Y);
      if (angulo_body) {
        angulo_body=192*(Pad.Held.Up || Pad.Held.X)+320*(Pad.Held.Down || Pad.Held.B);
      } else {
        angulo_body=64*(Pad.Held.Up || Pad.Held.X)+448*(Pad.Held.Down || Pad.Held.B);
      }
      y+=velocidade*(Pad.Held.Down || Pad.Held.B)-velocidade*(Pad.Held.Up || Pad.Held.X);
    }
    if (x<0) { x=0; }
    if (x>223) { x=223; }
    if (y<240) { y=240; }
    if (y>399) { y=399; }
    PA_DualSetRotsetNoZoom(1,angulo_body);
    PA_DualSetSpriteXY(0,x,y);
    PA_DualSetSpriteXY(1,x,y);
  }
}

void atira() {
  if (atirando) {
    x_tiro+=PA_Cos(angulo_tiro)*vel_tiro;
    y_tiro-=PA_Sin(angulo_tiro)*vel_tiro;
    PA_DualSetSpriteXY(2,x_tiro>>8,y_tiro>>8);
    if (x_tiro<-8<<8 || x_tiro>260<<8 || y_tiro<-8<<8 || y_tiro>440<<8) {
      atirando=0;
    }
  } else {
    if (Pad.Newpress.L || Pad.Newpress.R) {
      atirando=1;
      angulo_tiro=angulo_turret;
      x_tiro=(x+12)<<8;
      y_tiro=(y+12)<<8;
      x_tiro+=PA_Cos(angulo_tiro)*24;
      y_tiro-=PA_Sin(angulo_tiro)*24;
      PA_DualSetRotsetNoZoom(2,angulo_tiro);
      PA_DualSetSpriteXY(2,x_tiro>>8,y_tiro>>8);
    }
  }
}

// Function: main()
int main(int argc, char ** argv)
{
  PA_Init(); // Initializes PA_Lib
  PA_InitVBL(); // Initializes a standard VBL
  PA_DualLoadSpritePal(0, (void*)tank_turret_Pal);
  PA_DualCreateSprite(0, (void*)tank_turret_Sprite, OBJ_SIZE_32X32, 1, 0, x, y);
  PA_DualLoadSpritePal(1, (void*)tank_body_Pal);
  PA_DualCreateSprite(1, (void*)tank_body_Sprite, OBJ_SIZE_32X32, 1, 0, x, y);
  PA_DualLoadSpritePal(2, (void*)tiro_Pal);
  PA_DualCreateSprite(2, (void*)tiro_Sprite, OBJ_SIZE_8X8, 1, 0, -8, -8);
  PA_DualSetSpriteRotEnable(0, 0);
  PA_DualSetSpriteRotEnable(1, 1);
  PA_DualSetSpriteRotEnable(2, 2);
  PA_EasyBgLoad(0,3,set_bg_1);
  PA_EasyBgLoad(1,3,set_bg_2);
  // Infinite loop to keep the program running
  while (1)
  {
    giraturret();
    movetanque();
    atira();
    PA_WaitForVBL();
  }
  return 0;
} // End of main()

Imagens para fazer os fundos:

3 comentários:

Leonardo Zimbres disse...

ok, então vai ser 1 tiro por vez né?
Tem como você disponibilizar o código fonte tb? Deve estar massa, dando para atirar com o L/R e mirando com a stylus.

Anônimo disse...

Da hora a iniciativa de vocês.. eu poderia ajudar com material tb

Estou programando pra DS também, mas focado em usar o DS com robótica. Eu tava usando a PA_lib, mas dá uns paus locos na lib do Dserial2, um treco q comprei pra conectar no robo.

Sabe aquele demo mais embaixo do aviao??? voce tem o codigo dele?? pq no dserial tem acelerometro, dai daria pra fazer o aviao mudar de posicao soh inclinando o DS.. lol...

qlq coisa me add no msn...

f_odSelot Pat hotmAail dot cMom

tira as letras SPAM.. hehe todo cuidado eh pouco, pricipalmente depois que vi que eh facil detectar emails, inclusive na forma at dot, com expressao regular.. lol

Marcelo disse...

opa voce tem um github ou teria como enviar os codigos

abs
marcelo