merge: fix(frontend): Ensure physics run consistently across different device framerates (!823)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/823

Closes #684

Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
Marie 2024-12-17 21:50:39 +00:00
commit 241949da04
4 changed files with 41 additions and 43 deletions

View file

@ -53,7 +53,7 @@
"is-file-animated": "1.0.2", "is-file-animated": "1.0.2",
"json5": "2.2.3", "json5": "2.2.3",
"katex": "0.16.10", "katex": "0.16.10",
"matter-js": "0.19.0", "matter-js": "0.20.0",
"misskey-bubble-game": "workspace:*", "misskey-bubble-game": "workspace:*",
"misskey-js": "workspace:*", "misskey-js": "workspace:*",
"misskey-reversi": "workspace:*", "misskey-reversi": "workspace:*",

View file

@ -557,7 +557,7 @@ let bgmNodes: ReturnType<typeof sound.createSourceNode> | null = null;
let renderer: Matter.Render | null = null; let renderer: Matter.Render | null = null;
let monoTextures: Record<string, Blob> = {}; let monoTextures: Record<string, Blob> = {};
let monoTextureUrls: Record<string, string> = {}; let monoTextureUrls: Record<string, string> = {};
let tickRaf: number | null = null; let tickInterval: number | null = null;
let game = new DropAndFusionGame({ let game = new DropAndFusionGame({
seed: seed, seed: seed,
gameMode: props.gameMode, gameMode: props.gameMode,
@ -663,13 +663,20 @@ function getTextureImageUrl(mono: Mono) {
} }
} }
function startTicking(tickFunction: () => void) {
tickInterval = window.setInterval(tickFunction, game.TICK_DELTA);
}
function stopTicking() {
if (tickInterval !== null) {
window.clearInterval(tickInterval);
tickInterval = null;
}
}
function tick() { function tick() {
const hasNextTick = game.tick(); const hasNextTick = game.tick();
if (hasNextTick) { if (!hasNextTick) stopTicking();
tickRaf = window.requestAnimationFrame(tick);
} else {
tickRaf = null;
}
} }
function tickReplay() { function tickReplay() {
@ -700,11 +707,7 @@ function tickReplay() {
if (!hasNextTick) break; if (!hasNextTick) break;
} }
if (hasNextTick) { if (!hasNextTick) stopTicking();
tickRaf = window.requestAnimationFrame(tickReplay);
} else {
tickRaf = null;
}
} }
async function start() { async function start() {
@ -716,7 +719,7 @@ async function start() {
}); });
Matter.Render.run(renderer); Matter.Render.run(renderer);
game.start(); game.start();
window.requestAnimationFrame(tick); startTicking(tick);
gameLoaded.value = true; gameLoaded.value = true;
@ -803,9 +806,7 @@ function reset() {
function dispose() { function dispose() {
game.dispose(); game.dispose();
if (renderer) Matter.Render.stop(renderer); if (renderer) Matter.Render.stop(renderer);
if (tickRaf) { stopTicking();
window.cancelAnimationFrame(tickRaf);
}
} }
function backToTitle() { function backToTitle() {
@ -829,7 +830,7 @@ function replay() {
}); });
Matter.Render.run(renderer); Matter.Render.run(renderer);
game.start(); game.start();
window.requestAnimationFrame(tickReplay); startTicking(tickReplay);
}); });
} }

View file

