Fixed an issue with resizing and pacman level, changed ball attracts coins

This commit is contained in:
Renan LE CARO 2025-04-09 09:24:15 +02:00
parent 83b9c0dec5
commit 183a11f989
10 changed files with 1837 additions and 1761 deletions

View file

@ -28,11 +28,11 @@ Some upgrades currently are not really useful
## To do
- change fortunate ball to work more like coin magnet, carrying the balls around to catch them at next puck bounce
- add a test to forbid more than 5% grey bricks on black background, remove grey bricks border
## Done
- change fortunate ball to work more like coin magnet, carrying the balls around to catch them at next puck bounce
- add a test to forbid more than 5% grey bricks on black background, remove grey bricks border
- simplified texts to make translation easier
- fixed some issues around saved level unlocks
- change donation text to not suggest an amount

View file

@ -1,4 +1,4 @@
// npx nodemon checks.js
const fs= require('fs')
const english = JSON.parse(fs.readFileSync('./src/i18n/en.json'))
console.log(Object.entries(english).sort((a,b)=>a[1].length-b[1].length).slice(-10,-1).map(([k,v])=>k+'\n'+k.split('').map(c=>'=').join('')+'\n\n'+v).join('\n\n'))
console.debug(Object.entries(english).sort((a,b)=>a[1].length-b[1].length).slice(-10,-1).map(([k,v])=>k+'\n'+k.split('').map(c=>'=').join('')+'\n\n'+v).join('\n\n'))

60
dist/index.html vendored

File diff suppressed because one or more lines are too long

View file

