Ball no longer continues through bricks with piercing + sturdy bricks

This commit is contained in:
Renan LE CARO 2025-03-12 16:50:28 +01:00
parent 021f25cf7c
commit 7d8f5f59b0
5 changed files with 91 additions and 229 deletions

View file

@ -22,12 +22,7 @@ There's also an easy mode for kids (slower ball).
# bugs # bugs
- having Hot Start and Single puck hit streak perks in a run resets combo from start [29014379]
- The ball goes through Sturdy bricks sometimes, but it does not break
nor bounce back after hitting them (and indeed this does not cause a
miss). In the video you can clearly witness it several time, and it
becomes especially apparent towards the end. I guess this is somehow
related to Color Piercing or Piercing (or both).
- Easy Cleanup activates twice if the latest Respawn happens before all - Easy Cleanup activates twice if the latest Respawn happens before all
the coins have been caught or fallen off screen. As you can see, I had the coins have been caught or fallen off screen. As you can see, I had
Lv 1 on both the perks: the ball hit the second to last brick, the last Lv 1 on both the perks: the ball hit the second to last brick, the last

View file

@ -28,8 +28,6 @@ echo "\"$versionCode\"" > src/version.json
# remove all exif metadata from pictures, because i think fdroid doesn't like that. odd # remove all exif metadata from pictures, because i think fdroid doesn't like that. odd
find -name '*.jp*g' -o -name '*.png' | xargs exiftool -all= find -name '*.jp*g' -o -name '*.png' | xargs exiftool -all=
# expose the git log to the app itself
git log --pretty=format:' %s' > src/git-log.txt
npx prettier --write src/ npx prettier --write src/

78
dist/index.html vendored
View file

