perf: adaptive performance mode for mobile
Auto-detect low-end devices (< 4 cores or touch) and reduce visual complexity: 60% fewer particles, 6 vs 16 speed lines, 15 vs 40 stars, halved datacenter buildings/racks, skip LED blinking animations, fewer GPU graveyard chips, reduced afterimages and exhaust particles. Toggle in fight viewer (LO/HI button), persisted in localStorage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
78f83a7520
commit
5af5ee1cba
@@ -2,6 +2,38 @@
|
||||
// Gameplay constants — all tunable magic numbers in one place
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
// --- Performance mode ---
|
||||
const PERF_KEY = 'bf_perf_mode'
|
||||
|
||||
function detectLowEnd(): boolean {
|
||||
if (typeof navigator === 'undefined') return false
|
||||
const cores = navigator.hardwareConcurrency || 4
|
||||
const mobile = navigator.maxTouchPoints > 0
|
||||
return cores < 4 || mobile
|
||||
}
|
||||
|
||||
function loadPerfPref(): boolean | null {
|
||||
try {
|
||||
const v = localStorage.getItem(PERF_KEY)
|
||||
if (v === '1') return true
|
||||
if (v === '0') return false
|
||||
} catch {}
|
||||
return null
|
||||
}
|
||||
|
||||
let _perfMode = loadPerfPref() ?? detectLowEnd()
|
||||
|
||||
export function isPerfMode(): boolean { return _perfMode }
|
||||
export function setPerfMode(on: boolean): void {
|
||||
_perfMode = on
|
||||
try { localStorage.setItem(PERF_KEY, on ? '1' : '0') } catch {}
|
||||
}
|
||||
|
||||
/** Scale a particle count down in performance mode (40%) */
|
||||
export function perfParticles(count: number): number {
|
||||
return _perfMode ? Math.max(1, Math.round(count * 0.4)) : count
|
||||
}
|
||||
|
||||
// --- Choreography selection probabilities ---
|
||||
export const CREATOR_ULTIMATE_CHANCE = 0.5 // Creator ultimate chance (non-crit); 1.0 on crits
|
||||
export const CREATOR_THEMED_MOVE_RATIO = 0.6 // Creator uses creator-themed moves 60% of the time
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import type { FightContext } from './types'
|
||||
import { perfParticles, isPerfMode } from './config'
|
||||
|
||||
export function spawnSparks(ctx: FightContext, x: number, y: number, count: number, color: string): void {
|
||||
const { k, safeColor } = ctx
|
||||
const n = perfParticles(count)
|
||||
const intense = count > 8
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
const angle = Math.random() * Math.PI * 2
|
||||
const speed = (intense ? 150 : 100) + Math.random() * (intense ? 400 : 300)
|
||||
const size = (intense ? 3 : 2) + Math.random() * (intense ? 6 : 4)
|
||||
@@ -31,7 +33,8 @@ export function spawnSparks(ctx: FightContext, x: number, y: number, count: numb
|
||||
|
||||
export function spawnBulletHoles(ctx: FightContext, x: number, y: number, count: number): void {
|
||||
const { k, safeColor, trackedTimeout, trackedInterval, clearTracked } = ctx
|
||||
for (let i = 0; i < count; i++) {
|
||||
const n = perfParticles(count)
|
||||
for (let i = 0; i < n; i++) {
|
||||
const hole = k.add([
|
||||
k.circle(3 + Math.random() * 3),
|
||||
k.pos(x + (Math.random() - 0.5) * 40, y + (Math.random() - 0.5) * 60),
|
||||
@@ -53,7 +56,8 @@ export function spawnExhaust(ctx: FightContext, x: number, y: number, duration:
|
||||
const endTime = performance.now() + duration * 1000
|
||||
const interval = trackedInterval(() => {
|
||||
if (performance.now() > endTime) { clearTracked(interval); return }
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const exhaustCount = isPerfMode() ? 1 : 3
|
||||
for (let i = 0; i < exhaustCount; i++) {
|
||||
const p = k.add([
|
||||
k.circle(3 + Math.random() * 5),
|
||||
k.pos(x + (Math.random() - 0.5) * 15, y),
|
||||
|
||||
Reference in New Issue
Block a user