@ -10,13 +10,11 @@ app.use(bodyParser.text({
}));
app.get('/src/data/levels.json', (req, res) => {
console.log('src/data/levels.json')
res.json(JSON.parse(fs.readFileSync('src/data/levels.json')))
})
app.post('/src/data/levels.json', (req, res) => {
if(req.body?.trim()) {
console.log('Levels updated')
fs.writeFileSync('src/data/levels.json', req.body)
}
res.end('OK')

View file

@ -77,7 +77,7 @@
"size": 6,
"bricks": "_______gggg__rrrr__yyyy",
"svg": 8,
"color": ""
"color": "#5da3ea"
},
{
"name": "France",
@ -413,12 +413,13 @@
"name": "Wiki",
"size": 10,
"bricks": "_______________________GGGG_____GGkkGG___GkggggkG__GgWWWWgG__GkggggkG___GGkkGG_____GGGG_______________________",
"svg": null
"svg": null,
"color": "#1c71d8"
},
{
"name": "Baby Dog",
"size": 8,
"bricks": "_______W__eeeeWWWWeeWeWWWegWegeeeeWWWWee_eWggWe__eWWWWe____WW",
"bricks": "_______W__eeeeWWWWeeWeWWWeBWeBeeeeWWWWee_eWBBWe__eWWWWe____WW___",
"svg": null
},
{
@ -570,7 +571,7 @@
{
"name": "icon:soft_reset",
"size": 8,
"bricks": "___rg_____rrgg___rryggg_rryWggggrryWgggg_ryyggg___rrgg_____rg___",
"bricks": "____yy______yyy_____yyyy____yyyyyyyyyyyyyyyyyyyy_yyyyyy___yyyy__",
"svg": null
},
{
@ -782,7 +783,7 @@
"size": 8,
"bricks": "_________tttttt__tttttt__gggggg__gggggg__WWWWWW__WWWWWW",
"svg": null,
"color": "#986a44"
"color": "#26a269"
},
{
"name": "Finland",
@ -1039,7 +1040,7 @@
"size": 24,
"bricks": "____________________________________________________ggggg______ggggg_______gg___g______g___gg_____gg________________gg___gg__________________gg_gggggggggg____gggggggggggggtttttggggggggbbbbbgggggtWWWttttggggbbbbWWWbgg_gtWttttttggggbbbbWbbbg__gtttttttgg__ggbbbbbbbg__gtttttttg____gbbbbbbbg__ggtttttgg____ggbbbbbgg___ggtttgg______ggbbbgg_____ggggg________ggggg___________________________________________________________________________________________________________________________________________________________________________________________________________________________",
"svg": null,
"color": "#1a5fb4",
"color": "#26a269",
"credit": "https://prohama.com/sunglasses-pattern-1/"
},
{
@ -1109,7 +1110,7 @@
{
"name": "icon:fountain_toss",
"size": 12,
"bricks": "________________tttt______tttggttt____tggggggt____t__gg__t____tllggllt___ltbyggbbtl_lbtttggtytblgyttybbtttyggggttbbtyggg_gggggggggg____gggggg___",
"bricks": "__________________________________________________WWWWWWWW___WttttttttW_WtytttytyttWWtttyttttttWlWtyttttytWl_lWWWWWWWWl___llllllll______________",
"svg": null,
"color": ""
},
@ -1122,8 +1123,8 @@
},
{
"name": "Gear",
"size": 14,
"bricks": "_________________________________l_l_l_______l_lllll_l______lllllll_____lllll_lllll____lll___lll____lll_____lll____lll___lll____lllll_lllll_____lllllll______l_lllll_l_______l_l_l__________________",
"size": 13,
"bricks": "_________________l_l_l______l_lllll_l_____lllllll____lllll_lllll___lll___lll___lll_____lll___lll___lll___lllll_lllll____lllllll_____l_lllll_l______l_l_l_________________",
"svg": null,
"color": ""
},
@ -1279,7 +1280,7 @@
"size": 11,
"bricks": "___gggg_____gggrrgg_____ggrrg_______gggg_____gggyygg_____ggyyg_______gggg_____gggCCgg_____ggCCg_______gggg________gg_____",
"svg": null,
"color": "",
"color": "#240a8b",
"credit": "Left a wonderful review on the play store."
},
{
@ -1287,7 +1288,7 @@
"size": 13,
"bricks": "_______________________________________OOOORgRgRgOOOOWOORgRgRgOOOOOWORgRgRgOWOOWOORgRgRgOOWOOWORgRgRgOWOOWOORgRgRgOOOOOOORgRgRgOOO_______________________________________",
"svg": null,
"color": "",
"color": "#62a0ea",
"credit": "Colin helped a lot with the game design https://colin-crapahute.bearblog.dev/"
},
{
@ -1295,7 +1296,7 @@
"size": 15,
"bricks": "_________________________________ggggggggg_____g_________g___g___________g_g_____________gg_____________gg_____yyy_____ggg__yyyyyyy__ggggtyyyyyyyyytggggtttttttttttgggg_ttttttttt_gg_____ttttt___________________________________",
"svg": null,
"color": "",
"color": "#240a8b",
"credit": "Early adopter of the game"
},
{
@ -1309,7 +1310,7 @@
{
"name": "icon:minefield",
"size": 7,
"bricks": "W__W__W_W___W___W_W__W_____W_W___W____g_____ggg__",
"bricks": "W__W__W_W___W___W_W__W_____W_W___W____l_____lll__",
"svg": null,
"color": ""
},
@ -1327,4 +1328,4 @@
"svg": null,
"color": ""
}
]
]

View file

@ -3,7 +3,7 @@
"B": "black",
"W": "#FFFFFF",
"g": "#231f20",
"y": "#ffd300",
"y": "#FFD300",
"b": "#6262EA",
"t": "#5DA3EA",
"s": "#E67070",

View file

