mirror of
https://gitlab.com/lecarore/breakout71.git
synced 2025-04-20 12:15:06 -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
|
@ -31,7 +31,6 @@ There's also an easy mode for kids (slower ball).
|
|||
# bugs
|
||||
|
||||
- perk : travel map
|
||||
- stairs level has no bg, probably svg -1
|
||||
* [colin] parfois je dois appuyer plusieurs fois sur "Start a new run" pour vraiment commencer une nouvelle partie. dans ce cas, lhécran de jeu derrière se "désassombrit" comme si le jeu avait démarré plusieurs parties en même temps.
|
||||
* [colin] lorsque le puck est trop petit, l'affichage du combo disparaît. mais c'est peut-être volontaire pour qu'il ne dépasse pas du puck ? afficher simplement le chiffre serait suffisant et tiendrait dans le puck
|
||||
* [colin] le niveau bug parfois et ne peux pas démarrer. dans ce cas, la balle apparait comme démarrant sans être attachée au puck, comme si la partie avait déjà commencée. il faut redémarrer B71 pour que ça fonctionne
|
||||
|
|
283
dist/index.html
vendored
283
dist/index.html
vendored
File diff suppressed because one or more lines are too long
|
@ -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