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.

Beginners > [SOLVED] sprites are acting crazy

#72518 - deltree - Sun Feb 19, 2006 2:23 pm

solution for this problem:
never define an array without specify the size of it. else, it will work weirdly or not at all.

--------------------------------------------------------------

please, help me, I've spent hours on this, and I don't know what's wrong with it:
Code:
#include <mygba.h>
// Graphics Includes (palette+ship+bullets)
#include "gfx/general.pal.c"
#include "gfx/tir.raw.c"
#include "gfx/vaisseau.raw.c"
// sprites
u8 player_sprite,bullet_sprite,bullets_sprite[10]; // Sprite object number
//positions
u16 player_x,player_y,bullets_y[],bullets_x[];
//variables
int num_bullets=0,press_A=0,vbl_ok=0,i=0;

void vbl_func()
{
   vbl_ok=1;
   ham_SetObjXY (player_sprite,player_x,player_y);
   //move bullets
   for (i=0;i<num_bullets;i++)
   {
      if (bullets_y[i]>10) bullets_y[i]--;
      ham_SetObjXY(bullets_sprite[i],bullets_x[i],bullets_y[i]);
   }
   ham_CopyObjToOAM();
} // End of vblFunc()

int main()
{
    ham_Init();
   ham_SetBgMode(2); // Setup the background mode
    ham_LoadObjPal((void*)general_Palette,256);
    //create the player
   player_x=50;
   player_y=60;
   player_sprite = ham_CreateObj((void*)vaisseau_Bitmap,OBJ_SIZE_16X16,OBJ_MODE_NORMAL,1,0,0,0,0,0,0,player_x,player_y);
   //create the bullet sprite
   bullet_sprite=ham_CreateObj((void*)tir_Bitmap,OBJ_SIZE_8X8,OBJ_MODE_NORMAL,1,0,0,0,0,0,0,240,10);
   ham_StartIntHandler(INT_TYPE_VBL,(void*)&vbl_func);
    while(1)
    {
      if (vbl_ok==1)
      {
         vbl_ok=0;
         //control the player
         if(F_CTRLINPUT_LEFT_PRESSED && player_x > 0) player_x--;
         if(F_CTRLINPUT_UP_PRESSED && player_y > 0) player_y--;
         if(F_CTRLINPUT_DOWN_PRESSED && player_y < 144) player_y++;
         if(F_CTRLINPUT_RIGHT_PRESSED && player_x < 224) player_x++;
         
         if(F_CTRLINPUT_A_PRESSED && num_bullets<10 && press_A==0)
         {
            press_A=1;
            bullets_x[num_bullets]=player_x;
            bullets_y[num_bullets]=player_y;
            bullets_sprite[num_bullets]=ham_CloneObj(bullet_sprite,bullets_x[num_bullets],bullets_y[num_bullets]);
            num_bullets++;
         }
         else if(!F_CTRLINPUT_A_PRESSED ) press_A=0;
      }
    }
} // End of main()

the resulting rom is here:
http://superdeltree.free.fr/jeux/devgba/test/shmups.gba

it behaves properly untils the 5th missile is launched, and after, everything is fucked up. the missile don't move properly, the plane sprite dissapear, then the plane sprite come in place of one missile sprite. Please someone explain me what's wrong...


Last edited by deltree on Mon Feb 20, 2006 10:17 am; edited 2 times in total

#72528 - deltree - Sun Feb 19, 2006 4:17 pm

Code:

#include <mygba.h>
// Graphics Includes (palette+ship+bullets)
#include "gfx/general.pal.c"
#include "gfx/tir.raw.c"
#include "gfx/vaisseau.raw.c"
// sprites
u8 player_sprite;
u8 bullets_sprite[]; // Sprite object number
//positions
int i=0;

int main()
{
    ham_Init();
   ham_SetBgMode(0); // Setup the background mode
    ham_LoadObjPal((void*)general_Palette,256);
   player_sprite = ham_CreateObj((void*)vaisseau_Bitmap,OBJ_SIZE_16X16,OBJ_MODE_NORMAL,1,0,0,0,0,0,0,50,100);
   //create the bullet sprite
   for (i=0;i<10;i++)   {
      bullets_sprite[i]=ham_CreateObj((void*)tir_Bitmap,OBJ_SIZE_8X8,OBJ_MODE_NORMAL,1,0,0,0,0,0,0,2+i*10,10);
   }
   ham_SetObjXY (player_sprite,50,100);
   ham_CopyObjToOAM();
    while(1)
    {
    }
} // End of main()


