in libs/game/physics.ts [113:209]
move(dt: number) {
// Sprite movement logic is done in milliseconds to avoid rounding errors with Fx8 numbers
const dtMs = Math.min(MAX_TIME_STEP, dt * 1000);
const dt2 = Math.idiv(dtMs, 2);
const scene = game.currentScene();
const tileMap = scene.tileMap;
const movingSprites = this.sprites
.map(sprite => this.createMovingSprite(sprite, dtMs, dt2));
// clear obstacles if moving on that axis
this.sprites.forEach(s => {
if (s.vx || s.vy) s.clearObstacles();
});
this.map.clear();
this.map.resizeBuckets(this.sprites);
const MAX_STEP_COUNT = Fx.toInt(
Fx.idiv(
Fx.imul(
Fx.div(
this.maxVelocity,
this.minSingleStep
),
dtMs
),
1000
)
);
const overlapHandlers = scene.overlapHandlers.slice();
// buffers store the moving sprites on each step; switch back and forth between the two
let selected = 0;
let buffers = [movingSprites, []];
for (let count = 0; count < MAX_STEP_COUNT && buffers[selected].length !== 0; ++count) {
const currMovers = buffers[selected];
selected ^= 1;
const remainingMovers = buffers[selected];
for (let ms of currMovers) {
const s = ms.sprite;
// if still moving and speed has changed from a collision or overlap;
// reverse direction if speed has reversed
if (ms.cachedVx !== s._vx) {
if (s._vx == Fx.zeroFx8) {
ms.dx = Fx.zeroFx8;
} else if (s._vx < Fx.zeroFx8 && ms.cachedVx > Fx.zeroFx8
|| s._vx > Fx.zeroFx8 && ms.cachedVx < Fx.zeroFx8) {
ms.dx = Fx.neg(ms.dx);
ms.xStep = Fx.neg(ms.xStep);
}
ms.cachedVx = s._vx;
}
if (ms.cachedVy !== s._vy) {
if (s._vy == Fx.zeroFx8) {
ms.dy = Fx.zeroFx8;
} else if (s._vy < Fx.zeroFx8 && ms.cachedVy > Fx.zeroFx8
|| s._vy > Fx.zeroFx8 && ms.cachedVy < Fx.zeroFx8) {
ms.dy = Fx.neg(ms.dy);
ms.yStep = Fx.neg(ms.yStep);
}
ms.cachedVy = s._vy;
}
// identify how much to move in this step
const stepX = Fx.abs(ms.xStep) > Fx.abs(ms.dx) ? ms.dx : ms.xStep;
const stepY = Fx.abs(ms.yStep) > Fx.abs(ms.dy) ? ms.dy : ms.yStep;
ms.dx = Fx.sub(ms.dx, stepX);
ms.dy = Fx.sub(ms.dy, stepY);
s._lastX = s._x;
s._lastY = s._y;
s._x = Fx.add(s._x, stepX);
s._y = Fx.add(s._y, stepY);
if (!(s.flags & SPRITE_NO_SPRITE_OVERLAPS)) {
this.map.insertAABB(s);
}
if (tileMap && tileMap.enabled) {
this.tilemapCollisions(ms, tileMap);
}
// if sprite still needs to move, add it to the next step of movements
if (Fx.abs(ms.dx) > MIN_MOVE_GAP || Fx.abs(ms.dy) > MIN_MOVE_GAP) {
remainingMovers.push(ms);
}
}
// this step is done; check collisions between sprites
this.spriteCollisions(currMovers, overlapHandlers);
// clear moving sprites buffer for next step
while (currMovers.length) currMovers.pop();
}
}