diff --git a/inc/sprite_eng.h b/inc/sprite_eng.h index ee55f4cc..bdeeaf64 100644 --- a/inc/sprite_eng.h +++ b/inc/sprite_eng.h @@ -44,8 +44,8 @@ #define SPR_FLAG_INSERT_HEAD 0x4000 /** * \brief - * Disable animation auto loop..
- * By default animation always restart fater the last frame has been played. + * Disable animation auto loop.
+ * By default animation always restart after the last frame has been played. * This flag prevent the animation to restart and so the animation end on the last frame forever (see #SPR_getAnimationDone(..)) */ #define SPR_FLAG_DISABLE_ANIMATION_LOOP 0x2000 @@ -844,8 +844,8 @@ bool SPR_getAutoAnimation(Sprite* sprite); void SPR_setAnimationLoop(Sprite* sprite, bool value); /** * \brief - * Return TRUE if the sprite reached the last frame of the current animation.
- * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reach + * Returns TRUE if the sprite reached the end of the current animation.
+ * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reached * the last *tick* of the last animation frame.
* When auto animation is disabled the function returns TRUE as soon we are on last animation frame. * diff --git a/inc/sprite_eng_legacy.h b/inc/sprite_eng_legacy.h index 38895598..87509681 100644 --- a/inc/sprite_eng_legacy.h +++ b/inc/sprite_eng_legacy.h @@ -44,8 +44,8 @@ #define SPR_FLAG_INSERT_HEAD 0x4000 /** * \brief - * Disable animation auto loop..
- * By default animation always restart fater the last frame has been played. + * Disable animation auto loop.
+ * By default animation always restart after the last frame has been played. * This flag prevent the animation to restart and so the animation end on the last frame forever (see #SPR_getAnimationDone(..)) */ #define SPR_FLAG_DISABLE_ANIMATION_LOOP 0x2000 @@ -837,8 +837,8 @@ bool SPR_getAutoAnimation(Sprite* sprite); void SPR_setAnimationLoop(Sprite* sprite, bool value); /** * \brief - * Return TRUE if the sprite reached the last frame of the current animation.
- * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reach + * Returns TRUE if the sprite reached the end of the current animation.
+ * When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reached * the last *tick* of the last animation frame.
* When auto animation is disabled the function returns TRUE as soon we are on last animation frame. * diff --git a/lib/libmd.a b/lib/libmd.a index 537f7e1d..feb9f4ff 100644 Binary files a/lib/libmd.a and b/lib/libmd.a differ diff --git a/lib/libmd_debug.a b/lib/libmd_debug.a index 724db483..feb9f4ff 100644 Binary files a/lib/libmd_debug.a and b/lib/libmd_debug.a differ diff --git a/src/sprite_eng.c b/src/sprite_eng.c index f018ed88..58188393 100644 --- a/src/sprite_eng.c +++ b/src/sprite_eng.c @@ -47,6 +47,9 @@ #define NEED_UPDATE 0x000F +#define STATE_ANIMATION_DONE 0x0010 + + // shared from vdp_spr.c unit extern void logVDPSprite(u16 index); @@ -1147,6 +1150,8 @@ void SPR_nextFrame(Sprite* sprite) // loop frameInd = anim->loop; + // set animation done state (allows SPR_isAnimationDone(..) to correctly report state when called from frame change callback) + sprite->status |= STATE_ANIMATION_DONE; } // set new frame @@ -1203,8 +1208,10 @@ bool SPR_isAnimationDone(Sprite* sprite) // for debug checkSpriteValid(sprite, "SPR_isAnimationDone"); - // last tick on last animation frame (use <= 1 so it also works when AutoAnimation is disabled) - return (sprite->timer <= 1) && (sprite->frameInd == (sprite->animation->numFrame - 1)); + // check for animation done state (mainly used for frame change callback) or + return (sprite->status & STATE_ANIMATION_DONE) || + // if we are on last tick from last frame (if auto animation is disabled then only test for last frame) + ((sprite->frameInd == (sprite->animation->numFrame - 1)) && ((sprite->timer == 1) || (sprite->timer == -1))); } bool SPR_setVRAMTileIndex(Sprite* sprite, s16 value) @@ -1937,6 +1944,9 @@ static u16 updateFrame(Sprite* sprite, u16 status) // set frame sprite->frame = frame; + // init timer for this frame *before* frame change callback so it can modify change it if needed. + if (SPR_getAutoAnimation(sprite)) + sprite->timer = frame->timer; // frame change event handler defined ? --> call it if (sprite->onFrameChange) @@ -1945,16 +1955,6 @@ static u16 updateFrame(Sprite* sprite, u16 status) sprite->status = status; sprite->onFrameChange(sprite); status = sprite->status; - - // init timer for this frame *after* callback call and only if auto animation is enabled and timer was not manually changed in callback - if (sprite->timer == 0) - sprite->timer = frame->timer; - } - else - { - // init timer for this frame *after* callback call to allow SPR_isAnimationDone(..) to correctly report TRUE when animation is done in the callbacnk - if (SPR_getAutoAnimation(sprite)) - sprite->timer = frame->timer; } // require tile data upload @@ -1964,8 +1964,8 @@ static u16 updateFrame(Sprite* sprite, u16 status) if (status & SPR_FLAG_AUTO_VISIBILITY) status |= NEED_VISIBILITY_UPDATE; - // frame update done - status &= ~NEED_FRAME_UPDATE; + // frame update done, also clear ANIMATION_DONE state + status &= ~(NEED_FRAME_UPDATE | STATE_ANIMATION_DONE); END_PROFIL(PROFIL_UPDATE_FRAME) diff --git a/src/sprite_eng_legacy.c b/src/sprite_eng_legacy.c index 47c45d32..dd65544d 100644 --- a/src/sprite_eng_legacy.c +++ b/src/sprite_eng_legacy.c @@ -49,6 +49,8 @@ #define NEED_UPDATE 0x001F +#define STATE_ANIMATION_DONE 0x0020 + // shared from vdp_spr.c unit extern void logVDPSprite(u16 index); @@ -1161,6 +1163,8 @@ void SPR_nextFrame(Sprite* sprite) // loop frameInd = anim->loop; + // set animation done state (allows SPR_isAnimationDone(..) to correctly report state when called from frame change callback) + sprite->status |= STATE_ANIMATION_DONE; } // set new frame @@ -1221,8 +1225,10 @@ bool SPR_isAnimationDone(Sprite* sprite) if (!isSpriteValid(sprite, "SPR_isAnimationDone")) return FALSE; - // last tick on last animation frame (use <= 1 so it also works when AutoAnimation is disabled) - return (sprite->timer <= 1) && (sprite->frameInd == (sprite->animation->numFrame - 1)); + // check for animation done state (mainly used for frame change callback) or + return (sprite->status & STATE_ANIMATION_DONE) || + // if we are on last tick from last frame (if auto animation is disabled then only test for last frame) + ((sprite->frameInd == (sprite->animation->numFrame - 1)) && ((sprite->timer == 1) || (sprite->timer == -1))); } @@ -1895,6 +1901,9 @@ static u16 updateFrame(Sprite* sprite, u16 status) sprite->lastNumSprite = currentNumSprite; // set frame sprite->frame = frame; + // init timer for this frame *before* frame change callback so it can modify change it if needed. + if (SPR_getAutoAnimation(sprite)) + sprite->timer = frame->timer; // frame change event handler defined ? --> call it if (sprite->onFrameChange) @@ -1905,10 +1914,6 @@ static u16 updateFrame(Sprite* sprite, u16 status) status = sprite->status; } - // init timer for this frame *after* calling callback (this allows SPR_isAnimationDone(..) to correctly report TRUE when animation is done) - if (SPR_getAutoAnimation(sprite)) - sprite->timer = frame->timer; - // require tile data upload if (status & SPR_FLAG_AUTO_TILE_UPLOAD) status |= NEED_TILES_UPLOAD; @@ -1916,8 +1921,8 @@ static u16 updateFrame(Sprite* sprite, u16 status) if (status & SPR_FLAG_AUTO_VISIBILITY) status |= NEED_VISIBILITY_UPDATE; - // frame update done - status &= ~NEED_FRAME_UPDATE; + // frame update done, also clear ANIMATION_DONE state + status &= ~(NEED_FRAME_UPDATE | STATE_ANIMATION_DONE); END_PROFIL(PROFIL_UPDATE_FRAME)