I simplified the code a lot, to check the origin of the problem:
this code is only supposed to display 10 bullet sprites aligned, and 1 ship sprite on botton of screen.
then, it's supposed to move the ship sprite to (50,100)...
but instead, it's the bullet #9 that move at this position!!

#72532 - Cearn - Sun Feb 19, 2006 5:23 pm

That's one interesting demo you got there o_O

Looking at that and the code from the OP, I think this may be the problem:
deltree wrote:
Code:
u16 player_x,player_y,bullets_y[],bullets_x[];

Sooo ... how many elements do bullets_y[] and bullets_x[] have exactly? Hint: it's not 10.

Don't know if this will solve all the problems, but I'm guessing it'll go a long way.

Two other issues you may run into in the future:
Having loop counters (i) as global variables is probably a bad idea. What if you're calling a function that also uses it in it's own loop?

When using unsigned variables, checks with 0 may not work the way you might hope. By definition, they are always positive.

And, of course, the usual rant: don't #include code or data. And ints generally work better than bytes and halfwords. :P

#72540 - deltree - Sun Feb 19, 2006 6:07 pm

Quote:
Sooo ... how many elements do bullets_y[] and bullets_x[] have exactly? Hint: it's not 10.

I Thought declaring the array like this would allow me to have as many elements as I needed to have, on the fly.

Having loop counters (i) as global variables is probably a bad idea. What if you're calling a function that also uses it in it's own loop?

the i variable, I always use it in the "for" loop, only. I may have multiple function using this variable, why not? exept for interrupt function, that are called whenever...

thanx a lot for all these tips whatsoever.
It's getting so much on my nerves, those types and declares, sometime I just wanna give up.

#72541 - tepples - Sun Feb 19, 2006 6:45 pm

deltree wrote:
Quote:
Sooo ... how many elements do bullets_y[] and bullets_x[] have exactly? Hint: it's not 10.

I Thought declaring the array like this would allow me to have as many elements as I needed to have, on the fly.

Nope, the way to do dynamic allocation in C is realloc(). But in an embedded environment, it's probably best to assume the worst case and have a maximum of however many bullets on the screen.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#72550 - Cearn - Sun Feb 19, 2006 8:34 pm

deltree wrote:
Quote:
Sooo ... how many elements do bullets_y[] and bullets_x[] have exactly? Hint: it's not 10.

I Thought declaring the array like this would allow me to have as many elements as I needed to have, on the fly.

Sorry, not in this language. Arrays always have a static size. As tepples' said, you can allocate your own memory (don't forget to free it afterwards), but it's slower and you don't have much memory to begin with.

deltree wrote:

cearn wrote:
Having loop counters (i) as global variables is probably a bad idea. What if you're calling a function that also uses it in it's own loop?

the i variable, I always use it in the "for" loop, only. I may have multiple function using this variable, why not? exept for interrupt function, that are called whenever...

Consider what happens here:
Code:
int ii=0;

void clear_row(int *row, int width)
{
    for(ii=0; ii<width; ii++)
        row[ii]= 0;
}

void clear_matrix(int *matrix, int width, int height)
{
    for(ii=0; ii<height; ii++)
        clear_row(&matrix[ii*height], width);
}

Inside clear_matrix(), ii starts as 0, then jumps to clear_row() where it is updated to width. When you return to clear_matrix(), the value will still be width, and not zero as it should be. Aside from that, being global also means it'll take up memory, which it has to be loaded from and stored into again whenever you use it, which equals slow code.

deltree wrote:

It's getting so much on my nerves, those types and declares, sometime I just wanna give up.

It can be frustrating if you're used to javascript or something like that, but the power of C (in both speed and compactness) comes from the fact that it is a pretty low level language. The price for that is that you have to be careful and to take care of memory stuff yourself.

#72556 - deltree - Sun Feb 19, 2006 9:29 pm

Thank for the help, it works now.
That's a good lesson to learn, next time I won't waste so much time about it.
about global variable:
I'm perfectly aware of the problem you describe, this is very logic.
it's the same as having a "for..." loop inside another one, the variable mustn't have the same name of course.
Well, I guess it can avoid mistakes, so I'll do as you said, local, not global.