@ -1421,30 +1421,6 @@ function shouldPierceByColor(vhit, hhit, chit) {
if (typeof chit !== "undefined" && bricks[chit] !== ballsColor) return false; if (typeof chit !== "undefined" && bricks[chit] !== ballsColor) return false;
return true; return true;
} }
function ballBrickHitCheck(ball) {
const radius = ballSize / 2;
// Make ball/coin bonce, and return bricks that were hit
const { x, y, previousX, previousY } = ball;
const vhit = hitsSomething(previousX, y, radius);
const hhit = hitsSomething(x, previousY, radius);
const chit = typeof vhit == "undefined" && typeof hhit == "undefined" && hitsSomething(x, y, radius) || undefined;
let pierce = ball.piercedSinceBounce < perks.pierce * 3;
if (pierce && (typeof vhit !== "undefined" || typeof hhit !== "undefined" || typeof chit !== "undefined")) ball.piercedSinceBounce++;
if (shouldPierceByColor(vhit, hhit, chit)) pierce = true;
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.y = ball.previousY;
ball.vy *= -1;
}
}
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.x = ball.previousX;
ball.vx *= -1;
}
}
return vhit ?? hhit ?? chit;
}
function coinBrickHitCheck(coin) { function coinBrickHitCheck(coin) {
// Make ball/coin bonce, and return bricks that were hit // Make ball/coin bonce, and return bricks that were hit
const radius = coinSize / 2; const radius = coinSize / 2;
@ -1796,7 +1772,37 @@ function ballTick(ball, delta) {
runStatistics.balls_lost++; runStatistics.balls_lost++;
if (!balls.find((b)=>!b.destroyed)) gameOver("Game Over", "You dropped the ball after catching " + score + " coins. "); if (!balls.find((b)=>!b.destroyed)) gameOver("Game Over", "You dropped the ball after catching " + score + " coins. ");
} }
const hitBrick = ballBrickHitCheck(ball); const radius = ballSize / 2;
// Make ball/coin bonce, and return bricks that were hit
const { x, y, previousX, previousY } = ball;
const vhit = hitsSomething(previousX, y, radius);
const hhit = hitsSomething(x, previousY, radius);
const chit = typeof vhit == "undefined" && typeof hhit == "undefined" && hitsSomething(x, y, radius) || undefined;
const hitBrick = vhit ?? hhit ?? chit;
let sturdyBounce = hitBrick && bricks[hitBrick] !== 'black' && perks.sturdy_bricks && perks.sturdy_bricks > Math.random() * 5;
let pierce = false;
if (sturdyBounce || typeof hitBrick === "undefined") ;
else if (shouldPierceByColor(vhit, hhit, chit)) pierce = true;
else if (ball.piercedSinceBounce < perks.pierce * 3) {
pierce = true;
ball.piercedSinceBounce++;
}
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.y = ball.previousY;
ball.vy *= -1;
}
}
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.x = ball.previousX;
ball.vx *= -1;
}
}
if (sturdyBounce) {
(0, _sounds.sounds).wallBeep(x);
return;
}
if (typeof hitBrick !== "undefined") { if (typeof hitBrick !== "undefined") {
const initialBrickColor = bricks[hitBrick]; const initialBrickColor = bricks[hitBrick];
explodeBrick(hitBrick, ball, false); explodeBrick(hitBrick, ball, false);
@ -2014,7 +2020,11 @@ function explodeBrick(index, ball, isExplosion) {
// Break bricks around // Break bricks around
for(let dx = -size; dx <= size; dx++)for(let dy = -size; dy <= size; dy++){ for(let dx = -size; dx <= size; dx++)for(let dy = -size; dy <= size; dy++){
const i = getRowColIndex(row + dy, col + dx); const i = getRowColIndex(row + dy, col + dx);
if (bricks[i] && i !== -1) explodeBrick(i, ball, true); if (bricks[i] && i !== -1) {
// Study bricks resist explisions too
if (bricks[i] !== 'black' && perks.sturdy_bricks > Math.random() * 5) continue;
explodeBrick(i, ball, true);
}
} }
// Blow nearby coins // Blow nearby coins
coins.forEach((c)=>{ coins.forEach((c)=>{
@ -2040,11 +2050,6 @@ function explodeBrick(index, ball, isExplosion) {
} else if (color) { } else if (color) {
// Even if it bounces we don't want to count that as a miss // Even if it bounces we don't want to count that as a miss
ball.hitSinceBounce++; ball.hitSinceBounce++;
if (perks.sturdy_bricks && perks.sturdy_bricks > Math.random() * 5) {
// Resist
(0, _sounds.sounds).coinBounce(ball.x, 1);
return;
}
// Flashing is take care of by the tick loop // Flashing is take care of by the tick loop
const x = brickCenterX(index), y = brickCenterY(index); const x = brickCenterX(index), y = brickCenterY(index);
bricks[index] = ""; bricks[index] = "";
@ -2124,7 +2129,7 @@ function render() {
if (!isSettingOn("basic") && !level.color && level.svg) { if (!isSettingOn("basic") && !level.color && level.svg) {
// Without this the light trails everything // Without this the light trails everything
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 0.4; ctx.globalAlpha = 1;
ctx.fillStyle = "#000"; ctx.fillStyle = "#000";
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "screen"; ctx.globalCompositeOperation = "screen";
@ -2278,7 +2283,10 @@ function render() {
if (hasCombo && perks.left_is_lava) ctx.fillRect(0, 0, 1, height); if (hasCombo && perks.left_is_lava) ctx.fillRect(0, 0, 1, height);
if (hasCombo && perks.right_is_lava) ctx.fillRect(width - 1, 0, 1, height); if (hasCombo && perks.right_is_lava) ctx.fillRect(width - 1, 0, 1, height);
} }
if (perks.top_is_lava && combo > baseCombo()) drawRedSquare(ctx, offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1); if (perks.top_is_lava && combo > baseCombo()) {
ctx.fillStyle = "red";
ctx.fillRect(offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1);
}
const redBottom = perks.compound_interest && 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")) {
@ -2445,10 +2453,6 @@ function roundRect(ctx, x, y, width, height, radius) {
ctx.quadraticCurveTo(x, y, x + radius, y); ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath(); ctx.closePath();
} }
function drawRedSquare(ctx, x, y, width, height) {
ctx.fillStyle = "red";
ctx.fillRect(x, y, width, height);
}
function drawIMG(ctx, img, size, x, y) { function drawIMG(ctx, img, size, x, y) {
const key = "svg" + img + "_" + size + "_" + img.complete; const key = "svg" + img + "_" + size + "_" + img.complete;
if (!cachedGraphics[key]) { if (!cachedGraphics[key]) {

View file

@ -700,47 +700,6 @@ function shouldPierceByColor(
return true; return true;
} }
function ballBrickHitCheck(ball: Ball) {
const radius = ballSize / 2;
// Make ball/coin bonce, and return bricks that were hit
const {x, y, previousX, previousY} = ball;
const vhit = hitsSomething(previousX, y, radius);
const hhit = hitsSomething(x, previousY, radius);
const chit =
(typeof vhit == "undefined" &&
typeof hhit == "undefined" &&
hitsSomething(x, y, radius)) ||
undefined;
let pierce = ball.piercedSinceBounce < perks.pierce * 3;
if (
pierce &&
(typeof vhit !== "undefined" ||
typeof hhit !== "undefined" ||
typeof chit !== "undefined")
) {
ball.piercedSinceBounce++;
}
if (shouldPierceByColor(vhit, hhit, chit)) {
pierce = true;
}
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.y = ball.previousY;
ball.vy *= -1;
}
}
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.x = ball.previousX;
ball.vx *= -1;
}
}
return vhit ?? hhit ?? chit;
}
function coinBrickHitCheck(coin: Coin) { function coinBrickHitCheck(coin: Coin) {
// Make ball/coin bonce, and return bricks that were hit // Make ball/coin bonce, and return bricks that were hit
@ -1266,7 +1225,48 @@ function ballTick(ball: Ball, delta: number) {
); );
} }
} }
const hitBrick = ballBrickHitCheck(ball); const radius = ballSize / 2;
// Make ball/coin bonce, and return bricks that were hit
const {x, y, previousX, previousY} = ball;
const vhit = hitsSomething(previousX, y, radius);
const hhit = hitsSomething(x, previousY, radius);
const chit =
(typeof vhit == "undefined" &&
typeof hhit == "undefined" &&
hitsSomething(x, y, radius)) ||
undefined;
const hitBrick = vhit ?? hhit ?? chit;
let sturdyBounce=hitBrick && bricks[hitBrick]!=='black' && perks.sturdy_bricks && perks.sturdy_bricks > Math.random() * 5
let pierce = false;
if(sturdyBounce || typeof hitBrick === "undefined") {
// cannot pierce
}else if(shouldPierceByColor(vhit, hhit, chit)){
pierce = true;
}else if (ball.piercedSinceBounce < perks.pierce * 3 ){
pierce=true
ball.piercedSinceBounce++;
}
if (typeof vhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.y = ball.previousY;
ball.vy *= -1;
}
}
if (typeof hhit !== "undefined" || typeof chit !== "undefined") {
if (!pierce) {
ball.x = ball.previousX;
ball.vx *= -1;
}
}
if(sturdyBounce){
sounds.wallBeep(x)
return
}
if (typeof hitBrick !== "undefined") { if (typeof hitBrick !== "undefined") {
const initialBrickColor = bricks[hitBrick]; const initialBrickColor = bricks[hitBrick];
@ -1567,6 +1567,8 @@ function explodeBrick(index: number, ball: Ball, isExplosion: boolean) {
for (let dy = -size; dy <= size; dy++) { for (let dy = -size; dy <= size; dy++) {
const i = getRowColIndex(row + dy, col + dx); const i = getRowColIndex(row + dy, col + dx);
if (bricks[i] && i !== -1) { if (bricks[i] && i !== -1) {
// Study bricks resist explisions too
if(bricks[i]!=='black' && perks.sturdy_bricks > Math.random() * 5) continue
explodeBrick(i, ball, true); explodeBrick(i, ball, true);
} }
} }
@ -1605,11 +1607,6 @@ function explodeBrick(index: number, ball: Ball, isExplosion: boolean) {
// Even if it bounces we don't want to count that as a miss // Even if it bounces we don't want to count that as a miss
ball.hitSinceBounce++; ball.hitSinceBounce++;
if (perks.sturdy_bricks && perks.sturdy_bricks > Math.random() * 5) {
// Resist
sounds.coinBounce(ball.x, 1);
return;
}
// Flashing is take care of by the tick loop // Flashing is take care of by the tick loop
const x = brickCenterX(index), const x = brickCenterX(index),
y = brickCenterY(index); y = brickCenterY(index);
@ -1732,7 +1729,7 @@ function render() {
if (!isSettingOn("basic") && !level.color && level.svg) { if (!isSettingOn("basic") && !level.color && level.svg) {
// Without this the light trails everything // Without this the light trails everything
ctx.globalCompositeOperation = "source-over"; ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 0.4; ctx.globalAlpha = 1;
ctx.fillStyle = "#000"; ctx.fillStyle = "#000";
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
@ -1962,8 +1959,10 @@ function render() {
if (hasCombo && perks.right_is_lava) ctx.fillRect(width - 1, 0, 1, height); if (hasCombo && perks.right_is_lava) ctx.fillRect(width - 1, 0, 1, height);
} }
if (perks.top_is_lava && combo > baseCombo()) if (perks.top_is_lava && combo > baseCombo()){
drawRedSquare(ctx, offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1); ctx.fillStyle = "red";
ctx.fillRect(offsetXRoundedDown, 0, gameZoneWidthRoundedUp, 1);
}
const redBottom = perks.compound_interest && 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")) {
@ -2294,16 +2293,6 @@ function roundRect(
ctx.closePath(); ctx.closePath();
} }
function drawRedSquare(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
width: number,
height: number,
) {
ctx.fillStyle = "red";
ctx.fillRect(x, y, width, height);
}
function drawIMG( function drawIMG(
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,

View file

@ -1,124 +0,0 @@
Lives just save the ball once and show as a line.
Deduplicated backgrounds to make the game smaller
wip
Ignore build files
Build and deploy of version 29028296
Updated to use typescript strict typing
wip
Build and deploy of version 29022953
Adjustments to creative mode
Creative mode, cleanup loop fix
Farming points with respawn should be fixed, the sapper-generated bombs no longer count as a broken brick
Typed existing game.ts
Tried to use ts to catch bugs, it's pretty useless for now.
wip
Build and deploy of version 29020191
Build and deploy of version 29020186
Build and deploy of version 29020162
Build and deploy of version 29020161
Build and deploy of version 29020161
Build and deploy of version 29020156
Move to parcel
Ingnore parcel files
When trying a perk or level, actually play the run
Automatic deploy 29019801
Try to get the horizontally bouncing balls unstuck, and allow ball to go fast when tethered
Avoid caching angles of coins that look the same, more coin angles
wip
Automatic deploy 29019704
Better handling of large combo
Automatic deploy 29018692
Automatic deploy 29017278
Avoid fullscreen on ctrl+f
Automatic deploy 29017275
Added a palette for bricks color
wip
wip
Automatic deploy 29017191
Automatic deploy 29015398
Added random patterns as background of levels instead of repeating their name
Automatic deploy 29015054
Fix : bg color of dollar level, puck width and coins centering
Automatic deploy 29014379
Automatic deploy 29014360
Removed gif recording, increased webm recording resolution
Feedback
Automatic deploy 29014300
Removed console.log that were triggering GC, and made all balls the same color to avoid another memory leak and simplify code
Automatic deploy 29014045
Typos
Automatic deploy 29013936
Explanation for perks in help, coins speed limit to avoid clipping, adapted coin spawn rate
Automatic deploy 29011564
Track total play time and added meta description
Automatic deploy 29011519
Automatic deploy 29011397
Typo
Automatic deploy 29011331
Pause abuse delay, f for fullscreen toggle, keyboard support
Automatic deploy 29010156
Automatic deploy 29010123
Automatic deploy 29010003
Automatic deploy 29009984
Automatic deploy 29009918
Automatic deploy 29008583
Automatic deploy 29008176
Automatic deploy 29007858
wip
Automatic deploy 29007301
Automatic deploy 29007124
Automatic deploy 29005750
Automatic deploy 29005697
Added statistics (the last ones weren't actually recording anything)
Automatic deploy 29002316
Automatic deploy 29002312
Automatic deploy 29002304
Automatic deploy 29002302
Automatic deploy 29002301
Automatic deploy 29002295
wip
Automatic deploy 29000827
Automatic deploy 29000798
Automatic deploy 29000794
Automatic deploy 28999986
Wind perk
wip
Automatic deploy 28999931
wip
Automatic deploy 28999417
wip
wip
Automatic deploy 28998184
Adjusted neon effect, more screenshake after bigger_explosion perk is chosen
Automatic deploy 28996852
Automatic deploy 28996655
Automatic deploy 28996651
wip
Automatic deploy 28996415
Fixed small issues
wip
wip
wip
wip
wip
Automatic deploy 28994348
wip
wip
wip
Added some fastlane screenshots in repo for fdroid
Automatic deploy 28994244
Automatic deploy 28994243
wip
Automatic deploy 28994240
wip
Automatic deploy 28994204
wip
wip
Automatic deploy 28994174
wip
Automatic deploy 28994149
Automatic deploy 28994147
wip
wip
Added GPL3 license
Initial commit