gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Mode 0, Background 0, and sprites... all work but one (UGH)

#4149 - slippers2k - Thu Mar 20, 2003 11:18 pm

Help!

I've successfully managed to load a background in mode 0. It is background 0, loaded with appropriate tiles (I understand background 0 has transparency information in it which is fine for me as long as I can get a demo going).

I load the background, and I load all my sprites. My input commands work just fine for the numbered sprites and the computer ai (which is REALLY simple right now) works great. But my player's sprite will not move at all (the graphic stays put)! It does "move" apparently, but the sprite will not budge.

I've tried changing the player sprite's character number, changing the offset into OAMData (i.e. (u16*)0x6010000), and other general checks to see if things were going to work. Nothing.

Is it that I'm loading my sprites into mode 0? Is it that there is a problem with my character number naming system? Or is it something else? Code provided (sorry about the mess...)

Code:

// new_pong_proj.c AGBmain Entry point is contained here (main program loop)

#include <gba.h>      //extra-large header file - screenmode, keys, sprite info and more
#include "stdlib.h"      //standard code needed for certain functions (not sure which)
#include <mathluts.h>   //precompiled sin and cos values (not necessary)
#include <interupts.h>   //GBA interrupt information above and beyond that of gba.h
#include "TEST.h"      //background file
#include "SPRITE1.h"   //sprite#1 - my first car
#include "SPRITE2.h"   //sprite#2 - a big square tennis ball
#include "SPRITE4.h"    //sprite#4 - blue car (computer opponent)
#include "NUMBER0.h"   //numbered sprites for keeping score onscreen (Jan 26 2003)
#include "NUMBER1.h"
#include "NUMBER2.h"
#include "NUMBER3.h"
#include "NUMBER4.h"
#include "NUMBER5.h"
#include "NUMBER6.h"
#include "NUMBER7.h"
#include "NUMBER8.h"
#include "NUMBER9.h"
#include "CARPONG.h"    //splash screen

#include "levelone1.c"   //my first level map
#include "levelone1.h"   //my first level map header

// GLOBAL VARIABLES

u16* OAM = (u16*)0x7000000;
OAMEntry sprites[128];
pRotData rotData = (pRotData)sprites;

//determines whether ball travels toward player or computer

int direction_x = 1;
int direction_y = 1;

//variables for scrolling the background

/////////////////////////SPRITE GLOBAL VARIABLES//////////////////////////////////////

///these are global so i do not have to pass them to GetInput -dovoto

//x and y for sprite 1 - yellow car
s16 x = 0;
s16 y = 50;


int count = 0;

//Character number global vars below allow us to swap sprite contents on the fly
//(Jan 26 2003)

u16 char_number = 0;
u16 char_number_yellow = 0;
u16 char_number_blue = 0;
u16 char_number_n0 = 0;
u16 char_number_n1 = 0;
u16 char_number_n2 = 0;
u16 char_number_n3 = 0;
u16 char_number_n4 = 0;
u16 char_number_n5 = 0;
u16 char_number_n6 = 0;
u16 char_number_n7 = 0;
u16 char_number_n8 = 0;
u16 char_number_n9 = 0;

u16 char_number_ntemp = 0;

//x and y for tennis ball (yes, I know it's square :)
s16 xs = 100;
s16 ys = 50;

//x and y for sprite 4 - blue car
s16 x4 = 180;
s16 y4 = 50;

//for collision detection: define bounding boxes for the 64x64 sprites - me (12/9/02)
//UPDATE: 12/12/02 - decided to use 32x32 sprites for paddles
//(game will be "car pong")

s16 x_ur = 0;
s16 y_ll = 0;

s16 xs_ur = 0;
s16 ys_ll = 0;

s16 x4_ur = 0;
s16 y4_ll = 0;

/////////////////////////////// RGB macro
/************************************************************\
* The GBA stores 15 bit color in blue green red format meaning
* the first 5 bits are the red the next 5 bits are green and the next
* 5 blue. This macro just shifts the colors over the correct amount.
* RGB is the more standard way to represent color.
\************************************************************/
#define RGB(r,g,b) ((r)+((g)<<5)+((b)<<10)) /*both do the same thing but just in case you prefer RGB notation i included both macros */
#define BGR(b,g,r) ((r)+((g)<<5)+((b)<<10))

