I am new right here so let me know if my query is unsuitable or if I’ve not requested it accurately. I am making an attempt to make a GBA sport with top-down grid-based motion (like within the GBA Pokemon or Closing Fantasy video games). I have been following the Tonc GBA programming textbook, and have been having issues even getting my sprite (the “walker”) to maneuver across the display screen easily. I do not consider my points to be platform specific—they simply need to do with the logic of find out how to transfer a sprite round a map.
I based mostly my try off the code present in this discussion board put up, although I needed to translate all the pieces from Lua(?) to C and in addition tailored a few of the logic to suit how the GBA does its replace loop (although I am not completely assured I perceive how the draw/replace loop works with the GBA, so I may need made some logical errors on this translation).
To start with, some constants and variables:
#outline TILE_WIDTH 8
#outline TILE_HEIGHT 8
#outline INIT_TILE_X 12
#outline INIT_TILE_Y 4
#outline TURN_DELAY 3 /* measured in variety of frames */
enum route {LEFT, RIGHT, UP, DOWN, NEUTRAL};
enum route heading = NEUTRAL; /* route walker goes */
enum route key_heading = NEUTRAL; /* route participant is holding */
int tile_x = INIT_TILE_X;
int tile_y = INIT_TILE_Y;
int x = INIT_TILE_X * TILE_WIDTH; /* pixel place */
int y = INIT_TILE_Y * TILE_HEIGHT;
bool can_move = true;
int turn_timer = 0; /* used to pressure a delay when altering instructions */
Then two helper features:
void update_key_heading() {
if (key_hit(KEY_LEFT)) key_heading = LEFT;
if (key_hit(KEY_RIGHT)) key_heading = RIGHT;
if (key_hit(KEY_UP)) key_heading = UP;
if (key_hit(KEY_DOWN)) key_heading = DOWN;
if (key_is_up(KEY_LEFT) && key_is_up(KEY_RIGHT)
&& key_is_up(KEY_UP) && key_is_up(KEY_DOWN)) {
key_heading = NEUTRAL;
}
return;
}
void update_position() {
int dest_x = tile_x * TILE_WIDTH;
int dest_y = tile_y * TILE_HEIGHT;
if (x == dest_x && y == dest_y) {
/* we have made it to our vacation spot, so we're allowed to set a brand new one */
can_move = true;
return;
}
if (x != dest_x) {
/* if have not reached dest_x, transfer horizontally */
x += (dest_x > x) ? 1 : -1;
} else {
/* if have not reached dest_y, transfer vertically */
y += (dest_y > y) ? 1 : -1;
}
return;
}
To make clear, key_hit() checks (utilizing a masks) if the important thing in query was simply hit now (i.e., was up earlier than however is down now).
Lastly, this is my infinite sport loop (which calls another features that I did not outline right here, however I believed I might put the entire major() perform for completeness).
int major() {
bg_init(); /* load background */
sprite_init(); /* load sprite */
REG_DISPCNT= DCNT_MODE0 | DCNT_BG0 | DCNT_OBJ | DCNT_OBJ_1D; /* set show mode */
whereas(1) {
vid_vsync();
key_poll(); /* test what keys are held down */
update_key_heading();
if (can_move) {
/* learn a brand new route to maneuver */
heading = key_heading;
if (key_heading != NEUTRAL && key_heading != heading) {
turn_timer = TURN_DELAY;
}
/* set the brand new participant tile coordinates, that might be
the brand new vacation spot */
change (heading) {
case UP:
tile_y -= 1;
break;
case DOWN:
tile_y += 1;
break;
case LEFT:
tile_x -= 1;
break;
case RIGHT:
tile_x += 1;
break;
case NEUTRAL:
break;
}
can_move = false;
}
if (turn_timer == 0) {
update_position();
} else {
--turn_timer;
}
obj_set_pos(walker, x, y); /* set the sprite's pixel-position to (x,y) */
oam_copy(oam_mem, obj_buffer, 1); /* draw the sprite */
}
I traced the logic and might’t discover any obvious errors, however after I hearth up the sport in a GBA emulator, the motion is sort of unplayably buggy, actually nothing like, say, a Pokemon sport. Issues are effective if I enter the instructions very slowly and intentionally, taking care to not enter two completely different instructions without delay, however that’s not how folks usually use D-pads.
One supply of bugginess that I can speculate being the difficulty is that a number of keys might be hit without delay (key_hit checks every key utilizing a bit masks), and happening is checked final, so the key_heading is “extra doubtless” to be set to DOWN than LEFT. Certainly, if I take a look at a standard use-case of holding a number of instructions at once—say I wish to go 20 tiles proper and three tiles up, I might maintain the best button on the D-pad after which kind of faucet the up button 3 times whereas nonetheless holding the best button down—sometimes the sprite will get caught shifting down, despite the fact that I do not assume I am urgent the down button at any level!
I believed this could be fastened by tweaking the flip delay parameter (which I would not have even considered including with out that discussion board put up to information me), however it doesn’t matter what I set it to, it is nonetheless very erratic with the walker stepping into bizarre instructions typically.
I do know this could be quite a bit to ask, however would anybody be capable to see any obvious issues with the best way I’ve arrange motion right here?
Or, if the best way I’ve achieved it’s simply too janky to be salvaged, I might additionally admire if anybody may clarify (or refer me to) a extra sturdy technique to deal with this sort of participant motion. Thanks prematurely!
