184 lines
5.8 KiB
TypeScript
184 lines
5.8 KiB
TypeScript
import type { GameConfig } from '../config/gameConfig'
|
|
|
|
/**
|
|
* Масштабированные размеры для текущего окна.
|
|
* Раньше это был глобальный объект S, наполняемый recalc() через циклы по строковым ключам.
|
|
*/
|
|
export type Metrics = {
|
|
width: number
|
|
height: number
|
|
// геометрия сцены
|
|
gridSize: number
|
|
enemyPaddingX: number
|
|
enemyAlienOffset: number
|
|
armorBarPad: number
|
|
armorBarFont: number
|
|
missTargetPadX: number
|
|
missTargetPadY: number
|
|
missTargetYRange: number
|
|
inputAreaHeight: number
|
|
removeZone: number
|
|
shooterOffset: number
|
|
playerY: number
|
|
playerRadius: number
|
|
playerGlow: number
|
|
// враги
|
|
enemySimpleHeight: number
|
|
enemyHeavyHeight: number
|
|
enemySimpleFont: number
|
|
enemyHeavyFont: number
|
|
enemyArmorBarHeight: number
|
|
enemyArmorBarOffset: number
|
|
enemyArmorLabelOffset: number
|
|
enemyGlow: number
|
|
enemyFlashGlow: number
|
|
enemyLineWidth: number
|
|
enemyPulseRate: number
|
|
enemyAlphaBase: number
|
|
enemyAlphaRange: number
|
|
enemyGlowPulse: number
|
|
bossFontSizeFactor: number
|
|
bossHeightFactor: number
|
|
bossWordGap: number
|
|
flashDuration: number
|
|
// снаряды
|
|
projectileSpeed: number
|
|
projectileGlow: number
|
|
projectileHitRadius: number
|
|
projectileMissRadius: number
|
|
projectileFont: number
|
|
projectileCircleRadius: number
|
|
projectileCircleAlpha: number
|
|
projectileTrailLength: number
|
|
projectileTrailDecay: number
|
|
projectileTrailAlpha: number
|
|
trailSizeBase: number
|
|
trailSizeInc: number
|
|
trailGlow: number
|
|
// частицы
|
|
particleVel: number
|
|
particleSizeMin: number
|
|
particleSizeMax: number
|
|
particleGlow: number
|
|
particleDecayBase: number
|
|
particleDecayRange: number
|
|
particleDamping: number
|
|
particleHit: number
|
|
particleMiss: number
|
|
particleDestroySimple: number
|
|
particleDestroyHeavy: number
|
|
particleArmorBreak: number
|
|
// тряска / волны / ввод
|
|
shakeHit: number
|
|
shakeMiss: number
|
|
shakeDamage: number
|
|
shakeHitDuration: number
|
|
shakeMissDuration: number
|
|
shakeDamageDuration: number
|
|
wavePauseFont: number
|
|
wavePauseFrames: number
|
|
gridSpeed: number
|
|
inputShootDelayMs: number
|
|
glitchDurationMs: number
|
|
}
|
|
|
|
export class MetricsStore {
|
|
current: Metrics
|
|
|
|
constructor(private readonly config: GameConfig) {
|
|
this.current = computeMetrics(config, window.innerWidth, window.innerHeight)
|
|
}
|
|
|
|
rebuild(width: number, height: number): void {
|
|
this.current = computeMetrics(this.config, width, height)
|
|
}
|
|
}
|
|
|
|
export function computeMetrics(config: GameConfig, width: number, height: number): Metrics {
|
|
const V = config.visual
|
|
const R = config.ratio
|
|
const C = config.counts
|
|
const S = config.speed
|
|
const T = config.timing
|
|
|
|
const vw = (value: number) => Math.round((value * width) / 1000)
|
|
const vh = (value: number) => Math.round((value * height) / 1000)
|
|
|
|
return {
|
|
width,
|
|
height,
|
|
gridSize: vw(V.gridSize),
|
|
enemyPaddingX: vw(V.enemyPaddingX),
|
|
enemyAlienOffset: vw(V.enemyAlienOffset),
|
|
armorBarPad: vw(V.armorBarPad),
|
|
armorBarFont: vw(V.armorBarFont),
|
|
missTargetPadX: vw(V.missTargetPadX),
|
|
missTargetPadY: vh(V.missTargetPadY),
|
|
missTargetYRange: R.missTargetYRange,
|
|
inputAreaHeight: vh(V.inputAreaHeight),
|
|
removeZone: vh(V.removeZone),
|
|
shooterOffset: vh(V.shooterOffset),
|
|
playerY: vh(V.playerY),
|
|
playerRadius: vh(V.playerRadius),
|
|
playerGlow: vh(V.playerGlow),
|
|
enemySimpleHeight: vh(V.enemySimpleHeight),
|
|
enemyHeavyHeight: vh(V.enemyHeavyHeight),
|
|
enemySimpleFont: vh(V.enemySimpleFont),
|
|
enemyHeavyFont: vh(V.enemyHeavyFont),
|
|
enemyArmorBarHeight: vh(V.enemyArmorBarHeight),
|
|
enemyArmorBarOffset: vh(V.enemyArmorBarOffset),
|
|
enemyArmorLabelOffset: vh(V.enemyArmorLabelOffset),
|
|
enemyGlow: vh(V.enemyGlow),
|
|
enemyFlashGlow: vh(V.enemyFlashGlow),
|
|
enemyLineWidth: vh(V.enemyLineWidth),
|
|
enemyPulseRate: R.enemyPulseRate,
|
|
enemyAlphaBase: R.enemyAlphaBase,
|
|
enemyAlphaRange: R.enemyAlphaRange,
|
|
enemyGlowPulse: R.enemyGlowPulse,
|
|
bossFontSizeFactor: R.bossFontSizeFactor,
|
|
bossHeightFactor: R.bossHeightFactor,
|
|
bossWordGap: R.bossWordGap,
|
|
flashDuration: C.flashDuration,
|
|
projectileSpeed: height / (S.projectileCrossTime * 60),
|
|
projectileGlow: vh(V.projectileGlow),
|
|
projectileHitRadius: vh(V.projectileHitRadius),
|
|
projectileMissRadius: vh(V.projectileMissRadius),
|
|
projectileFont: vh(V.projectileFont),
|
|
projectileCircleRadius: vh(V.projectileCircleRadius),
|
|
projectileCircleAlpha: R.projectileCircleAlpha,
|
|
projectileTrailLength: R.projectileTrailLength,
|
|
projectileTrailDecay: R.projectileTrailDecay,
|
|
projectileTrailAlpha: R.projectileTrailAlpha,
|
|
trailSizeBase: vh(V.trailSizeBase),
|
|
trailSizeInc: vh(V.trailSizeInc),
|
|
trailGlow: vh(V.trailGlow),
|
|
particleVel: vh(V.particleVel),
|
|
particleSizeMin: vh(V.particleSizeMin),
|
|
particleSizeMax: vh(V.particleSizeMax),
|
|
particleGlow: vh(V.particleGlow),
|
|
particleDecayBase: R.particleDecayBase,
|
|
particleDecayRange: R.particleDecayRange,
|
|
particleDamping: R.particleDamping,
|
|
particleHit: C.particleHit,
|
|
particleMiss: C.particleMiss,
|
|
particleDestroySimple: C.particleDestroySimple,
|
|
particleDestroyHeavy: C.particleDestroyHeavy,
|
|
particleArmorBreak: C.particleArmorBreak,
|
|
shakeHit: vh(V.shakeHit),
|
|
shakeMiss: vh(V.shakeMiss),
|
|
shakeDamage: vh(V.shakeDamage),
|
|
shakeHitDuration: C.shakeHitDuration,
|
|
shakeMissDuration: C.shakeMissDuration,
|
|
shakeDamageDuration: C.shakeDamageDuration,
|
|
wavePauseFont: vh(V.wavePauseFont),
|
|
wavePauseFrames: C.wavePauseFrames,
|
|
gridSpeed: (S.gridSpeed * height) / 1000,
|
|
inputShootDelayMs: T.inputShootDelay,
|
|
glitchDurationMs: T.glitchDuration,
|
|
}
|
|
}
|
|
|
|
export function framesFromMs(ms: number): number {
|
|
return ms / (1000 / 60)
|
|
}
|