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 > math class is hard

#6877 - hnager - Wed Jun 04, 2003 2:11 am

This one has been haunting me for a day and a half now - I'm working on some sprite tests inorder to teach myself gba development - below is a snipet of a 'tank game' which I'm making...I'm using 16 pre rotated sprites (one thing at a time...sprite rotation will come later). You can see that the right/left buttons affect the tank's current frame (used as an index in an array and set in attribute2).

My problem is with up/down. To start - I've had no luck using a lookup table because the index is cast to a (float) : PI*angle/180 - I went back to using the math functions for now (one thing at a time ;). The other problem I'm having is that the motion just doesn't seem 'right'. It should be like a classic tank game...but it's both too fast (and responsive) and the speed doesnt seem consistent for all the angles.

In short - help! My math is rusty and I could stare at it all night and miss the obvious - if there is one.

// DEFINES //////////////////////
#define TANK_SPEED 2
#define PI (float)3.14159


etc etc

main(){

...

while(1){

if(!(KEYS & KEY_UP)){

angle = (90+360-22.5*tank1_direction);
dx = TANK_SPEED * cos(PI*angle/180);
dy = TANK_SPEED * sin(PI*angle/180);

tank1.x += (int)(dx+.5);
tank1.y -= (int)(dy+.5);

}
if(!(KEYS & KEY_DOWN)){

angle = (90+360-22.5*tank1_direction);
dx = TANK_SPEED * cos(PI*angle/180);
dy = TANK_SPEED * sin(PI*angle/180);

tank1.x += (int)(dx+.5);
tank1.y -= (int)(dy+.5);
//tank1.y += 1;

}
if(!(KEYS & KEY_LEFT)){
if(--tank1_direction < 0) tank1_direction = 15;

}
if(!(KEYS & KEY_RIGHT)){
if(++tank1_direction > 15) tank1_direction = 0;

}

...

} //end while

...

} //end main

#7125 - Ein_Vante - Tue Jun 10, 2003 4:39 am

Perhaps you should use a 2x3 matrix to keep track of rotation and position instead? Speed will vary depending on your direction if you're moving one pixel/point per step, you must use floats or at least fixed point for this(precision vs. speed) since the diagonal is obviosly longer than the height or width of anything cubic.
I can't tell if you're using floats or integers in that code segment of your, so I simply have to guess.

If you want to vary the responsivness of the tank, make it more tanklike, then you might want to vary the ability to turn based on how fast it's moving. Pre-calc a table for this and multiply your ability to turn with whatever number you find that correspond to the speed and also decrease the speed when turning.
The table should range between 1-0 where 1 gives absolute ability to turn and 0 won't turn at all, but taking into account that you decrease your speed when turning the turning will just seem "sluggish" at top speed.
And that corresponds pretty well to a tank considering that it turns by varying the speeds on its tracks.

Well, that's just some ideas I come up with, perhaps you'll find something that you can use in them.

#7169 - djei-dot - Wed Jun 11, 2003 10:43 am

Maybe it is a dumb answer, but shouldn't you wait for Vblank? I've done some studies with the gbaguy's tutorials and in simple instructions - pixel drawing when key is pressed, etc. - it is really fast (and that surprised me since all the complaints in this forum are about the GBA being slow). I think that if you put the WaitForVBlank instruction it will be significantly slower.

#7199 - hnager - Thu Jun 12, 2003 2:53 am

same as WaitForVsync()? That definately helps keep things going at a manageable speed, but it still is pretty quick (at or around 60 times a second - i believe). What kinds of techniques do people use to create slower motion without keypresses being ignored (if you only capture everyother frame for example).

#7211 - tepples - Thu Jun 12, 2003 10:18 am

Fixed-point arithmetic to the rescue: Set up your game coordinate system so that 256 units equal one pixel. Then you can easily represent velocities smaller than one pixel per delta-t.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#7221 - hnager - Thu Jun 12, 2003 1:54 pm

Thanks - I'll try that, would shifting dx and dy do the same? It also sounds as if I should take advantage of hardware rotation (sprites) instead of the fixed 15 frames I have now, how else would I slow down the frame increment? Currently I have it ++ and -- based on left and right.

#7222 - niltsair - Thu Jun 12, 2003 2:18 pm

I create timers based on VBlank. Then I just check if the amount of ms occur before taking into acount the same keypress again(when it's being holded).

To do this, just create a global variable (or as many as you want timer) that will hold the count. Create another global variable that will tell the state of the timer (enabled/stoped). Now, on each VBlank interupt, increase the value by 1 if the timer is enabled.

In code where you need to use timer, declare those 2 variables as external, and just access them to know time. I used this technique because VBlank has a much more reliable behavior in the different emulators than the hardward timers.

#7225 - hnager - Thu Jun 12, 2003 2:24 pm

Out of curiousity - why do you declare as external?

could I also do something like:

if(!(KEYS & KEY_RIGHT)){
if(!(count%3)){
if(++tank1_direction > 15) tank1_direction = 0;
}
}

??

#7231 - niltsair - Thu Jun 12, 2003 2:44 pm

You delcare the timer's variables(count, state) in the same source file as where the interupt are declared. Then you redeclare it somewhere else (might be in a header used be every files) the exact same way you did previously, but with an external in front. This tell the compiler that it needs to find an already existing variable somewhere in your source files, at linking stage.

It basicly allow you to use global variable that are usually unreacheable because not in the same .cpp file.