@ -51,7 +51,7 @@ export class DropAndFusionGame extends EventEmitter<{
public readonly DROP_COOLTIME = 30; // frame public readonly DROP_COOLTIME = 30; // frame
public readonly PLAYAREA_MARGIN = 25; public readonly PLAYAREA_MARGIN = 25;
private STOCK_MAX = 4; private STOCK_MAX = 4;
private TICK_DELTA = 1000 / 60; // 60fps public readonly TICK_DELTA = 1000 / 60; // 60fps
public frame = 0; public frame = 0;
public engine: Matter.Engine; public engine: Matter.Engine;

View file

@ -824,8 +824,8 @@ importers:
specifier: 0.16.10 specifier: 0.16.10
version: 0.16.10 version: 0.16.10
matter-js: matter-js:
specifier: 0.19.0 specifier: 0.20.0
version: 0.19.0 version: 0.20.0
misskey-bubble-game: misskey-bubble-game:
specifier: workspace:* specifier: workspace:*
version: link:../misskey-bubble-game version: link:../misskey-bubble-game
@ -2639,7 +2639,6 @@ packages:
'@humanwhocodes/config-array@0.11.14': '@humanwhocodes/config-array@0.11.14':
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'} engines: {node: '>=10.10.0'}
deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1': '@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
@ -2651,7 +2650,6 @@ packages:
'@humanwhocodes/object-schema@2.0.3': '@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
deprecated: Use @eslint/object-schema instead
'@humanwhocodes/retry@0.3.0': '@humanwhocodes/retry@0.3.0':
resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
@ -4447,7 +4445,6 @@ packages:
'@types/form-data@2.5.0': '@types/form-data@2.5.0':
resolution: {integrity: sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==} resolution: {integrity: sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==}
deprecated: This is a stub types definition. form-data provides its own type definitions, so you do not need this installed.
'@types/glob@7.2.0': '@types/glob@7.2.0':
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
@ -6500,7 +6497,6 @@ packages:
eslint@8.57.0: eslint@8.57.0:
resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
hasBin: true hasBin: true
eslint@9.14.0: eslint@9.14.0:
@ -6992,12 +6988,10 @@ packages:
glob@7.2.3: glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0: glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
deprecated: Glob versions prior to v9 are no longer supported
global-dirs@3.0.1: global-dirs@3.0.1:
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
@ -7292,7 +7286,6 @@ packages:
inflight@1.0.6: inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@ -8116,6 +8109,9 @@ packages:
matter-js@0.19.0: matter-js@0.19.0:
resolution: {integrity: sha512-v2huwvQGOHTGOkMqtHd2hercCG3f6QAObTisPPHg8TZqq2lz7eIY/5i/5YUV8Ibf3mEioFEmwibcPUF2/fnKKQ==} resolution: {integrity: sha512-v2huwvQGOHTGOkMqtHd2hercCG3f6QAObTisPPHg8TZqq2lz7eIY/5i/5YUV8Ibf3mEioFEmwibcPUF2/fnKKQ==}
matter-js@0.20.0:
resolution: {integrity: sha512-iC9fYR7zVT3HppNnsFsp9XOoQdQN2tUyfaKg4CHLH8bN+j6GT4Gw7IH2rP0tflAebrHFw730RR3DkVSZRX8hwA==}
mdast-util-find-and-replace@3.0.1: mdast-util-find-and-replace@3.0.1:
resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==} resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==}
@ -9676,7 +9672,6 @@ packages:
rimraf@3.0.2: rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true hasBin: true
rollup@4.26.0: rollup@4.26.0:
@ -11819,7 +11814,7 @@ snapshots:
'@babel/traverse': 7.23.5 '@babel/traverse': 7.23.5
'@babel/types': 7.24.7 '@babel/types': 7.24.7
convert-source-map: 2.0.0 convert-source-map: 2.0.0
debug: 4.3.5(supports-color@5.5.0) debug: 4.3.7(supports-color@8.1.1)
gensync: 1.0.0-beta.2 gensync: 1.0.0-beta.2
json5: 2.2.3 json5: 2.2.3
semver: 6.3.1 semver: 6.3.1
@ -11871,7 +11866,7 @@ snapshots:
'@babel/helper-environment-visitor@7.24.7': '@babel/helper-environment-visitor@7.24.7':
dependencies: dependencies:
'@babel/types': 7.24.7 '@babel/types': 7.25.7
'@babel/helper-function-name@7.24.7': '@babel/helper-function-name@7.24.7':
dependencies: dependencies:
@ -11884,7 +11879,7 @@ snapshots:
'@babel/helper-module-imports@7.22.15': '@babel/helper-module-imports@7.22.15':
dependencies: dependencies:
'@babel/types': 7.24.7 '@babel/types': 7.25.7
'@babel/helper-module-imports@7.24.7': '@babel/helper-module-imports@7.24.7':
dependencies: dependencies:
@ -11917,7 +11912,7 @@ snapshots:
'@babel/helper-simple-access@7.22.5': '@babel/helper-simple-access@7.22.5':
dependencies: dependencies:
'@babel/types': 7.24.7 '@babel/types': 7.25.7
'@babel/helper-simple-access@7.24.7': '@babel/helper-simple-access@7.24.7':
dependencies: dependencies:
@ -11928,7 +11923,7 @@ snapshots:
'@babel/helper-split-export-declaration@7.24.7': '@babel/helper-split-export-declaration@7.24.7':
dependencies: dependencies:
'@babel/types': 7.24.7 '@babel/types': 7.25.7
'@babel/helper-string-parser@7.24.7': {} '@babel/helper-string-parser@7.24.7': {}
@ -11946,7 +11941,7 @@ snapshots:
dependencies: dependencies:
'@babel/template': 7.22.15 '@babel/template': 7.22.15
'@babel/traverse': 7.24.7 '@babel/traverse': 7.24.7
'@babel/types': 7.24.7 '@babel/types': 7.25.7
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -12119,8 +12114,8 @@ snapshots:
'@babel/template@7.22.15': '@babel/template@7.22.15':
dependencies: dependencies:
'@babel/code-frame': 7.24.7 '@babel/code-frame': 7.24.7
'@babel/parser': 7.24.7 '@babel/parser': 7.25.7
'@babel/types': 7.24.7 '@babel/types': 7.25.7
'@babel/template@7.24.0': '@babel/template@7.24.0':
dependencies: dependencies:
@ -12142,9 +12137,9 @@ snapshots:
'@babel/helper-function-name': 7.24.7 '@babel/helper-function-name': 7.24.7
'@babel/helper-hoist-variables': 7.24.7 '@babel/helper-hoist-variables': 7.24.7
'@babel/helper-split-export-declaration': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7
'@babel/parser': 7.24.7 '@babel/parser': 7.25.7
'@babel/types': 7.24.7 '@babel/types': 7.25.7
debug: 4.3.5(supports-color@5.5.0) debug: 4.3.7(supports-color@8.1.1)
globals: 11.12.0 globals: 11.12.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -12157,9 +12152,9 @@ snapshots:
'@babel/helper-function-name': 7.24.7 '@babel/helper-function-name': 7.24.7
'@babel/helper-hoist-variables': 7.24.7 '@babel/helper-hoist-variables': 7.24.7
'@babel/helper-split-export-declaration': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7
'@babel/parser': 7.24.7 '@babel/parser': 7.25.7
'@babel/types': 7.24.7 '@babel/types': 7.25.7
debug: 4.3.5(supports-color@5.5.0) debug: 4.3.7(supports-color@8.1.1)
globals: 11.12.0 globals: 11.12.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -19721,6 +19716,8 @@ snapshots:
matter-js@0.19.0: {} matter-js@0.19.0: {}
matter-js@0.20.0: {}
mdast-util-find-and-replace@3.0.1: mdast-util-find-and-replace@3.0.1:
dependencies: dependencies:
'@types/mdast': 4.0.3 '@types/mdast': 4.0.3
@ -21858,7 +21855,7 @@ snapshots:
socks-proxy-agent@8.0.2: socks-proxy-agent@8.0.2:
dependencies: dependencies:
agent-base: 7.1.0 agent-base: 7.1.0
debug: 4.3.5(supports-color@5.5.0) debug: 4.3.7(supports-color@8.1.1)
socks: 2.7.1 socks: 2.7.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color