65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
export const MOB_ANIMATION_NEAR_DISTANCE = 32;
|
|
export const MOB_ANIMATION_MEDIUM_DISTANCE = 62;
|
|
export const MOB_ANIMATION_MEDIUM_INTERVAL = 1 / 30;
|
|
export const MOB_ANIMATION_FAR_INTERVAL = 1 / 15;
|
|
|
|
const MAX_FRAME_DELTA = 0.05;
|
|
const CADENCE_EPSILON = 1e-6;
|
|
|
|
/** `0` means every render frame; `null` means the animation may stay frozen. */
|
|
export type MobAnimationInterval = number | null;
|
|
|
|
export interface MobAnimationCadenceState {
|
|
accumulatedDelta: number;
|
|
}
|
|
|
|
export function createMobAnimationCadenceState(): MobAnimationCadenceState {
|
|
return { accumulatedDelta: 0 };
|
|
}
|
|
|
|
/**
|
|
* Keeps combat-critical actors at full fidelity while throttling background
|
|
* presentation only. Gameplay movement and combat simulation do not use this.
|
|
*/
|
|
export function resolveMobAnimationInterval(
|
|
active: boolean,
|
|
forceFullFidelity: boolean,
|
|
distanceSquared: number,
|
|
inFrontOfCamera: boolean,
|
|
): MobAnimationInterval {
|
|
if (!active) return null;
|
|
if (forceFullFidelity) return 0;
|
|
if (distanceSquared <= MOB_ANIMATION_NEAR_DISTANCE ** 2) return 0;
|
|
if (!inFrontOfCamera) return null;
|
|
if (distanceSquared <= MOB_ANIMATION_MEDIUM_DISTANCE ** 2) {
|
|
return MOB_ANIMATION_MEDIUM_INTERVAL;
|
|
}
|
|
return MOB_ANIMATION_FAR_INTERVAL;
|
|
}
|
|
|
|
/**
|
|
* Accumulates capped render deltas and returns the elapsed time to evaluate on
|
|
* this frame. This preserves animation speed at a lower sampling frequency.
|
|
*/
|
|
export function advanceMobAnimationCadence(
|
|
state: MobAnimationCadenceState,
|
|
delta: number,
|
|
interval: MobAnimationInterval,
|
|
): number {
|
|
const safeDelta = Number.isFinite(delta)
|
|
? Math.min(Math.max(0, delta), MAX_FRAME_DELTA)
|
|
: 0;
|
|
|
|
if (interval === null) {
|
|
state.accumulatedDelta = 0;
|
|
return 0;
|
|
}
|
|
|
|
state.accumulatedDelta += safeDelta;
|
|
if (interval > 0 && state.accumulatedDelta + CADENCE_EPSILON < interval) return 0;
|
|
|
|
const updateDelta = state.accumulatedDelta;
|
|
state.accumulatedDelta = 0;
|
|
return updateDelta;
|
|
}
|