@@ -242,76 +242,64 @@ class Spider { |
| 242 | | 242 | |
| 243 | // Check home branch collision (one-way platform) | 243 | // Check home branch collision (one-way platform) |
| 244 | if (window.homeBranch && this.isAirborne && this.vel.y > 0.1) { | 244 | if (window.homeBranch && this.isAirborne && this.vel.y > 0.1) { |
| 245 | - // Only when actually falling | | |
| 246 | let branch = window.homeBranch | 245 | let branch = window.homeBranch |
| 247 | | 246 | |
| 248 | - // Check if spider is within branch X range | 247 | + // Calculate the actual geometric bounds |
| 249 | - let branchStart = Math.min(branch.startX, branch.endX) | 248 | + let leftX = Math.min(branch.startX, branch.endX) |
| 250 | - let branchEnd = Math.max(branch.startX, branch.endX) | 249 | + let rightX = Math.max(branch.startX, branch.endX) |
| 251 | | 250 | |
| 252 | - // FIX: Extend collision detection beyond visual tip | 251 | + // IMPORTANT: Extend the check zone beyond the mathematical end |
| 253 | - // The visual branch ends at branchEnd, but we need collision slightly beyond | 252 | + // The branch visually extends past endX due to strokeWeight and bezier curves |
| 254 | - let collisionPadding = 15 // Extra collision at the tip | 253 | + let checkPadding = 20 // Add padding for the visual overhang |
| 255 | | 254 | |
| 256 | if ( | 255 | if ( |
| 257 | - this.pos.x >= branchStart - 10 && | 256 | + this.pos.x >= leftX - checkPadding && |
| 258 | - this.pos.x <= branchEnd + collisionPadding | 257 | + this.pos.x <= rightX + checkPadding |
| 259 | ) { | 258 | ) { |
| 260 | - // Calculate position along branch (0 to 1) | 259 | + // Calculate normalized position along branch |
| 261 | - // FIX: Clamp t to ensure we handle tip properly | 260 | + let t |
| 262 | - let t = (this.pos.x - branchStart) / (branchEnd - branchStart) | | |
| 263 | | 261 | |
| 264 | - // Allow t to go slightly beyond 1.0 for tip collision | 262 | + if (branch.side === 'left') { |
| 265 | - if (this.pos.x > branchEnd) { | 263 | + // Left branch: startX is base, endX is tip |
| 266 | - t = 1.0 // At the tip, use tip thickness | 264 | + t = (this.pos.x - branch.startX) / (branch.endX - branch.startX) |
| 267 | } else { | 265 | } else { |
| 268 | - t = constrain(t, 0, 1) | 266 | + // Right branch: startX is base, endX is tip (but startX > endX) |
| | 267 | + t = (branch.startX - this.pos.x) / (branch.startX - branch.endX) |
| 269 | } | 268 | } |
| 270 | | 269 | |
| 271 | - // Branch visual thickness tapers from full at start to 35% at end | 270 | + // CRITICAL FIX: Allow t to exceed 1 for the tip overhang |
| 272 | - let branchTopThickness | 271 | + // The visual branch extends past the mathematical endpoint |
| 273 | - if (t >= 1.0) { | 272 | + let maxT = 1.15 // Allow 15% overshoot for visual overhang |
| 274 | - // At the very tip, maintain minimum collision thickness | 273 | + t = constrain(t, 0, maxT) |
| 275 | - branchTopThickness = branch.thickness * 0.35 | | |
| 276 | - } else { | | |
| 277 | - branchTopThickness = lerp( | | |
| 278 | - branch.thickness * 0.9, | | |
| 279 | - branch.thickness * 0.35, | | |
| 280 | - t | | |
| 281 | - ) | | |
| 282 | - } | | |
| 283 | | 274 | |
| 284 | - // The branch is drawn centered at branch.y | 275 | + // Calculate thickness |
| 285 | - let branchSurfaceY = branch.y - branchTopThickness | 276 | + let visualThickness |
| 286 | - | 277 | + if (t > 1.0) { |
| 287 | - // FIX: Correct angle calculation based on branch side | 278 | + // Past the mathematical end - use minimum tip thickness |
| 288 | - let angleCorrection | 279 | + visualThickness = branch.thickness * 0.35 |
| 289 | - if (branch.side === 'right') { | | |
| 290 | - // Right branch slopes down to the left (negative angle) | | |
| 291 | - // Use distance from the end point (which is on the left for right branches) | | |
| 292 | - angleCorrection = -(this.pos.x - branchEnd) * abs(branch.angle) | | |
| 293 | } else { | 280 | } else { |
| 294 | - // Left branch slopes down to the right (positive angle) | 281 | + // Normal taper |
| 295 | - // Use distance from the start point | 282 | + visualThickness = lerp(branch.thickness, branch.thickness * 0.35, t) |
| 296 | - angleCorrection = (this.pos.x - branchStart) * abs(branch.angle) | | |
| 297 | } | 283 | } |
| 298 | - branchSurfaceY += angleCorrection | | |
| 299 | | 284 | |
| 300 | - // Check if spider is crossing the branch from above | 285 | + // The branch is drawn centered at branch.y; compute top/bottom with rotation |
| 301 | - let prevY = this.pos.y - this.vel.y | 286 | + let rotationOffset = this.pos.x * branch.angle |
| | 287 | + let branchTopY = (branch.y - visualThickness) + rotationOffset |
| | 288 | + let branchBottomY = (branch.y + visualThickness) + rotationOffset |
| 302 | | 289 | |
| 303 | - // FIX: More generous collision detection at the tip | 290 | + // Check collision |
| 304 | - let collisionBuffer = t >= 0.9 ? 5 : 0 // Extra buffer near tip | 291 | + let prevY = this.pos.y - this.vel.y |
| 305 | | 292 | |
| | 293 | + // One-way platform collision |
| 306 | if ( | 294 | if ( |
| 307 | - prevY <= branchSurfaceY + collisionBuffer && // Was above (with buffer) | 295 | + prevY <= branchTopY && // Was above |
| 308 | - this.pos.y + this.radius >= branchSurfaceY && // Now at or below | 296 | + this.pos.y + this.radius >= branchTopY && // Now at or below |
| 309 | - this.pos.y < branch.y + branch.thickness | 297 | + this.pos.y - this.radius < branchBottomY // Not completely below the rotated bottom |
| 310 | ) { | 298 | ) { |
| 311 | - // Not too far below | 299 | + // Not completely below |
| 312 | | 300 | |
| 313 | - // Place spider on the branch surface | 301 | + // Land on branch |
| 314 | - this.pos.y = branchSurfaceY - this.radius | 302 | + this.pos.y = branchTopY - this.radius |
| 315 | this.land() | 303 | this.land() |
| 316 | this.attachedObstacle = null | 304 | this.attachedObstacle = null |
| 317 | } | 305 | } |
@@ -2199,7 +2187,7 @@ class Bird { |
| 2199 | | 2187 | |
| 2200 | // If spider has no stamina, GAME OVER! | 2188 | // If spider has no stamina, GAME OVER! |
| 2201 | if (jumpStamina <= 0) { | 2189 | if (jumpStamina <= 0) { |
| 2202 | - triggerGameOver('Exhausted spider caught by bird!') | 2190 | + triggerGameOver('Oof') |
| 2203 | return | 2191 | return |
| 2204 | } | 2192 | } |
| 2205 | | 2193 | |