diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue index 19ee029ea720524effce94411ac41c2b5f80b202..b316a79569a30ed8a05ecc8cce487cdbfa24b0d9 100644 --- a/packages/frontend/src/pages/drop-and-fusion.game.vue +++ b/packages/frontend/src/pages/drop-and-fusion.game.vue @@ -144,7 +144,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { onDeactivated, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; +import { computed, onDeactivated, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; import * as Matter from 'matter-js'; import * as Misskey from 'misskey-js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; @@ -165,15 +165,17 @@ import * as sound from '@/scripts/sound.js'; import MkRange from '@/components/MkRange.vue'; import copyToClipboard from '@/scripts/copy-to-clipboard.js'; -const NORMAL_BASE_SIZE = 30; -const NORAML_MONOS: Mono[] = [{ +type FrontendMonoDefinition = { + id: string; + img: string; + imgSizeX: number; + imgSizeY: number; + spriteScale: number; + sfxPitch: number; +}; + +const NORAML_MONOS: FrontendMonoDefinition[] = [{ id: '9377076d-c980-4d83-bdaf-175bc58275b7', - level: 10, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 512, - dropCandidate: false, sfxPitch: 0.25, img: '/client-assets/drop-and-fusion/exploding_head.png', imgSizeX: 256, @@ -181,12 +183,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'be9f38d2-b267-4b1a-b420-904e22e80568', - level: 9, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 256, - dropCandidate: false, sfxPitch: 0.5, img: '/client-assets/drop-and-fusion/face_with_symbols_on_mouth.png', imgSizeX: 256, @@ -194,12 +190,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'beb30459-b064-4888-926b-f572e4e72e0c', - level: 8, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 128, - dropCandidate: false, sfxPitch: 0.75, img: '/client-assets/drop-and-fusion/cold_face.png', imgSizeX: 256, @@ -207,12 +197,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'feab6426-d9d8-49ae-849c-048cdbb6cdf0', - level: 7, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 64, - dropCandidate: false, sfxPitch: 1, img: '/client-assets/drop-and-fusion/zany_face.png', imgSizeX: 256, @@ -220,12 +204,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'd6d8fed6-6d18-4726-81a1-6cf2c974df8a', - level: 6, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 32, - dropCandidate: false, sfxPitch: 1.5, img: '/client-assets/drop-and-fusion/pleading_face.png', imgSizeX: 256, @@ -233,12 +211,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '249c728e-230f-4332-bbbf-281c271c75b2', - level: 5, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 16, - dropCandidate: true, sfxPitch: 2, img: '/client-assets/drop-and-fusion/face_with_open_mouth.png', imgSizeX: 256, @@ -246,12 +218,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '23d67613-d484-4a93-b71e-3e81b19d6186', - level: 4, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 8, - dropCandidate: true, sfxPitch: 2.5, img: '/client-assets/drop-and-fusion/smiling_face_with_sunglasses.png', imgSizeX: 256, @@ -259,12 +225,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '3cbd0add-ad7d-4685-bad0-29f6dddc0b99', - level: 3, - sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25, - shape: 'circle', - score: 4, - dropCandidate: true, sfxPitch: 3, img: '/client-assets/drop-and-fusion/grinning_squinting_face.png', imgSizeX: 256, @@ -272,12 +232,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '8f86d4f4-ee02-41bf-ad38-1ce0ae457fb5', - level: 2, - sizeX: NORMAL_BASE_SIZE * 1.25, - sizeY: NORMAL_BASE_SIZE * 1.25, - shape: 'circle', - score: 2, - dropCandidate: true, sfxPitch: 3.5, img: '/client-assets/drop-and-fusion/smiling_face_with_hearts.png', imgSizeX: 256, @@ -285,12 +239,6 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '64ec4add-ce39-42b4-96cb-33908f3f118d', - level: 1, - sizeX: NORMAL_BASE_SIZE, - sizeY: NORMAL_BASE_SIZE, - shape: 'circle', - score: 1, - dropCandidate: true, sfxPitch: 4, img: '/client-assets/drop-and-fusion/heart_suit.png', imgSizeX: 256, @@ -298,16 +246,8 @@ const NORAML_MONOS: Mono[] = [{ spriteScale: 1.12, }]; -const YEN_BASE_SIZE = 30; -const YEN_SATSU_BASE_SIZE = 70; -const YEN_MONOS: Mono[] = [{ +const YEN_MONOS: FrontendMonoDefinition[] = [{ id: '880f9bd9-802f-4135-a7e1-fd0e0331f726', - level: 10, - sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25 * 1.25 * 1.25, - sizeY: YEN_SATSU_BASE_SIZE * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 10000, - dropCandidate: false, sfxPitch: 0.25, img: '/client-assets/drop-and-fusion/10000yen.png', imgSizeX: 512, @@ -315,12 +255,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: 'e807beb6-374a-4314-9cc2-aa5f17d96b6b', - level: 9, - sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25 * 1.25, - sizeY: YEN_SATSU_BASE_SIZE * 1.25 * 1.25, - shape: 'rectangle', - score: 5000, - dropCandidate: false, sfxPitch: 0.5, img: '/client-assets/drop-and-fusion/5000yen.png', imgSizeX: 512, @@ -328,12 +262,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '033445b7-8f90-4fc9-beca-71a9e87cb530', - level: 8, - sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25, - sizeY: YEN_SATSU_BASE_SIZE * 1.25, - shape: 'rectangle', - score: 2000, - dropCandidate: false, sfxPitch: 0.75, img: '/client-assets/drop-and-fusion/2000yen.png', imgSizeX: 512, @@ -341,12 +269,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '410a09ec-5f7f-46f6-b26f-cbca4ccbd091', - level: 7, - sizeX: YEN_SATSU_BASE_SIZE * 2, - sizeY: YEN_SATSU_BASE_SIZE, - shape: 'rectangle', - score: 1000, - dropCandidate: false, sfxPitch: 1, img: '/client-assets/drop-and-fusion/1000yen.png', imgSizeX: 512, @@ -354,12 +276,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '2aae82bc-3fa4-49ad-a6b5-94d888e809f5', - level: 6, - sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 500, - dropCandidate: false, sfxPitch: 1.5, img: '/client-assets/drop-and-fusion/500yen.png', imgSizeX: 256, @@ -367,12 +283,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: 'a619bd67-d08f-4cc0-8c7e-c8072a4950cd', - level: 5, - sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 100, - dropCandidate: true, sfxPitch: 2, img: '/client-assets/drop-and-fusion/100yen.png', imgSizeX: 256, @@ -380,12 +290,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: 'c1c5d8e4-17d6-4455-befd-12154d731faa', - level: 4, - sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25, - sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25, - shape: 'circle', - score: 50, - dropCandidate: true, sfxPitch: 2.5, img: '/client-assets/drop-and-fusion/50yen.png', imgSizeX: 256, @@ -393,12 +297,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '7082648c-e428-44c4-887a-25c07a8ebdd5', - level: 3, - sizeX: YEN_BASE_SIZE * 1.25 * 1.25, - sizeY: YEN_BASE_SIZE * 1.25 * 1.25, - shape: 'circle', - score: 10, - dropCandidate: true, sfxPitch: 3, img: '/client-assets/drop-and-fusion/10yen.png', imgSizeX: 256, @@ -406,12 +304,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '0d8d40d5-e6e0-4d26-8a95-b8d842363379', - level: 2, - sizeX: YEN_BASE_SIZE * 1.25, - sizeY: YEN_BASE_SIZE * 1.25, - shape: 'circle', - score: 5, - dropCandidate: true, sfxPitch: 3.5, img: '/client-assets/drop-and-fusion/5yen.png', imgSizeX: 256, @@ -419,12 +311,6 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }, { id: '9dec1b38-d99d-40de-8288-37367b983d0d', - level: 1, - sizeX: YEN_BASE_SIZE, - sizeY: YEN_BASE_SIZE, - shape: 'circle', - score: 1, - dropCandidate: true, sfxPitch: 4, img: '/client-assets/drop-and-fusion/1yen.png', imgSizeX: 256, @@ -432,15 +318,8 @@ const YEN_MONOS: Mono[] = [{ spriteScale: 0.97, }]; -const SQUARE_BASE_SIZE = 28; -const SQUARE_MONOS: Mono[] = [{ +const SQUARE_MONOS: FrontendMonoDefinition[] = [{ id: 'f75fd0ba-d3d4-40a4-9712-b470e45b0525', - level: 10, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 512, - dropCandidate: false, sfxPitch: 0.25, img: '/client-assets/drop-and-fusion/keycap_10.png', imgSizeX: 256, @@ -448,12 +327,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '7b70f4af-1c01-45fd-af72-61b1f01e03d1', - level: 9, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 256, - dropCandidate: false, sfxPitch: 0.5, img: '/client-assets/drop-and-fusion/keycap_9.png', imgSizeX: 256, @@ -461,12 +334,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '41607ef3-b6d6-4829-95b6-3737bf8bb956', - level: 8, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 128, - dropCandidate: false, sfxPitch: 0.75, img: '/client-assets/drop-and-fusion/keycap_8.png', imgSizeX: 256, @@ -474,12 +341,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '8a8310d2-0374-460f-bb50-ca9cd3ee3416', - level: 7, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 64, - dropCandidate: false, sfxPitch: 1, img: '/client-assets/drop-and-fusion/keycap_7.png', imgSizeX: 256, @@ -487,12 +348,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '1092e069-fe1a-450b-be97-b5d477ec398c', - level: 6, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 32, - dropCandidate: false, sfxPitch: 1.5, img: '/client-assets/drop-and-fusion/keycap_6.png', imgSizeX: 256, @@ -500,12 +355,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '2294734d-7bb8-4781-bb7b-ef3820abf3d0', - level: 5, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 16, - dropCandidate: true, sfxPitch: 2, img: '/client-assets/drop-and-fusion/keycap_5.png', imgSizeX: 256, @@ -513,12 +362,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'ea8a61af-e350-45f7-ba6a-366fcd65692a', - level: 4, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25, - shape: 'rectangle', - score: 8, - dropCandidate: true, sfxPitch: 2.5, img: '/client-assets/drop-and-fusion/keycap_4.png', imgSizeX: 256, @@ -526,12 +369,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'd0c74815-fc1c-4fbe-9953-c92e4b20f919', - level: 3, - sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25, - shape: 'rectangle', - score: 4, - dropCandidate: true, sfxPitch: 3, img: '/client-assets/drop-and-fusion/keycap_3.png', imgSizeX: 256, @@ -539,12 +376,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: 'd8fbd70e-611d-402d-87da-1a7fd8cd2c8d', - level: 2, - sizeX: SQUARE_BASE_SIZE * 1.25, - sizeY: SQUARE_BASE_SIZE * 1.25, - shape: 'rectangle', - score: 2, - dropCandidate: true, sfxPitch: 3.5, img: '/client-assets/drop-and-fusion/keycap_2.png', imgSizeX: 256, @@ -552,12 +383,6 @@ const SQUARE_MONOS: Mono[] = [{ spriteScale: 1.12, }, { id: '35e476ee-44bd-4711-ad42-87be245d3efd', - level: 1, - sizeX: SQUARE_BASE_SIZE, - sizeY: SQUARE_BASE_SIZE, - shape: 'rectangle', - score: 1, - dropCandidate: true, sfxPitch: 4, img: '/client-assets/drop-and-fusion/keycap_1.png', imgSizeX: 256, @@ -574,11 +399,23 @@ const emit = defineEmits<{ (ev: 'end'): void; }>(); -const monoDefinitions = - props.gameMode === 'normal' ? NORAML_MONOS : - props.gameMode === 'square' ? SQUARE_MONOS : - props.gameMode === 'yen' ? YEN_MONOS : - [] as never; +const monoDefinitions = computed(() => { + return props.gameMode === 'normal' ? NORAML_MONOS : + props.gameMode === 'square' ? SQUARE_MONOS : + props.gameMode === 'yen' ? YEN_MONOS : + [] as never; +}); + +function getMonoRenderOptions(mono: Mono) { + const def = monoDefinitions.value.find(x => x.id === mono.id)!; + return { + sprite: { + texture: def.img, + xScale: (mono.sizeX / def.imgSizeX) * def.spriteScale, + yScale: (mono.sizeY / def.imgSizeY) * def.spriteScale, + }, + }; +} let viewScale = 1; let seed: string = Date.now().toString(); @@ -592,8 +429,8 @@ let monoTextureUrls: Record<string, string> = {}; let tickRaf: number | null = null; let game = new DropAndFusionGame({ seed: seed, - monoDefinitions, - hasComboBonus: props.gameMode !== 'yen', + gameMode: props.gameMode, + getMonoRenderOptions, }); attachGameEvents(); @@ -646,7 +483,7 @@ function createRendererInstance(game: DropAndFusionGame) { } function loadMonoTextures() { - async function loadSingleMonoTexture(mono: Mono) { + async function loadSingleMonoTexture(mono: FrontendMonoDefinition) { if (renderer == null) return; // Matter-js内ã«ã‚ャッシュãŒã‚ã‚‹å ´åˆã¯ã‚¹ã‚ップ @@ -673,22 +510,24 @@ function loadMonoTextures() { renderer.textures[mono.img] = image; } - return Promise.all(monoDefinitions.map(x => loadSingleMonoTexture(x))); + return Promise.all(monoDefinitions.value.map(x => loadSingleMonoTexture(x))); } function getTextureImageUrl(mono: Mono) { + const def = monoDefinitions.value.find(x => x.id === mono.id)!; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (monoTextureUrls[mono.img]) { - return monoTextureUrls[mono.img]; + if (monoTextureUrls[def.img]) { + return monoTextureUrls[def.img]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - } else if (monoTextures[mono.img]) { + } else if (monoTextures[def.img]) { // Gameクラス内ã«ã‚ャッシュãŒã‚ã‚‹å ´åˆã¯ãれを使ㆠ- const out = URL.createObjectURL(monoTextures[mono.img]); - monoTextureUrls[mono.img] = out; + const out = URL.createObjectURL(monoTextures[def.img]); + monoTextureUrls[def.img] = out; return out; } else { - return mono.img; + return def.img; } } @@ -797,8 +636,8 @@ async function restart() { reset(); game = new DropAndFusionGame({ seed: seed, - monoDefinitions, - hasComboBonus: props.gameMode !== 'yen', + gameMode: props.gameMode, + getMonoRenderOptions, }); attachGameEvents(); await start(); @@ -838,8 +677,8 @@ function replay() { dispose(); game = new DropAndFusionGame({ seed: seed, - monoDefinitions, - hasComboBonus: props.gameMode !== 'yen', + gameMode: props.gameMode, + getMonoRenderOptions, replaying: true, }); attachGameEvents(); @@ -986,28 +825,32 @@ function attachGameEvents() { game.addListener('changeHolding', value => { holdingStock.value = value; - sound.playUrl('/client-assets/drop-and-fusion/hold.mp3', { - volume: 0.5 * sfxVolume.value, - playbackRate: replayPlaybackRate.value, - }); + if (!props.mute) { + sound.playUrl('/client-assets/drop-and-fusion/hold.mp3', { + volume: 0.5 * sfxVolume.value, + playbackRate: replayPlaybackRate.value, + }); + } }); game.addListener('dropped', (x) => { - const panV = x - game.PLAYAREA_MARGIN; - const panW = game.GAME_WIDTH - game.PLAYAREA_MARGIN - game.PLAYAREA_MARGIN; - const pan = ((panV / panW) - 0.5) * 2; - if (props.gameMode === 'yen') { - sound.playUrl('/client-assets/drop-and-fusion/drop_yen.mp3', { - volume: sfxVolume.value, - pan, - playbackRate: replayPlaybackRate.value, - }); - } else { - sound.playUrl('/client-assets/drop-and-fusion/drop.mp3', { - volume: sfxVolume.value, - pan, - playbackRate: replayPlaybackRate.value, - }); + if (!props.mute) { + const panV = x - game.PLAYAREA_MARGIN; + const panW = game.GAME_WIDTH - game.PLAYAREA_MARGIN - game.PLAYAREA_MARGIN; + const pan = ((panV / panW) - 0.5) * 2; + if (props.gameMode === 'yen') { + sound.playUrl('/client-assets/drop-and-fusion/drop_yen.mp3', { + volume: sfxVolume.value, + pan, + playbackRate: replayPlaybackRate.value, + }); + } else { + sound.playUrl('/client-assets/drop-and-fusion/drop.mp3', { + volume: sfxVolume.value, + pan, + playbackRate: replayPlaybackRate.value, + }); + } } if (replaying.value) return; @@ -1020,7 +863,7 @@ function attachGameEvents() { }, game.DROP_INTERVAL); }); - game.addListener('fusioned', (x, y, scoreDelta) => { + game.addListener('fusioned', (x, y, nextMono, scoreDelta) => { if (!canvasEl.value) return; const rect = canvasEl.value.getBoundingClientRect(); @@ -1028,6 +871,65 @@ function attachGameEvents() { const domY = rect.top + (y * viewScale); os.popup(MkRippleEffect, { x: domX, y: domY }, {}, 'end'); os.popup(MkPlusOneEffect, { x: domX, y: domY, value: scoreDelta + (props.gameMode === 'yen' ? '円' : '') }, {}, 'end'); + + if (nextMono) { + const def = monoDefinitions.value.find(x => x.id === nextMono.id)!; + if (!props.mute) { + const panV = x - game.PLAYAREA_MARGIN; + const panW = game.GAME_WIDTH - game.PLAYAREA_MARGIN - game.PLAYAREA_MARGIN; + const pan = ((panV / panW) - 0.5) * 2; + const pitch = def.sfxPitch; + if (props.gameMode === 'yen') { + sound.playUrl('/client-assets/drop-and-fusion/fusion_yen.mp3', { + volume: 0.25 * sfxVolume.value, + pan: pan, + playbackRate: (pitch / 4) * replayPlaybackRate.value, + }); + } else { + sound.playUrl('/client-assets/drop-and-fusion/fusion.mp3', { + volume: sfxVolume.value, + pan: pan, + playbackRate: pitch * replayPlaybackRate.value, + }); + } + } + } else { + if (!props.mute) { + // TODO: èžåˆå¾Œã®ãƒ¢ãƒŽãŒãªã„å ´åˆã§ã‚‚何らã‹ã®åŠ¹æžœéŸ³ã‚’å†ç”Ÿ + } + } + }); + + const minCollisionEnergyForSound = 2.5; + const maxCollisionEnergyForSound = 9; + const soundPitchMax = 4; + const soundPitchMin = 0.5; + + game.addListener('collision', (energy, bodyA, bodyB) => { + if (!props.mute && (energy > minCollisionEnergyForSound)) { + const volume = (Math.min(maxCollisionEnergyForSound, energy - minCollisionEnergyForSound) / maxCollisionEnergyForSound) / 4; + const panV = + bodyA.label === '_wall_' ? bodyB.position.x - game.PLAYAREA_MARGIN : + bodyB.label === '_wall_' ? bodyA.position.x - game.PLAYAREA_MARGIN : + ((bodyA.position.x + bodyB.position.x) / 2) - game.PLAYAREA_MARGIN; + const panW = game.GAME_WIDTH - game.PLAYAREA_MARGIN - game.PLAYAREA_MARGIN; + const pan = ((panV / panW) - 0.5) * 2; + const pitch = soundPitchMin + ((soundPitchMax - soundPitchMin) * (1 - (Math.min(10, energy) / 10))); + + if (props.gameMode === 'yen') { + sound.playUrl('/client-assets/drop-and-fusion/collision_yen.mp3', { + volume: volume * sfxVolume.value, + pan: pan, + playbackRate: Math.max(1, pitch) * replayPlaybackRate.value, + }); + } else { + sound.playUrl('/client-assets/drop-and-fusion/collision.mp3', { + volume: volume * sfxVolume.value, + pan: pan, + playbackRate: pitch * replayPlaybackRate.value, + }); + } + } }); game.addListener('monoAdded', (mono) => { @@ -1045,14 +947,16 @@ function attachGameEvents() { }); game.addListener('gameOver', () => { - if (props.gameMode === 'yen') { - sound.playUrl('/client-assets/drop-and-fusion/gameover_yen.mp3', { - volume: 0.5 * sfxVolume.value, - }); - } else { - sound.playUrl('/client-assets/drop-and-fusion/gameover.mp3', { - volume: sfxVolume.value, - }); + if (!props.mute) { + if (props.gameMode === 'yen') { + sound.playUrl('/client-assets/drop-and-fusion/gameover_yen.mp3', { + volume: 0.5 * sfxVolume.value, + }); + } else { + sound.playUrl('/client-assets/drop-and-fusion/gameover.mp3', { + volume: sfxVolume.value, + }); + } } if (replaying.value) { @@ -1093,40 +997,6 @@ function attachGameEvents() { }); } }); - - game.addListener('sfx', (type, params) => { - if (props.mute) return; - - if (type === 'fusion') { - if (props.gameMode === 'yen') { - sound.playUrl('/client-assets/drop-and-fusion/fusion_yen.mp3', { - volume: 0.25 * params.volume * sfxVolume.value, - pan: params.pan, - playbackRate: (params.pitch / 4) * replayPlaybackRate.value, - }); - } else { - sound.playUrl('/client-assets/drop-and-fusion/fusion.mp3', { - volume: params.volume * sfxVolume.value, - pan: params.pan, - playbackRate: params.pitch * replayPlaybackRate.value, - }); - } - } else if (type === 'collision') { - if (props.gameMode === 'yen') { - sound.playUrl('/client-assets/drop-and-fusion/collision_yen.mp3', { - volume: params.volume * sfxVolume.value, - pan: params.pan, - playbackRate: Math.max(1, params.pitch) * replayPlaybackRate.value, - }); - } else { - sound.playUrl('/client-assets/drop-and-fusion/collision.mp3', { - volume: params.volume * sfxVolume.value, - pan: params.pan, - playbackRate: params.pitch * replayPlaybackRate.value, - }); - } - } - }); } useInterval(() => { @@ -1153,7 +1023,7 @@ onMounted(async () => { scope: ['dropAndFusionGame'], key: 'yenTotal', }); - } catch (err) { + } catch (err: any) { if (err.code === 'NO_SUCH_KEY') { // nop } else { diff --git a/packages/frontend/src/scripts/drop-and-fusion-engine.ts b/packages/frontend/src/scripts/drop-and-fusion-engine.ts index 8c5892e381f7ea7ca06c0de40b39a09d5354fa50..930cde00cb067e0056c4f36ab70858d4bc9b1c02 100644 --- a/packages/frontend/src/scripts/drop-and-fusion-engine.ts +++ b/packages/frontend/src/scripts/drop-and-fusion-engine.ts @@ -15,11 +15,6 @@ export type Mono = { shape: 'circle' | 'rectangle'; score: number; dropCandidate: boolean; - sfxPitch: number; - img: string; - imgSizeX: number; - imgSizeY: number; - spriteScale: number; }; type Log = { @@ -34,16 +29,266 @@ type Log = { operation: 'surrender'; }; +const NORMAL_BASE_SIZE = 30; +const NORAML_MONOS: Mono[] = [{ + id: '9377076d-c980-4d83-bdaf-175bc58275b7', + level: 10, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 512, + dropCandidate: false, +}, { + id: 'be9f38d2-b267-4b1a-b420-904e22e80568', + level: 9, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 256, + dropCandidate: false, +}, { + id: 'beb30459-b064-4888-926b-f572e4e72e0c', + level: 8, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 128, + dropCandidate: false, +}, { + id: 'feab6426-d9d8-49ae-849c-048cdbb6cdf0', + level: 7, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 64, + dropCandidate: false, +}, { + id: 'd6d8fed6-6d18-4726-81a1-6cf2c974df8a', + level: 6, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 32, + dropCandidate: false, +}, { + id: '249c728e-230f-4332-bbbf-281c271c75b2', + level: 5, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 16, + dropCandidate: true, +}, { + id: '23d67613-d484-4a93-b71e-3e81b19d6186', + level: 4, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 8, + dropCandidate: true, +}, { + id: '3cbd0add-ad7d-4685-bad0-29f6dddc0b99', + level: 3, + sizeX: NORMAL_BASE_SIZE * 1.25 * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25 * 1.25, + shape: 'circle', + score: 4, + dropCandidate: true, +}, { + id: '8f86d4f4-ee02-41bf-ad38-1ce0ae457fb5', + level: 2, + sizeX: NORMAL_BASE_SIZE * 1.25, + sizeY: NORMAL_BASE_SIZE * 1.25, + shape: 'circle', + score: 2, + dropCandidate: true, +}, { + id: '64ec4add-ce39-42b4-96cb-33908f3f118d', + level: 1, + sizeX: NORMAL_BASE_SIZE, + sizeY: NORMAL_BASE_SIZE, + shape: 'circle', + score: 1, + dropCandidate: true, +}]; + +const YEN_BASE_SIZE = 30; +const YEN_SATSU_BASE_SIZE = 70; +const YEN_MONOS: Mono[] = [{ + id: '880f9bd9-802f-4135-a7e1-fd0e0331f726', + level: 10, + sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25 * 1.25 * 1.25, + sizeY: YEN_SATSU_BASE_SIZE * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 10000, + dropCandidate: false, +}, { + id: 'e807beb6-374a-4314-9cc2-aa5f17d96b6b', + level: 9, + sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25 * 1.25, + sizeY: YEN_SATSU_BASE_SIZE * 1.25 * 1.25, + shape: 'rectangle', + score: 5000, + dropCandidate: false, +}, { + id: '033445b7-8f90-4fc9-beca-71a9e87cb530', + level: 8, + sizeX: (YEN_SATSU_BASE_SIZE * 2) * 1.25, + sizeY: YEN_SATSU_BASE_SIZE * 1.25, + shape: 'rectangle', + score: 2000, + dropCandidate: false, +}, { + id: '410a09ec-5f7f-46f6-b26f-cbca4ccbd091', + level: 7, + sizeX: YEN_SATSU_BASE_SIZE * 2, + sizeY: YEN_SATSU_BASE_SIZE, + shape: 'rectangle', + score: 1000, + dropCandidate: false, +}, { + id: '2aae82bc-3fa4-49ad-a6b5-94d888e809f5', + level: 6, + sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 500, + dropCandidate: false, +}, { + id: 'a619bd67-d08f-4cc0-8c7e-c8072a4950cd', + level: 5, + sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 100, + dropCandidate: true, +}, { + id: 'c1c5d8e4-17d6-4455-befd-12154d731faa', + level: 4, + sizeX: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25, + sizeY: YEN_BASE_SIZE * 1.25 * 1.25 * 1.25, + shape: 'circle', + score: 50, + dropCandidate: true, +}, { + id: '7082648c-e428-44c4-887a-25c07a8ebdd5', + level: 3, + sizeX: YEN_BASE_SIZE * 1.25 * 1.25, + sizeY: YEN_BASE_SIZE * 1.25 * 1.25, + shape: 'circle', + score: 10, + dropCandidate: true, +}, { + id: '0d8d40d5-e6e0-4d26-8a95-b8d842363379', + level: 2, + sizeX: YEN_BASE_SIZE * 1.25, + sizeY: YEN_BASE_SIZE * 1.25, + shape: 'circle', + score: 5, + dropCandidate: true, +}, { + id: '9dec1b38-d99d-40de-8288-37367b983d0d', + level: 1, + sizeX: YEN_BASE_SIZE, + sizeY: YEN_BASE_SIZE, + shape: 'circle', + score: 1, + dropCandidate: true, +}]; + +const SQUARE_BASE_SIZE = 28; +const SQUARE_MONOS: Mono[] = [{ + id: 'f75fd0ba-d3d4-40a4-9712-b470e45b0525', + level: 10, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 512, + dropCandidate: false, +}, { + id: '7b70f4af-1c01-45fd-af72-61b1f01e03d1', + level: 9, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 256, + dropCandidate: false, +}, { + id: '41607ef3-b6d6-4829-95b6-3737bf8bb956', + level: 8, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 128, + dropCandidate: false, +}, { + id: '8a8310d2-0374-460f-bb50-ca9cd3ee3416', + level: 7, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 64, + dropCandidate: false, +}, { + id: '1092e069-fe1a-450b-be97-b5d477ec398c', + level: 6, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 32, + dropCandidate: false, +}, { + id: '2294734d-7bb8-4781-bb7b-ef3820abf3d0', + level: 5, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 16, + dropCandidate: true, +}, { + id: 'ea8a61af-e350-45f7-ba6a-366fcd65692a', + level: 4, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25, + shape: 'rectangle', + score: 8, + dropCandidate: true, +}, { + id: 'd0c74815-fc1c-4fbe-9953-c92e4b20f919', + level: 3, + sizeX: SQUARE_BASE_SIZE * 1.25 * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25 * 1.25, + shape: 'rectangle', + score: 4, + dropCandidate: true, +}, { + id: 'd8fbd70e-611d-402d-87da-1a7fd8cd2c8d', + level: 2, + sizeX: SQUARE_BASE_SIZE * 1.25, + sizeY: SQUARE_BASE_SIZE * 1.25, + shape: 'rectangle', + score: 2, + dropCandidate: true, +}, { + id: '35e476ee-44bd-4711-ad42-87be245d3efd', + level: 1, + sizeX: SQUARE_BASE_SIZE, + sizeY: SQUARE_BASE_SIZE, + shape: 'rectangle', + score: 1, + dropCandidate: true, +}]; + export class DropAndFusionGame extends EventEmitter<{ changeScore: (newScore: number) => void; changeCombo: (newCombo: number) => void; changeStock: (newStock: { id: string; mono: Mono }[]) => void; changeHolding: (newHolding: { id: string; mono: Mono } | null) => void; dropped: (x: number) => void; - fusioned: (x: number, y: number, scoreDelta: number) => void; + fusioned: (x: number, y: number, nextMono: Mono | null, scoreDelta: number) => void; + collision: (energy: number, bodyA: Matter.Body, bodyB: Matter.Body) => void; monoAdded: (mono: Mono) => void; gameOver: () => void; - sfx(type: string, params: { volume: number; pan: number; pitch: number; }): void; }> { private PHYSICS_QUALITY_FACTOR = 16; // 低ã„ã»ã©ãƒ‘フォーマンスãŒé«˜ã„ãŒã‚¬ã‚¿ã‚¬ã‚¿ã—ã¦å®‰å®šã—ãªããªã‚‹ã€é€†ã«é«˜ã™ãŽã¦ã‚‚何故ã‹ä¸å®‰å®šã«ãªã‚‹ private COMBO_INTERVAL = 60; // frame @@ -60,8 +305,7 @@ export class DropAndFusionGame extends EventEmitter<{ private tickCallbackQueue: { frame: number; callback: () => void; }[] = []; private overflowCollider: Matter.Body; private isGameOver = false; - private monoDefinitions: Mono[] = []; - private hasComboBonus = true; + private gameMode: 'normal' | 'yen' | 'square'; private rng: () => number; private logs: Log[] = []; private replaying = false; @@ -84,6 +328,17 @@ export class DropAndFusionGame extends EventEmitter<{ private stock: { id: string; mono: Mono }[] = []; private holding: { id: string; mono: Mono } | null = null; + private get monoDefinitions() { + switch (this.gameMode) { + case 'normal': + return NORAML_MONOS; + case 'yen': + return YEN_MONOS; + case 'square': + return SQUARE_MONOS; + } + } + private _combo = 0; private get combo() { return this._combo; @@ -102,23 +357,27 @@ export class DropAndFusionGame extends EventEmitter<{ this.emit('changeScore', value); } + private getMonoRenderOptions: null | ((mono: Mono) => Partial<Matter.IBodyRenderOptions>) = null; + public replayPlaybackRate = 1; constructor(env: { - monoDefinitions: Mono[]; seed: string; - hasComboBonus: boolean; + gameMode: DropAndFusionGame['gameMode']; replaying?: boolean; + getMonoRenderOptions?: (mono: Mono) => Partial<Matter.IBodyRenderOptions>; }) { super(); + //#region BIND + this.tick = this.tick.bind(this); + //#endregion + this.replaying = !!env.replaying; - this.monoDefinitions = env.monoDefinitions; - this.hasComboBonus = env.hasComboBonus; + this.gameMode = env.gameMode; + this.getMonoRenderOptions = env.getMonoRenderOptions ?? null; this.rng = seedrandom(env.seed); - this.tick = this.tick.bind(this); - this.engine = Matter.Engine.create({ constraintIterations: 2 * this.PHYSICS_QUALITY_FACTOR, positionIterations: 6 * this.PHYSICS_QUALITY_FACTOR, @@ -182,13 +441,7 @@ export class DropAndFusionGame extends EventEmitter<{ frictionStatic: 5, slop: 1.0, //mass: 0, - render: { - sprite: { - texture: mono.img, - xScale: (mono.sizeX / mono.imgSizeX) * mono.spriteScale, - yScale: (mono.sizeY / mono.imgSizeY) * mono.spriteScale, - }, - }, + render: this.getMonoRenderOptions ? this.getMonoRenderOptions(mono) : undefined, }; if (mono.shape === 'circle') { return Matter.Bodies.circle(x, y, mono.sizeX / 2, options); @@ -217,7 +470,7 @@ export class DropAndFusionGame extends EventEmitter<{ Matter.Composite.remove(this.engine.world, [bodyA, bodyB]); const currentMono = this.monoDefinitions.find(y => y.id === bodyA.label)!; - const nextMono = this.monoDefinitions.find(x => x.level === currentMono.level + 1); + const nextMono = this.monoDefinitions.find(x => x.level === currentMono.level + 1) ?? null; if (nextMono) { const body = this.createBody(nextMono, newX, newY); @@ -231,28 +484,17 @@ export class DropAndFusionGame extends EventEmitter<{ }, }); - const comboBonus = this.hasComboBonus ? 1 + ((this.combo - 1) / 5) : 1; - const additionalScore = Math.round(currentMono.score * comboBonus); - this.score += additionalScore; - this.emit('monoAdded', nextMono); - this.emit('fusioned', newX, newY, additionalScore); - - const panV = newX - this.PLAYAREA_MARGIN; - const panW = this.GAME_WIDTH - this.PLAYAREA_MARGIN - this.PLAYAREA_MARGIN; - const pan = ((panV / panW) - 0.5) * 2; - this.emit('sfx', 'fusion', { volume: 1, pan, pitch: nextMono.sfxPitch }); - } else { - // nop } + + const comboBonus = this.gameMode === 'yen' ? 1 : 1 + ((this.combo - 1) / 5); + const additionalScore = Math.round(currentMono.score * comboBonus); + this.score += additionalScore; + + this.emit('fusioned', newX, newY, nextMono, additionalScore); } private onCollision(event: Matter.IEventCollision<Matter.Engine>) { - const minCollisionEnergyForSound = 2.5; - const maxCollisionEnergyForSound = 9; - const soundPitchMax = 4; - const soundPitchMin = 0.5; - for (const pairs of event.pairs) { const { bodyA, bodyB } = pairs; @@ -277,6 +519,8 @@ export class DropAndFusionGame extends EventEmitter<{ }); } } else { + const energy = pairs.collision.depth; + if (bodyA.label === '_overflow_' || bodyB.label === '_overflow_') continue; if (bodyA.label !== '_wall_' && bodyB.label !== '_wall_') { @@ -284,18 +528,7 @@ export class DropAndFusionGame extends EventEmitter<{ if (!this.gameOverReadyBodyIds.includes(bodyB.id)) this.gameOverReadyBodyIds.push(bodyB.id); } - const energy = pairs.collision.depth; - if (energy > minCollisionEnergyForSound) { - const volume = (Math.min(maxCollisionEnergyForSound, energy - minCollisionEnergyForSound) / maxCollisionEnergyForSound) / 4; - const panV = - bodyA.label === '_wall_' ? bodyB.position.x - this.PLAYAREA_MARGIN : - bodyB.label === '_wall_' ? bodyA.position.x - this.PLAYAREA_MARGIN : - ((bodyA.position.x + bodyB.position.x) / 2) - this.PLAYAREA_MARGIN; - const panW = this.GAME_WIDTH - this.PLAYAREA_MARGIN - this.PLAYAREA_MARGIN; - const pan = ((panV / panW) - 0.5) * 2; - const pitch = soundPitchMin + ((soundPitchMax - soundPitchMin) * (1 - (Math.min(10, energy) / 10))); - this.emit('sfx', 'collision', { volume, pan, pitch }); - } + this.emit('collision', energy, bodyA, bodyB); } } }