@@ -968,6 +968,12 @@ class Obstacle { |
| 968 | this.bobSpeed = random(0.02, 0.04) | 968 | this.bobSpeed = random(0.02, 0.04) |
| 969 | this.bobAmount = 0 | 969 | this.bobAmount = 0 |
| 970 | | 970 | |
| | 971 | + // Wind effect properties |
| | 972 | + this.windSway = 0 // Current sway amount |
| | 973 | + this.windSwayTarget = 0 // Target sway for smooth animation |
| | 974 | + this.windBob = 0 // Additional vertical movement from wind |
| | 975 | + this.basketSwing = 0 // For balloon basket swinging |
| | 976 | + |
| 971 | // Type-specific initialization | 977 | // Type-specific initialization |
| 972 | if (this.type === 'balloon') { | 978 | if (this.type === 'balloon') { |
| 973 | this.bobAmount = 8 // Balloons bob more | 979 | this.bobAmount = 8 // Balloons bob more |
@@ -1006,6 +1012,57 @@ class Obstacle { |
| 1006 | let bob = sin(frameCount * this.bobSpeed + this.bobOffset) * this.bobAmount | 1012 | let bob = sin(frameCount * this.bobSpeed + this.bobOffset) * this.bobAmount |
| 1007 | this.y = this.originalY + bob | 1013 | this.y = this.originalY + bob |
| 1008 | | 1014 | |
| | 1015 | + // ENHANCED: Apply wind effects |
| | 1016 | + if (windActive) { |
| | 1017 | + // Different wind responses by type |
| | 1018 | + if (this.type === 'balloon') { |
| | 1019 | + // Balloons are highly affected by wind |
| | 1020 | + this.windSwayTarget = cos(windDirection) * windStrength * 15 // Strong horizontal push |
| | 1021 | + this.windBob = |
| | 1022 | + sin(frameCount * 0.04 + this.bobOffset) * windStrength * 3 // Extra vertical movement |
| | 1023 | + |
| | 1024 | + // Basket swings opposite to balloon movement (pendulum effect) |
| | 1025 | + this.basketSwing = |
| | 1026 | + -this.windSway * 0.5 + sin(frameCount * 0.06) * windStrength * 0.3 |
| | 1027 | + |
| | 1028 | + // Actually move the balloon |
| | 1029 | + this.originalX += cos(windDirection) * windStrength * 0.08 |
| | 1030 | + |
| | 1031 | + // Keep on screen with stronger resistance at edges |
| | 1032 | + if (this.originalX < 50) { |
| | 1033 | + this.originalX = 50 |
| | 1034 | + this.windSwayTarget *= -0.5 // Bounce back effect |
| | 1035 | + } |
| | 1036 | + if (this.originalX > width - 50) { |
| | 1037 | + this.originalX = width - 50 |
| | 1038 | + this.windSwayTarget *= -0.5 |
| | 1039 | + } |
| | 1040 | + } else if (this.type === 'beetle') { |
| | 1041 | + // Beetles resist but still affected |
| | 1042 | + this.windSwayTarget = cos(windDirection) * windStrength * 3 |
| | 1043 | + // Fight against wind |
| | 1044 | + this.driftAngle -= cos(windDirection) * windStrength * 0.01 |
| | 1045 | + } else if (this.type === 'leaf') { |
| | 1046 | + // Leaves flutter in wind |
| | 1047 | + this.windSwayTarget = cos(windDirection) * windStrength * 5 |
| | 1048 | + this.rotation += windStrength * 0.02 // Spin faster |
| | 1049 | + } |
| | 1050 | + } else { |
| | 1051 | + // No wind, return to normal |
| | 1052 | + this.windSwayTarget = 0 |
| | 1053 | + this.windBob = 0 |
| | 1054 | + this.basketSwing = 0 |
| | 1055 | + } |
| | 1056 | + |
| | 1057 | + // Smooth sway animation |
| | 1058 | + this.windSway = lerp(this.windSway, this.windSwayTarget, 0.1) |
| | 1059 | + |
| | 1060 | + // Apply wind sway to position |
| | 1061 | + this.x = this.originalX + this.windSway |
| | 1062 | + |
| | 1063 | + // Apply wind bob to vertical position |
| | 1064 | + this.y = this.originalY + bob + this.windBob |
| | 1065 | + |
| 1009 | // Beetle-specific drift | 1066 | // Beetle-specific drift |
| 1010 | if (this.type === 'beetle') { | 1067 | if (this.type === 'beetle') { |
| 1011 | // Store initial position if not set | 1068 | // Store initial position if not set |
@@ -1201,272 +1258,293 @@ class Obstacle { |
| 1201 | } | 1258 | } |
| 1202 | | 1259 | |
| 1203 | display () { | 1260 | display () { |
| | 1261 | + push() |
| | 1262 | + translate(this.x, this.y) |
| | 1263 | + |
| | 1264 | + if (this.type === 'balloon') { |
| | 1265 | + // ============================================ |
| | 1266 | + // HOT AIR BALLOON WITH CANVAS TEXTURE |
| | 1267 | + // ============================================ |
| 1204 | push() | 1268 | push() |
| 1205 | - translate(this.x, this.y) | 1269 | + |
| | 1270 | + // ENHANCED: Tilt balloon based on wind |
| | 1271 | + if (windActive) { |
| | 1272 | + rotate(this.windSway * 0.01) // Slight tilt in wind direction |
| | 1273 | + } |
| 1206 | | 1274 | |
| 1207 | - if (this.type === 'balloon') { | 1275 | + // Balloon shadow |
| 1208 | - // ============================================ | 1276 | + noStroke() |
| 1209 | - // HOT AIR BALLOON WITH CANVAS TEXTURE | 1277 | + fill(0, 0, 0, 30) |
| 1210 | - // ============================================ | 1278 | + ellipse(5, 5, this.radius * 2.1) |
| | 1279 | + |
| | 1280 | + // Main balloon with canvas panel texture |
| | 1281 | + // Draw vertical panels like a real hot air balloon |
| | 1282 | + let numPanels = 8 |
| | 1283 | + for (let i = 0; i < numPanels; i++) { |
| 1211 | push() | 1284 | push() |
| 1212 | | 1285 | |
| 1213 | - // Balloon shadow | 1286 | + // Rotate for each panel |
| 1214 | - noStroke() | 1287 | + rotate((TWO_PI / numPanels) * i) |
| 1215 | - fill(0, 0, 0, 30) | | |
| 1216 | - ellipse(5, 5, this.radius * 2.1) | | |
| 1217 | - | | |
| 1218 | - // Main balloon with canvas panel texture | | |
| 1219 | - // Draw vertical panels like a real hot air balloon | | |
| 1220 | - let numPanels = 8 | | |
| 1221 | - for (let i = 0; i < numPanels; i++) { | | |
| 1222 | - push() | | |
| 1223 | - | | |
| 1224 | - // Rotate for each panel | | |
| 1225 | - rotate((TWO_PI / numPanels) * i) | | |
| 1226 | - | | |
| 1227 | - // Alternate panel colors for classic hot air balloon look | | |
| 1228 | - if (i % 2 === 0) { | | |
| 1229 | - fill( | | |
| 1230 | - red(this.balloonColor), | | |
| 1231 | - green(this.balloonColor), | | |
| 1232 | - blue(this.balloonColor) | | |
| 1233 | - ) | | |
| 1234 | - } else { | | |
| 1235 | - // Slightly darker alternate panels | | |
| 1236 | - fill( | | |
| 1237 | - red(this.balloonColor) * 0.9, | | |
| 1238 | - green(this.balloonColor) * 0.9, | | |
| 1239 | - blue(this.balloonColor) * 0.9 | | |
| 1240 | - ) | | |
| 1241 | - } | | |
| 1242 | | 1288 | |
| 1243 | - // Draw panel as pie slice | 1289 | + // Alternate panel colors for classic hot air balloon look |
| 1244 | - noStroke() | 1290 | + if (i % 2 === 0) { |
| 1245 | - arc( | 1291 | + fill( |
| 1246 | - 0, | 1292 | + red(this.balloonColor), |
| 1247 | - 0, | 1293 | + green(this.balloonColor), |
| 1248 | - this.radius * 2, | 1294 | + blue(this.balloonColor) |
| 1249 | - this.radius * 2, | 1295 | + ) |
| 1250 | - -PI / numPanels, | 1296 | + } else { |
| 1251 | - PI / numPanels, | 1297 | + // Slightly darker alternate panels |
| 1252 | - PIE | 1298 | + fill( |
| | 1299 | + red(this.balloonColor) * 0.9, |
| | 1300 | + green(this.balloonColor) * 0.9, |
| | 1301 | + blue(this.balloonColor) * 0.9 |
| 1253 | ) | 1302 | ) |
| 1254 | - | | |
| 1255 | - pop() | | |
| 1256 | - } | | |
| 1257 | - | | |
| 1258 | - // Add panel seams (the ropes/stitching between panels) | | |
| 1259 | - stroke(60, 40, 20, 110) | | |
| 1260 | - strokeWeight(1) | | |
| 1261 | - for (let i = 0; i < numPanels; i++) { | | |
| 1262 | - let angle = (TWO_PI / numPanels) * i | | |
| 1263 | - let x1 = cos(angle) * this.radius * 0.2 | | |
| 1264 | - let y1 = sin(angle) * this.radius * 0.2 | | |
| 1265 | - let x2 = cos(angle) * this.radius * 0.95 | | |
| 1266 | - let y2 = sin(angle) * this.radius * 0.95 | | |
| 1267 | - line(x1, y1, x2, y2) | | |
| 1268 | } | 1303 | } |
| 1269 | | 1304 | |
| 1270 | - // Add circular reinforcement bands | 1305 | + // Draw panel as pie slice |
| 1271 | - noFill() | | |
| 1272 | - stroke(80, 50, 30, 80) | | |
| 1273 | - strokeWeight(1.5) | | |
| 1274 | - ellipse(0, 0, this.radius * 1.4) | | |
| 1275 | - ellipse(0, 0, this.radius * 0.8) | | |
| 1276 | - | | |
| 1277 | - // Matte fabric shading (subtle, non-glossy) | | |
| 1278 | - noStroke() | | |
| 1279 | - // Soft radial shading toward top-left to imply ambient light without specular shine | | |
| 1280 | - for ( | | |
| 1281 | - let r = this.radius * 1.2; | | |
| 1282 | - r > this.radius * 0.2; | | |
| 1283 | - r -= this.radius * 0.15 | | |
| 1284 | - ) { | | |
| 1285 | - fill(255, 255, 255, 8) // very low alpha | | |
| 1286 | - ellipse(-this.radius * 0.25, -this.radius * 0.35, r * 0.25, r * 0.18) | | |
| 1287 | - } | | |
| 1288 | - // Global matte overlay to reduce plastic look | | |
| 1289 | noStroke() | 1306 | noStroke() |
| 1290 | - fill(230, 210, 190, 18) | 1307 | + arc( |
| 1291 | - ellipse(0, 0, this.radius * 2, this.radius * 2) | 1308 | + 0, |
| 1292 | - | 1309 | + 0, |
| 1293 | - // Bottom opening of balloon (where flame goes) | 1310 | + this.radius * 2, |
| 1294 | - fill(40, 20, 10) | 1311 | + this.radius * 2, |
| 1295 | - ellipse(0, this.radius * 0.9, this.radius * 0.4, this.radius * 0.15) | 1312 | + -PI / numPanels, |
| 1296 | - | 1313 | + PI / numPanels, |
| 1297 | - // Support ropes from balloon to basket | 1314 | + PIE |
| 1298 | - stroke(80, 60, 40) | 1315 | + ) |
| 1299 | - strokeWeight(2) | | |
| 1300 | - // Four support ropes | | |
| 1301 | - line(-this.radius * 0.3, this.radius * 0.85, -8, this.radius + 20) | | |
| 1302 | - line(this.radius * 0.3, this.radius * 0.85, 8, this.radius + 20) | | |
| 1303 | - line(-this.radius * 0.15, this.radius * 0.9, -4, this.radius + 20) | | |
| 1304 | - line(this.radius * 0.15, this.radius * 0.9, 4, this.radius + 20) | | |
| 1305 | | 1316 | |
| 1306 | - // FLAME EFFECT (between balloon and basket) | 1317 | + pop() |
| 1307 | - push() | 1318 | + } |
| 1308 | - translate(0, this.radius + 10) | | |
| 1309 | | 1319 | |
| 1310 | - // Flame glow | 1320 | + // Add panel seams (the ropes/stitching between panels) |
| 1311 | - noStroke() | 1321 | + stroke(60, 40, 20, 110) |
| 1312 | - fill(255, 200, 0, 30 + sin(frameCount * 0.2) * 20) | 1322 | + strokeWeight(1) |
| 1313 | - ellipse(0, 0, 30, 30) | 1323 | + for (let i = 0; i < numPanels; i++) { |
| 1314 | - fill(255, 150, 0, 50 + sin(frameCount * 0.3) * 30) | 1324 | + let angle = (TWO_PI / numPanels) * i |
| 1315 | - ellipse(0, 0, 20, 25) | 1325 | + let x1 = cos(angle) * this.radius * 0.2 |
| | 1326 | + let y1 = sin(angle) * this.radius * 0.2 |
| | 1327 | + let x2 = cos(angle) * this.radius * 0.95 |
| | 1328 | + let y2 = sin(angle) * this.radius * 0.95 |
| | 1329 | + line(x1, y1, x2, y2) |
| | 1330 | + } |
| | 1331 | + |
| | 1332 | + // Add circular reinforcement bands |
| | 1333 | + noFill() |
| | 1334 | + stroke(80, 50, 30, 80) |
| | 1335 | + strokeWeight(1.5) |
| | 1336 | + ellipse(0, 0, this.radius * 1.4) |
| | 1337 | + ellipse(0, 0, this.radius * 0.8) |
| 1316 | | 1338 | |
| 1317 | - // Animated flame | 1339 | + // Matte fabric shading (subtle, non-glossy) |
| 1318 | - push() | 1340 | + noStroke() |
| 1319 | - let flameHeight = 12 + sin(frameCount * 0.4) * 4 | 1341 | + // Soft radial shading toward top-left to imply ambient light without specular shine |
| 1320 | - let flameWave = sin(frameCount * 0.3) * 2 | 1342 | + for ( |
| | 1343 | + let r = this.radius * 1.2; |
| | 1344 | + r > this.radius * 0.2; |
| | 1345 | + r -= this.radius * 0.15 |
| | 1346 | + ) { |
| | 1347 | + fill(255, 255, 255, 8) // very low alpha |
| | 1348 | + ellipse(-this.radius * 0.25, -this.radius * 0.35, r * 0.25, r * 0.18) |
| | 1349 | + } |
| | 1350 | + // Global matte overlay to reduce plastic look |
| | 1351 | + noStroke() |
| | 1352 | + fill(230, 210, 190, 18) |
| | 1353 | + ellipse(0, 0, this.radius * 2, this.radius * 2) |
| | 1354 | + |
| | 1355 | + // Bottom opening of balloon (where flame goes) |
| | 1356 | + fill(40, 20, 10) |
| | 1357 | + ellipse(0, this.radius * 0.9, this.radius * 0.4, this.radius * 0.15) |
| | 1358 | + |
| | 1359 | + // Support ropes from balloon to basket |
| | 1360 | + stroke(80, 60, 40) |
| | 1361 | + strokeWeight(2) |
| | 1362 | + // Four support ropes |
| | 1363 | + line(-this.radius * 0.3, this.radius * 0.85, -8, this.radius + 20) |
| | 1364 | + line(this.radius * 0.3, this.radius * 0.85, 8, this.radius + 20) |
| | 1365 | + line(-this.radius * 0.15, this.radius * 0.9, -4, this.radius + 20) |
| | 1366 | + line(this.radius * 0.15, this.radius * 0.9, 4, this.radius + 20) |
| | 1367 | + |
| | 1368 | + // FLAME EFFECT (between balloon and basket) |
| | 1369 | + push() |
| | 1370 | + translate(0, this.radius + 10) |
| 1321 | | 1371 | |
| 1322 | - // Outer flame (orange) | 1372 | + // Flame glow |
| 1323 | - fill(255, 150, 0) | 1373 | + noStroke() |
| 1324 | - beginShape() | 1374 | + fill(255, 200, 0, 30 + sin(frameCount * 0.2) * 20) |
| 1325 | - vertex(-5, 5) | 1375 | + ellipse(0, 0, 30, 30) |
| 1326 | - bezierVertex( | 1376 | + fill(255, 150, 0, 50 + sin(frameCount * 0.3) * 30) |
| 1327 | - -5 + flameWave, | 1377 | + ellipse(0, 0, 20, 25) |
| 1328 | - -flameHeight * 0.5, | | |
| 1329 | - -2 + flameWave, | | |
| 1330 | - -flameHeight * 0.8, | | |
| 1331 | - flameWave, | | |
| 1332 | - -flameHeight | | |
| 1333 | - ) | | |
| 1334 | - bezierVertex( | | |
| 1335 | - 2 + flameWave, | | |
| 1336 | - -flameHeight * 0.8, | | |
| 1337 | - 5 + flameWave, | | |
| 1338 | - -flameHeight * 0.5, | | |
| 1339 | - 5, | | |
| 1340 | - 5 | | |
| 1341 | - ) | | |
| 1342 | - endShape(CLOSE) | | |
| 1343 | | 1378 | |
| 1344 | - // Inner flame (yellow/white) | 1379 | + // Animated flame |
| 1345 | - fill(255, 255, 150) | 1380 | + push() |
| 1346 | - beginShape() | 1381 | + let flameHeight = 12 + sin(frameCount * 0.4) * 4 |
| 1347 | - vertex(-2, 5) | 1382 | + let flameWave = sin(frameCount * 0.3) * 2 |
| 1348 | - bezierVertex( | 1383 | + |
| 1349 | - -2 + flameWave * 0.5, | 1384 | + // Outer flame (orange) |
| 1350 | - -flameHeight * 0.3, | 1385 | + fill(255, 150, 0) |
| 1351 | - -1 + flameWave * 0.5, | 1386 | + beginShape() |
| 1352 | - -flameHeight * 0.5, | 1387 | + vertex(-5, 5) |
| 1353 | - flameWave * 0.5, | 1388 | + bezierVertex( |
| 1354 | - -flameHeight * 0.7 | 1389 | + -5 + flameWave, |
| 1355 | - ) | 1390 | + -flameHeight * 0.5, |
| 1356 | - bezierVertex( | 1391 | + -2 + flameWave, |
| 1357 | - 1 + flameWave * 0.5, | 1392 | + -flameHeight * 0.8, |
| 1358 | - -flameHeight * 0.5, | 1393 | + flameWave, |
| 1359 | - 2 + flameWave * 0.5, | 1394 | + -flameHeight |
| 1360 | - -flameHeight * 0.3, | 1395 | + ) |
| 1361 | - 2, | 1396 | + bezierVertex( |
| 1362 | - 5 | 1397 | + 2 + flameWave, |
| 1363 | - ) | 1398 | + -flameHeight * 0.8, |
| 1364 | - endShape(CLOSE) | 1399 | + 5 + flameWave, |
| | 1400 | + -flameHeight * 0.5, |
| | 1401 | + 5, |
| | 1402 | + 5 |
| | 1403 | + ) |
| | 1404 | + endShape(CLOSE) |
| | 1405 | + |
| | 1406 | + // Inner flame (yellow/white) |
| | 1407 | + fill(255, 255, 150) |
| | 1408 | + beginShape() |
| | 1409 | + vertex(-2, 5) |
| | 1410 | + bezierVertex( |
| | 1411 | + -2 + flameWave * 0.5, |
| | 1412 | + -flameHeight * 0.3, |
| | 1413 | + -1 + flameWave * 0.5, |
| | 1414 | + -flameHeight * 0.5, |
| | 1415 | + flameWave * 0.5, |
| | 1416 | + -flameHeight * 0.7 |
| | 1417 | + ) |
| | 1418 | + bezierVertex( |
| | 1419 | + 1 + flameWave * 0.5, |
| | 1420 | + -flameHeight * 0.5, |
| | 1421 | + 2 + flameWave * 0.5, |
| | 1422 | + -flameHeight * 0.3, |
| | 1423 | + 2, |
| | 1424 | + 5 |
| | 1425 | + ) |
| | 1426 | + endShape(CLOSE) |
| 1365 | | 1427 | |
| 1366 | - // Flame tip (bright white) | 1428 | + // Flame tip (bright white) |
| 1367 | - fill(255, 255, 255) | 1429 | + fill(255, 255, 255) |
| 1368 | - ellipse(flameWave * 0.5, -flameHeight * 0.5, 3, 5) | 1430 | + ellipse(flameWave * 0.5, -flameHeight * 0.5, 3, 5) |
| 1369 | - pop() | 1431 | + pop() |
| 1370 | | 1432 | |
| 1371 | - pop() | 1433 | + pop() |
| 1372 | | 1434 | |
| 1373 | - // BIGGER, MORE DETAILED BASKET | 1435 | + // BIGGER, MORE DETAILED BASKET WITH SWING |
| 1374 | - push() | 1436 | + push() |
| 1375 | - translate(0, this.radius + 25) | 1437 | + translate(0, this.radius + 25) |
| | 1438 | + |
| | 1439 | + // ENHANCED: Apply basket swing |
| | 1440 | + if (windActive) { |
| | 1441 | + rotate(this.basketSwing * 0.02) |
| | 1442 | + } |
| 1376 | | 1443 | |
| 1377 | - // Basket shadow | 1444 | + // Basket shadow |
| 1378 | - noStroke() | 1445 | + noStroke() |
| 1379 | - fill(0, 0, 0, 20) | 1446 | + fill(0, 0, 0, 20) |
| 1380 | - rect(-11, 2, 22, 15, 2) | 1447 | + rect(-11, 2, 22, 15, 2) |
| 1381 | | 1448 | |
| 1382 | - // Main basket - bigger to see ant better | 1449 | + // Main basket - bigger to see ant better |
| 1383 | - fill(101, 67, 33) | 1450 | + fill(101, 67, 33) |
| 1384 | - stroke(80, 50, 20) | 1451 | + stroke(80, 50, 20) |
| 1385 | - strokeWeight(1.5) | 1452 | + strokeWeight(1.5) |
| 1386 | - rect(-10, 0, 20, 14, 2) // Bigger basket | 1453 | + rect(-10, 0, 20, 14, 2) // Bigger basket |
| 1387 | | 1454 | |
| 1388 | - // Woven basket texture | 1455 | + // Woven basket texture |
| 1389 | - stroke(80, 50, 20, 150) | 1456 | + stroke(80, 50, 20, 150) |
| 1390 | - strokeWeight(1) | 1457 | + strokeWeight(1) |
| 1391 | - // Vertical weaves | 1458 | + // Vertical weaves |
| 1392 | - for (let i = -8; i < 8; i += 3) { | 1459 | + for (let i = -8; i < 8; i += 3) { |
| 1393 | - line(i, 1, i, 13) | 1460 | + line(i, 1, i, 13) |
| 1394 | - } | 1461 | + } |
| 1395 | - // Horizontal weaves | 1462 | + // Horizontal weaves |
| 1396 | - for (let i = 3; i < 12; i += 3) { | 1463 | + for (let i = 3; i < 12; i += 3) { |
| 1397 | - line(-9, i, 9, i) | 1464 | + line(-9, i, 9, i) |
| 1398 | - } | 1465 | + } |
| 1399 | | 1466 | |
| 1400 | - // Basket rim (thicker, more pronounced) | 1467 | + // Basket rim (thicker, more pronounced) |
| 1401 | - stroke(60, 40, 20) | 1468 | + stroke(60, 40, 20) |
| 1402 | - strokeWeight(2) | 1469 | + strokeWeight(2) |
| 1403 | - line(-10, 0, 10, 0) | 1470 | + line(-10, 0, 10, 0) |
| 1404 | | 1471 | |
| 1405 | - // Corner reinforcements | 1472 | + // Corner reinforcements |
| 1406 | - fill(80, 50, 20) | 1473 | + fill(80, 50, 20) |
| 1407 | - noStroke() | 1474 | + noStroke() |
| 1408 | - ellipse(-9, 0, 3) | 1475 | + ellipse(-9, 0, 3) |
| 1409 | - ellipse(9, 0, 3) | 1476 | + ellipse(9, 0, 3) |
| 1410 | | 1477 | |
| 1411 | - pop() | 1478 | + pop() |
| 1412 | | 1479 | |
| 1413 | - // DETAILED ANT PILOT (bigger, more visible) | 1480 | + // DETAILED ANT PILOT (bigger, more visible) |
| 1414 | - push() | 1481 | + push() |
| 1415 | - translate(0, this.radius + 28) | 1482 | + translate(0, this.radius + 28) |
| | 1483 | + |
| | 1484 | + // ENHANCED: Ant holds on tighter in wind |
| | 1485 | + if (windActive) { |
| | 1486 | + rotate(-this.basketSwing * 0.01) // Ant leans opposite to basket |
| | 1487 | + } |
| 1416 | | 1488 | |
| 1417 | - // Ant body | 1489 | + // Ant body |
| 1418 | - fill(20) | 1490 | + fill(20) |
| 1419 | - noStroke() | 1491 | + noStroke() |
| 1420 | - ellipse(0, 0, 8, 5) // Thorax | 1492 | + ellipse(0, 0, 8, 5) // Thorax |
| 1421 | - ellipse(0, -3, 6, 5) // Head | 1493 | + ellipse(0, -3, 6, 5) // Head |
| 1422 | - ellipse(0, 3, 7, 6) // Abdomen | 1494 | + ellipse(0, 3, 7, 6) // Abdomen |
| 1423 | | 1495 | |
| 1424 | - // Ant eyes | 1496 | + // Ant eyes |
| 1425 | - fill(255, 100, 100) | 1497 | + fill(255, 100, 100) |
| 1426 | - ellipse(-2, -3, 2) | 1498 | + ellipse(-2, -3, 2) |
| 1427 | - ellipse(2, -3, 2) | 1499 | + ellipse(2, -3, 2) |
| 1428 | | 1500 | |
| 1429 | - // Antennae | 1501 | + // Antennae |
| 1430 | - stroke(20) | 1502 | + stroke(20) |
| 1431 | - strokeWeight(1) | 1503 | + strokeWeight(1) |
| 1432 | - line(-1, -5, -3, -8) | 1504 | + line(-1, -5, -3, -8) |
| 1433 | - line(1, -5, 3, -8) | 1505 | + line(1, -5, 3, -8) |
| 1434 | | 1506 | |
| 1435 | - // Little ant arms holding basket edge | 1507 | + // Little ant arms holding basket edge |
| 1436 | - strokeWeight(1.5) | 1508 | + strokeWeight(1.5) |
| 1437 | - line(-3, 0, -6, -3) | 1509 | + line(-3, 0, -6, -3) |
| 1438 | - line(3, 0, 6, -3) | 1510 | + line(3, 0, 6, -3) |
| 1439 | | 1511 | |
| 1440 | - // Ant legs visible over basket edge | 1512 | + // Ant legs visible over basket edge |
| 1441 | - line(-2, 2, -4, 5) | 1513 | + line(-2, 2, -4, 5) |
| 1442 | - line(2, 2, 4, 5) | 1514 | + line(2, 2, 4, 5) |
| 1443 | | 1515 | |
| 1444 | - // Optional: Tiny pilot goggles | 1516 | + // Optional: Tiny pilot goggles |
| 1445 | - stroke(100, 50, 0) | 1517 | + stroke(100, 50, 0) |
| 1446 | - strokeWeight(1) | 1518 | + strokeWeight(1) |
| 1447 | - noFill() | 1519 | + noFill() |
| 1448 | - ellipse(-2, -3, 3) | 1520 | + ellipse(-2, -3, 3) |
| 1449 | - ellipse(2, -3, 3) | 1521 | + ellipse(2, -3, 3) |
| 1450 | - line(-0.5, -3, 0.5, -3) | 1522 | + line(-0.5, -3, 0.5, -3) |
| 1451 | | 1523 | |
| 1452 | - pop() | 1524 | + pop() |
| 1453 | | 1525 | |
| 1454 | - // Sandbags hanging from basket (optional detail) | 1526 | + // Sandbags hanging from basket (optional detail) |
| 1455 | - push() | 1527 | + push() |
| 1456 | - translate(0, this.radius + 25) | 1528 | + translate(0, this.radius + 25) |
| 1457 | - fill(80, 60, 40) | 1529 | + |
| 1458 | - noStroke() | 1530 | + // ENHANCED: Sandbags swing in wind |
| 1459 | - ellipse(-12, 10, 4, 5) | 1531 | + if (windActive) { |
| 1460 | - ellipse(12, 10, 4, 5) | 1532 | + rotate(this.basketSwing * 0.03) |
| 1461 | - // Sandbag ropes | 1533 | + } |
| 1462 | - stroke(60, 40, 20) | 1534 | + |
| 1463 | - strokeWeight(0.5) | 1535 | + fill(80, 60, 40) |
| 1464 | - line(-10, 7, -12, 10) | 1536 | + noStroke() |
| 1465 | - line(10, 7, 12, 10) | 1537 | + ellipse(-12, 10, 4, 5) |
| 1466 | - pop() | 1538 | + ellipse(12, 10, 4, 5) |
| | 1539 | + // Sandbag ropes |
| | 1540 | + stroke(60, 40, 20) |
| | 1541 | + strokeWeight(0.5) |
| | 1542 | + line(-10, 7, -12, 10) |
| | 1543 | + line(10, 7, 12, 10) |
| | 1544 | + pop() |
| 1467 | | 1545 | |
| 1468 | - pop() | 1546 | + pop() |
| 1469 | - } else if (this.type === 'beetle') { | 1547 | + } else if (this.type === 'beetle') { |
| 1470 | push() | 1548 | push() |
| 1471 | rotate(this.rotation) | 1549 | rotate(this.rotation) |
| 1472 | | 1550 | |