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 > Sprite animation

#6138 - e_mpika - Sun May 18, 2003 4:34 am

Hallo everyone, im quite new to gba porgramming so bear with me!
im trying to animat a sprite, i just want to loop it, the are 3 frame of a man walking.
ive learnt alot and think i understand most of it so far, basically this code is a copy and paste of tutorial stuff ive come accross, please could you help me animate my man, i have set up the man and loaded the sprite data and stuff, i just need to be able to loop between attribute2's, i have made a struce to hold the frame numbers in.

//my code for a man, by eddy parris.

#include "gba.h"
#include "screenmode.h"
#include "sprite.h"
#include "spred_sprite.h"

//#include "palette.h"
#include "keypad.h"

s16 x = 50;
s16 y = 60;
u16 char_number = 0;
u16 frame =0;

void GetInput(void);

void MoveSprite(OAMEntry* sp, int x, int y);

OAMEntry sprites[128];

typedef struct
{
u16 x; //x and y position on screen
u16 y;
u16 spriteFrame[3]; //animation frame
int activeFrame; //which frame is active
}Sprite;

Sprite man;


void CopyOAM()
{
u16 loop;
u16* temp;
temp = (u16*)sprites;


for(loop = 0; loop < 128*4; loop++)
{
OAMmem[loop] = temp[loop];
}
}

void GetInput(void)
{
if(!(*KEYS & KEY_UP))
{
y--;
}
if(!(*KEYS & KEY_DOWN))
{
y++;
}
if(!(*KEYS & KEY_LEFT))
{
x--;
}
if(!(*KEYS & KEY_RIGHT))
{
x++;
}
if(!(*KEYS & KEY_A))
{
x++;
y++;
}
}


void MoveSprite(OAMEntry* sp, int x, int y)
{
if(x < 0)
x = 512 + x;
if(y < 0)
y = 256 + y;

sp->attribute1 = sp->attribute1 & 0xFE00;
sp->attribute1 = sp->attribute1 | x;

sp->attribute0 = sp->attribute0 & 0xFF00;
sp->attribute0 = sp->attribute0 | y;
}

void InitializeSprites()
{
u16 loop;
for(loop = 0; loop < 128; loop++)
{
sprites[loop].attribute0 = 160;
sprites[loop].attribute1 = 240;
}
}


void WaitForVsync()
{
while((volatile u16)REG_VCOUNT != 160){}
}



int main()
{
u16 loop;


SetMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);

for(loop = 0; loop < 256; loop++)
OBJPaletteMem[loop] = spred_sprite_pal[loop];

InitializeSprites();

sprites[0].attribute0 = COLOR_256 | WIDE | y;
sprites[0].attribute1 = SIZE_32 | x;
sprites[0].attribute2 = 0;


for(loop = 0; loop < 768; loop++)
{
OAMdata[loop] = spred_sprite_pak[loop];
}

man.activeFrame = 0; //set the initial active frame markers
man.spriteFrame[0] = 0; //set the frame markers
man.spriteFrame[1] = 16;
man.spriteFrame[2] = 32;

while(1)
{

GetInput();
MoveSprite(&sprites[0],x,y);

WaitForVsync();

CopyOAM();

}
}

#6448 - Daedro - Mon May 26, 2003 2:44 am

I woudly really like this answered too.

#6452 - Quirky - Mon May 26, 2003 8:09 am

One way to do it would be to add an interrupt on vblank, count the number of game frames and then animate in the main loop every X frames. I assume that you have loaded just 1 frame into OAM? Well, what you need to do is load the next animation frame in on the next loop.

Read one of the interrupt tutorials, but basically something like this to set the interrupts up:

Code:

int game_frames;
void init_interrupts(void) {
  REG_IME = 0x00;                       // Disable interrupts
  REG_INTERUPT = (u32)IRQHandler;    // interrupt function address
  REG_IE = INT_VBLANK;   // enable vblank interrupt only
  REG_IF = 0x00;
  REG_DISPSTAT = 0x8;      // bit 3, display vblank intrpt
  REG_IME = 0x01;
  game_frames = 0;
}



Then you need to add the code to handle interrupts :
Code:

void IRQHandler(void) {
 
  REG_IME = 0x00;     // Disable interrupts
  u16 Int_Flag;
  Int_Flag = REG_IF; // Read the interrupt flags
 
  if (Int_Flag == INT_VBLANK) {
    game_frames++;
   
  }
 
   
  REG_IME = 0x1;                  // Enable interrupts
  REG_IF = Int_Flag;              // Write back the interrupt flags 
}


Finally, in your main game loop, do something like this:

Code:

int spriteFrame = 0;
while(1)
{
  GetInput();
  MoveSprite(&sprites[0],x,y);
  // choose a number here, 20 might look rubbish
  if (game_frame == 20) {
    SetSpriteFrame(&sprites[0], spriteFrame);
  }
  WaitForVsync();
  CopyOAM();
}


void SetSpriteFrame(OAMEntry* sp, int frame) {
 
  // load the next animation frame...
  // 768 is the size of 1 frame, probably :)
  int loop;
  int offset = 768*frame;
  for(loop = 0; loop < 768; loop++)  {
    OAMdata[loop] = spred_sprite_pak[offset+loop];
  }
 
}


That assumes you have your sprite data set up so that you have 1 frame in the first 768 bytes (?)

Play around with it though, it should at least give you some ideas...