/* * sprite_moveto — запустить tween-перемещение к (tx,ty): раз в interval * кадров тикер делает до max_step шагов вдоль ГЛАВНОЙ оси (большая * |дельта|); минорная ось подтягивается DDA-аккумулятором — нелинейные * 2/3/2/3 сами собой, деления нет. Пример: (0,0)→(100,50), max_step 5, * interval 4 → 20 порций × 4 кадра = 80 кадров (1.6 с). * * Всё дорогое (выбор главной оси, |дельты|, знаки) считается здесь один * раз; тикеру остаётся БЕЗЗНАКОВАЯ арифметика (см. sprite.h: acc/rem — * на Z80 беззнаковое 16-бит сравнение в разы дешевле знаковых сравнений * классического Брезенхэма, ради этого и переформулировано 2026-07-14). * За mv_dmaj шагов главной оси минорная получает ровно mv_dmin шагов * (аккумулятор со стартом dmaj/2 — симметричное округление), так что * обе координаты приходят в цель одновременно; «приехали» = mv_rem == 0. * * Если цель == текущая позиция — сразу SPR_MOVE_DONE (тикер не * включается). Кадровые статусы (SPR_ANIM_*) не трогаются. */ #include "../_bgi.h" #include void sprite_moveto(sprite_t *s, int tx, int ty, uint8_t max_step, uint8_t interval) { int dx = tx - s->x; int dy = ty - s->y; int8_t sgnx = 1, sgny = 1; if (dx < 0) { dx = -dx; sgnx = -1; } if (dy < 0) { dy = -dy; sgny = -1; } s->an_flags &= (uint8_t)~SPR_MOVE_DONE; if (dx == 0 && dy == 0) { s->an_flags = (s->an_flags & (uint8_t)~SPR_MOVE_ON) | SPR_MOVE_DONE; return; } s->mv_tx = tx; s->mv_ty = ty; /* Главная ось — с большей |дельтой| (при равенстве — X, диагональ * ровная в обе стороны). */ if ((uint16_t)dy > (uint16_t)dx) { s->mv_ymaj = 1; s->mv_dmaj = (uint16_t)dy; s->mv_dmin = (uint16_t)dx; s->mv_sgnmaj = sgny; s->mv_sgnmin = sgnx; } else { s->mv_ymaj = 0; s->mv_dmaj = (uint16_t)dx; s->mv_dmin = (uint16_t)dy; s->mv_sgnmaj = sgnx; s->mv_sgnmin = sgny; } s->mv_rem = s->mv_dmaj; /* шагов до цели */ s->mv_acc = s->mv_dmaj >> 1; /* симметричное округление minor */ if (!max_step) max_step = 1; if (!interval) interval = 1; s->mv_step = max_step; s->mv_speed = interval; s->mv_timer = interval; s->an_flags |= SPR_MOVE_ON; _spr_tick_fn = _sprite_tick; }