//DMA_Copy - FAST memory copying on the gba Mar 20 2003

void DMA_Copy(u8 channel, void* source, void* dest, u32 WordCount, u32 mode)
{
   switch (channel)
   {
      case 0:
         REG_DMA0SAD = (u32)source;
         REG_DMA0DAD = (u32)dest;         
         REG_DMA0CNT = WordCount | mode;
         break;
      case 1:
         REG_DMA1SAD = (u32)source;
         REG_DMA1DAD = (u32)dest;
         REG_DMA1CNT = WordCount | mode;
         break;
      case 2:
         REG_DMA2SAD = (u32)source;
         REG_DMA2DAD = (u32)dest;
         REG_DMA2CNT = WordCount | mode;
         break;

      case 3:
         REG_DMA3SAD = (u32)source;
         REG_DMA3DAD = (u32)dest;
         REG_DMA3CNT = WordCount | mode;
         break;

   }
}

//my plot pixle function from day 2 -dovoto
void PlotPixel(int x,int y, unsigned short int c) {VideoBuffer[(y) *120 + (x)] = (c);}

// functions (all functions -dovoto unless otherwise stated)

void InitializeSprites(void)
{
   int loop;
   for(loop = 0; loop < 128; loop++)
   {
      sprites[loop].attribute0 = 160;  //y to > 159
      sprites[loop].attribute1 = 240;  //x to > 239
   }
}

//wait for the screen to stop drawing
void WaitForVsync(void)
{
   while((volatile u16)REG_VCOUNT != 160){}   

}

///Test for key presses
void GetInput(void)
{

   //for collision detection: define bounding boxes for the 64x64 sprites - me (12/9/02)
   // x_ur = X coordinate of first sprite at upper right corner (BAD variable naming...sorry!)
   // y_ll = Y coordinate of first sprite at lower left corner

   // xs_ur = X coordinate of second sprite at upper right corner
   // ys_ll = Y coordinate of second sprite at lower left corner

   x_ur = x + 32;
   y_ll = y + 32;

   xs_ur = xs + 16;
   ys_ll = ys + 16;

   x4_ur = x4 + 32;
   y4_ll = y4 + 32;

   if(!(*KEYS & KEY_UP))
   {
       y--;
      if(y==ys_ll)
         if(x<=xs_ur)
            if(x_ur>=xs)
               y++;
      //experimental
      //y4--;
   }
   if(!(*KEYS & KEY_DOWN))
   {
       y++;
      if(y_ll==ys)
         if(x<=xs_ur)
            if(x_ur>=xs)
               y--;
      //experimental
      //y4++;
   }
   if(!(*KEYS & KEY_LEFT))
   {
       x--;
      if(x==xs_ur)
         if(y<=ys_ll)
            if(y_ll>=ys)
               x++;
   }
   if(!(*KEYS & KEY_RIGHT))
   {
       x++;
      if(x_ur==xs)
         if(y<=ys_ll)
            if(y_ll>=ys)
               x--;
   }
   if(!(*KEYS & KEY_START))
   {
      while(1) //man-made infinite loop with a break condition
      {
         WaitForVsync();
         if(!(*KEYS & KEY_START))
            break;
      }
   }
   if(!(*KEYS & KEY_A))
   {
      sprites[0].attribute2 = char_number_blue;
   }
   if(!(*KEYS & KEY_B))
   {
      sprites[0].attribute2 = char_number_yellow;
   }
   if(!(*KEYS & KEY_L))
   {
      if (count == 0)
      {
         sprites[3].attribute2 = char_number_n1;
      }
      if (count == 1)
      {
         sprites[3].attribute2 = char_number_n2;
      }
      if (count == 2)
      {
         sprites[3].attribute2 = char_number_n3;
      }
      if (count == 3)
      {
         sprites[3].attribute2 = char_number_n4;
      }
      if (count == 4)
      {
         sprites[3].attribute2 = char_number_n5;
      }
      if (count == 5)
      {
         sprites[3].attribute2 = char_number_n6;
      }
      if (count == 6)
      {
         sprites[3].attribute2 = char_number_n7;
      }
      if (count == 7)
      {
         sprites[3].attribute2 = char_number_n8;
      }
      if (count == 8)
      {
         sprites[3].attribute2 = char_number_n9;
      }
      if (count == 9)
      {
         sprites[3].attribute2 = char_number_ntemp;
         count = 0;
      }
      count++;
      //sprites[3].attribute2 = char_number_n1;
   }
   if(!(*KEYS & KEY_R))
   {
      sprites[3].attribute2 = char_number_n0;
   }

}

