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 > too many sprites....not enough space

#16451 - slboytoy - Mon Feb 16, 2004 9:46 pm

i'm trying to work in mode 4 (or any of the bitmodes if necessary) and i'm trying to build a program that uses a lot of sprites. at this point i have two problems so if anybody has any idea how to fix either one, let me know.

1) is there any way to extend the OAM memory so i can include 1 or two more sprites (each extra sprite will be 16x16)?

2) is there any reason why plotting pisels using
Code:
VideoBuffer[xpos+ypos*240] = RGB16(0,15,15)

isn't working? all it does is blank the entire screen (including the sprites that are drawn to the screen when the pixel plotting code is removed)

any help would be appreciated

#16453 - poslundc - Mon Feb 16, 2004 11:30 pm

slboytoy wrote:
1) is there any way to extend the OAM memory so i can include 1 or two more sprites (each extra sprite will be 16x16)?


OAM is designed to allow up to 128 sprites on screen at any one time. Do you really need more than 128 on at any given moment?

(In other words, there is no practical limit to how many sprites you use in your game, just how many are onscreen at the same time.)

Quote:
2) is there any reason why plotting pisels using
Code:
VideoBuffer[xpos+ypos*240] = RGB16(0,15,15)

isn't working? all it does is blank the entire screen (including the sprites that are drawn to the screen when the pixel plotting code is removed)


There could be a million reasons. Post your code and maybe we'll be able to help more specifically.

Dan.

#16455 - yaustar - Tue Feb 17, 2004 12:32 am

Doesnt mode four use a palette? or is it me being naive again?
_________________
[Blog] [Portfolio]

#16463 - Krakken - Tue Feb 17, 2004 9:10 am

Yes modes: 0, 1, 2 and 4 use a palette. You would only use that code for modes 3 and 5 which read the RGB value from the actual display data. Don't forget about the writing 2 bytes at a time to the VRAM in mode 4 too.

#16483 - slboytoy - Tue Feb 17, 2004 8:09 pm

sorry, i didn't mean OAM memory, i meant the character memory holding the sprite info. including a background palette to work with the VideoBuffer function help but it seems that this draws over my sprites. anybody see any reason why? here's the full code
Code:
#include "gba.h"       //GBA register definitions
#include "keypad.h"     //button registers
#include "dispcnt.h"    //REG_DISPCNT register #defines
#include "sprit.h"      //my generic sprite header file
#include "modemenu.h"   //mode menu info
#include "voltmenu.h"   //volt menu info
#include "linemenu.h"   //line menu info
#include "palette.h"   //palette info

#define MULTIBOOT const int __gba_multiboot
MULTIBOOT = 1;

#define RGB16(r,g,b)  ((r)+(g<<5)+(b<<10))

//create an OAM variable and make it point to the address of OAM
u16* OAM = (u16*)0x7000000;
u16 flag = 0;

//create the array of sprites (128 is the maximum)
OAMEntry sprites[128];

//create the rotation and scaling array (overlaps the OAMEntry array memory)
pRotData rotData = (pRotData)sprites;

//animated sprite structure required
typedef struct
{
   u16 x;         //x and y position on screen
   u16 y;
   u16 spriteFrame;        //animation frame
   int activeFrame;        //which frame is active
}Sprite;

//using the structure for different sprites
Sprite modeSprite;
Sprite voltSprite;
Sprite lineSprite;

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

//Set sprites to off screen
void InitializeSprites()
{
   u16 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()
{
   while((volatile u16)REG_VCOUNT != 160){}
}

void GetInput()
{
   u16 wait, a;

   if(!(*KEYS & KEY_UP))      //if the up key is pressed
   {
      for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
   }
   if(!(*KEYS & KEY_DOWN))         //if the up down is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
   }
   if(!(*KEYS & KEY_LEFT))      //if the left key is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
   }
   if(!(*KEYS & KEY_RIGHT))         //if the right key is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
   }
   if(!(*KEYS & KEY_A))         //if the a key is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
      //extending the menus
      modeSprite.x = 11;
      modeSprite.y = 35;
      voltSprite.x = 93;
      voltSprite.y = 35;
      lineSprite.x = 177;
      lineSprite.y = 45;
   }
   if(!(*KEYS & KEY_B))         //if the b key is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
      //minimizing the menu
      modeSprite.x = 240;
      modeSprite.y = 160;
      voltSprite.x = 240;
      voltSprite.y = 160;
      lineSprite.x = 240;
      lineSprite.y = 160;
   }
   if(!(*KEYS & KEY_START))         //if the start key is pressed
   {
       for (wait=0; wait<=10000; wait++)
      {
         a = a + wait;
         a = 0;
      }
   }
}

