Game state now contains a map of sounds to play next, for better perf

This commit is contained in:
Renan LE CARO 2025-03-17 19:47:16 +01:00
parent efa634cd8f
commit 581ee412d4
10 changed files with 1326 additions and 1153 deletions

View file

@ -8,7 +8,7 @@ import {
RunParams,
Upgrade,
} from "./types";
import { getAudioContext } from "./sounds";
import {getAudioContext, playPendingSounds} from "./sounds";
import {
currentLevelInfo,
getRowColIndex,
@ -429,7 +429,6 @@ export function bordersHitCheck(
return hhit + vhit * 2;
}
export function tick() {
const currentTick = performance.now();
const timeDeltaMs = currentTick - gameState.lastTick;
@ -458,6 +457,9 @@ export function tick() {
if (gameState.running) {
recordOneFrame(gameState);
}
if(isOptionOn('sound') ){
playPendingSounds(gameState)
}
requestAnimationFrame(tick);
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
import { Ball, GameState, PerkId, PerksMap } from "./types";
import { icons, upgrades } from "./loadGameData";
import {Ball, GameState, PerkId, PerksMap} from "./types";
import {icons, upgrades} from "./loadGameData";
export function getMajorityValue(arr: string[]): string {
const count: { [k: string]: number } = {};
@ -99,3 +99,18 @@ export function distanceBetween(
) {
return Math.sqrt(distance2(a, b));
}
export function defaultSounds() {
return {
aboutToPlaySound: {
wallBeep: {vol: 0, x: 0},
comboIncreaseMaybe: {vol: 0, x: 0},
comboDecrease: {vol: 0, x: 0},
coinBounce: {vol: 0, x: 0},
explode: {vol: 0, x: 0},
lifeLost: {vol: 0, x: 0},
coinCatch: {vol: 0, x: 0},
colorChange: {vol: 0, x: 0},
}
}
}

View file

@ -1,13 +1,9 @@
import { GameState, RunParams } from "./types";
import { getTotalScore } from "./settings";
import { allLevels, upgrades } from "./loadGameData";
import {
getPossibleUpgrades,
makeEmptyPerksMap,
sumOfKeys,
} from "./game_utils";
import { dontOfferTooSoon, resetBalls } from "./gameStateMutators";
import { isOptionOn } from "./options";
import {GameState, RunParams} from "./types";
import {getTotalScore} from "./settings";
import {allLevels, upgrades} from "./loadGameData";
import {defaultSounds, getPossibleUpgrades, makeEmptyPerksMap, sumOfKeys,} from "./game_utils";
import {dontOfferTooSoon, resetBalls} from "./gameStateMutators";
import {isOptionOn} from "./options";
export function newGameState(params: RunParams): GameState {
const totalScoreAtRunStart = getTotalScore();
@ -91,6 +87,7 @@ export function newGameState(params: RunParams): GameState {
levelWallBounces: 0,
needsRender: true,
autoCleanUses: 0,
...defaultSounds()
};
resetBalls(gameState);
@ -109,3 +106,4 @@ export function newGameState(params: RunParams): GameState {
}
return gameState;
}

View file

@ -1,48 +1,65 @@
import { gameState } from "./game";
import { isOptionOn } from "./options";
import {GameState} from "./types";
let lastPlay = Date.now()
export function playPendingSounds(gameState:GameState){
if(lastPlay>Date.now()-60){
return
}
lastPlay=Date.now()
for(let key in gameState.aboutToPlaySound){
const soundName = key as keyof GameState["aboutToPlaySound"]
const ex = gameState.aboutToPlaySound[soundName] as {vol:number, x:number}
if(ex.vol){
sounds[soundName](Math.min(2,ex.vol),pixelsToPan(gameState, ex.x), gameState.combo)
ex.vol=0
}
}
}
export const sounds = {
wallBeep: (pan: number) => {
wallBeep: (vol:number, pan: number, combo:number) => {
if (!isOptionOn("sound")) return;
createSingleBounceSound(800, pixelsToPan(pan));
createSingleBounceSound(800, pan, vol);
},
comboIncreaseMaybe: (combo: number, x: number, volume: number) => {
comboIncreaseMaybe: ( volume: number,pan: number,combo: number, ) => {
if (!isOptionOn("sound")) return;
let delta = 0;
if (!isNaN(lastComboPlayed)) {
if (lastComboPlayed < combo) delta = 1;
if (lastComboPlayed > combo) delta = -1;
}
playShepard(delta, pixelsToPan(x), volume);
playShepard(delta, pan, volume);
lastComboPlayed = combo;
},
comboDecrease() {
comboDecrease(volume: number,pan: number,combo: number) {
if (!isOptionOn("sound")) return;
playShepard(-1, 0.5, 0.5);
playShepard(-1, pan, volume);
},
coinBounce: (pan: number, volume: number) => {
coinBounce: (volume: number,pan: number,combo: number) => {
if (!isOptionOn("sound")) return;
createSingleBounceSound(1200, pixelsToPan(pan), volume, 0.1, "triangle");
createSingleBounceSound(1200, pan, volume, 0.1, "triangle");
},
explode: (pan: number) => {
explode: (volume: number,pan: number,combo: number) => {
if (!isOptionOn("sound")) return;
createExplosionSound(pixelsToPan(pan));
createExplosionSound(pan);
},
lifeLost(pan: number) {
lifeLost(volume: number,pan: number,combo: number) {
if (!isOptionOn("sound")) return;
createShatteredGlassSound(pixelsToPan(pan));
createShatteredGlassSound(pan);
},
coinCatch(pan: number) {
coinCatch(volume: number,pan: number,combo: number) {
if (!isOptionOn("sound")) return;
createSingleBounceSound(900, pixelsToPan(pan), 0.8, 0.1, "triangle");
createSingleBounceSound(900, (pan), volume, 0.1, "triangle");
},
colorChange(pan: number, volume: number) {
createSingleBounceSound(400, pixelsToPan(pan), volume, 0.5, "sine");
createSingleBounceSound(800, pixelsToPan(pan), volume * 0.5, 0.2, "square");
colorChange(volume: number,pan: number,combo: number) {
createSingleBounceSound(400, pan, volume, 0.5, "sine");
createSingleBounceSound(800, pan, volume * 0.5, 0.2, "square");
},
};
@ -158,7 +175,7 @@ function createExplosionSound(pan = 0.5) {
noiseSource.stop(context.currentTime + 1);
}
function pixelsToPan(pan: number) {
function pixelsToPan(gameState:GameState, pan: number) {
return Math.max(
0,
Math.min(

10
src/types.d.ts vendored
View file

@ -237,6 +237,16 @@ export type GameState = {
levelTime: number;
levelWallBounces: number;
autoCleanUses: number;
aboutToPlaySound:{
wallBeep:{vol:number, x:number},
comboIncreaseMaybe:{vol:number, x:number},
comboDecrease:{vol:number, x:number},
coinBounce:{vol:number, x:number},
explode:{vol:number, x:number},
lifeLost:{vol:number, x:number},
coinCatch:{vol:number, x:number},
colorChange:{vol:number, x:number},
}
};
export type RunParams = {