Files
DndGamePlayer/app/shared/fieldEffectStampPoints.ts
     Фонтош Иван Сергеевич 48a9c933af fix(effects): снизить лаги сцены на Mac
Pixi режется по contentRect, пульт идёт в preview (12 FPS, 0.5 DPR), штампы тумана/огня/дождя прореживаются, draft темноты и маркера не чаще 20 Гц.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 17:13:37 +08:00

69 lines
2.3 KiB
TypeScript

import type { NPoint } from './types/effects';
/** Верхняя граница спрайтов на один штрих тумана/огня/дождя. */
export const FIELD_STAMP_MAX_SPRITES = 40;
/**
* Минимальное расстояние между центрами спрайтов (норм. 0..1).
* Огонь крупнее пятна радиуса — реже ставим штампы.
*/
export function fieldStampMinSpacingN(type: 'fog' | 'fire' | 'rain', radiusN: number): number {
const factor = type === 'fire' ? 0.75 : type === 'rain' ? 0.55 : 0.5;
return Math.max(0.006, radiusN * factor);
}
/**
* Оставляет концы штриха и точки не ближе `minSpacingN`.
* Если точек всё ещё больше `maxPoints` — равномерный stride.
*/
export function decimateFieldStampPoints(
points: readonly NPoint[],
minSpacingN: number,
maxPoints: number = FIELD_STAMP_MAX_SPRITES,
): NPoint[] {
if (points.length <= 1) return points.slice();
const first = points[0];
const last = points[points.length - 1];
if (!first || !last) {
return points.filter((p): p is NPoint => Boolean(p));
}
const cap = Math.max(2, Math.floor(maxPoints));
const minDistSq = Math.max(0, minSpacingN) * Math.max(0, minSpacingN);
const kept: NPoint[] = [first];
for (let i = 1; i < points.length - 1; i += 1) {
const p = points[i];
const prev = kept[kept.length - 1];
if (!p || !prev) continue;
const dx = p.x - prev.x;
const dy = p.y - prev.y;
if (dx * dx + dy * dy >= minDistSq) kept.push(p);
}
const tail = kept[kept.length - 1];
if (!tail) {
kept.push(last);
} else {
const dx = last.x - tail.x;
const dy = last.y - tail.y;
if (dx * dx + dy * dy > 1e-12) kept.push(last);
}
if (kept.length <= cap) return kept;
const reduced: NPoint[] = [];
const lastIdx = kept.length - 1;
const stride = Math.max(1, Math.ceil(lastIdx / (cap - 1)));
for (let i = 0; i < kept.length; i += stride) {
const p = kept[i];
if (p) reduced.push(p);
}
const reducedTail = reduced[reduced.length - 1];
if (reducedTail !== last) reduced.push(last);
if (reduced.length > cap) {
const head = reduced[0];
if (!head) return kept.slice(0, cap);
return [head, ...reduced.slice(reduced.length - (cap - 1))];
}
return reduced;
}