@@ -8,19 +8,47 @@ class WebStrand { |
| 8 | this.vibration = 0; | 8 | this.vibration = 0; |
| 9 | this.path = []; | 9 | this.path = []; |
| 10 | this.segments = []; // For physics simulation | 10 | this.segments = []; // For physics simulation |
| 11 | - this.maxLength = 200; // Maximum strand length before it breaks | 11 | + this.maxLength = 260; // Maximum strand length before it breaks (increased by 30%) |
| 12 | this.tension = 0; | 12 | this.tension = 0; |
| 13 | this.broken = false; | 13 | this.broken = false; |
| | 14 | + this.recoil = 0; // Recoil amplitude for spring physics |
| | 15 | + this.recoilVelocity = 0; // Velocity of recoil oscillation |
| | 16 | + this.damping = 0.75; // Damping factor for recoil (much faster damping to prevent accumulation) |
| | 17 | + this.springConstant = 0.04; // Spring stiffness (much softer spring) |
| | 18 | + this.flexibility = 1.0; // How much the web can be dragged by flies |
| 14 | } | 19 | } |
| 15 | | 20 | |
| 16 | update() { | 21 | update() { |
| 17 | this.vibration *= 0.95; | 22 | this.vibration *= 0.95; |
| 18 | | 23 | |
| | 24 | + // Update recoil physics (spring oscillation) |
| | 25 | + if (abs(this.recoil) > 0.01 || abs(this.recoilVelocity) > 0.01) { |
| | 26 | + // Apply spring force (Hooke's law) |
| | 27 | + let springForce = -this.springConstant * this.recoil; |
| | 28 | + this.recoilVelocity += springForce; |
| | 29 | + |
| | 30 | + // Apply damping |
| | 31 | + this.recoilVelocity *= this.damping; |
| | 32 | + |
| | 33 | + // Update recoil position |
| | 34 | + this.recoil += this.recoilVelocity; |
| | 35 | + |
| | 36 | + // Clamp small values to stop oscillation |
| | 37 | + if (abs(this.recoil) < 0.01 && abs(this.recoilVelocity) < 0.01) { |
| | 38 | + this.recoil = 0; |
| | 39 | + this.recoilVelocity = 0; |
| | 40 | + } |
| | 41 | + } |
| | 42 | + |
| 19 | // Calculate strand length and tension | 43 | // Calculate strand length and tension |
| 20 | if (this.end) { | 44 | if (this.end) { |
| 21 | let length = dist(this.start.x, this.start.y, this.end.x, this.end.y); | 45 | let length = dist(this.start.x, this.start.y, this.end.x, this.end.y); |
| 22 | this.tension = length / this.maxLength; | 46 | this.tension = length / this.maxLength; |
| 23 | | 47 | |
| | 48 | + // Calculate flexibility factor (longer, less taut webs are more flexible) |
| | 49 | + this.flexibility = map(this.tension, 0.2, 1.0, 1.5, 0.3); // More flexible when less taut |
| | 50 | + this.flexibility = constrain(this.flexibility, 0.3, 1.5); |
| | 51 | + |
| 24 | // Break if overstretched or unsupported arc | 52 | // Break if overstretched or unsupported arc |
| 25 | if (this.tension > 1.5 || this.checkUnsupportedArc()) { | 53 | if (this.tension > 1.5 || this.checkUnsupportedArc()) { |
| 26 | this.broken = true; | 54 | this.broken = true; |
@@ -50,6 +78,9 @@ class WebStrand { |
| 50 | point.y += 0.22; | 78 | point.y += 0.22; |
| 51 | point.x += windX * (0.6 + i / this.path.length * 0.8); | 79 | point.x += windX * (0.6 + i / this.path.length * 0.8); |
| 52 | point.y += windY * 0.4; | 80 | point.y += windY * 0.4; |
| | 81 | + |
| | 82 | + // Apply recoil to path points (very subtle) |
| | 83 | + point.y += this.recoil * (1 + sin(i * 0.3) * 0.5); |
| 53 | } | 84 | } |
| 54 | } | 85 | } |
| 55 | | 86 | |
@@ -157,6 +188,9 @@ class WebStrand { |
| 157 | let sag = horizontalDist * 0.12; | 188 | let sag = horizontalDist * 0.12; |
| 158 | midY += sag * (1 - cos(PI * 0.5)); | 189 | midY += sag * (1 - cos(PI * 0.5)); |
| 159 | | 190 | |
| | 191 | + // Apply recoil deformation to the web (very subtle) |
| | 192 | + midY += this.recoil * 2; // Further reduced from 3 |
| | 193 | + |
| 160 | beginShape(); | 194 | beginShape(); |
| 161 | curveVertex(this.start.x, this.start.y); | 195 | curveVertex(this.start.x, this.start.y); |
| 162 | curveVertex(this.start.x, this.start.y); | 196 | curveVertex(this.start.x, this.start.y); |
@@ -182,6 +216,26 @@ class WebStrand { |
| 182 | vibrate(amount) { | 216 | vibrate(amount) { |
| 183 | this.vibration = min(this.vibration + amount, 10); | 217 | this.vibration = min(this.vibration + amount, 10); |
| 184 | } | 218 | } |
| | 219 | + |
| | 220 | + // Apply recoil force when spider interacts with the web |
| | 221 | + applyRecoil(force) { |
| | 222 | + // Newton's third law - the web recoils opposite to the applied force |
| | 223 | + this.recoilVelocity += force; |
| | 224 | + |
| | 225 | + // Also trigger vibration for visual feedback (scaled down) |
| | 226 | + this.vibrate(abs(force) * 1); |
| | 227 | + |
| | 228 | + // Add some energy dissipation through the web network (more subtle) |
| | 229 | + for (let node of webNodes) { |
| | 230 | + let d1 = dist(node.x, node.y, this.start.x, this.start.y); |
| | 231 | + let d2 = dist(node.x, node.y, this.end.x, this.end.y); |
| | 232 | + let minDist = min(d1, d2); |
| | 233 | + if (minDist < 100) { |
| | 234 | + let forceFalloff = map(minDist, 0, 100, 0.3, 0); |
| | 235 | + node.applyForce(0, force * forceFalloff * 0.15); |
| | 236 | + } |
| | 237 | + } |
| | 238 | + } |
| 185 | } | 239 | } |
| 186 | | 240 | |
| 187 | | 241 | |