mirror of
https://gitlab.com/lecarore/breakout71.git
synced 2025-04-22 21:16:14 -04:00
Split menus, fps display, set max coins and max particles
This commit is contained in:
parent
e3003f1c25
commit
2022b41937
17 changed files with 576 additions and 200 deletions
|
@ -42,7 +42,7 @@ export async function asyncAlert<t>({
|
|||
}): Promise<t | void> {
|
||||
updateAlertsOpen(+1);
|
||||
return new Promise((resolve) => {
|
||||
popupWrap.className = actionsAsGrid ? " " : "";
|
||||
popupWrap.className = actionsAsGrid ? " actionsAsGrid" : "";
|
||||
closeModaleButton.style.display = allowClose ? "" : "none";
|
||||
|
||||
const popup = document.createElement("div");
|
||||
|
|
|
@ -954,5 +954,40 @@
|
|||
"bricks": "__________tttt____tttt_______________W___________________rWWWr__",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
},
|
||||
{
|
||||
"name": "icon:restart",
|
||||
"size": 10,
|
||||
"bricks": "__GGGGGGGG__GGGGGGGG________GG________GG__G_____GG_GGG____GGGGGGG___GG_GGG____GG_GGGGGGGGG_GGGGGGGGG",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
},
|
||||
{
|
||||
"name": "icon:settings",
|
||||
"size": 8,
|
||||
"bricks": "__l__l___llllll_llllllll_ll__ll__ll__ll_llllllll_llllll___l__l__",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
},
|
||||
{
|
||||
"name": "icon:unlocks",
|
||||
"size": 7,
|
||||
"bricks": "eeee___e__e___e__e______llll___llll___llll___llll",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
},
|
||||
{
|
||||
"name": "icon:sandbox",
|
||||
"size": 8,
|
||||
"bricks": "________________________y_ttt__yyyttt_yyyytttyyyytttttyyyyyyyyyy",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
},
|
||||
{
|
||||
"name": "icon:continue",
|
||||
"size": 7,
|
||||
"bricks": "___t______tt__tttttt_ttttttttttttt____tt_____t___",
|
||||
"svg": null,
|
||||
"color": ""
|
||||
}
|
||||
]
|
||||
]
|
|
@ -66,6 +66,26 @@ body {
|
|||
#menu {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#FPSDisplay{
|
||||
z-index: 1;
|
||||
white-space: nowrap;
|
||||
padding: 10px;
|
||||
line-height: 20px;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
opacity: 0.8;
|
||||
|
||||
color:white;
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform-origin: top left;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
body.has-alert-open {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
|
@ -162,7 +182,7 @@ body:not(.has-alert-open) #popup {
|
|||
}
|
||||
|
||||
&.actionsAsGrid > div {
|
||||
max-width: 800px;
|
||||
max-width: none;
|
||||
|
||||
section {
|
||||
display: grid;
|
||||
|
|
228
src/game.ts
228
src/game.ts
|
@ -21,10 +21,17 @@ import {
|
|||
|
||||
import "./PWA/sw_loader";
|
||||
import { getCurrentLang, t } from "./i18n/i18n";
|
||||
import { getSettingValue, getTotalScore, setSettingValue } from "./settings";
|
||||
import {
|
||||
cycleMaxCoins, cycleMaxParticles,
|
||||
getCurrentMaxCoins,
|
||||
getCurrentMaxParticles,
|
||||
getSettingValue,
|
||||
getTotalScore,
|
||||
setSettingValue
|
||||
} from "./settings";
|
||||
import {
|
||||
forEachLiveOne,
|
||||
gameStateTick,
|
||||
gameStateTick, liveCount,
|
||||
normalizeGameState,
|
||||
pickRandomUpgrades,
|
||||
setLevel,
|
||||
|
@ -363,9 +370,28 @@ export function tick() {
|
|||
if (isOptionOn("sound")) {
|
||||
playPendingSounds(gameState);
|
||||
}
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
FPSCounter++
|
||||
}
|
||||
|
||||
let FPSCounter=0
|
||||
let FPSDisplay=document.getElementById('FPSDisplay') as HTMLDivElement
|
||||
setInterval(()=>{
|
||||
if(isOptionOn('show_fps')){
|
||||
FPSDisplay.innerText=FPSCounter+' FPS '+
|
||||
liveCount(gameState.coins)+' COINS '+
|
||||
(
|
||||
liveCount(gameState.particles)+
|
||||
liveCount(gameState.texts)+
|
||||
liveCount(gameState.lights)
|
||||
) + ' PARTICLES '
|
||||
}else{
|
||||
FPSDisplay.innerText=''
|
||||
}
|
||||
FPSCounter=0
|
||||
},1000)
|
||||
|
||||
window.addEventListener("visibilitychange", () => {
|
||||
if (document.hidden) {
|
||||
pause(true);
|
||||
|
@ -398,25 +424,8 @@ async function openScorePanel() {
|
|||
<p>${t("score_panel.upgrades_picked")}</p>
|
||||
<p>${pickedUpgradesHTMl(gameState)}</p>
|
||||
`,
|
||||
allowClose: true,
|
||||
actions: [
|
||||
{
|
||||
text: t("score_panel.resume"),
|
||||
help: t("score_panel.resume_help"),
|
||||
value: () => {},
|
||||
},
|
||||
{
|
||||
text: t("score_panel.restart"),
|
||||
help: t("score_panel.restart_help"),
|
||||
value: () => {
|
||||
restart({ levelToAvoid: currentLevelInfo(gameState).name });
|
||||
},
|
||||
},
|
||||
],
|
||||
allowClose: true
|
||||
});
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
(document.getElementById("menu") as HTMLButtonElement).addEventListener(
|
||||
|
@ -424,70 +433,34 @@ async function openScorePanel() {
|
|||
(e) => {
|
||||
e.preventDefault();
|
||||
if (!alertsOpen) {
|
||||
openSettingsPanel();
|
||||
openMainMenu();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
async function openSettingsPanel() {
|
||||
|
||||
async function openMainMenu() {
|
||||
pause(true);
|
||||
|
||||
const actions: AsyncAlertAction<() => void>[] = [];
|
||||
|
||||
for (const key of Object.keys(options) as OptionId[]) {
|
||||
if (options[key])
|
||||
actions.push({
|
||||
icon: isOptionOn(key)
|
||||
? icons["icon:checkmark_checked"]
|
||||
: icons["icon:checkmark_unchecked"],
|
||||
text: options[key].name,
|
||||
help: options[key].help,
|
||||
value: () => {
|
||||
toggleOption(key);
|
||||
if (key === "mobile-mode") fitSize();
|
||||
|
||||
openSettingsPanel();
|
||||
},
|
||||
});
|
||||
}
|
||||
const creativeModeThreshold = Math.max(...upgrades.map((u) => u.threshold));
|
||||
const actions:AsyncAlertAction<()=>void>[]=[{
|
||||
|
||||
if (document.fullscreenEnabled || document.webkitFullscreenEnabled) {
|
||||
if (document.fullscreenElement !== null) {
|
||||
actions.push({
|
||||
text: t("main_menu.fullscreen_exit"),
|
||||
help: t("main_menu.fullscreen_exit_help"),
|
||||
icon: icons["icon:exit_fullscreen"],
|
||||
value() {
|
||||
toggleFullScreen();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
text: t("main_menu.fullscreen"),
|
||||
help: t("main_menu.fullscreen_help"),
|
||||
|
||||
icon: icons["icon:fullscreen"],
|
||||
value() {
|
||||
toggleFullScreen();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
actions.push({
|
||||
text: t("main_menu.resume"),
|
||||
help: t("main_menu.resume_help"),
|
||||
value() {},
|
||||
});
|
||||
actions.push({
|
||||
text: t("main_menu.settings_title"),
|
||||
help: t("main_menu.settings_help"),
|
||||
icon:icons['icon:settings'],
|
||||
value() {
|
||||
openSettingsMenu()
|
||||
},
|
||||
},{
|
||||
icon:icons['icon:unlocks'],
|
||||
text: t("main_menu.unlocks"),
|
||||
help: t("main_menu.unlocks_help"),
|
||||
value() {
|
||||
openUnlocksList();
|
||||
},
|
||||
});
|
||||
|
||||
actions.push({
|
||||
},{
|
||||
icon:icons['icon:sandbox'],
|
||||
text: t("sandbox.title"),
|
||||
help:
|
||||
getTotalScore() < creativeModeThreshold
|
||||
|
@ -495,6 +468,7 @@ async function openSettingsPanel() {
|
|||
: t("sandbox.help"),
|
||||
disabled: getTotalScore() < creativeModeThreshold,
|
||||
async value() {
|
||||
|
||||
let creativeModePerks: Partial<{ [id in PerkId]: number }> =
|
||||
getSettingValue("creativeModePerks", {}),
|
||||
choice: "start" | Upgrade | void;
|
||||
|
@ -517,22 +491,98 @@ async function openSettingsPanel() {
|
|||
{
|
||||
text: t("sandbox.start"),
|
||||
value: "start",
|
||||
icon:icons['icon:continue'],
|
||||
},
|
||||
],
|
||||
}))
|
||||
) {
|
||||
if (choice === "start") {
|
||||
setSettingValue("creativeModePerks", creativeModePerks);
|
||||
restart({ perks: creativeModePerks });
|
||||
|
||||
break;
|
||||
break
|
||||
} else if (choice) {
|
||||
creativeModePerks[choice.id] =
|
||||
((creativeModePerks[choice.id] || 0) + 1) % (choice.max + 1);
|
||||
setSettingValue("creativeModePerks", creativeModePerks);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
icon:icons['icon:restart'],
|
||||
text: t("score_panel.restart"),
|
||||
help: t("score_panel.restart_help"),
|
||||
value: () => {
|
||||
restart({ levelToAvoid: currentLevelInfo(gameState).name });
|
||||
},
|
||||
},
|
||||
{
|
||||
icon:icons['icon:continue'],
|
||||
text: t("main_menu.resume"),
|
||||
help: t("main_menu.resume_help"),
|
||||
value() {},
|
||||
},
|
||||
] ;
|
||||
|
||||
|
||||
const cb = await asyncAlert<() => void>({
|
||||
title: t("main_menu.title"),
|
||||
text: ``,
|
||||
allowClose: true,
|
||||
actions,
|
||||
textAfterButtons: t("main_menu.footer_html", { appVersion }),
|
||||
});
|
||||
if (cb) {
|
||||
cb();
|
||||
gameState.needsRender = true;
|
||||
}
|
||||
}
|
||||
|
||||
async function openSettingsMenu() {
|
||||
pause(true);
|
||||
|
||||
const actions: AsyncAlertAction<() => void>[] = [];
|
||||
|
||||
for (const key of Object.keys(options) as OptionId[]) {
|
||||
if (options[key])
|
||||
actions.push({
|
||||
icon: isOptionOn(key)
|
||||
? icons["icon:checkmark_checked"]
|
||||
: icons["icon:checkmark_unchecked"],
|
||||
text: options[key].name,
|
||||
help: options[key].help,
|
||||
value: () => {
|
||||
toggleOption(key);
|
||||
if (key === "mobile-mode") fitSize();
|
||||
|
||||
openSettingsMenu();
|
||||
},
|
||||
});
|
||||
}
|
||||
if (document.fullscreenEnabled || document.webkitFullscreenEnabled) {
|
||||
if (document.fullscreenElement !== null) {
|
||||
actions.push({
|
||||
text: t("main_menu.fullscreen_exit"),
|
||||
help: t("main_menu.fullscreen_exit_help"),
|
||||
icon: icons["icon:exit_fullscreen"],
|
||||
value() {
|
||||
toggleFullScreen();
|
||||
openSettingsMenu();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
text: t("main_menu.fullscreen"),
|
||||
help: t("main_menu.fullscreen_help"),
|
||||
|
||||
icon: icons["icon:fullscreen"],
|
||||
value() {
|
||||
toggleFullScreen();
|
||||
openSettingsMenu();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
actions.push({
|
||||
text: t("main_menu.reset"),
|
||||
help: t("main_menu.reset_help"),
|
||||
|
@ -714,12 +764,34 @@ async function openSettingsPanel() {
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
actions.push({
|
||||
text: t("main_menu.max_coins",{max:getCurrentMaxCoins()}),
|
||||
help: t("main_menu.max_coins_help"),
|
||||
async value() {
|
||||
cycleMaxCoins()
|
||||
await openSettingsMenu()
|
||||
},
|
||||
});
|
||||
actions.push({
|
||||
text: t("main_menu.max_particles",{max:getCurrentMaxParticles()}),
|
||||
help: t("main_menu.max_particles_help"),
|
||||
async value() {
|
||||
cycleMaxParticles()
|
||||
await openSettingsMenu()
|
||||
},
|
||||
});
|
||||
|
||||
actions.push({
|
||||
text: t("main_menu.resume"),
|
||||
help: t("main_menu.resume_help"),
|
||||
value() {},
|
||||
});
|
||||
const cb = await asyncAlert<() => void>({
|
||||
title: t("main_menu.title"),
|
||||
text: ``,
|
||||
title: t("main_menu.settings_title"),
|
||||
text: t("main_menu.settings_help"),
|
||||
allowClose: true,
|
||||
actions,
|
||||
textAfterButtons: t("main_menu.footer_html", { appVersion }),
|
||||
actions
|
||||
});
|
||||
if (cb) {
|
||||
cb();
|
||||
|
@ -873,7 +945,7 @@ document.addEventListener("keyup", async (e) => {
|
|||
} else if (e.key === "Escape" && gameState.running) {
|
||||
pause(true);
|
||||
} else if (e.key.toLowerCase() === "m" && !alertsOpen) {
|
||||
openSettingsPanel().then();
|
||||
openMainMenu().then();
|
||||
} else if (e.key.toLowerCase() === "s" && !alertsOpen) {
|
||||
openScorePanel().then();
|
||||
} else if (e.key.toLowerCase() === "r" && !alertsOpen) {
|
||||
|
|
|
@ -31,7 +31,7 @@ import {
|
|||
import { t } from "./i18n/i18n";
|
||||
import { icons } from "./loadGameData";
|
||||
|
||||
import { addToTotalScore } from "./settings";
|
||||
import {addToTotalScore, getCurrentMaxCoins, getCurrentMaxParticles} from "./settings";
|
||||
import { background } from "./render";
|
||||
import { gameOver } from "./gameOver";
|
||||
import {
|
||||
|
@ -226,7 +226,7 @@ export function spawnExplosion(
|
|||
) {
|
||||
if (!!isOptionOn("basic")) return;
|
||||
|
||||
if (liveCount(gameState.particles) > gameState.MAX_PARTICLES) {
|
||||
if (liveCount(gameState.particles) > getCurrentMaxParticles()) {
|
||||
// Avoid freezing when lots of explosion happen at once
|
||||
count = 1;
|
||||
}
|
||||
|
@ -333,9 +333,9 @@ export function explodeBrick(
|
|||
gameState.levelSpawnedCoins += coinsToSpawn;
|
||||
gameState.runStatistics.coins_spawned += coinsToSpawn;
|
||||
gameState.runStatistics.bricks_broken++;
|
||||
const maxCoins = gameState.MAX_COINS * (isOptionOn("basic") ? 0.5 : 1);
|
||||
const maxCoins = getCurrentMaxCoins() * (isOptionOn("basic") ? 0.5 : 1);
|
||||
const spawnableCoins =
|
||||
liveCount(gameState.coins) > gameState.MAX_COINS
|
||||
liveCount(gameState.coins) > getCurrentMaxCoins()
|
||||
? 1
|
||||
: Math.floor(maxCoins - liveCount(gameState.coins)) / 3;
|
||||
|
||||
|
@ -1319,7 +1319,7 @@ export function ballTick(gameState: GameState, ball: Ball, delta: number) {
|
|||
if (gameState.perks.extra_life < 0) {
|
||||
gameState.perks.extra_life = 0;
|
||||
} else if (gameState.perks.sacrifice) {
|
||||
if (liveCount(gameState.coins) < gameState.MAX_COINS / 2) {
|
||||
if (liveCount(gameState.coins) < getCurrentMaxCoins() / 2) {
|
||||
// true duplication
|
||||
let remaining = liveCount(gameState.coins);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Ball, GameState, PerkId, PerksMap } from "./types";
|
||||
import { icons, upgrades } from "./loadGameData";
|
||||
|
||||
|
||||
|
||||
export function getMajorityValue(arr: string[]): string {
|
||||
const count: { [k: string]: number } = {};
|
||||
arr.forEach((v) => (count[v] = (count[v] || 0) + 1));
|
||||
|
|
|
@ -832,6 +832,66 @@
|
|||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>max_coins</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>max_coins_help</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>max_particles</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>max_particles_help</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>mobile</name>
|
||||
<description/>
|
||||
|
@ -1102,6 +1162,66 @@
|
|||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>settings_help</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>settings_title</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>show_fps</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>show_fps_help</name>
|
||||
<description/>
|
||||
<comment/>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-FR</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>sounds</name>
|
||||
<description/>
|
||||
|
|
|
@ -37,9 +37,9 @@
|
|||
"level_up.unlocked_perk": " (Perk)",
|
||||
"level_up.upgrade_perk_to_level": " lvl {{level}}",
|
||||
"main_menu.basic": "Basic graphics",
|
||||
"main_menu.basic_help": "Fewer particles and flashes, better performance.",
|
||||
"main_menu.download_save_file": "Download save file",
|
||||
"main_menu.download_save_file_help": "Get a transferable file with your score and stats",
|
||||
"main_menu.basic_help": "Better performance.",
|
||||
"main_menu.download_save_file": "Download score and stats",
|
||||
"main_menu.download_save_file_help": "Get a save file",
|
||||
"main_menu.footer_html": "<p> \n<span>Made in France by <a href=\"https://lecaro.me\">Renan LE CARO</a>.</span> \n<a href=\"https://paypal.me/renanlecaro\" target=\"_blank\">Donate</a>\n<a href=\"https://discord.gg/DZSPqyJkwP\" target=\"_blank\">Discord</a>\n<a href=\"https://f-droid.org/en/packages/me.lecaro.breakout/\" target=\"_blank\">F-Droid</a>\n<a href=\"https://play.google.com/store/apps/details?id=me.lecaro.breakout\" target=\"_blank\">Google Play</a>\n<a href=\"https://renanlecaro.itch.io/breakout71\" target=\"_blank\">itch.io</a> \n<a href=\"https://gitlab.com/lecarore/breakout71\" target=\"_blank\">Gitlab</a>\n<a href=\"https://breakout.lecaro.me/\" target=\"_blank\">Web version</a>\n<a href=\"https://news.ycombinator.com/item?id=43183131\" target=\"_blank\">HackerNews</a>\n<a href=\"https://breakout.lecaro.me/privacy.html\" target=\"_blank\">Privacy Policy</a>\n<span>v.{{appVersion}}</span>\n</p>\n",
|
||||
"main_menu.fullscreen": "Fullscreen",
|
||||
"main_menu.fullscreen_exit": "Exit Fullscreen",
|
||||
|
@ -51,8 +51,12 @@
|
|||
"main_menu.language_help": "Choose the game's language",
|
||||
"main_menu.load_save_file": "Load save file",
|
||||
"main_menu.load_save_file_help": "Select a save file on your device",
|
||||
"main_menu.max_coins": " {{max}} coins on screen maximum",
|
||||
"main_menu.max_coins_help": "Cosmetic only, no effect on score",
|
||||
"main_menu.max_particles": " {{max}} particles maximum",
|
||||
"main_menu.max_particles_help": "Limits the number of particles show on screen for visual effect. ",
|
||||
"main_menu.mobile": "Mobile mode",
|
||||
"main_menu.mobile_help": "Leaves space for your thumb under the puck.",
|
||||
"main_menu.mobile_help": "Leaves space under the puck.",
|
||||
"main_menu.pointer_lock": "Mouse pointer lock",
|
||||
"main_menu.pointer_lock_help": "Locks and hides the mouse cursor.",
|
||||
"main_menu.record": "Record gameplay videos",
|
||||
|
@ -69,6 +73,10 @@
|
|||
"main_menu.save_file_loaded": "Save file loaded",
|
||||
"main_menu.save_file_loaded_help": "The app will now reload to apply your save",
|
||||
"main_menu.save_file_loaded_ok": "Ok",
|
||||
"main_menu.settings_help": "Tailor the game play to your needs and taste",
|
||||
"main_menu.settings_title": "Settings",
|
||||
"main_menu.show_fps": "FPS counter",
|
||||
"main_menu.show_fps_help": "Monitor the app's performance",
|
||||
"main_menu.sounds": "Game sounds",
|
||||
"main_menu.sounds_help": "Can slow down some phones.",
|
||||
"main_menu.title": "Breakout 71",
|
||||
|
|
|
@ -37,31 +37,35 @@
|
|||
"level_up.unlocked_perk": " (Amélioration)",
|
||||
"level_up.upgrade_perk_to_level": " niveau {{level}}",
|
||||
"main_menu.basic": "Graphismes simplifiés",
|
||||
"main_menu.basic_help": "Moins de particules et effets, meilleures performances.",
|
||||
"main_menu.basic_help": "Meilleures performances.",
|
||||
"main_menu.download_save_file": "Sauvegarder mes progrès",
|
||||
"main_menu.download_save_file_help": "Obtenir un fichier de sauvegarde transférable",
|
||||
"main_menu.download_save_file_help": "Obtenir un fichier de sauvegarde",
|
||||
"main_menu.footer_html": " <p> \n<span>Programmé en France par <a href=\"https://lecaro.me\">Renan LE CARO</a>.</span>\n<a href=\"https://paypal.me/renanlecaro\" target=\"_blank\">Donner</a>\n<a href=\"https://discord.gg/DZSPqyJkwP\" target=\"_blank\">Discord</a>\n<a href=\"https://f-droid.org/en/packages/me.lecaro.breakout/\" target=\"_blank\">F-Droid</a>\n<a href=\"https://play.google.com/store/apps/details?id=me.lecaro.breakout\" target=\"_blank\">Google Play</a>\n<a href=\"https://renanlecaro.itch.io/breakout71\" target=\"_blank\">itch.io</a>\n<a href=\"https://gitlab.com/lecarore/breakout71\" target=\"_blank\">Gitlab</a>\n<a href=\"https://breakout.lecaro.me/\" target=\"_blank\">Version web</a>\n<a href=\"https://news.ycombinator.com/item?id=43183131\" target=\"_blank\">HackerNews</a>\n<a href=\"https://breakout.lecaro.me/privacy.html\" target=\"_blank\">Politique de confidentialité</a> \n<span>v.{{appVersion}}</span>\n</p>",
|
||||
"main_menu.fullscreen": "Plein écran",
|
||||
"main_menu.fullscreen_exit": "Quitter le plein écran",
|
||||
"main_menu.fullscreen_exit_help": "Peut ne pas fonctionner sur certaines machines",
|
||||
"main_menu.fullscreen_help": "Peut ne pas fonctionner sur certaines machines",
|
||||
"main_menu.fullscreen_exit_help": "Ne fonctionne pas toujours",
|
||||
"main_menu.fullscreen_help": "Ne fonctionne pas toujours",
|
||||
"main_menu.kid": "Mode enfants",
|
||||
"main_menu.kid_help": "Balle plus lente",
|
||||
"main_menu.language": "Langue",
|
||||
"main_menu.language_help": "Changer la langue d'affichage",
|
||||
"main_menu.load_save_file": "Charger une sauvegarde",
|
||||
"main_menu.load_save_file_help": "Sélectionnez une sauvegarde sur votre appareil ",
|
||||
"main_menu.load_save_file_help": "Depuis un fichier ",
|
||||
"main_menu.max_coins": "{{max}} pièces affichées maximum",
|
||||
"main_menu.max_coins_help": "Visuel uniquement, pas d'impact sur le score",
|
||||
"main_menu.max_particles": " {{max}} particules maximum",
|
||||
"main_menu.max_particles_help": "Limite le nombre de particules affichées à l'écran pour les effets visuels",
|
||||
"main_menu.mobile": "Mode mobile",
|
||||
"main_menu.mobile_help": "Laisse un espace pour le pouce sous le palet.",
|
||||
"main_menu.pointer_lock": "Verrouillage du pointeur de la souris",
|
||||
"main_menu.pointer_lock_help": "Verrouille et cache le curseur de la souris.",
|
||||
"main_menu.mobile_help": "Laisse un espace sous le palet.",
|
||||
"main_menu.pointer_lock": "Verrouillage du pointeur",
|
||||
"main_menu.pointer_lock_help": "Cache aussi le curseur de la souris.",
|
||||
"main_menu.record": "Enregistrer des vidéos de jeu",
|
||||
"main_menu.record_download": "Télécharger la vidéo ({{size}} MB)",
|
||||
"main_menu.record_help": "Obtenez une vidéo de chaque niveau.",
|
||||
"main_menu.reset": "Réinitialiser le jeu",
|
||||
"main_menu.reset_cancel": "Non",
|
||||
"main_menu.reset_confirm": "Oui",
|
||||
"main_menu.reset_help": "Effacer le meilleur score et les statistiques",
|
||||
"main_menu.reset_help": "Effacer les scores et statistiques",
|
||||
"main_menu.reset_instruction": "Vous perdrez tous les progrès que vous avez faits dans le jeu, êtes-vous sûr ?",
|
||||
"main_menu.resume": "Retourner à la partie",
|
||||
"main_menu.resume_help": "Continuer la partie en cours",
|
||||
|
@ -69,6 +73,10 @@
|
|||
"main_menu.save_file_loaded": "Sauvegarde chargée",
|
||||
"main_menu.save_file_loaded_help": "L'appli va redémarrer",
|
||||
"main_menu.save_file_loaded_ok": "Ok",
|
||||
"main_menu.settings_help": "Adaptez le jeu à vos besoins",
|
||||
"main_menu.settings_title": "Paramètre",
|
||||
"main_menu.show_fps": "Compteur de FPS",
|
||||
"main_menu.show_fps_help": "Surveiller la perf du jeu",
|
||||
"main_menu.sounds": "Sons du jeu",
|
||||
"main_menu.sounds_help": "Ralentis certains téléphones.",
|
||||
"main_menu.title": "Breakout 71",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<body>
|
||||
<button id="menu">☰ <span id="menuLabel">menu</span></button>
|
||||
<button id="score"></button>
|
||||
<div id="FPSDisplay"></div>
|
||||
<canvas id="game"></canvas>
|
||||
<div id="popup">
|
||||
<button id="close-modale"></button>
|
||||
|
|
|
@ -65,8 +65,6 @@ export function newGameState(params: RunParams): GameState {
|
|||
levelMisses: 0,
|
||||
levelSpawnedCoins: 0,
|
||||
lastPlayedCoinGrab: 0,
|
||||
MAX_COINS: 400,
|
||||
MAX_PARTICLES: 600,
|
||||
puckColor: "#FFF",
|
||||
ballSize: 20,
|
||||
coinSize: 14,
|
||||
|
|
|
@ -19,6 +19,11 @@ export const options = {
|
|||
name: t("main_menu.basic"),
|
||||
help: t("main_menu.basic_help"),
|
||||
},
|
||||
show_fps: {
|
||||
default: false,
|
||||
name: t("main_menu.show_fps"),
|
||||
help: t("main_menu.show_fps_help"),
|
||||
},
|
||||
pointerLock: {
|
||||
default: false,
|
||||
name: t("main_menu.pointer_lock"),
|
||||
|
|
|
@ -281,6 +281,7 @@ export function render(gameState: GameState) {
|
|||
const comboTextWidth = (comboText.length * gameState.puckHeight) / 1.8;
|
||||
const totalWidth = comboTextWidth + gameState.coinSize * 2;
|
||||
const left = gameState.puckPosition - totalWidth / 2;
|
||||
|
||||
if (totalWidth < gameState.puckWidth) {
|
||||
drawCoin(
|
||||
ctx,
|
||||
|
|
|
@ -33,3 +33,17 @@ export function addToTotalScore(gameState: GameState, points: number) {
|
|||
if (gameState.isCreativeModeRun) return;
|
||||
setSettingValue("breakout_71_total_score", getTotalScore() + points);
|
||||
}
|
||||
|
||||
|
||||
export function getCurrentMaxCoins(){
|
||||
return Math.pow(2,getSettingValue('max_coins', 1))*200
|
||||
}
|
||||
export function getCurrentMaxParticles(){
|
||||
return Math.pow(2,getSettingValue('max_particles', 1))*200
|
||||
}
|
||||
export function cycleMaxCoins(){
|
||||
setSettingValue('max_coins', (getSettingValue('max_coins', 1)+1)%6)
|
||||
}
|
||||
export function cycleMaxParticles(){
|
||||
setSettingValue('max_particles', (getSettingValue('max_particles', 1)+1)%6)
|
||||
}
|
4
src/types.d.ts
vendored
4
src/types.d.ts
vendored
|
@ -236,8 +236,8 @@ export type GameState = {
|
|||
levelSpawnedCoins: number;
|
||||
lastPlayedCoinGrab: number;
|
||||
|
||||
MAX_COINS: number;
|
||||
MAX_PARTICLES: number;
|
||||
// MAX_COINS: number;
|
||||
// MAX_PARTICLES: number;
|
||||
puckColor: colorString;
|
||||
ballSize: number;
|
||||
coinSize: number;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue