/* * _sprite_tick — тикер авто-анимаций (§9г): вызывается из sprite_update * (раз на КАДР, до heal/блит-проходов — dirty должен взводиться раньше). * Кадровая анимация и tween-перемещение НЕЗАВИСИМЫ (идут одновременно); * тикаются и у скрытых спрайтов («время идёт», ветка дороже). * * Кадровая: смена кадра = ±an_step к оси ленты (sy; при _SPR_ANIM_HORZ * — sx) — БЕЗ умножения; wrap цикла — прыжок оси в an_lo (посчитан * sprite_anim'ом один раз). Маятник разворачивается НА границе (…2,3, * 2,1,0,1…, без удвоения крайних). ANIM_ONCE замирает на last: * SPR_ANIM_ON снимается, SPR_ANIM_DONE взводится. * * Перемещение: раз в mv_speed кадров — порция ≤mv_step итераций * классического Брезенхэма (err-аккумулятор: большая ось шагает каждую * итерацию, меньшая подтягивается — нелинейные 2/3/2/3 сами собой, * деления нет). Цель достигнута — SPR_MOVE_ON→off, SPR_MOVE_DONE. */ #include "../_bgi.h" #include void _sprite_tick(void *arr, uint8_t count) { sprite_t *s = (sprite_t *)arr; uint8_t i; for (i = 0; i < count; i++, s++) { /* ---- кадровая анимация ---- */ if ((s->an_flags & SPR_ANIM_ON) && --s->an_timer == 0) { int *axis = (s->an_flags & _SPR_ANIM_HORZ) ? &s->sx : &s->sy; uint8_t moved = 1; s->an_timer = s->an_speed; if (!(s->an_flags & _SPR_ANIM_BACK)) { if (s->an_frame < s->an_last) { s->an_frame++; *axis += s->an_step; } else if (s->an_flags & _SPR_ANIM_ONCE) { s->an_flags &= (uint8_t)~SPR_ANIM_ON; s->an_flags |= SPR_ANIM_DONE; moved = 0; } else if (s->an_flags & _SPR_ANIM_PP) { s->an_flags |= _SPR_ANIM_BACK; /* разворот на границе */ if (s->an_frame > s->an_first) { s->an_frame--; *axis -= s->an_step; } else moved = 0; /* лента из 1 кадра */ } else { /* ANIM_LOOP: wrap */ s->an_frame = s->an_first; *axis = s->an_lo; } } else { /* маятник, назад */ if (s->an_frame > s->an_first) { s->an_frame--; *axis -= s->an_step; } else { s->an_flags &= (uint8_t)~_SPR_ANIM_BACK; if (s->an_frame < s->an_last) { s->an_frame++; *axis += s->an_step; } else moved = 0; } } if (moved) s->flags |= _SPR_DIRTY; } /* ---- tween-перемещение ---- */ if ((s->an_flags & SPR_MOVE_ON) && --s->mv_timer == 0) { uint8_t n = s->mv_step; int x = s->x, y = s->y; s->mv_timer = s->mv_speed; while (n--) { int e2; if (x == s->mv_tx && y == s->mv_ty) break; e2 = s->mv_err * 2; if (e2 >= s->mv_dy) { s->mv_err += s->mv_dy; x += s->mv_sgnx; } if (e2 <= s->mv_dx) { s->mv_err += s->mv_dx; y += s->mv_sgny; } } if (x != s->x || y != s->y) { s->x = x; s->y = y; s->flags |= _SPR_DIRTY; } if (x == s->mv_tx && y == s->mv_ty) { s->an_flags &= (uint8_t)~SPR_MOVE_ON; s->an_flags |= SPR_MOVE_DONE; } } } }