Removed console.log that were triggering GC, and made all balls the same color to avoid another memory leak and simplify code

This commit is contained in:
Renan LE CARO 2025-03-01 20:40:20 +01:00
parent ef0e3be6ad
commit 9d8ac5d4b8
2 changed files with 51 additions and 63 deletions

View file

@ -202,11 +202,6 @@ function brickCenterY(index) {
return (Math.floor(index / gridSize) + 0.5) * brickWidth; return (Math.floor(index / gridSize) + 0.5) * brickWidth;
} }
function getRowCol(index) {
return {
col: index % gridSize, row: Math.floor(index / gridSize),
};
}
function getRowColIndex(row, col) { function getRowColIndex(row, col) {
if (row < 0 || col < 0 || row >= gridSize || col >= gridSize) return -1; if (row < 0 || col < 0 || row >= gridSize || col >= gridSize) return -1;
@ -276,11 +271,13 @@ function addToScore(coin) {
} }
let balls = []; let balls = [];
let ballsColor = 'white'
function resetBalls() { function resetBalls() {
const count = 1 + (perks?.multiball || 0); const count = 1 + (perks?.multiball || 0);
const perBall = puckWidth / (count + 1); const perBall = puckWidth / (count + 1);
balls = []; balls = [];
ballsColor=currentLevelInfo()?.black_puck ? '#000' : "#FFF"
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const x = puck - puckWidth / 2 + perBall * (i + 1); const x = puck - puckWidth / 2 + perBall * (i + 1);
balls.push({ balls.push({
@ -292,7 +289,6 @@ function resetBalls() {
vy: -baseSpeed, vy: -baseSpeed,
sx: 0, sx: 0,
sy: 0, sy: 0,
color: currentLevelInfo()?.black_puck ? '#000' : "#FFF",
sparks: 0, sparks: 0,
piercedSinceBounce: 0, piercedSinceBounce: 0,
hitSinceBounce: 0, hitSinceBounce: 0,
@ -308,20 +304,17 @@ function putBallsAtPuck() {
const perBall = puckWidth / (count + 1); const perBall = puckWidth / (count + 1);
balls.forEach((ball, i) => { balls.forEach((ball, i) => {
const x = puck - puckWidth / 2 + perBall * (i + 1); const x = puck - puckWidth / 2 + perBall * (i + 1);
Object.assign(ball, { ball.x = x
x, ball.previousx = x
previousx: x, ball.y = gameZoneHeight - 1.5 * ballSize
y: gameZoneHeight - 1.5 * ballSize, ball.previousy = ball.y
previousy: gameZoneHeight - 1.5 * ballSize, ball.vx = Math.random() > 0.5 ? baseSpeed : -baseSpeed
vx: Math.random() > 0.5 ? baseSpeed : -baseSpeed, ball.vy = -baseSpeed
vy: -baseSpeed, ball.sx = 0
sx: 0, ball.sy = 0
sy: 0, ball.hitItem = []
hitItem: [], ball.hitSinceBounce = 0
hitSinceBounce: 0, ball.piercedSinceBounce = 0
piercedSinceBounce: 0,
// piercedSinceBounce: 0,
});
}); });
} }
@ -643,10 +636,12 @@ const upgrades = [
perks: {picky_eater: 1}, perks: {picky_eater: 1},
level: 'Mountain' level: 'Mountain'
}, },
fullHelp: `Whenever you break a brick the same color as your ball, your combo increases by one. If it's a different color, the ball takes that new color, but the combo resets. fullHelp: `Whenever you break a brick the same color as your ball, your combo increases by one.
The bricks with the right color will get a white border. Once you get a combo higher than your minimum, the bricks of the wrong color will get a red halo. If you have more than If it's a different color, the ball takes that new color, but the combo resets.
one ball, for example a blue and red ball, then you can hit both red and blue bricks and your combo won't reset. This is to make it manageable based on brick border effects alone The bricks with the right color will get a white border.
for color-blind players. Once you get a combo higher than your minimum, the bricks of the wrong color will get a red halo.
If you have more than one ball, they all change color whenever one of them hits a brick.
` `
}, },
{ {
@ -666,7 +661,7 @@ const upgrades = [
}, },
{ {
"threshold": 6000, "threshold": 6000,
"id": "catch_all_coins", "id": "compound_interest",
"giftable": true, "giftable": true,
"name": "Compound interest", "name": "Compound interest",
"max": 3, "max": 3,
@ -732,7 +727,7 @@ const upgrades = [
"id": "pierce_color", "id": "pierce_color",
"name": "Color pierce", "name": "Color pierce",
"max": 1, "max": 1,
"help": "Ball breaks same color bricks", "help": "Balls pierce bricks of their color",
fullHelp: `Whenever a ball hits a brick of the same color, it will just go through unimpeded. fullHelp: `Whenever a ball hits a brick of the same color, it will just go through unimpeded.
Once it reaches a brick of a different color, it will break it, take its color and bounce.` Once it reaches a brick of a different color, it will break it, take its color and bounce.`
}, },
@ -853,7 +848,6 @@ function shuffleLevels(nameToAvoid = null) {
runLevels = allLevels.filter(l => l.name === target) runLevels = allLevels.filter(l => l.name === target)
nextRunOverrides.level = null nextRunOverrides.level = null
if (runLevels.length) return if (runLevels.length) return
console.log('target level not found, will take random one : ' + target)
} }
runLevels = allLevels runLevels = allLevels
@ -1014,16 +1008,15 @@ function hitsSomething(x, y, radius) {
return (hasBrick(brickIndex(x - radius, y - radius)) ?? hasBrick(brickIndex(x + radius, y - radius)) ?? hasBrick(brickIndex(x + radius, y + radius)) ?? hasBrick(brickIndex(x - radius, y + radius))); return (hasBrick(brickIndex(x - radius, y - radius)) ?? hasBrick(brickIndex(x + radius, y - radius)) ?? hasBrick(brickIndex(x + radius, y + radius)) ?? hasBrick(brickIndex(x - radius, y + radius)));
} }
function shouldPierceByColor(ballOrCoin, vhit, hhit, chit) { function shouldPierceByColor( vhit, hhit, chit) {
if (!perks.pierce_color) return false if (!perks.pierce_color) return false
// if (ballOrCoin.color === 'white') return true if (typeof vhit !== 'undefined' && bricks[vhit] !== ballsColor) {
if (typeof vhit !== 'undefined' && bricks[vhit] !== ballOrCoin.color) {
return false return false
} }
if (typeof hhit !== 'undefined' && bricks[hhit] !== ballOrCoin.color) { if (typeof hhit !== 'undefined' && bricks[hhit] !== ballsColor) {
return false return false
} }
if (typeof chit !== 'undefined' && bricks[chit] !== ballOrCoin.color) { if (typeof chit !== 'undefined' && bricks[chit] !== ballsColor) {
return false return false
} }
return true return true
@ -1042,7 +1035,7 @@ function brickHitCheck(ballOrCoin, radius, isBall) {
if (pierce && (typeof vhit !== "undefined" || typeof hhit !== "undefined" || typeof chit !== "undefined")) { if (pierce && (typeof vhit !== "undefined" || typeof hhit !== "undefined" || typeof chit !== "undefined")) {
ballOrCoin.piercedSinceBounce++ ballOrCoin.piercedSinceBounce++
} }
if (isBall && shouldPierceByColor(ballOrCoin, vhit, hhit, chit)) { if (isBall && shouldPierceByColor( vhit, hhit, chit)) {
pierce = true pierce = true
} }
@ -1198,8 +1191,8 @@ function tick() {
} else if (coin.y > canvas.height + coinRadius) { } else if (coin.y > canvas.height + coinRadius) {
coin.destroyed = true; coin.destroyed = true;
if (perks.catch_all_coins) { if (perks.compound_interest) {
decreaseCombo(coin.points * perks.catch_all_coins, coin.x, canvas.height - coinRadius); decreaseCombo(coin.points * perks.compound_interest, coin.x, canvas.height - coinRadius);
} }
} }
@ -1295,7 +1288,7 @@ function tick() {
vy: (Math.random() - 0.5) * 10, vy: (Math.random() - 0.5) * 10,
}) })
} }
if (perks.catch_all_coins) { if (perks.compound_interest) {
let x = puck let x = puck
do { do {
x = offsetXRoundedDown + gameZoneWidthRoundedUp * Math.random() x = offsetXRoundedDown + gameZoneWidthRoundedUp * Math.random()
@ -1368,8 +1361,7 @@ function ballTick(ball, delta) {
if (perks.puck_repulse_ball && Math.abs(ball.x - puck) < puckWidth / 2 + ballSize * (9 + perks.puck_repulse_ball) / 10) { if (perks.puck_repulse_ball && Math.abs(ball.x - puck) < puckWidth / 2 + ballSize * (9 + perks.puck_repulse_ball) / 10) {
repulse(ball, { repulse(ball, {
x: puck, x: puck,
y: gameZoneHeight, y: gameZoneHeight
color: currentLevelInfo()?.black_puck ? '#000' : '#FFF',
}, perks.puck_repulse_ball, false) }, perks.puck_repulse_ball, false)
} }
@ -1504,7 +1496,7 @@ function ballTick(ball, delta) {
duration: 100 * ball.sparks, duration: 100 * ball.sparks,
time: levelTime, time: levelTime,
size: coinSize / 2, size: coinSize / 2,
color: ball.color, color: ballsColor,
x: ball.x, x: ball.x,
y: ball.y, y: ball.y,
vx: (Math.random() - 0.5) * baseSpeed, vx: (Math.random() - 0.5) * baseSpeed,
@ -1714,7 +1706,9 @@ function explodeBrick(index, ball, isExplosion) {
const x = brickCenterX(index), y = brickCenterY(index); const x = brickCenterX(index), y = brickCenterY(index);
sounds.explode(ball.x); sounds.explode(ball.x);
const {col, row} = getRowCol(index);
const col= index % gridSize
const row= Math.floor(index / gridSize)
const size = 1 + perks.bigger_explosions; const size = 1 + perks.bigger_explosions;
// Break bricks around // Break bricks around
for (let dx = -size; dx <= size; dx++) { for (let dx = -size; dx <= size; dx++) {
@ -1732,7 +1726,6 @@ function explodeBrick(index, ball, isExplosion) {
const d2 = Math.max(brickWidth, Math.abs(dx) + Math.abs(dy)); const d2 = Math.max(brickWidth, Math.abs(dx) + Math.abs(dy));
c.vx += (dx / d2) * 10 * size / c.weight; c.vx += (dx / d2) * 10 * size / c.weight;
c.vy += (dy / d2) * 10 * size / c.weight; c.vy += (dy / d2) * 10 * size / c.weight;
}); });
lastexplosion = Date.now(); lastexplosion = Date.now();
@ -1768,13 +1761,12 @@ function explodeBrick(index, ball, isExplosion) {
runStatistics.coins_spawned += coinsToSpawn runStatistics.coins_spawned += coinsToSpawn
runStatistics.bricks_broken++ runStatistics.bricks_broken++
const maxCoins = MAX_COINS * (isSettingOn("basic") ? 0.5 : 1) const maxCoins = MAX_COINS * (isSettingOn("basic") ? 0.5 : 1)
const spawnableCoins = 1 + Math.floor(maxCoins - coins.length) / 3 const spawnableCoins = Math.floor(maxCoins - coins.length) / 3
const pointsPerCoin = Math.ceil(coinsToSpawn / spawnableCoins) const pointsPerCoin = Math.max(1, Math.ceil(coinsToSpawn / spawnableCoins))
while (coinsToSpawn > 0) { while (coinsToSpawn > 0) {
const points = Math.min(pointsPerCoin, coinsToSpawn) const points = Math.min(pointsPerCoin, coinsToSpawn)
coinsToSpawn -= points coinsToSpawn -= points
console.log('Spawned a coin with ' + points + ' pts')
const coord = { const coord = {
x: x + (Math.random() - 0.5) * (brickWidth - coinSize), x: x + (Math.random() - 0.5) * (brickWidth - coinSize),
y: y + (Math.random() - 0.5) * (brickWidth - coinSize), y: y + (Math.random() - 0.5) * (brickWidth - coinSize),
@ -1798,18 +1790,17 @@ function explodeBrick(index, ball, isExplosion) {
} }
combo += Math.max(0, perks.streak_shots + perks.catch_all_coins + perks.sides_are_lava + perks.top_is_lava + perks.picky_eater combo += Math.max(0, perks.streak_shots + perks.compound_interest + perks.sides_are_lava + perks.top_is_lava + perks.picky_eater
- Math.round(Math.random() * perks.soft_reset)); - Math.round(Math.random() * perks.soft_reset));
if (!isExplosion) { if (!isExplosion) {
// color change // color change
if ((perks.picky_eater || perks.pierce_color) && color !== ball.color) { if ((perks.picky_eater || perks.pierce_color) && color !== ballsColor && color) {
// reset streak if (perks.picky_eater) {
if (perks.picky_eater && !balls.find(b => b.color === color)) {
// Let's be nice, if you have two balls of two colors, none of those colors reset the combo.
resetCombo(ball.x, ball.y); resetCombo(ball.x, ball.y);
} }
ball.color = color;
ballsColor = color;
} else { } else {
sounds.comboIncreaseMaybe(ball.x, 1); sounds.comboIncreaseMaybe(ball.x, 1);
} }
@ -1851,8 +1842,8 @@ function render() {
scoreInfo += "🖤 "; scoreInfo += "🖤 ";
} }
scoreInfo += 'L'+(currentLevel+1)+'/'+max_levels()+' '; scoreInfo += 'L' + (currentLevel + 1) + '/' + max_levels() + ' ';
scoreInfo += '$'+score.toString(); scoreInfo += '$' + score.toString();
scoreDisplay.innerText = scoreInfo; scoreDisplay.innerText = scoreInfo;
// Clear // Clear
@ -1871,7 +1862,7 @@ function render() {
if (!coin.destroyed) drawFuzzyBall(ctx, coin.color, coinSize * 2, coin.x, coin.y); if (!coin.destroyed) drawFuzzyBall(ctx, coin.color, coinSize * 2, coin.x, coin.y);
}); });
balls.forEach((ball) => { balls.forEach((ball) => {
drawFuzzyBall(ctx, ball.color, ballSize * 2, ball.x, ball.y); drawFuzzyBall(ctx, ballsColor, ballSize * 2, ball.x, ball.y);
}); });
ctx.globalAlpha = 0.5; ctx.globalAlpha = 0.5;
bricks.forEach((color, index) => { bricks.forEach((color, index) => {
@ -1985,7 +1976,7 @@ function render() {
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
const puckColor = level.black_puck ? '#000' : '#FFF' const puckColor = level.black_puck ? '#000' : '#FFF'
balls.forEach((ball) => { balls.forEach((ball) => {
drawBall(ctx, ball.color, ballSize, ball.x, ball.y, puckColor); drawBall(ctx, ballsColor, ballSize, ball.x, ball.y, puckColor);
// effect // effect
if (isTelekinesisActive(ball)) { if (isTelekinesisActive(ball)) {
ctx.strokeStyle = puckColor; ctx.strokeStyle = puckColor;
@ -2027,7 +2018,7 @@ function render() {
if (perks.top_is_lava && combo > baseCombo()) if (perks.top_is_lava && combo > baseCombo())
drawRedSquare(ctx, offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1); drawRedSquare(ctx, offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1);
const redBottom = perks.catch_all_coins && combo > baseCombo() const redBottom = perks.compound_interest && combo > baseCombo()
ctx.fillStyle = redBottom ? 'red' : puckColor; ctx.fillStyle = redBottom ? 'red' : puckColor;
if (isSettingOn("mobile-mode")) { if (isSettingOn("mobile-mode")) {
ctx.fillRect(offsetXRoundedDown, gameZoneHeight, gameZoneWidthRoundedUp, 1); ctx.fillRect(offsetXRoundedDown, gameZoneHeight, gameZoneWidthRoundedUp, 1);
@ -2054,13 +2045,10 @@ function renderAllBricks(destinationCtx) {
ctx.globalAlpha = 1; ctx.globalAlpha = 1;
const level = currentLevelInfo(); const level = currentLevelInfo();
const ballColors = new Set(balls.map(b => b.color))
let ballsColorsKey = ''
ballColors.forEach(value => ballsColorsKey += value);
const redBorderOnBricksWithWrongColor = combo > baseCombo() && perks.picky_eater const redBorderOnBricksWithWrongColor = combo > baseCombo() && perks.picky_eater
const newKey = gameZoneWidth + "_" + bricks.join("_") + bombSVG.complete + '_' + redBorderOnBricksWithWrongColor + '_' + ballsColorsKey; const newKey = gameZoneWidth + "_" + bricks.join("_") + bombSVG.complete + '_' + redBorderOnBricksWithWrongColor + '_' + ballsColor;
if (newKey !== cachedBricksRenderKey) { if (newKey !== cachedBricksRenderKey) {
cachedBricksRenderKey = newKey; cachedBricksRenderKey = newKey;
@ -2076,7 +2064,7 @@ function renderAllBricks(destinationCtx) {
const x = brickCenterX(index), y = brickCenterY(index); const x = brickCenterX(index), y = brickCenterY(index);
if (!color) return; if (!color) return;
const borderColor = (ballColors.has(color) && puckColor) || (redBorderOnBricksWithWrongColor && 'red') || color const borderColor = (ballsColor===color && puckColor) || (color!=='black' && redBorderOnBricksWithWrongColor && 'red') || color
drawBrick(ctx, color, borderColor, x, y); drawBrick(ctx, color, borderColor, x, y);
if (color === 'black') { if (color === 'black') {
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
@ -2184,7 +2172,8 @@ function drawCoin(ctx, color, size, x, y, bg, rawAngle) {
function drawFuzzyBall(ctx, color, width, x, y) { function drawFuzzyBall(ctx, color, width, x, y) {
const key = "fuzzy-circle" + color + "_" + width; const key = "fuzzy-circle" + color + "_" + width;
if(!color)
debugger
const size = Math.round(width * 3); const size = Math.round(width * 3);
if (!cachedGraphics[key]) { if (!cachedGraphics[key]) {
const can = document.createElement("canvas"); const can = document.createElement("canvas");
@ -3218,7 +3207,6 @@ function setKeyPressed(key, on) {
} }
document.addEventListener('keydown', e => { document.addEventListener('keydown', e => {
console.log(e.key)
if (e.key.toLowerCase() === 'f') { if (e.key.toLowerCase() === 'f') {
toggleFullScreen() toggleFullScreen()
} else if (e.key in pressed) { } else if (e.key in pressed) {

View file

@ -8005,7 +8005,7 @@ let allLevels=[
"svg": "" "svg": ""
}, },
{ {
"name": "perk:catch_all_coins", "name": "perk:compound_interest",
"size": 8, "size": 8,
"bricks": [ "bricks": [
"", "",