diff --git a/js/entities/entity.js b/js/entities/entity.js index d81cfbb..2a86ac4 100644 --- a/js/entities/entity.js +++ b/js/entities/entity.js @@ -149,6 +149,20 @@ class Entity { isPixelSolid(x, y) { // Use ceiling for y coordinate to better detect ground below const pixel = getPixel(Math.floor(x), Math.ceil(y)); + + // For player entity, don't collide with trees (WOOD and LEAF) + if (this.type === ENTITY_TYPES.PLAYER) { + return pixel !== EMPTY && + pixel !== WATER && + pixel !== FIRE && + pixel !== SQUARE && + pixel !== CIRCLE && + pixel !== TRIANGLE && + pixel !== WOOD && + pixel !== LEAF; + } + + // For other entities, use the original collision detection return pixel !== EMPTY && pixel !== WATER && pixel !== FIRE && diff --git a/js/entities/player.js b/js/entities/player.js index 2e1c62c..181bac4 100644 --- a/js/entities/player.js +++ b/js/entities/player.js @@ -23,6 +23,7 @@ class Player extends Entity { this.direction = 1; // 1 = right, -1 = left this.lastUpdate = performance.now(); this.lastDirection = 1; // Track last direction to prevent unnecessary flipping + this.isClimbing = false; // Track climbing state // Animation properties this.frameWidth = 32; @@ -62,8 +63,15 @@ class Player extends Entity { if (collisionResult.collision) { if (collisionResult.horizontal) { - newX = this.x; - this.vx = 0; + // Try to climb up if there's a 1-pixel step + if (this.tryClimbing(newX, newY)) { + // Successfully climbed, continue with adjusted position + newY -= 1; // Move up one pixel to climb + } else { + // Can't climb, stop horizontal movement + newX = this.x; + this.vx = 0; + } } if (collisionResult.vertical) { @@ -89,24 +97,9 @@ class Player extends Entity { } updateAnimation(deltaTime) { - // Update animation timer consistently this.animationTimer += deltaTime; - /* - // Only change animation frame at fixed intervals to prevent blinking - if (this.animationTimer >= this.animationSpeed) { - // Only update animation if actually moving horizontally - if (Math.abs(this.vx) > 0.005 && this.isMoving) { - this.currentFrame = (this.currentFrame + 1) % this.frameCount; - } else if (!this.isMoving || Math.abs(this.vx) < 0.005) { - // Reset to standing frame when not moving - this.currentFrame = 0; - } - - // Reset timer but keep remainder to maintain smooth timing - this.animationTimer %= this.animationSpeed; - } - */ + // Only update direction when it actually changes to prevent flipping if (Math.abs(this.vx) > 0.005) { const newDirection = this.vx > 0 ? 1 : -1; @@ -115,6 +108,24 @@ class Player extends Entity { this.lastDirection = newDirection; } } + + // Update animation frame based on climbing state + if (this.isClimbing) { + // Use a specific frame for climbing + this.currentFrame = 1; // Use frame 1 for climbing animation + } else if (this.isJumping) { + // Use a specific frame for jumping + this.currentFrame = 2; // Use frame 2 for jumping animation + } else if (Math.abs(this.vx) > 0.01 && this.isMoving) { + // Animate walking + if (this.animationTimer >= this.animationSpeed) { + this.currentFrame = (this.currentFrame + 1) % this.frameCount; + this.animationTimer %= this.animationSpeed; + } + } else { + // Standing still + this.currentFrame = 0; + } } render(ctx, offsetX, offsetY) { @@ -215,6 +226,32 @@ class Player extends Entity { } } + // Try to climb up a small step + tryClimbing(newX, newY) { + const halfWidth = this.width / 2; + + // Check if there's a solid pixel in front of the player + const frontX = newX + (this.direction * halfWidth); + const frontY = newY; + + // Check if there's a solid pixel at the current level + if (this.isPixelSolid(frontX, frontY)) { + // Check if there's empty space one pixel above + if (!this.isPixelSolid(frontX, frontY - 1) && + !this.isPixelSolid(this.x, this.y - 1)) { + + // Check if there's ground to stand on after climbing + if (this.isPixelSolid(frontX, frontY + 1)) { + this.isClimbing = true; + return true; + } + } + } + + this.isClimbing = false; + return false; + } + centerCamera() { // Get current camera center in world coordinates const cameraWidth = canvas.width / PIXEL_SIZE;