int main()
{
   u16 loop;       //generic loop variable
   int xpos, ypos;

   //set initial sprite locations
   modeSprite.x = 240;
   modeSprite.y = 160;

   voltSprite.x = 240;
   voltSprite.y = 160;

   lineSprite.x = 240;
   lineSprite.y = 160;


      SetMode(MODE_4 | OBJ_ENABLE | OBJ_MAP_1D | BG2_ENABLE); //set mode 4, enable sprites, 1d mapping and enable background 2

   for(loop = 0; loop < 256; loop++)          //load the palette into object memory
      OBJPaletteMem[loop] = Palette[loop];
   for(loop = 0; loop < 256; loop++)          //load the palette into background memory
      BGPaletteMem[loop] = Palette[loop];

   InitializeSprites();

   //load the sprite data into memory
   for(loop = 8192; loop < 8192+2048; loop++)                       //load sprite image data
   {
      OAMData[loop] = modeData[loop-8192];
   }

   for(loop = 10240; loop < 10240+3072; loop++)
   {
      OAMData[loop] = voltData[loop-10240];
   }

   for(loop = 13312; loop < 13312+3072; loop++)
   {
      OAMData[loop] = lineData[loop-13312];
   }


   while(1)                                //main loop
        {
         //colouring the background
         for(xpos=0; xpos<120; xpos++)   //loop through all x
         {
            for(ypos=0; ypos<160; ypos++)  //loop through all y
            {
               VideoBuffer[xpos+ypos*120] = RGB16(0,20,24);
            }
         }

         //initilaize the sprite attributes
         sprites[0].attribute0 = COLOR_256 | TALL | 20;   //setup sprite info, 256 colour, shape and y-coord
         sprites[0].attribute1 = SIZE_64 | 15;           //size 64x32 and x-coord
         sprites[0].attribute2 = 512 | PRIORITY(3);      //pointer to tile where sprite starts

         sprites[1].attribute0 = COLOR_256 | TALL | 20;   //setup sprite info, 256 colour, shape and y-coord
         sprites[1].attribute1 = SIZE_64 | 100;          //size 64x32 and x-coord
         sprites[1].attribute2 = 640 | PRIORITY(3);      //pointer to tile where sprite starts

         sprites[2].attribute0 = COLOR_256 | TALL | 17;   //setup sprite info, 256 colour, shape and y-coord
         sprites[2].attribute1 = SIZE_64 | 180;          //size 64x32 and x-coord
         sprites[2].attribute2 = 832 | PRIORITY(3);      //pointer to tile where sprite starts
         
         sprites[3].attribute0 = COLOR_256 | TALL | modeSprite.y;   //setup sprite info, 256 colour, shape and y-coord
         sprites[3].attribute1 = SIZE_64 | modeSprite.x;             //size 64x32 and x-coord
         sprites[3].attribute2 = 576 | PRIORITY(1);

         sprites[4].attribute0 = COLOR_256 | TALL | voltSprite.y;   //setup sprite info, 256 colour, shape and y-coord
         sprites[4].attribute1 = SIZE_64 | voltSprite.x;             //size 64x32 and x-coord
         sprites[4].attribute2 = 704 | PRIORITY(1);

         sprites[5].attribute0 = COLOR_256 | TALL | voltSprite.y+25;   //setup sprite info, 256 colour, shape and y-coord
         sprites[5].attribute1 = SIZE_64 | voltSprite.x-7;             //size 64x32 and x-coord
         sprites[5].attribute2 = 768 | PRIORITY(1);

         sprites[6].attribute0 = COLOR_256 | TALL | lineSprite.y;   //setup sprite info, 256 colour, shape and y-coord
         sprites[6].attribute1 = SIZE_64 | lineSprite.x;             //size 64x32 and x-coord
         sprites[6].attribute2 = 896 | PRIORITY(1);

         sprites[7].attribute0 = COLOR_256 | TALL | lineSprite.y+25;   //setup sprite info, 256 colour, shape and y-coord
         sprites[7].attribute1 = SIZE_64 | lineSprite.x-6;             //size 64x32 and x-coord
         sprites[7].attribute2 = 960 | PRIORITY(1);

         GetInput();
         WaitForVsync();         //waits for the screen to stop drawing
         CopyOAM();         //Copies sprite array into OAM.
   }
}

#16486 - poslundc - Tue Feb 17, 2004 8:47 pm

slboytoy wrote:
sorry, i didn't mean OAM memory, i meant the character memory holding the sprite info.


Sorry, I don't have time at the moment to look over your code, but in response to your first query you can swap some of the character data in and out of VRAM during VBlank, so like OAM you're only limited to the 32K of sprite VRAM available per frame, not in your game.

Timing may be an issue depending on how many sprites you want to swap in and out of each frame; for more information on that see tepples' excellent Sprite VRAM memory management FAQ.

Dan.