better handling web drift
- SHA
3a2c3d0ed38136c68e45c79b65aa84d422a9c9f0- Parents
-
5fa41f1 - Tree
71a4e73
3a2c3d0
3a2c3d0ed38136c68e45c79b65aa84d422a9c9f05fa41f1
71a4e73| Status | File | + | - |
|---|---|---|---|
| M |
js/entities.js
|
70 | 20 |
| M |
js/game.js
|
61 | 32 |
js/entities.jsmodified@@ -14,6 +14,7 @@ class Spider { | ||
| 14 | 14 | this.maxSpeed = 15 |
| 15 | 15 | this.munchRadius = 20 |
| 16 | 16 | this.munchCooldown = 0 |
| 17 | + this.attachedObstacle = null // Track which obstacle spider is on | |
| 17 | 18 | } |
| 18 | 19 | |
| 19 | 20 | jump(targetX, targetY) { |
@@ -101,8 +102,18 @@ class Spider { | ||
| 101 | 102 | } |
| 102 | 103 | |
| 103 | 104 | update () { |
| 105 | + // If attached to a moving obstacle, move with it | |
| 106 | + if (this.attachedObstacle && !this.isAirborne) { | |
| 107 | + // Calculate angle from obstacle center to spider | |
| 108 | + let angle = atan2(this.pos.y - this.attachedObstacle.y, this.pos.x - this.attachedObstacle.x) | |
| 109 | + // Keep spider on the surface of the obstacle | |
| 110 | + this.pos.x = this.attachedObstacle.x + cos(angle) * (this.attachedObstacle.radius + this.radius) | |
| 111 | + this.pos.y = this.attachedObstacle.y + sin(angle) * (this.attachedObstacle.radius + this.radius) | |
| 112 | + } | |
| 113 | + | |
| 104 | 114 | if (this.isAirborne) { |
| 105 | 115 | this.acc.add(this.gravity) |
| 116 | + this.attachedObstacle = null // Clear attachment when jumping | |
| 106 | 117 | } |
| 107 | 118 | |
| 108 | 119 | this.vel.add(this.acc) |
@@ -121,6 +132,7 @@ class Spider { | ||
| 121 | 132 | if (this.pos.y >= height - this.radius) { |
| 122 | 133 | this.pos.y = height - this.radius |
| 123 | 134 | this.land() |
| 135 | + this.attachedObstacle = null | |
| 124 | 136 | } |
| 125 | 137 | |
| 126 | 138 | // Check wall collisions |
@@ -180,6 +192,7 @@ class Spider { | ||
| 180 | 192 | // Place spider on the branch surface |
| 181 | 193 | this.pos.y = branchSurfaceY - this.radius |
| 182 | 194 | this.land() |
| 195 | + this.attachedObstacle = null | |
| 183 | 196 | } |
| 184 | 197 | } |
| 185 | 198 | } |
@@ -242,6 +255,7 @@ class Spider { | ||
| 242 | 255 | let angle = atan2(this.pos.y - obstacle.y, this.pos.x - obstacle.x) |
| 243 | 256 | this.pos.x = obstacle.x + cos(angle) * (obstacle.radius + this.radius) |
| 244 | 257 | this.pos.y = obstacle.y + sin(angle) * (obstacle.radius + this.radius) |
| 258 | + this.attachedObstacle = obstacle // Track which obstacle we're on | |
| 245 | 259 | this.land() |
| 246 | 260 | } |
| 247 | 261 | |
@@ -258,6 +272,7 @@ class Spider { | ||
| 258 | 272 | p5.Vector.mult(line, projLength) |
| 259 | 273 | ) |
| 260 | 274 | this.pos = closestPoint |
| 275 | + this.attachedObstacle = null // Not on an obstacle | |
| 261 | 276 | this.land() |
| 262 | 277 | } |
| 263 | 278 | |
@@ -822,7 +837,7 @@ class Obstacle { | ||
| 822 | 837 | pop() |
| 823 | 838 | |
| 824 | 839 | } else if (this.type === 'beetle') { |
| 825 | - // Big beetle! | |
| 840 | + // Big floating beetle! | |
| 826 | 841 | push() |
| 827 | 842 | rotate(this.rotation) |
| 828 | 843 | |
@@ -831,18 +846,49 @@ class Obstacle { | ||
| 831 | 846 | fill(0, 0, 0, 40) |
| 832 | 847 | ellipse(3, 3, this.radius * 1.8, this.radius * 2.2) |
| 833 | 848 | |
| 834 | - // Wings (if flying at night) | |
| 849 | + // Wings - always visible and flapping since they're floating | |
| 850 | + push() | |
| 851 | + // Wing flap animation | |
| 852 | + let wingAngle = sin(this.wingPhase) * 0.3 | |
| 853 | + let wingSpread = 15 + sin(this.wingPhase) * 10 | |
| 854 | + | |
| 855 | + // Left wing | |
| 856 | + push() | |
| 857 | + translate(-this.radius * 0.4, 0) | |
| 858 | + rotate(-wingAngle) | |
| 859 | + fill(255, 255, 255, 120) | |
| 860 | + stroke(0, 0, 0, 100) | |
| 861 | + strokeWeight(0.5) | |
| 862 | + ellipse(-wingSpread * 0.7, 0, wingSpread * 1.2, 15) | |
| 863 | + // Wing details | |
| 864 | + noStroke() | |
| 865 | + fill(200, 200, 200, 80) | |
| 866 | + ellipse(-wingSpread * 0.6, 0, wingSpread * 0.8, 10) | |
| 867 | + pop() | |
| 868 | + | |
| 869 | + // Right wing | |
| 870 | + push() | |
| 871 | + translate(this.radius * 0.4, 0) | |
| 872 | + rotate(wingAngle) | |
| 873 | + fill(255, 255, 255, 120) | |
| 874 | + stroke(0, 0, 0, 100) | |
| 875 | + strokeWeight(0.5) | |
| 876 | + ellipse(wingSpread * 0.7, 0, wingSpread * 1.2, 15) | |
| 877 | + // Wing details | |
| 878 | + noStroke() | |
| 879 | + fill(200, 200, 200, 80) | |
| 880 | + ellipse(wingSpread * 0.6, 0, wingSpread * 0.8, 10) | |
| 881 | + pop() | |
| 882 | + | |
| 883 | + // Extra glow at night | |
| 835 | 884 | if (gamePhase === 'NIGHT') { |
| 836 | - push() | |
| 837 | - fill(255, 255, 255, 100 + sin(this.wingPhase) * 50) | |
| 838 | 885 | noStroke() |
| 839 | - let wingSpread = sin(this.wingPhase) * 15 | |
| 840 | - ellipse(-wingSpread, 0, 20, 12) | |
| 841 | - ellipse(wingSpread, 0, 20, 12) | |
| 842 | - pop() | |
| 886 | + fill(255, 255, 200, 30 + sin(this.wingPhase * 2) * 20) | |
| 887 | + ellipse(0, 0, this.radius * 3, this.radius * 2) | |
| 843 | 888 | } |
| 889 | + pop() | |
| 844 | 890 | |
| 845 | - // Main beetle body | |
| 891 | + // Main beetle body (on top of wings) | |
| 846 | 892 | fill(red(this.beetleColor), green(this.beetleColor), blue(this.beetleColor)) |
| 847 | 893 | stroke(0) |
| 848 | 894 | strokeWeight(2) |
@@ -865,26 +911,30 @@ class Obstacle { | ||
| 865 | 911 | ellipse(this.radius * 0.2, this.radius * 0.4, this.radius * 0.35) |
| 866 | 912 | ellipse(-this.radius * 0.25, this.radius * 0.3, this.radius * 0.25) |
| 867 | 913 | |
| 868 | - // Legs | |
| 914 | + // No legs - they're flying! | |
| 915 | + // Just small leg stubs tucked under the body | |
| 869 | 916 | stroke(0) |
| 870 | - strokeWeight(2) | |
| 871 | - for (let i = 0; i < 3; i++) { | |
| 872 | - let legY = -this.radius * 0.3 + i * this.radius * 0.3 | |
| 873 | - let legMove = sin(this.wingPhase * 2 + i) * 2 | |
| 874 | - line(-this.radius * 0.8, legY, -this.radius * 1.2 + legMove, legY + 5) | |
| 875 | - line(this.radius * 0.8, legY, this.radius * 1.2 - legMove, legY + 5) | |
| 876 | - } | |
| 917 | + strokeWeight(1) | |
| 918 | + // Tiny tucked legs | |
| 919 | + line(-this.radius * 0.5, -this.radius * 0.2, -this.radius * 0.6, -this.radius * 0.1) | |
| 920 | + line(this.radius * 0.5, -this.radius * 0.2, this.radius * 0.6, -this.radius * 0.1) | |
| 921 | + line(-this.radius * 0.5, this.radius * 0.2, -this.radius * 0.6, this.radius * 0.1) | |
| 922 | + line(this.radius * 0.5, this.radius * 0.2, this.radius * 0.6, this.radius * 0.1) | |
| 877 | 923 | |
| 878 | 924 | // Antennae |
| 879 | 925 | strokeWeight(1) |
| 880 | 926 | line(-3, -this.radius * 1.1, -8, -this.radius * 1.4) |
| 881 | 927 | line(3, -this.radius * 1.1, 8, -this.radius * 1.4) |
| 882 | 928 | |
| 883 | - // Eyes | |
| 929 | + // Eyes (bigger and more prominent) | |
| 884 | 930 | fill(255, 0, 0) |
| 885 | 931 | noStroke() |
| 886 | - ellipse(-5, -this.radius * 0.7, 4) | |
| 887 | - ellipse(5, -this.radius * 0.7, 4) | |
| 932 | + ellipse(-5, -this.radius * 0.7, 5) | |
| 933 | + ellipse(5, -this.radius * 0.7, 5) | |
| 934 | + // Eye shine | |
| 935 | + fill(255, 150, 150) | |
| 936 | + ellipse(-4, -this.radius * 0.72, 2) | |
| 937 | + ellipse(6, -this.radius * 0.72, 2) | |
| 888 | 938 | |
| 889 | 939 | pop() |
| 890 | 940 | |
js/game.jsmodified@@ -117,25 +117,25 @@ function setup() { | ||
| 117 | 117 | obstacles.push(new Obstacle(x, y, 20, 'leaf')); // Use leaf as invisible anchor |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | - // Create fewer, bigger, quirkier obstacles | |
| 121 | - let numObstacles = Math.floor((width * height) / 120000); // Much fewer | |
| 122 | - numObstacles = constrain(numObstacles, 8, 15); | |
| 120 | + // Create more obstacles for denser coverage | |
| 121 | + let numObstacles = Math.floor((width * height) / 60000); // More obstacles | |
| 122 | + numObstacles = constrain(numObstacles, 15, 25); | |
| 123 | 123 | |
| 124 | - // Create ant balloons (2-3) | |
| 125 | - let numBalloons = Math.floor(random(2, 4)); | |
| 124 | + // Create ant balloons (4-6) | |
| 125 | + let numBalloons = Math.floor(random(4, 7)); | |
| 126 | 126 | for (let i = 0; i < numBalloons; i++) { |
| 127 | 127 | let attempts = 0; |
| 128 | 128 | let placed = false; |
| 129 | 129 | |
| 130 | 130 | while (!placed && attempts < 30) { |
| 131 | - let x = random(120, width - 120); | |
| 132 | - let y = random(80, height * 0.5); // Balloons float in upper half | |
| 133 | - let radius = random(40, 55); // Bigger | |
| 131 | + let x = random(80, width - 80); | |
| 132 | + let y = random(60, height * 0.55); // Balloons float in upper half | |
| 133 | + let radius = random(35, 45); // Good size for hopping | |
| 134 | 134 | |
| 135 | 135 | let valid = true; |
| 136 | 136 | // Check distance from other obstacles |
| 137 | 137 | for (let obstacle of obstacles) { |
| 138 | - if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 80) { | |
| 138 | + if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 50) { | |
| 139 | 139 | valid = false; |
| 140 | 140 | break; |
| 141 | 141 | } |
@@ -144,7 +144,7 @@ function setup() { | ||
| 144 | 144 | // Check distance from home branch |
| 145 | 145 | if (valid && window.homeBranch) { |
| 146 | 146 | let branchY = window.homeBranch.y; |
| 147 | - if (Math.abs(y - branchY) < radius + 50) { | |
| 147 | + if (Math.abs(y - branchY) < radius + 35) { | |
| 148 | 148 | valid = false; |
| 149 | 149 | } |
| 150 | 150 | } |
@@ -157,20 +157,20 @@ function setup() { | ||
| 157 | 157 | } |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | - // Create beetles (2-3) | |
| 161 | - let numBeetles = Math.floor(random(2, 4)); | |
| 160 | + // Create beetles (3-5) | |
| 161 | + let numBeetles = Math.floor(random(3, 6)); | |
| 162 | 162 | for (let i = 0; i < numBeetles; i++) { |
| 163 | 163 | let attempts = 0; |
| 164 | 164 | let placed = false; |
| 165 | 165 | |
| 166 | 166 | while (!placed && attempts < 30) { |
| 167 | - let x = random(100, width - 100); | |
| 168 | - let y = random(height * 0.3, height * 0.7); // Middle areas | |
| 169 | - let radius = random(35, 50); | |
| 167 | + let x = random(70, width - 70); | |
| 168 | + let y = random(height * 0.2, height * 0.8); // Spread throughout middle/lower | |
| 169 | + let radius = random(30, 40); | |
| 170 | 170 | |
| 171 | 171 | let valid = true; |
| 172 | 172 | for (let obstacle of obstacles) { |
| 173 | - if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 70) { | |
| 173 | + if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 45) { | |
| 174 | 174 | valid = false; |
| 175 | 175 | break; |
| 176 | 176 | } |
@@ -179,7 +179,7 @@ function setup() { | ||
| 179 | 179 | // Check distance from home branch |
| 180 | 180 | if (valid && window.homeBranch) { |
| 181 | 181 | let branchY = window.homeBranch.y; |
| 182 | - if (Math.abs(y - branchY) < radius + 40) { | |
| 182 | + if (Math.abs(y - branchY) < radius + 30) { | |
| 183 | 183 | valid = false; |
| 184 | 184 | } |
| 185 | 185 | } |
@@ -192,20 +192,23 @@ function setup() { | ||
| 192 | 192 | } |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | - // Create leaves (3-4) for more stable anchor points | |
| 196 | - let numLeaves = Math.floor(random(3, 5)); | |
| 195 | + // Create LOTS of leaves (8-12) for excellent hopping coverage | |
| 196 | + let numLeaves = Math.floor(random(8, 13)); | |
| 197 | 197 | for (let i = 0; i < numLeaves; i++) { |
| 198 | 198 | let attempts = 0; |
| 199 | 199 | let placed = false; |
| 200 | 200 | |
| 201 | 201 | while (!placed && attempts < 30) { |
| 202 | - let x = random(80, width - 80); | |
| 203 | - let y = random(100, height - 150); | |
| 204 | - let radius = random(30, 40); | |
| 202 | + // Distribute leaves more evenly across the screen | |
| 203 | + let gridX = (i % 4) * (width / 4) + random(50, width/4 - 50); | |
| 204 | + let gridY = Math.floor(i / 4) * (height / 3) + random(50, height/3 - 50); | |
| 205 | + let x = constrain(gridX, 50, width - 50); | |
| 206 | + let y = constrain(gridY, 60, height - 100); | |
| 207 | + let radius = random(20, 30); | |
| 205 | 208 | |
| 206 | 209 | let valid = true; |
| 207 | 210 | for (let obstacle of obstacles) { |
| 208 | - if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 60) { | |
| 211 | + if (dist(x, y, obstacle.x, obstacle.y) < radius + obstacle.radius + 35) { | |
| 209 | 212 | valid = false; |
| 210 | 213 | break; |
| 211 | 214 | } |
@@ -219,15 +222,41 @@ function setup() { | ||
| 219 | 222 | } |
| 220 | 223 | } |
| 221 | 224 | |
| 222 | - // Add guaranteed edge anchor points (smaller, stable leaves) | |
| 223 | - obstacles.push(new Obstacle(50, height/2, 25, 'leaf')); | |
| 224 | - obstacles.push(new Obstacle(width - 50, height/2, 25, 'leaf')); | |
| 225 | - obstacles.push(new Obstacle(width/2, 60, 25, 'leaf')); | |
| 226 | - | |
| 227 | - // Bottom anchors for better coverage | |
| 228 | - if (width > 1000) { | |
| 229 | - obstacles.push(new Obstacle(width/3, height - 130, 25, 'leaf')); | |
| 230 | - obstacles.push(new Obstacle(2*width/3, height - 130, 25, 'leaf')); | |
| 225 | + // Add even more guaranteed coverage points (smaller leaves) | |
| 226 | + // Corners | |
| 227 | + obstacles.push(new Obstacle(50, 80, 18, 'leaf')); | |
| 228 | + obstacles.push(new Obstacle(width - 50, 80, 18, 'leaf')); | |
| 229 | + obstacles.push(new Obstacle(50, height - 100, 18, 'leaf')); | |
| 230 | + obstacles.push(new Obstacle(width - 50, height - 100, 18, 'leaf')); | |
| 231 | + | |
| 232 | + // Edge midpoints | |
| 233 | + obstacles.push(new Obstacle(35, height/3, 18, 'leaf')); | |
| 234 | + obstacles.push(new Obstacle(35, 2*height/3, 18, 'leaf')); | |
| 235 | + obstacles.push(new Obstacle(width - 35, height/3, 18, 'leaf')); | |
| 236 | + obstacles.push(new Obstacle(width - 35, 2*height/3, 18, 'leaf')); | |
| 237 | + obstacles.push(new Obstacle(width/3, 45, 18, 'leaf')); | |
| 238 | + obstacles.push(new Obstacle(2*width/3, 45, 18, 'leaf')); | |
| 239 | + obstacles.push(new Obstacle(width/3, height - 90, 18, 'leaf')); | |
| 240 | + obstacles.push(new Obstacle(2*width/3, height - 90, 18, 'leaf')); | |
| 241 | + | |
| 242 | + // Fill any remaining gaps for smooth hopping | |
| 243 | + if (width > 600) { | |
| 244 | + // Create a grid of small leaves to ensure no dead zones | |
| 245 | + for (let x = width/5; x < width; x += width/5) { | |
| 246 | + for (let y = height/4; y < height - 100; y += height/4) { | |
| 247 | + // Check if there's already an obstacle nearby | |
| 248 | + let needsLeaf = true; | |
| 249 | + for (let obstacle of obstacles) { | |
| 250 | + if (dist(x, y, obstacle.x, obstacle.y) < 80) { | |
| 251 | + needsLeaf = false; | |
| 252 | + break; | |
| 253 | + } | |
| 254 | + } | |
| 255 | + if (needsLeaf) { | |
| 256 | + obstacles.push(new Obstacle(x + random(-20, 20), y + random(-20, 20), 15, 'leaf')); | |
| 257 | + } | |
| 258 | + } | |
| 259 | + } | |
| 231 | 260 | } |
| 232 | 261 | |
| 233 | 262 | // Spawn initial food boxes |