@@ -365,7 +365,11 @@ class Fly { |
| 365 | } | 365 | } |
| 366 | | 366 | |
| 367 | update () { | 367 | update () { |
| 368 | - if (this.stuck) return | 368 | + if (this.stuck) { |
| | 369 | + // If stuck, check if we need to move with a drifting web |
| | 370 | + this.updatePositionOnWeb() |
| | 371 | + return |
| | 372 | + } |
| 369 | | 373 | |
| 370 | if (this.caught) { | 374 | if (this.caught) { |
| 371 | this.vel.mult(0.95) | 375 | this.vel.mult(0.95) |
@@ -374,6 +378,8 @@ class Fly { |
| 374 | fliesCaught++ | 378 | fliesCaught++ |
| 375 | webSilk = min(webSilk + 5, maxWebSilk) | 379 | webSilk = min(webSilk + 5, maxWebSilk) |
| 376 | } | 380 | } |
| | 381 | + // While caught but not yet stuck, also follow the web |
| | 382 | + this.updatePositionOnWeb() |
| 377 | return | 383 | return |
| 378 | } | 384 | } |
| 379 | | 385 | |
@@ -396,6 +402,54 @@ class Fly { |
| 396 | // Check web collisions | 402 | // Check web collisions |
| 397 | this.checkWebCollisions() | 403 | this.checkWebCollisions() |
| 398 | } | 404 | } |
| | 405 | + |
| | 406 | + updatePositionOnWeb() { |
| | 407 | + // Find the web strand(s) this fly is attached to |
| | 408 | + for (let strand of webStrands) { |
| | 409 | + if (strand.broken) continue |
| | 410 | + |
| | 411 | + // Check if fly is on this strand |
| | 412 | + let closestPoint = null |
| | 413 | + let closestDistance = Infinity |
| | 414 | + |
| | 415 | + if (strand.path && strand.path.length > 1) { |
| | 416 | + for (let i = 0; i < strand.path.length - 1; i++) { |
| | 417 | + let p1 = strand.path[i] |
| | 418 | + let p2 = strand.path[i + 1] |
| | 419 | + |
| | 420 | + // Find closest point on this segment |
| | 421 | + let line = p5.Vector.sub(p2, p1) |
| | 422 | + let lineLength = line.mag() |
| | 423 | + if (lineLength === 0) continue |
| | 424 | + line.normalize() |
| | 425 | + |
| | 426 | + let pointToStart = p5.Vector.sub(this.pos, p1) |
| | 427 | + let projLength = constrain(pointToStart.dot(line), 0, lineLength) |
| | 428 | + |
| | 429 | + let projPoint = p5.Vector.add(p1, p5.Vector.mult(line, projLength)) |
| | 430 | + let d = p5.Vector.dist(this.pos, projPoint) |
| | 431 | + |
| | 432 | + if (d < closestDistance && d < this.radius + 5) { |
| | 433 | + closestDistance = d |
| | 434 | + closestPoint = projPoint |
| | 435 | + } |
| | 436 | + } |
| | 437 | + } |
| | 438 | + |
| | 439 | + // If we found a close point on this strand, stick to it |
| | 440 | + if (closestPoint) { |
| | 441 | + // Move fly to follow the strand's movement |
| | 442 | + this.pos.x = closestPoint.x |
| | 443 | + this.pos.y = closestPoint.y |
| | 444 | + |
| | 445 | + // Add small vibration when on a moving web |
| | 446 | + if (strand.vibration > 0) { |
| | 447 | + this.pos.x += random(-1, 1) * strand.vibration * 0.1 |
| | 448 | + this.pos.y += random(-1, 1) * strand.vibration * 0.1 |
| | 449 | + } |
| | 450 | + } |
| | 451 | + } |
| | 452 | + } |
| 399 | | 453 | |
| 400 | checkWebCollisions () { | 454 | checkWebCollisions () { |
| 401 | let currentlyTouching = new Set() | 455 | let currentlyTouching = new Set() |
@@ -726,6 +780,45 @@ class Obstacle { |
| 726 | // Mark strand as broken | 780 | // Mark strand as broken |
| 727 | strand.broken = true | 781 | strand.broken = true |
| 728 | | 782 | |
| | 783 | + // Release any flies stuck to this strand |
| | 784 | + for (let fly of flies) { |
| | 785 | + if (fly.stuck || fly.caught) { |
| | 786 | + // Check if fly is touching this breaking strand |
| | 787 | + let touchingStrand = false |
| | 788 | + if (strand.path && strand.path.length > 1) { |
| | 789 | + for (let i = 0; i < strand.path.length - 1; i++) { |
| | 790 | + let p1 = strand.path[i] |
| | 791 | + let p2 = strand.path[i + 1] |
| | 792 | + let d = fly.pointToLineDistance(fly.pos, p1, p2) |
| | 793 | + if (d < fly.radius + 5) { |
| | 794 | + touchingStrand = true |
| | 795 | + break |
| | 796 | + } |
| | 797 | + } |
| | 798 | + } |
| | 799 | + |
| | 800 | + // If fly was on this strand, release it |
| | 801 | + if (touchingStrand) { |
| | 802 | + fly.stuck = false |
| | 803 | + fly.caught = false |
| | 804 | + fly.currentSpeed = fly.baseSpeed |
| | 805 | + fly.touchedStrands.clear() |
| | 806 | + fly.slowedBy.clear() |
| | 807 | + // Give it a little downward velocity to start falling |
| | 808 | + fly.vel = createVector(random(-0.5, 0.5), 2) |
| | 809 | + |
| | 810 | + // Create release particles |
| | 811 | + for (let j = 0; j < 3; j++) { |
| | 812 | + let p = new Particle(fly.pos.x, fly.pos.y) |
| | 813 | + p.color = color(255, 255, 100, 150) |
| | 814 | + p.vel = createVector(random(-1, 1), random(0, 2)) |
| | 815 | + p.size = 2 |
| | 816 | + particles.push(p) |
| | 817 | + } |
| | 818 | + } |
| | 819 | + } |
| | 820 | + } |
| | 821 | + |
| 729 | // Create dramatic snap particles | 822 | // Create dramatic snap particles |
| 730 | let snapX = attachedToStart ? strand.start.x : strand.end.x | 823 | let snapX = attachedToStart ? strand.start.x : strand.end.x |
| 731 | let snapY = attachedToStart ? strand.start.y : strand.end.y | 824 | let snapY = attachedToStart ? strand.start.y : strand.end.y |