diff --git a/game.js b/game.js index 4ce6302..63168c4 100644 --- a/game.js +++ b/game.js @@ -57,7 +57,8 @@ const GAME_CONFIG = { CHARGE_JUMP_MIN_VELOCITY: -400, // Minimum jump velocity CHARGE_JUMP_MAX_VELOCITY: -700, // Maximum jump velocity when fully charged CHARGE_JUMP_HORIZONTAL_VELOCITY: 150, // Horizontal velocity boost when fully charged - CHARGE_JUMP_SQUASH_HEIGHT: 0.1 // Squash to 10% of original height + CHARGE_JUMP_SQUASH_HEIGHT: 0.1, // Squash to 10% of original height + COLLISION_AXIS_BIAS: 0.5 // Pixel bias for vertical resolution on near-tie overlaps }; class CommitRunnerScene extends Phaser.Scene { @@ -679,6 +680,9 @@ class CommitRunnerScene extends Phaser.Scene { // Update charge bar display this.updateChargeBar(); + // Scroll the world to the left before collision checks + this.scrollWorld(deltaSeconds); + // Check if player is on the ground FIRST (before handling jumps) this.checkGrounded(); @@ -691,9 +695,6 @@ class CommitRunnerScene extends Phaser.Scene { // Recharge jump when grounded this.handleJumpCharge(deltaSeconds); - // Scroll the world to the left - this.scrollWorld(deltaSeconds); - // Update score based on distance survived this.score += deltaSeconds * 10; // 10 points per second this.scoreText.setText(`Score: ${Math.floor(this.score)}`); @@ -987,6 +988,8 @@ class CommitRunnerScene extends Phaser.Scene { let standingOnObstacle = false; let highestObstacleY = screenHeight; + const overlapBias = GAME_CONFIG.COLLISION_AXIS_BIAS; + // Check ONLY green obstacles for (let i = 0; i < this.greenObstacles.length; i++) { const obstacle = this.greenObstacles[i]; @@ -1011,24 +1014,28 @@ class CommitRunnerScene extends Phaser.Scene { const overlapTop = playerBottom - obstacleTop; const overlapBottom = obstacleBottom - playerTop; - const minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom); + const minHorizontalOverlap = Math.min(overlapLeft, overlapRight); + const minVerticalOverlap = Math.min(overlapTop, overlapBottom); + const shouldResolveVertically = minVerticalOverlap <= (minHorizontalOverlap + overlapBias); - // Push out in direction of smallest overlap - if (minOverlap === overlapTop && this.player.body.velocity.y >= 0) { - // Landing on top - if (obstacleTop < highestObstacleY) { - highestObstacleY = obstacleTop; - standingOnObstacle = true; + // Push out with stable axis selection (prefer vertical when nearly equal) + if (shouldResolveVertically) { + if (overlapTop <= overlapBottom && this.player.body.velocity.y >= 0) { + // Landing on top + if (obstacleTop < highestObstacleY) { + highestObstacleY = obstacleTop; + standingOnObstacle = true; + } + } else if (this.player.body.velocity.y <= 0) { + // Hit bottom (jumping into ceiling) + this.player.y = obstacleBottom + (GRID.TILE_SIZE / 2); + this.player.setVelocityY(0); } - } else if (minOverlap === overlapBottom && this.player.body.velocity.y <= 0) { - // Hit bottom (jumping into ceiling) - this.player.y = obstacleBottom + (GRID.TILE_SIZE / 2); - this.player.setVelocityY(0); - } else if (minOverlap === overlapLeft) { + } else if (overlapLeft <= overlapRight) { // Hit from left side this.player.x = obstacleLeft - (GRID.TILE_SIZE / 2); this.player.setVelocityX(0); - } else if (minOverlap === overlapRight) { + } else { // Hit from right side this.player.x = obstacleRight + (GRID.TILE_SIZE / 2); this.player.setVelocityX(0);