diff --git a/packages/frontend/assets/drop-and-fusion/dropper.png b/packages/frontend/assets/drop-and-fusion/dropper.png new file mode 100644 index 0000000000..f4300aa5c0 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/dropper.png differ diff --git a/packages/frontend/assets/drop-and-fusion/frame-dark.svg b/packages/frontend/assets/drop-and-fusion/frame-dark.svg new file mode 100644 index 0000000000..3fa7c0da81 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/frame-dark.svg differ diff --git a/packages/frontend/assets/drop-and-fusion/frame-light.svg b/packages/frontend/assets/drop-and-fusion/frame-light.svg new file mode 100644 index 0000000000..6052ccbaa0 Binary files /dev/null and b/packages/frontend/assets/drop-and-fusion/frame-light.svg differ diff --git a/packages/frontend/assets/drop-and-fusion/frame.svg b/packages/frontend/assets/drop-and-fusion/frame.svg deleted file mode 100644 index 4276dae833..0000000000 Binary files a/packages/frontend/assets/drop-and-fusion/frame.svg and /dev/null differ diff --git a/packages/frontend/src/pages/drop-and-fusion.vue b/packages/frontend/src/pages/drop-and-fusion.vue index d0ca5157ef..7f4a885b44 100644 --- a/packages/frontend/src/pages/drop-and-fusion.vue +++ b/packages/frontend/src/pages/drop-and-fusion.vue @@ -11,7 +11,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- SCORE: +
SCORE:
+
HIGH SCORE: -
@@ -33,7 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- + +
{{ comboPrev }} Chain!
+ (); const canvasEl = shallowRef(); @@ -191,7 +196,7 @@ const FRUITS = [{ const GAME_WIDTH = 450; const GAME_HEIGHT = 600; -const PHYSICS_QUALITY_FACTOR = 32; // 低いほどパフォーマンスが高いがガタガタして安定しなくなる +const PHYSICS_QUALITY_FACTOR = 16; // 低いほどパフォーマンスが高いがガタガタして安定しなくなる、逆に高すぎても何故か不安定になる let viewScaleX = 1; let viewScaleY = 1; @@ -203,6 +208,7 @@ const comboPrev = ref(0); const dropReady = ref(true); const gameOver = ref(false); const gameStarted = ref(false); +const highScore = ref(null); class Game extends EventEmitter<{ changeScore: (score: number) => void; @@ -251,6 +257,8 @@ class Game extends EventEmitter<{ this.emit('changeScore', value); } + private comboIntervalId: number | null = null; + constructor() { super(); @@ -294,6 +302,8 @@ class Game extends EventEmitter<{ //#region walls const WALL_OPTIONS: Matter.IChamferableBodyDefinition = { isStatic: true, + friction: 0.7, + slop: 1.0, render: { strokeStyle: 'transparent', fillStyle: 'transparent', @@ -308,7 +318,7 @@ class Game extends EventEmitter<{ ]); //#endregion - this.overflowCollider = Matter.Bodies.rectangle(GAME_WIDTH / 2, 0, GAME_WIDTH, 125, { + this.overflowCollider = Matter.Bodies.rectangle(GAME_WIDTH / 2, 0, GAME_WIDTH, 200, { isStatic: true, isSensor: true, render: { @@ -328,11 +338,13 @@ class Game extends EventEmitter<{ private createBody(fruit: typeof FRUITS[number], x: number, y: number) { return Matter.Bodies.circle(x, y, fruit.size / 2, { label: fruit.id, - density: 0.0005, + //density: 0.0005, + density: fruit.size / 1000, + restitution: 0.2, frictionAir: 0.01, - restitution: 0.4, - friction: 0.5, + friction: 0.7, frictionStatic: 5, + slop: 1.0, //mass: 0, render: { sprite: { @@ -372,7 +384,7 @@ class Game extends EventEmitter<{ this.activeBodyIds.push(body.id); }, 100); - const additionalScore = Math.round(currentFruit.score * (1 + (this.combo / 3))); + const additionalScore = Math.round(currentFruit.score * (1 + ((this.combo - 1) / 3))); this.score += additionalScore; const pan = ((newX / GAME_WIDTH) - 0.5) * 2; @@ -449,7 +461,7 @@ class Game extends EventEmitter<{ } }); - window.setInterval(() => { + this.comboIntervalId = window.setInterval(() => { if (this.latestFusionedAt < Date.now() - this.COMBO_INTERVAL) { this.combo = 0; } @@ -469,7 +481,7 @@ class Game extends EventEmitter<{ this.emit('changeStock', this.stock); const x = Math.min(GAME_WIDTH - this.PLAYAREA_MARGIN - (st.fruit.size / 2), Math.max(this.PLAYAREA_MARGIN + (st.fruit.size / 2), _x)); - const body = this.createBody(st.fruit, x, st.fruit.size / 2); + const body = this.createBody(st.fruit, x, 50 + st.fruit.size / 2); Matter.Composite.add(this.engine.world, body); this.activeBodyIds.push(body.id); this.latestDroppedBodyId = body.id; @@ -480,6 +492,7 @@ class Game extends EventEmitter<{ } public dispose() { + if (this.comboIntervalId) window.clearInterval(this.comboIntervalId); Matter.Render.stop(this.render); Matter.Runner.stop(this.runner); Matter.World.clear(this.engine.world, false); @@ -567,10 +580,28 @@ function attachGame() { currentPick.value = null; dropReady.value = false; gameOver.value = true; + + if (score.value > (highScore.value ?? 0)) { + highScore.value = score.value; + + misskeyApi('i/registry/set', { + scope: ['dropAndFusionGame'], + key: 'highScore', + value: highScore.value, + }); + } }); } -onMounted(() => { +onMounted(async () => { + try { + highScore.value = await misskeyApi('i/registry/get', { + scope: ['dropAndFusionGame'], + key: 'highScore', + }); + } catch (err) { + } + game = new Game(); attachGame(); @@ -667,7 +698,9 @@ definePageMetadata({ top: 0; left: 0; width: 100%; - filter: drop-shadow(0 6px 16px #0007); + // なんかiOSでちらつく + //filter: drop-shadow(0 6px 16px #0007); + border-radius: 16px; pointer-events: none; user-select: none; } @@ -699,13 +732,28 @@ definePageMetadata({ text-align: center; font-weight: bold; font-style: oblique; + color: #fff; + -webkit-text-stroke: 1px rgb(255, 145, 0); + text-shadow: 0 0 6px #0005; pointer-events: none; user-select: none; } .currentFruit { position: absolute; - margin-top: 20px; + margin-top: 80px; + z-index: 2; + filter: drop-shadow(0 6px 16px #0007); + pointer-events: none; + user-select: none; +} + +.dropper { + position: absolute; + top: 0; + width: 70px; + margin-top: -10px; + margin-left: -30px; z-index: 2; filter: drop-shadow(0 6px 16px #0007); pointer-events: none; @@ -714,7 +762,7 @@ definePageMetadata({ .currentFruitArrow { position: absolute; - margin-top: 20px; + margin-top: 100px; z-index: 3; animation: currentFruitArrow 2s ease infinite; pointer-events: none; @@ -723,10 +771,10 @@ definePageMetadata({ .dropGuide { position: absolute; - top: 50px; + top: 120px; z-index: 3; width: 3px; - height: calc(100% - 50px); + height: calc(100% - 120px); background: #f002; pointer-events: none; user-select: none;