mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-23 22:43:36 +00:00
104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
import { TileRef } from "../../../core/game/GameMap";
|
|
import type { GameView } from "../../../core/game/GameView";
|
|
|
|
export type GridSegmentMotionPlanView = {
|
|
planId: number;
|
|
startTick: number;
|
|
ticksPerStep: number;
|
|
points: Uint32Array;
|
|
segmentSteps: Uint32Array;
|
|
segCumSteps: Uint32Array;
|
|
};
|
|
|
|
export type SampledMotionPosition = {
|
|
x: number;
|
|
y: number;
|
|
isComplete: boolean;
|
|
tile0: TileRef;
|
|
tile1: TileRef;
|
|
};
|
|
|
|
function clamp01(v: number): number {
|
|
if (v <= 0) return 0;
|
|
if (v >= 1) return 1;
|
|
return v;
|
|
}
|
|
|
|
export function sampleGridSegmentPlan(
|
|
game: GameView,
|
|
plan: GridSegmentMotionPlanView,
|
|
tickFloat: number,
|
|
): SampledMotionPosition | null {
|
|
const points = plan.points;
|
|
if (points.length === 0) {
|
|
return null;
|
|
}
|
|
if (points.length === 1 || plan.segmentSteps.length === 0) {
|
|
const t = points[0] as TileRef;
|
|
return { x: game.x(t), y: game.y(t), isComplete: true, tile0: t, tile1: t };
|
|
}
|
|
|
|
const ticksPerStep = Math.max(1, plan.ticksPerStep);
|
|
const stepFloat = (tickFloat - plan.startTick) / ticksPerStep;
|
|
|
|
const segCum = plan.segCumSteps;
|
|
const totalSteps = segCum.length === 0 ? 0 : segCum[segCum.length - 1] >>> 0;
|
|
if (totalSteps <= 0) {
|
|
const t = points[points.length - 1] as TileRef;
|
|
return { x: game.x(t), y: game.y(t), isComplete: true, tile0: t, tile1: t };
|
|
}
|
|
|
|
if (stepFloat <= 0) {
|
|
const t = points[0] as TileRef;
|
|
const t1 = points[1] as TileRef;
|
|
return {
|
|
x: game.x(t),
|
|
y: game.y(t),
|
|
isComplete: false,
|
|
tile0: t,
|
|
tile1: t1,
|
|
};
|
|
}
|
|
if (stepFloat >= totalSteps) {
|
|
const t = points[points.length - 1] as TileRef;
|
|
return { x: game.x(t), y: game.y(t), isComplete: true, tile0: t, tile1: t };
|
|
}
|
|
|
|
// Find the segment containing stepFloat.
|
|
let seg = 0;
|
|
let lo = 0;
|
|
let hi = plan.segmentSteps.length - 1;
|
|
while (lo <= hi) {
|
|
const mid = (lo + hi) >>> 1;
|
|
const start = segCum[mid] >>> 0;
|
|
const end = segCum[mid + 1] >>> 0;
|
|
if (stepFloat < start) {
|
|
hi = mid - 1;
|
|
} else if (stepFloat >= end) {
|
|
lo = mid + 1;
|
|
} else {
|
|
seg = mid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const segStart = segCum[seg] >>> 0;
|
|
const steps = Math.max(1, plan.segmentSteps[seg] >>> 0);
|
|
const u = clamp01((stepFloat - segStart) / steps);
|
|
|
|
const tile0 = points[seg] as TileRef;
|
|
const tile1 = points[seg + 1] as TileRef;
|
|
const x0 = game.x(tile0);
|
|
const y0 = game.y(tile0);
|
|
const x1 = game.x(tile1);
|
|
const y1 = game.y(tile1);
|
|
|
|
return {
|
|
x: x0 + (x1 - x0) * u,
|
|
y: y0 + (y1 - y0) * u,
|
|
isComplete: false,
|
|
tile0,
|
|
tile1,
|
|
};
|
|
}
|