@ -155,7 +155,8 @@ export const fitSize = () => {
const baseWidth = Math.round(
Math.min(gameState.canvasWidth, gameState.gameZoneHeight * 0.73),
);
gameState.brickWidth = Math.floor(baseWidth / gameState.gridSize / 2) * 2;
gameState.brickWidth = Math.floor(baseWidth / gameState.gridSize / 2) * 2;
gameState.gameZoneWidth = gameState.brickWidth * gameState.gridSize;
gameState.offsetX = Math.floor(
(gameState.canvasWidth - gameState.gameZoneWidth) / 2,
@ -974,8 +975,10 @@ document.addEventListener("keyup", async (e) => {
export const gameState = newGameState({});
export function restart(params: RunParams) {
fitSize();
// fitSize();
Object.assign(gameState, newGameState(params));
// Recompute brick size according to level
fitSize();
pauseRecording();
setLevel(gameState, 0);
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import _palette from "./data/palette.json";
import _rawLevelsList from "./data/levels.json";
import _appVersion from "./data/version.json";
import {rawUpgrades} from "./upgrades";
describe("json data checks", () => {
it("_rawLevelsList has icon levels", () => {
@ -8,6 +9,14 @@ describe("json data checks", () => {
_rawLevelsList.filter((l) => l.name.startsWith("icon:")).length,
).toBeGreaterThan(10);
});
it("all upgrades have icons", () => {
const missingIcon = rawUpgrades.filter((u) => !_rawLevelsList.find(l=>l.name=='icon:'+u.id))
expect(
missingIcon,
).toEqual([]);
});
it("_rawLevelsList has non-icon few levels", () => {
expect(
_rawLevelsList.filter((l) => !l.name.startsWith("icon:")).length,
@ -29,6 +38,18 @@ describe("json data checks", () => {
it("Has a few colors", () => {
expect(Object.keys(_palette).length).toBeGreaterThan(10);
});
it("Avoids dark bricks on dark bg", () => {
const levelsWithDarkBricksAndBG = _rawLevelsList
.filter(l=>!l.color && !l.name.match(/^icon:/))
.map(l=>({
name:l.name,
bricks:l.bricks.split('').filter(c=>c!=='_').length,
darkBricks:l.bricks.split('').filter(c=>c==='g').length,
}))
.filter(l=>l.darkBricks>0.05*l.bricks)
expect(levelsWithDarkBricksAndBG).toEqual([]);
});
it("Has an _appVersion", () => {
expect(parseInt(_appVersion)).toBeGreaterThan(2000);
});

View file

@ -257,11 +257,10 @@ export function render(gameState: GameState) {
coin.size,
coin.x,
coin.y,
// Red border around coins with asceticism
(hasCombo && gameState.perks.asceticism && "#FF0000") ||
(color === "#ffd300" && "#ffd300") ||
(color == "#231f20" &&
gameState.level.color == "#000000" &&
"#FFFFFF") ||
// Gold coins
// (color === "#ffd300" && "#ffd300") ||
gameState.level.color,
coin.a,
);
@ -408,7 +407,7 @@ export function render(gameState: GameState) {
gameState.coinSize,
left + gameState.coinSize / 2,
gameState.gameZoneHeight - gameState.puckHeight / 2,
gameState.puckColor,
"#ffd300",
0,
);
drawText(
@ -895,9 +894,15 @@ export function drawFuzzyBall(
x: number,
y: number,
) {
const key = "fuzzy-circle" + color + "_" + width;
if (!color) debugger;
if (!color?.startsWith('#')) debugger;
const size = Math.round(width * 3);
if (!size || isNaN(size)) {
debugger;
return
}
if (!cachedGraphics[key]) {
const can = document.createElement("canvas");
can.width = size;
@ -919,6 +924,7 @@ export function drawFuzzyBall(
canctx.fillStyle = gradient;
canctx.fillRect(0, 0, size, size);
cachedGraphics[key] = can;
}
ctx.drawImage(
cachedGraphics[key],
@ -944,12 +950,6 @@ export function drawBrick(
const width = brx - tlx,
height = bry - tly;
const whiteBorder =
offset == -1 &&
color == "#231f20" &&
gameState.level.color == "#000000" &&
"#FFFFFF";
const key =
"brick" +
color +
@ -962,8 +962,7 @@ export function drawBrick(
offset +
"_" +
borderOnly +
"_" +
whiteBorder;
"_" ;
if (!cachedGraphics[key]) {
const can = document.createElement("canvas");
@ -977,9 +976,9 @@ export function drawBrick(
canctx.setLineDash(offset !== -1 ? redBorderDash : emptyArray);
canctx.lineDashOffset = offset;
canctx.strokeStyle = (offset !== -1 && "#FF000033") || whiteBorder || color;
canctx.strokeStyle = (offset !== -1 && "#FF000033") || color;
canctx.lineJoin = "round";
canctx.lineWidth = whiteBorder ? 1 : bord;
canctx.lineWidth = bord;
roundRect(
canctx,
bord / 2,