//move the sprite
void MoveSprite(OAMEntry* sp, int x, int y)
{
   if(x < 0)         //if it is off the left corect
      x = 512 + x;
   if(y < 0)         //if off the top corect
      y = 256 + y;

   /////////////////////////COLLISION DETECTION CODE/////////////////
   ///////////////////(FOR TENNIS BALL)//////////////////////////////

   xs -= direction_x;

   if (xs == 0)
   {
      direction_x *= -1;
      xs++;
   }

   if (xs == 220)
   {
      direction_x *= -1;
      xs--;
   }

   if (xs==x4)
      if(ys<=y4_ll)
         if(ys_ll>=y4)
            {
               direction_x *= -1;
               xs--;
            }

   if (xs==x_ur)
      if(ys<=y_ll)
         if(ys_ll>=y)
            {
               direction_x *= -1;
               xs++;
            }

   ys -= direction_y;

   if (ys == 0)
   {
      direction_y = -1;
      ys++;
   }
   if (ys == 140)
   {
      direction_y *= -1;
      ys--;
   }

   //experimental (12/14/2002)
   y4 = ys;

   //approaching tennis ball from the left
   //if((x)==(xs))
   //   x--;

   //approaching from the right
   //if((x)<(xs))
   //   x++;

   //////////////END COLLISION DETECTION CODE ///////////////////////
   ///(CALL YOUR INSURANCE COMPANY!!! :)/////////////////////////////

   sp->attribute1 = sp->attribute1 & 0xFE00;  //clear the old x value
   sp->attribute1 = sp->attribute1 | x;
   
   sp->attribute0 = sp->attribute0 & 0xFF00;  //clear the old y value
   sp->attribute0 = sp->attribute0 | y;
}   

///Copy our sprite array to OAM
void CopyOAM(void)
{
   u16 loop;
   u16* temp;
   temp = (u16*)sprites;
   for(loop = 0; loop < 128*4; loop++)
   {
      OAM[loop] = temp[loop];
   }
}

