diff --git a/include/sprite.h b/include/sprite.h index ba4dee49..df9f6be5 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -236,7 +236,7 @@ void sprite_object_reset_transform(SpriteObject* sprite_object); * * @param sprite_object pointer to SpriteObject to update. Cannot be **NULL**. */ -void sprite_object_update(SpriteObject* sprite_object); +IWRAM_CODE void sprite_object_update(SpriteObject* sprite_object); /** * @brief Shake SpriteObject on screen and play a sound diff --git a/source/game.c b/source/game.c index 6fb82863..0fa90619 100644 --- a/source/game.c +++ b/source/game.c @@ -561,7 +561,7 @@ static inline void discarded_jokers_update_loop(void) static inline void held_jokers_update_loop(void) { - const int spacing_lut[MAX_JOKERS_HELD_SIZE][MAX_JOKERS_HELD_SIZE] = { + static const int spacing_lut[MAX_JOKERS_HELD_SIZE][MAX_JOKERS_HELD_SIZE] = { {0, 0, 0, 0, 0 }, {13, -13, 0, 0, 0 }, {26, 0, -26, 0, 0 }, @@ -1838,6 +1838,7 @@ static inline void card_draw(void) card_object->sprite_object->x = deck_x; card_object->sprite_object->y = deck_y; + sprite_position(card_object->sprite_object->sprite, fx2int(deck_x), fx2int(deck_y)); hand[++hand_top] = card_object; @@ -2828,10 +2829,17 @@ static inline void cards_in_hand_update_loop(void) { hand_y -= int2fx(CARD_FOCUSED_SEL_Y); } - if (i != selected_card_idx && hand[i]->sprite_object->y > hand_y) { hand[i]->sprite_object->y = hand_y; + sprite_position( + hand[i]->sprite_object->sprite, + fx2int(hand[i]->sprite_object->x), + fx2int(hand_y) + ); + // Set target y to match y. Ensures target is updated even when vy becomes + // 0, preventing immediate snap back. + hand[i]->sprite_object->ty = hand_y; hand[i]->sprite_object->vy = 0; } diff --git a/source/game/main_menu.c b/source/game/main_menu.c index ca9b0eab..5b7303a2 100644 --- a/source/game/main_menu.c +++ b/source/game/main_menu.c @@ -124,9 +124,8 @@ void game_main_menu_on_init(void) void game_main_menu_on_update(void) { - card_object_update(main_menu_ace); main_menu_ace->sprite_object->trotation = lu_sin((g_game_vars.timer << 8) / 2) / 3; - main_menu_ace->sprite_object->rotation = main_menu_ace->sprite_object->trotation; + card_object_update(main_menu_ace); // Seed randomization g_game_vars.rng_seed++; diff --git a/source/sprite.c b/source/sprite.c index 72072f90..a2de41fc 100644 --- a/source/sprite.c +++ b/source/sprite.c @@ -209,8 +209,27 @@ void sprite_object_reset_transform(SpriteObject* sprite_object) sprite_object->vrotation = 0; } -void sprite_object_update(SpriteObject* sprite_object) +static inline bool sprite_object_has_velocity(const SpriteObject* sprite_object) { + return sprite_object->vx != 0 || sprite_object->vy != 0 || sprite_object->vscale != 0 || + sprite_object->vrotation != 0; +} + +static inline bool sprite_object_at_target(const SpriteObject* s) +{ + return s->x == s->tx && s->y == s->ty && s->scale == s->tscale && s->rotation == s->trotation; +} + +static inline bool is_sprite_object_static(const SpriteObject* sprite_object) +{ + return !sprite_object_has_velocity(sprite_object) && sprite_object_at_target(sprite_object); +} + +IWRAM_CODE void sprite_object_update(SpriteObject* sprite_object) +{ + if (is_sprite_object_static(sprite_object)) + return; + sprite_object->vx += ((sprite_object->tx - sprite_object->x) * g_game_vars.game_speed) / 8; sprite_object->vy += ((sprite_object->ty - sprite_object->y) * g_game_vars.game_speed) / 8; @@ -220,10 +239,10 @@ void sprite_object_update(SpriteObject* sprite_object) // Rotate the card when it's played sprite_object->vrotation += (sprite_object->trotation - sprite_object->rotation) / 8; - // set velocity to 0 if it's close enough to the target const FIXED epsilon = (FIX_ONE >> 6); // = 1/2^6 = 0.015625 - if (sprite_object->vx < epsilon && sprite_object->vx > -epsilon && - sprite_object->vy < epsilon && sprite_object->vy > -epsilon) + + // Snap to target position when velocity is negligible to avoid infinite approach + if (abs(sprite_object->vx) < epsilon && abs(sprite_object->vy) < epsilon) { sprite_object->vx = 0; sprite_object->vy = 0; @@ -243,10 +262,10 @@ void sprite_object_update(SpriteObject* sprite_object) } // Set scale to 0 if it's close enough to the target - if (sprite_object->vscale < epsilon && sprite_object->vscale > -epsilon) + if (abs(sprite_object->vscale) < epsilon) { sprite_object->vscale = 0; - sprite_object->scale = sprite_object->tscale; // Set the scale to the target scale + sprite_object->scale = sprite_object->tscale; } else { @@ -256,14 +275,13 @@ void sprite_object_update(SpriteObject* sprite_object) sprite_object->scale += sprite_object->vscale; } - // Set rotation to 0 if it's close enough to the target - if (sprite_object->vrotation < epsilon && sprite_object->vrotation > -epsilon) + // For rotation, prioritize snapping to target if close enough, then zero velocity. + if (abs(sprite_object->vrotation) < epsilon) { sprite_object->vrotation = 0; - // Set the rotation to the target rotation sprite_object->rotation = sprite_object->trotation; } - else + else // Apply damping and update rotation if not yet settled { sprite_object->vrotation = (sprite_object->vrotation * SPRING_DAMP_NUMERATOR + SPRING_DAMP_ROUNDING) >>