Refactor config setup and fix relax draggables
This commit is contained in:
194
src/main.js
194
src/main.js
@@ -1,43 +1,89 @@
|
|||||||
(() => {
|
(() => {
|
||||||
const { World, Body, Constraint, Events, Vector } = Matter;
|
const { World, Body, Constraint, Events, Vector } = Matter;
|
||||||
|
|
||||||
const { config: baseConfig, defaultMessageConfig } = window.PhysilinksConfig
|
const fromWindow = (key, fallback = {}) => window[key] ?? fallback;
|
||||||
?.create
|
|
||||||
? window.PhysilinksConfig.create()
|
|
||||||
: {
|
|
||||||
config: {},
|
|
||||||
defaultMessageConfig: {
|
|
||||||
durationMs: 4200,
|
|
||||||
position: { xPercent: 50, yPercent: 10 },
|
|
||||||
text: null,
|
|
||||||
colors: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const config = {
|
const getFactory = (key, fallbackFactory) => {
|
||||||
...baseConfig,
|
const mod = fromWindow(key);
|
||||||
link: { ...(baseConfig?.link || {}) },
|
return typeof mod.create === "function" ? mod.create : fallbackFactory;
|
||||||
messages: { ...(baseConfig?.messages || {}) },
|
};
|
||||||
|
|
||||||
|
const createConfig = getFactory("PhysilinksConfig", () => ({
|
||||||
|
config: {},
|
||||||
|
defaultMessageConfig: {
|
||||||
|
durationMs: 4200,
|
||||||
|
position: { xPercent: 50, yPercent: 10 },
|
||||||
|
text: null,
|
||||||
|
colors: null,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { config: baseConfig, defaultMessageConfig } = createConfig();
|
||||||
|
|
||||||
|
const normalizeMessages = (
|
||||||
|
sceneMessages = {},
|
||||||
|
defaults = defaultMessageConfig,
|
||||||
|
) => ({
|
||||||
|
durationMs: Number.isFinite(sceneMessages.durationMs)
|
||||||
|
? sceneMessages.durationMs
|
||||||
|
: defaults.durationMs,
|
||||||
|
text:
|
||||||
|
typeof sceneMessages.text === "string" && sceneMessages.text.trim()
|
||||||
|
? sceneMessages.text.trim()
|
||||||
|
: defaults.text,
|
||||||
|
position: {
|
||||||
|
xPercent:
|
||||||
|
typeof sceneMessages.position?.xPercent === "number"
|
||||||
|
? sceneMessages.position.xPercent
|
||||||
|
: defaults.position.xPercent,
|
||||||
|
yPercent:
|
||||||
|
typeof sceneMessages.position?.yPercent === "number"
|
||||||
|
? sceneMessages.position.yPercent
|
||||||
|
: defaults.position.yPercent,
|
||||||
|
},
|
||||||
|
colors: Array.isArray(sceneMessages.colors)
|
||||||
|
? sceneMessages.colors
|
||||||
|
: defaults.colors,
|
||||||
|
});
|
||||||
|
|
||||||
|
const normalizeSceneConfig = (sceneConfig = {}) => {
|
||||||
|
const { link = {}, messages = {}, ...rest } = sceneConfig;
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
link: { ...link },
|
||||||
|
messages: normalizeMessages(messages),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = { ...normalizeSceneConfig(baseConfig) };
|
||||||
|
|
||||||
|
const setConfigForScene = (sceneConfig = {}) => {
|
||||||
|
const normalized = normalizeSceneConfig(sceneConfig);
|
||||||
|
Object.assign(config, normalized);
|
||||||
|
config.link = { ...normalized.link };
|
||||||
|
config.messages = normalized.messages;
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
scenes = [],
|
scenes = [],
|
||||||
defaultSceneId,
|
defaultSceneId,
|
||||||
order: sceneOrder = [],
|
order: sceneOrder = [],
|
||||||
} = window.PhysilinksScenes || {};
|
} = fromWindow("PhysilinksScenes", {});
|
||||||
|
|
||||||
const { getSceneById, getSceneIdFromUrl, setSceneIdInUrl, getNextSceneId } =
|
const { getSceneById, getSceneIdFromUrl, setSceneIdInUrl, getNextSceneId } =
|
||||||
window.PhysilinksSceneRegistry || {};
|
fromWindow("PhysilinksSceneRegistry", {});
|
||||||
|
|
||||||
const ui = window.PhysilinksUI.create();
|
const createUI = getFactory("PhysilinksUI");
|
||||||
|
const ui = createUI();
|
||||||
const { sceneEl } = ui;
|
const { sceneEl } = ui;
|
||||||
|
|
||||||
let width = sceneEl.clientWidth;
|
let width = sceneEl.clientWidth;
|
||||||
let height = sceneEl.clientHeight;
|
let height = sceneEl.clientHeight;
|
||||||
const BALL_BASELINE = 680; // reference height used for relative ball sizing
|
const BALL_BASELINE = 680; // reference height used for relative ball sizing
|
||||||
|
|
||||||
|
const createEngine = getFactory("PhysilinksEngine");
|
||||||
const { engine, render, runner, startRunner, stopRunner, setRenderSize } =
|
const { engine, render, runner, startRunner, stopRunner, setRenderSize } =
|
||||||
window.PhysilinksEngine.create({
|
createEngine({
|
||||||
sceneEl,
|
sceneEl,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -64,13 +110,14 @@
|
|||||||
(getSceneById && getSceneById(scenes, initialSceneId)) || scenes[0] || null;
|
(getSceneById && getSceneById(scenes, initialSceneId)) || scenes[0] || null;
|
||||||
|
|
||||||
if (currentScene && currentScene.config) {
|
if (currentScene && currentScene.config) {
|
||||||
Object.assign(config, currentScene.config);
|
setConfigForScene(currentScene.config);
|
||||||
config.link = { ...currentScene.config.link };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const rebuildSceneBodies = () => {
|
const rebuildSceneBodies = () => {
|
||||||
boundaries.forEach((b) => World.remove(world, b));
|
boundaries.forEach((b) => World.remove(world, b));
|
||||||
boundaries = currentScene.createBodies(width, height);
|
const nextBoundaries = currentScene.createBodies(width, height);
|
||||||
|
boundaries.length = 0;
|
||||||
|
boundaries.push(...nextBoundaries);
|
||||||
rotators = boundaries.filter((b) => b.plugin && b.plugin.rotSpeed);
|
rotators = boundaries.filter((b) => b.plugin && b.plugin.rotSpeed);
|
||||||
oscillators = boundaries.filter((b) => b.plugin && b.plugin.oscillate);
|
oscillators = boundaries.filter((b) => b.plugin && b.plugin.oscillate);
|
||||||
World.add(world, boundaries);
|
World.add(world, boundaries);
|
||||||
@@ -91,12 +138,41 @@
|
|||||||
let spawnSystem = null;
|
let spawnSystem = null;
|
||||||
let input = null;
|
let input = null;
|
||||||
|
|
||||||
|
const storage = fromWindow("PhysilinksStorage", {});
|
||||||
const {
|
const {
|
||||||
loadHighScore = () => 0,
|
loadHighScore = () => 0,
|
||||||
loadLongestChain = () => 0,
|
loadLongestChain = () => 0,
|
||||||
saveHighScore = () => {},
|
saveHighScore = () => {},
|
||||||
saveLongestChain = () => {},
|
saveLongestChain = () => {},
|
||||||
} = window.PhysilinksStorage || {};
|
} = storage;
|
||||||
|
|
||||||
|
const resetEngineForScene = (
|
||||||
|
sceneConfig,
|
||||||
|
{ prevRadius, timeScaleOverride, resetPlugins = true } = {},
|
||||||
|
) => {
|
||||||
|
if (resetPlugins) {
|
||||||
|
world.plugin = world.plugin || {};
|
||||||
|
world.plugin.stormSteps = Array.isArray(sceneConfig?.spawnIntervals)
|
||||||
|
? sceneConfig.spawnIntervals
|
||||||
|
: null;
|
||||||
|
world.plugin.squareOffset = 0;
|
||||||
|
engine.plugin = engine.plugin || {};
|
||||||
|
engine.plugin.stormState = null;
|
||||||
|
}
|
||||||
|
spawnSystem.updateBallRadius(prevRadius);
|
||||||
|
engine.gravity.scale =
|
||||||
|
typeof sceneConfig?.gravityScale === "number"
|
||||||
|
? sceneConfig.gravityScale
|
||||||
|
: defaultGravityScale;
|
||||||
|
engine.gravity.x = 0;
|
||||||
|
engine.gravity.y = config.gravity;
|
||||||
|
engine.timing.timeScale =
|
||||||
|
typeof timeScaleOverride === "number"
|
||||||
|
? timeScaleOverride
|
||||||
|
: typeof sceneConfig?.timeScale === "number"
|
||||||
|
? sceneConfig.timeScale
|
||||||
|
: defaultTimeScale;
|
||||||
|
};
|
||||||
|
|
||||||
const applyScene = (sceneId) => {
|
const applyScene = (sceneId) => {
|
||||||
const next = (getSceneById && getSceneById(scenes, sceneId)) || scenes[0];
|
const next = (getSceneById && getSceneById(scenes, sceneId)) || scenes[0];
|
||||||
@@ -105,50 +181,9 @@
|
|||||||
ui.setSceneSelection(next.id);
|
ui.setSceneSelection(next.id);
|
||||||
setSceneIdInUrl(next.id);
|
setSceneIdInUrl(next.id);
|
||||||
const prevRadius = config.ballRadius;
|
const prevRadius = config.ballRadius;
|
||||||
Object.assign(config, next.config);
|
setConfigForScene(next.config);
|
||||||
config.link = { ...(next.config?.link || {}) };
|
|
||||||
const sceneMessages = next.config?.messages || {};
|
|
||||||
config.messages = {
|
|
||||||
durationMs: Number.isFinite(sceneMessages.durationMs)
|
|
||||||
? sceneMessages.durationMs
|
|
||||||
: defaultMessageConfig.durationMs,
|
|
||||||
text:
|
|
||||||
typeof sceneMessages.text === "string" && sceneMessages.text.trim()
|
|
||||||
? sceneMessages.text.trim()
|
|
||||||
: defaultMessageConfig.text,
|
|
||||||
position: {
|
|
||||||
xPercent:
|
|
||||||
typeof sceneMessages.position?.xPercent === "number"
|
|
||||||
? sceneMessages.position.xPercent
|
|
||||||
: defaultMessageConfig.position.xPercent,
|
|
||||||
yPercent:
|
|
||||||
typeof sceneMessages.position?.yPercent === "number"
|
|
||||||
? sceneMessages.position.yPercent
|
|
||||||
: defaultMessageConfig.position.yPercent,
|
|
||||||
},
|
|
||||||
colors: Array.isArray(sceneMessages.colors)
|
|
||||||
? sceneMessages.colors
|
|
||||||
: defaultMessageConfig.colors,
|
|
||||||
};
|
|
||||||
ui.setMessageDefaults(config.messages);
|
ui.setMessageDefaults(config.messages);
|
||||||
world.plugin = world.plugin || {};
|
resetEngineForScene(next.config, { prevRadius });
|
||||||
world.plugin.stormSteps = Array.isArray(next.config?.spawnIntervals)
|
|
||||||
? next.config.spawnIntervals
|
|
||||||
: null;
|
|
||||||
world.plugin.squareOffset = 0;
|
|
||||||
engine.plugin = engine.plugin || {};
|
|
||||||
engine.plugin.stormState = null;
|
|
||||||
engine.gravity.scale =
|
|
||||||
typeof next.config.gravityScale === "number"
|
|
||||||
? next.config.gravityScale
|
|
||||||
: defaultGravityScale;
|
|
||||||
engine.timing.timeScale =
|
|
||||||
typeof next.config.timeScale === "number"
|
|
||||||
? next.config.timeScale
|
|
||||||
: defaultTimeScale;
|
|
||||||
spawnSystem.updateBallRadius(prevRadius);
|
|
||||||
engine.gravity.x = 0;
|
|
||||||
engine.gravity.y = config.gravity;
|
|
||||||
clearedCount = 0;
|
clearedCount = 0;
|
||||||
levelWon = false;
|
levelWon = false;
|
||||||
clearedByColor = {};
|
clearedByColor = {};
|
||||||
@@ -193,7 +228,8 @@
|
|||||||
ui.showGameOver(score);
|
ui.showGameOver(score);
|
||||||
};
|
};
|
||||||
|
|
||||||
spawnSystem = window.PhysilinksSpawn.create({
|
const createSpawn = getFactory("PhysilinksSpawn");
|
||||||
|
spawnSystem = createSpawn({
|
||||||
config,
|
config,
|
||||||
world,
|
world,
|
||||||
balls,
|
balls,
|
||||||
@@ -205,7 +241,8 @@
|
|||||||
isGameOver: () => gameOver,
|
isGameOver: () => gameOver,
|
||||||
ballBaseline: BALL_BASELINE,
|
ballBaseline: BALL_BASELINE,
|
||||||
});
|
});
|
||||||
const goals = window.PhysilinksGoals.create({
|
const createGoals = getFactory("PhysilinksGoals");
|
||||||
|
const goals = createGoals({
|
||||||
config,
|
config,
|
||||||
getCurrentScene: () => currentScene,
|
getCurrentScene: () => currentScene,
|
||||||
getScore: () => score,
|
getScore: () => score,
|
||||||
@@ -245,13 +282,10 @@
|
|||||||
ui.hideGameOver();
|
ui.hideGameOver();
|
||||||
ui.hideWin();
|
ui.hideWin();
|
||||||
ui.setPauseState(false);
|
ui.setPauseState(false);
|
||||||
engine.gravity.scale =
|
resetEngineForScene(currentScene?.config || {}, {
|
||||||
typeof currentScene?.config?.gravityScale === "number"
|
timeScaleOverride: 1,
|
||||||
? currentScene.config.gravityScale
|
resetPlugins: false,
|
||||||
: defaultGravityScale;
|
});
|
||||||
engine.gravity.x = 0;
|
|
||||||
engine.gravity.y = config.gravity;
|
|
||||||
engine.timing.timeScale = 1;
|
|
||||||
startRunner();
|
startRunner();
|
||||||
updateHud();
|
updateHud();
|
||||||
if (isGridScene()) {
|
if (isGridScene()) {
|
||||||
@@ -341,7 +375,10 @@
|
|||||||
remaining.push(b);
|
remaining.push(b);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
boundaries = remaining;
|
boundaries.length = 0;
|
||||||
|
boundaries.push(...remaining);
|
||||||
|
rotators = rotators.filter((b) => boundaries.includes(b));
|
||||||
|
oscillators = oscillators.filter((b) => boundaries.includes(b));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -508,7 +545,8 @@
|
|||||||
goals.maybeAnnounceGoalProgress(goal);
|
goals.maybeAnnounceGoalProgress(goal);
|
||||||
};
|
};
|
||||||
|
|
||||||
input = window.PhysilinksInput.create({
|
const createInput = getFactory("PhysilinksInput");
|
||||||
|
input = createInput({
|
||||||
render,
|
render,
|
||||||
world,
|
world,
|
||||||
balls,
|
balls,
|
||||||
|
|||||||
Reference in New Issue
Block a user