int main(void)
{
   int index = 0;  //some looping variables for loops :)
   u16 loop;
   
   
   
   SetMode(MODE_4 | BG2_ENABLE| OBJ_ENABLE | OBJ_MAP_1D); //set mode 2 and enable sprites and 2d mapping

   for(loop = 0; loop < 256; loop++)
      OBJPaletteMem[loop] = SPRITE1Palette[loop];   //loop through and store the palette from your pict
                           //palette into obj palette mem OBJPaletteMem is
                           //defined in gba.h.  sprite1Palette is from
                           //pcx2gba tool sprite1.h.

   while(1)
   {
      for(loop = 0; loop < 256; loop++)
         BGPaletteMem[loop] = CARPONGPalette[loop];

      for (y = 0; y < 160; y++)
      {
         for (x = 0; x < 120; x++)
         {
            PlotPixel(x,y,CARPONGData[y*120+x]);
         }
      }

      if(!(*KEYS & KEY_START))
         break;
   }

   //Regular background (mode 4) is now disabled, going to load mode 0 background (Mar 18 2003)
   //for(loop = 0; loop < 256; loop++)
   //   BGPaletteMem[loop] = TESTPalette[loop];   //loop through and store the palette from your pict
   //                        //palette into video palette mem
   //
   //for(y = 0; y < 160; y++)
   //{
   //   for(x = 0; x < 120; x++)

   //   {
   //      PlotPixel(x,y,TESTData[y*120+x]);//testData contains the color values of your pict
         //if((x>0)&&((x%10)==0))
         //   PlotPixel(x,y,RGB(31,31,31));
         // HISTORY: Above two lines are debug scaffolding... used to delineate x coords
         // (Dec 9 2002)
         
   //   }
   //}

   //

   int x=0,y=0; //just some looping vars

   //this is a temparary pointer that we will point to the last screen memory block(31)
   u16* bg0map =(u16*)ScreenBaseBlock(31);

   //bg0map now points to were we are going to put our map data

   //now we set up background 0 to be a 256 x 256 256 color background and make sure it
   //it looks in the right place for its map data
   REG_BG0CNT = BG_COLOR256 | TEXTBG_SIZE_256x256 | (31 << SCREEN_SHIFT) | WRAPAROUND;

   //good old set mode function. here we just set it to mode 0 and enable background 0
   SetMode(MODE_0 | BG0_ENABLE| OBJ_ENABLE | OBJ_MAP_1D); //added OBJ_ENABLE and OBJ_MAP_1D
                                             //Mar 18 2003


   //now we use our DMA copy routine to copy in the palette
   DMA_Copy(3,(void*)levelone1Map.pal,(void*)BGPaletteMem,256,DMA_16NOW);

   //now we copy in the tile data
   DMA_Copy(3,(void*)levelone1Map.tiledata,(void*)CharBaseBlock(0),levelone1Map.tileDataSize/4,DMA_32NOW);

   //now we copy in the map. this could be done with dma as well but this is a bit more flexible
   for(y = 0; y < 32; y++) //loop through all 32x32 tiles
   {
      for(x = 0; x < 32; x++)
      {
      //this is were the data from our map editor is copied to video memory
         bg0map[x + y * 32] = levelone1Map.layers[0].data[x + y * levelone1Map.layers[0].w];
   
      }
   
   }


//our main loop..this is were we would normaly do stuff
//for now we just let you scroll around a bit with the keys
//to see your map.


//while(1)
//{

     //while(!(REG_DISPSTAT & 1));//wait for vblank to start

//use the hardware to scroll around some
     //if(!(KEYS & KEY_LEFT))x--;
     //if(!(KEYS & KEY_RIGHT))x++;
     //if(!(KEYS & KEY_UP))y--;
     //if(!(KEYS & KEY_DOWN))y++;

//We load x and y into the offset registers and the GBA scrolls the background for us
     //REG_BG0VOFS = y ;
     //REG_BG0HOFS = x ;

     //while((REG_DISPSTAT & 1));//wait for vblank to end

//}//end while
//}//end main


   //

   x = 10;
   y = 10;
   InitializeSprites();  //set all 128 sprites to offscreen

   //this is were we define our sprite atributes for the first sprite
   //256 color 64x64 sprite that starts at character 0.  Character 0 is
   //the first sprite data memory location.

   sprites[0].attribute0 = COLOR_256 | SQUARE | y; 
   sprites[0].attribute1 = SIZE_32 | x;
   sprites[0].attribute2 = char_number; //bit map mode so the first 512 chars are not available
                               //UPDATE: mode 0 - no more need to add 512 (3/18/03)

   char_number_yellow = char_number;

   sprites[1].attribute0 = COLOR_256 | SQUARE | ys; 
   sprites[1].attribute1 = SIZE_16 | xs;
   sprites[1].attribute2 = char_number+(128); //bit map mode so the first 512 chars are not available each 64x64 sprite uses 128 tiles
                                    ////UPDATE: mode 0 - no more need to add 512 (3/18/03)
                        
   sprites[2].attribute0 = COLOR_256 | SQUARE | y4;
   sprites[2].attribute1 = SIZE_32 | x4;
   sprites[2].attribute2 = char_number+(128+64);

   char_number_blue = char_number+(128+64);

   //DEFINING NUMBER SPRITES

   sprites[3].attribute0 = COLOR_256 | SQUARE | y+10;//0;
   sprites[3].attribute1 = SIZE_32 | x+10;//0;
   sprites[3].attribute2 = char_number+(128+128);

   char_number_n0 = char_number+(128+128);
   char_number_ntemp = char_number_n0;

   sprites[4].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[4].attribute1 = SIZE_32 | 0;
   sprites[4].attribute2 = char_number+(128+192);

   char_number_n1 = char_number+(128+192);

   sprites[5].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[5].attribute1 = SIZE_32 | 0;
   sprites[5].attribute2 = char_number+(128+256);

   char_number_n2 = char_number+(128+256);

   sprites[6].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[6].attribute1 = SIZE_32 | 0;
   sprites[6].attribute2 = char_number+(128+320);

   char_number_n3 = char_number+(128+320);

   sprites[7].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[7].attribute1 = SIZE_32 | 0;
   sprites[7].attribute2 = char_number+(128+384);

   char_number_n4 = char_number+(128+384);

   sprites[8].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[8].attribute1 = SIZE_32 | 0;
   sprites[8].attribute2 = char_number+(128+448);

   char_number_n5 = char_number+(128+448);

   sprites[9].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[9].attribute1 = SIZE_32 | 0;
   sprites[9].attribute2 = char_number+(128+512);

   char_number_n6 = char_number+(128+512);

   sprites[10].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[10].attribute1 = SIZE_32 | 0;
   sprites[10].attribute2 = char_number+(128+576);

   char_number_n7 = char_number+(128+576);

   sprites[11].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[11].attribute1 = SIZE_32 | 0;
   sprites[11].attribute2 = char_number+(128+640);

   char_number_n8 = char_number+(128+640);

   sprites[12].attribute0 = COLOR_256 | SQUARE | 0;
   sprites[12].attribute1 = SIZE_32 | 0;
   sprites[12].attribute2 = char_number+(128+704);

   char_number_n9 = char_number+(128+704);

//allright now to copy in the sprites bitmap.  The data in sprite1Data is allready striped
//so we just copy it in one row of tiles at a time.  The only difference between this and a
//2D sprite is that we would need to keep in mind the fact that the tiles are not all in a row.
//We could just use one big for loop.  There are 8 rows (64x64 = 8x8 tiles) so we loop through
//all 8.  There is 512 bytes per row (8 tiles * 8x8 = 512) but since we copy 2 bytes at a
//time that equals 256.  The width of char memory is 32 * 8x8 = 1024 (512 double bytes).
//   
      for(index = 0; index < 256*4; index++)
      {
         OAMData[index] = SPRITE1Data[index];  //copy it starting 512 tiles into oamdata mem.  remember one tile = 32bytes and OAMdata is 16 bit pointer so offset is 512*16
                                       //UPDATE: 512 tile offset no longer needed
                                       //Mar 20 2003
      }//end index loop
      for(index =0 ; index <256*2 ; index++)
      {
         OAMData[index+256*8] = SPRITE2Data[index]; 
         
      }//end index loop
      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*12] = SPRITE4Data[index];
      }

      //inserting number sprites to OAM
      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*16] = NUMBER0Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*20] = NUMBER1Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*24] = NUMBER2Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*28] = NUMBER3Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*32] = NUMBER4Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*36] = NUMBER5Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*40] = NUMBER6Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*44] = NUMBER7Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*48] = NUMBER8Data[index];
      }

      for(index = 0; index < 256*4; index++)
      {
         OAMData[index+256*52] = NUMBER9Data[index];
      }

   while(1)
   {
      while(!(REG_DISPSTAT & 1));//wait for vblank to start
      GetInput();    //get input changes the x and y based on input
      MoveSprite(&sprites[0],x,y); //changes sprite atributes based on new x,y
      MoveSprite(&sprites[1],xs,ys);
      MoveSprite(&sprites[2],x4,y4);
      REG_BG0VOFS = y ;
      REG_BG0HOFS = x ;
      while((REG_DISPSTAT & 1));//wait for vblank to end
      WaitForVsync();         //waits for the screen to stop drawing
      CopyOAM();            //Copies our sprite array into OAM.
   }
}

//end of entry point


That's all, folks... thanks for your time. Any assistance would be most appreciated. This is one of the last hurdles before I add more levels and more logic into the engine. Let me know if you'd like a demo!

-slippers2k
_________________
Subaru -
Because you never thought you'd get your ego handed to you by a station wagon on the track.

#4154 - Paul Shirley - Fri Mar 21, 2003 11:26 am

...removed: misread part of the post...