@@ -365,7 +365,11 @@ class Fly { |
| 365 | 365 | } |
| 366 | 366 | |
| 367 | 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 | 374 | if (this.caught) { |
| 371 | 375 | this.vel.mult(0.95) |
@@ -374,6 +378,8 @@ class Fly { |
| 374 | 378 | fliesCaught++ |
| 375 | 379 | webSilk = min(webSilk + 5, maxWebSilk) |
| 376 | 380 | } |
| 381 | + // While caught but not yet stuck, also follow the web |
| 382 | + this.updatePositionOnWeb() |
| 377 | 383 | return |
| 378 | 384 | } |
| 379 | 385 | |
@@ -396,6 +402,54 @@ class Fly { |
| 396 | 402 | // Check web collisions |
| 397 | 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 | 454 | checkWebCollisions () { |
| 401 | 455 | let currentlyTouching = new Set() |
@@ -726,6 +780,45 @@ class Obstacle { |
| 726 | 780 | // Mark strand as broken |
| 727 | 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 | 822 | // Create dramatic snap particles |
| 730 | 823 | let snapX = attachedToStart ? strand.start.x : strand.end.x |
| 731 | 824 | let snapY = attachedToStart ? strand.start.y : strand.end.y |