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
--- /dev/null
+++ b/packages/frontend/assets/drop-and-fusion/frame-dark.svg
@@ -0,0 +1,28 @@
+
+
+
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
--- /dev/null
+++ b/packages/frontend/assets/drop-and-fusion/frame-light.svg
@@ -0,0 +1,28 @@
+
+
+
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
--- a/packages/frontend/assets/drop-and-fusion/frame.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
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;