-
SCORE: (MAX CHAIN: )
-
HIGH SCORE: -
+
SCORE: {{ gameMode === 'yen' ? '円' : 'pt' }}
+
HIGH SCORE: {{ gameMode === 'yen' ? '円' : 'pt' }}-
@@ -167,230 +167,404 @@ const NORMAL_BASE_SIZE = 30;
const NORAML_MONOS: Mono[] = [{
id: '9377076d-c980-4d83-bdaf-175bc58275b7',
level: 10,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'be9f38d2-b267-4b1a-b420-904e22e80568',
level: 9,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'beb30459-b064-4888-926b-f572e4e72e0c',
level: 8,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'feab6426-d9d8-49ae-849c-048cdbb6cdf0',
level: 7,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'd6d8fed6-6d18-4726-81a1-6cf2c974df8a',
level: 6,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '249c728e-230f-4332-bbbf-281c271c75b2',
level: 5,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '23d67613-d484-4a93-b71e-3e81b19d6186',
level: 4,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '3cbd0add-ad7d-4685-bad0-29f6dddc0b99',
level: 3,
- size: NORMAL_BASE_SIZE * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '8f86d4f4-ee02-41bf-ad38-1ce0ae457fb5',
level: 2,
- size: NORMAL_BASE_SIZE * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '64ec4add-ce39-42b4-96cb-33908f3f118d',
level: 1,
- size: NORMAL_BASE_SIZE,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}];
+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,
+ sfxPitch: 0.25,
+ img: '/client-assets/drop-and-fusion/10000yen.png',
+ imgSizeX: 512,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ 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,
+ imgSizeY: 256,
+ spriteScale: 0.97,
+}];
+
const SQUARE_BASE_SIZE = 28;
const SQUARE_MONOS: Mono[] = [{
id: 'f75fd0ba-d3d4-40a4-9712-b470e45b0525',
level: 10,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '7b70f4af-1c01-45fd-af72-61b1f01e03d1',
level: 9,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '41607ef3-b6d6-4829-95b6-3737bf8bb956',
level: 8,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '8a8310d2-0374-460f-bb50-ca9cd3ee3416',
level: 7,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '1092e069-fe1a-450b-be97-b5d477ec398c',
level: 6,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '2294734d-7bb8-4781-bb7b-ef3820abf3d0',
level: 5,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'ea8a61af-e350-45f7-ba6a-366fcd65692a',
level: 4,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'd0c74815-fc1c-4fbe-9953-c92e4b20f919',
level: 3,
- size: SQUARE_BASE_SIZE * 1.25 * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: 'd8fbd70e-611d-402d-87da-1a7fd8cd2c8d',
level: 2,
- size: SQUARE_BASE_SIZE * 1.25,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}, {
id: '35e476ee-44bd-4711-ad42-87be245d3efd',
level: 1,
- size: SQUARE_BASE_SIZE,
+ 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',
- imgSize: 256,
+ imgSizeX: 256,
+ imgSizeY: 256,
spriteScale: 1.12,
}];
const props = defineProps<{
- gameMode: 'normal' | 'square';
+ gameMode: 'normal' | 'square' | 'yen';
mute: boolean;
}>();
@@ -398,7 +572,11 @@ const emit = defineEmits<{
(ev: 'end'): void;
}>();
-const monoDefinitions = props.gameMode === 'normal' ? NORAML_MONOS : SQUARE_MONOS;
+const monoDefinitions =
+ props.gameMode === 'normal' ? NORAML_MONOS :
+ props.gameMode === 'square' ? SQUARE_MONOS :
+ props.gameMode === 'yen' ? YEN_MONOS :
+ [] as never;
let viewScale = 1;
let seed: string = Date.now().toString();
@@ -413,6 +591,7 @@ let tickRaf: number | null = null;
let game = new DropAndFusionGame({
seed: seed,
monoDefinitions,
+ hasComboBonus: props.gameMode !== 'yen',
});
attachGameEvents();
@@ -616,6 +795,7 @@ async function restart() {
game = new DropAndFusionGame({
seed: seed,
monoDefinitions,
+ hasComboBonus: props.gameMode !== 'yen',
});
attachGameEvents();
await start();
@@ -640,7 +820,7 @@ function reset() {
function dispose() {
game.dispose();
- Matter.Render.stop(renderer);
+ if (renderer) Matter.Render.stop(renderer);
if (tickRaf) {
window.cancelAnimationFrame(tickRaf);
}
@@ -656,6 +836,7 @@ function replay() {
game = new DropAndFusionGame({
seed: seed,
monoDefinitions,
+ hasComboBonus: props.gameMode !== 'yen',
replaying: true,
});
attachGameEvents();
@@ -812,11 +993,19 @@ function attachGameEvents() {
const panV = x - game.PLAYAREA_MARGIN;
const panW = game.GAME_WIDTH - game.PLAYAREA_MARGIN - game.PLAYAREA_MARGIN;
const pan = ((panV / panW) - 0.5) * 2;
- sound.playUrl('/client-assets/drop-and-fusion/poi2.mp3', {
- volume: sfxVolume.value,
- pan,
- playbackRate: replayPlaybackRate.value,
- });
+ 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;
@@ -853,9 +1042,15 @@ function attachGameEvents() {
});
game.addListener('gameOver', () => {
- sound.playUrl('/client-assets/drop-and-fusion/gameover.mp3', {
- volume: sfxVolume.value,
- });
+ 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) {
endReplay();
@@ -1173,10 +1368,15 @@ definePageMetadata({
position: absolute;
z-index: 10;
top: 50%;
- width: 100%;
+ left: 0;
+ right: 0;
+ margin: auto;
+ width: calc(100% - 50px);
+ max-width: 320px;
padding: 16px;
box-sizing: border-box;
background: #0007;
+ border-radius: 16px;
color: #fff;
text-align: center;
font-weight: bold;
diff --git a/packages/frontend/src/pages/drop-and-fusion.vue b/packages/frontend/src/pages/drop-and-fusion.vue
index 0938ca6a8..80c466a2b 100644
--- a/packages/frontend/src/pages/drop-and-fusion.vue
+++ b/packages/frontend/src/pages/drop-and-fusion.vue
@@ -26,6 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
{{ i18n.ts.start }}
@@ -42,12 +43,12 @@ SPDX-License-Identifier: AGPL-3.0-only
-
{{ i18n.ts.ranking }} ({{ gameMode }})
+
{{ i18n.t('lastNDays', { n: 7 }) }} {{ i18n.ts.ranking }} ({{ gameMode }})
- {{ r.score.toLocaleString() }} pt
+ {{ r.score.toLocaleString() }} {{ gameMode === 'yen' ? '円' : 'pt' }}
{{ i18n.ts.loading }}
@@ -94,7 +95,7 @@ import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import { misskeyApiGet } from '@/scripts/misskey-api.js';
-const gameMode = ref<'normal' | 'square'>('normal');
+const gameMode = ref<'normal' | 'square' | 'yen'>('normal');
const gameStarted = ref(false);
const mute = ref(false);
const ranking = ref(null);
diff --git a/packages/frontend/src/scripts/drop-and-fusion-engine.ts b/packages/frontend/src/scripts/drop-and-fusion-engine.ts
index 41af9cb7a..ad02c2832 100644
--- a/packages/frontend/src/scripts/drop-and-fusion-engine.ts
+++ b/packages/frontend/src/scripts/drop-and-fusion-engine.ts
@@ -10,13 +10,15 @@ import seedrandom from 'seedrandom';
export type Mono = {
id: string;
level: number;
- size: number;
+ sizeX: number;
+ sizeY: number;
shape: 'circle' | 'rectangle';
score: number;
dropCandidate: boolean;
sfxPitch: number;
img: string;
- imgSize: number;
+ imgSizeX: number;
+ imgSizeY: number;
spriteScale: number;
};
@@ -59,6 +61,7 @@ export class DropAndFusionGame extends EventEmitter<{
private overflowCollider: Matter.Body;
private isGameOver = false;
private monoDefinitions: Mono[] = [];
+ private hasComboBonus = true;
private rng: () => number;
private logs: Log[] = [];
private replaying = false;
@@ -66,7 +69,9 @@ export class DropAndFusionGame extends EventEmitter<{
/**
* フィールドに出ていて、かつ合体の対象となるアイテム
*/
- private activeBodyIds: Matter.Body['id'][] = [];
+ private fusionReadyBodyIds: Matter.Body['id'][] = [];
+
+ private gameOverReadyBodyIds: Matter.Body['id'][] = [];
/**
* fusion予約アイテムのペア
@@ -74,8 +79,6 @@ export class DropAndFusionGame extends EventEmitter<{
*/
private fusionReservedPairs: { bodyA: Matter.Body; bodyB: Matter.Body }[] = [];
- private latestDroppedBodyId: Matter.Body['id'] | null = null;
-
private latestDroppedAt = 0;
private latestFusionedAt = 0; // frame
private stock: { id: string; mono: Mono }[] = [];
@@ -101,11 +104,17 @@ export class DropAndFusionGame extends EventEmitter<{
public replayPlaybackRate = 1;
- constructor(env: { monoDefinitions: Mono[]; seed: string; replaying?: boolean }) {
+ constructor(env: {
+ monoDefinitions: Mono[];
+ seed: string;
+ hasComboBonus: boolean;
+ replaying?: boolean;
+ }) {
super();
this.replaying = !!env.replaying;
this.monoDefinitions = env.monoDefinitions;
+ this.hasComboBonus = env.hasComboBonus;
this.rng = seedrandom(env.seed);
this.tick = this.tick.bind(this);
@@ -147,6 +156,7 @@ export class DropAndFusionGame extends EventEmitter<{
//#endregion
this.overflowCollider = Matter.Bodies.rectangle(this.GAME_WIDTH / 2, 0, this.GAME_WIDTH, 200, {
+ label: '_overflow_',
isStatic: true,
isSensor: true,
render: {
@@ -165,7 +175,7 @@ export class DropAndFusionGame extends EventEmitter<{
const options: Matter.IBodyDefinition = {
label: mono.id,
//density: 0.0005,
- density: mono.size / 1000,
+ density: ((mono.sizeX + mono.sizeY) / 2) / 1000,
restitution: 0.2,
frictionAir: 0.01,
friction: 0.7,
@@ -175,16 +185,16 @@ export class DropAndFusionGame extends EventEmitter<{
render: {
sprite: {
texture: mono.img,
- xScale: (mono.size / mono.imgSize) * mono.spriteScale,
- yScale: (mono.size / mono.imgSize) * mono.spriteScale,
+ xScale: (mono.sizeX / mono.imgSizeX) * mono.spriteScale,
+ yScale: (mono.sizeY / mono.imgSizeY) * mono.spriteScale,
},
},
};
if (mono.shape === 'circle') {
- return Matter.Bodies.circle(x, y, mono.size / 2, options);
+ return Matter.Bodies.circle(x, y, mono.sizeX / 2, options);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
} else if (mono.shape === 'rectangle') {
- return Matter.Bodies.rectangle(x, y, mono.size, mono.size, options);
+ return Matter.Bodies.rectangle(x, y, mono.sizeX, mono.sizeY, options);
} else {
throw new Error('unrecognized shape');
}
@@ -202,8 +212,9 @@ export class DropAndFusionGame extends EventEmitter<{
const newX = (bodyA.position.x + bodyB.position.x) / 2;
const newY = (bodyA.position.y + bodyB.position.y) / 2;
+ this.fusionReadyBodyIds = this.fusionReadyBodyIds.filter(x => x !== bodyA.id && x !== bodyB.id);
+ this.gameOverReadyBodyIds = this.gameOverReadyBodyIds.filter(x => x !== bodyA.id && x !== bodyB.id);
Matter.Composite.remove(this.engine.world, [bodyA, bodyB]);
- this.activeBodyIds = this.activeBodyIds.filter(x => x !== bodyA.id && x !== bodyB.id);
const currentMono = this.monoDefinitions.find(y => y.id === bodyA.label)!;
const nextMono = this.monoDefinitions.find(x => x.level === currentMono.level + 1);
@@ -216,11 +227,11 @@ export class DropAndFusionGame extends EventEmitter<{
this.tickCallbackQueue.push({
frame: this.frame + this.msToFrame(100),
callback: () => {
- this.activeBodyIds.push(body.id);
+ this.fusionReadyBodyIds.push(body.id);
},
});
- const comboBonus = 1 + ((this.combo - 1) / 5);
+ const comboBonus = this.hasComboBonus ? 1 + ((this.combo - 1) / 5) : 1;
const additionalScore = Math.round(currentMono.score * comboBonus);
this.score += additionalScore;
@@ -245,14 +256,6 @@ export class DropAndFusionGame extends EventEmitter<{
for (const pairs of event.pairs) {
const { bodyA, bodyB } = pairs;
- if (bodyA.id === this.overflowCollider.id || bodyB.id === this.overflowCollider.id) {
- if (bodyA.id === this.latestDroppedBodyId || bodyB.id === this.latestDroppedBodyId) {
- continue;
- }
- this.gameOver();
- break;
- }
-
const shouldFusion = (bodyA.label === bodyB.label) &&
!this.fusionReservedPairs.some(x =>
x.bodyA.id === bodyA.id ||
@@ -261,7 +264,7 @@ export class DropAndFusionGame extends EventEmitter<{
x.bodyB.id === bodyB.id);
if (shouldFusion) {
- if (this.activeBodyIds.includes(bodyA.id) && this.activeBodyIds.includes(bodyB.id)) {
+ if (this.fusionReadyBodyIds.includes(bodyA.id) && this.fusionReadyBodyIds.includes(bodyB.id)) {
this.fusion(bodyA, bodyB);
} else {
this.fusionReservedPairs.push({ bodyA, bodyB });
@@ -274,12 +277,19 @@ export class DropAndFusionGame extends EventEmitter<{
});
}
} else {
+ if (bodyA.label === '_overflow_' || bodyB.label === '_overflow_') continue;
+
+ if (bodyA.label !== '_wall_' && bodyB.label !== '_wall_') {
+ if (!this.gameOverReadyBodyIds.includes(bodyA.id)) this.gameOverReadyBodyIds.push(bodyA.id);
+ 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 =
- pairs.bodyA.label === '_wall_' ? bodyB.position.x - this.PLAYAREA_MARGIN :
- pairs.bodyB.label === '_wall_' ? bodyA.position.x - this.PLAYAREA_MARGIN :
+ 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;
@@ -290,6 +300,21 @@ export class DropAndFusionGame extends EventEmitter<{
}
}
+ private onCollisionActive(event: Matter.IEventCollision
) {
+ for (const pairs of event.pairs) {
+ const { bodyA, bodyB } = pairs;
+
+ // ハコからあふれたかどうかの判定
+ if (bodyA.id === this.overflowCollider.id || bodyB.id === this.overflowCollider.id) {
+ if (this.gameOverReadyBodyIds.includes(bodyA.id) || this.gameOverReadyBodyIds.includes(bodyB.id)) {
+ this.gameOver();
+ break;
+ }
+ continue;
+ }
+ }
+ }
+
public surrender() {
this.logs.push({
frame: this.frame,
@@ -314,6 +339,7 @@ export class DropAndFusionGame extends EventEmitter<{
this.emit('changeStock', this.stock);
Matter.Events.on(this.engine, 'collisionStart', this.onCollision.bind(this));
+ Matter.Events.on(this.engine, 'collisionActive', this.onCollisionActive.bind(this));
}
public getLogs() {
@@ -360,17 +386,18 @@ export class DropAndFusionGame extends EventEmitter<{
this.emit('changeStock', this.stock);
const inputX = Math.round(_x);
- const x = Math.min(this.GAME_WIDTH - this.PLAYAREA_MARGIN - (head.mono.size / 2), Math.max(this.PLAYAREA_MARGIN + (head.mono.size / 2), inputX));
- const body = this.createBody(head.mono, x, 50 + head.mono.size / 2);
+ const x = Math.min(this.GAME_WIDTH - this.PLAYAREA_MARGIN - (head.mono.sizeX / 2), Math.max(this.PLAYAREA_MARGIN + (head.mono.sizeX / 2), inputX));
+ const body = this.createBody(head.mono, x, 50 + head.mono.sizeY / 2);
this.logs.push({
frame: this.frame,
operation: 'drop',
x: inputX,
});
Matter.Composite.add(this.engine.world, body);
- this.activeBodyIds.push(body.id);
- this.latestDroppedBodyId = body.id;
+
+ this.fusionReadyBodyIds.push(body.id);
this.latestDroppedAt = Date.now();
+
this.emit('dropped', x);
this.emit('monoAdded', head.mono);
}