Upload index.html
Browse files- index.html +39 -15
index.html
CHANGED
|
@@ -22,7 +22,7 @@
|
|
| 22 |
<script>
|
| 23 |
(() => {
|
| 24 |
"use strict";
|
| 25 |
-
// ============ Aquarium
|
| 26 |
const canvas = document.getElementById("tank");
|
| 27 |
const ctx = canvas.getContext("2d");
|
| 28 |
let W = 0, H = 0;
|
|
@@ -52,8 +52,10 @@ class Fish {
|
|
| 52 |
this.angle = Math.random() < 0.5 ? rand(-0.4, 0.4) : Math.PI + rand(-0.4, 0.4);
|
| 53 |
this.hue = pick(HUES);
|
| 54 |
this.phase = rand(0, Math.PI * 2);
|
| 55 |
-
//
|
| 56 |
-
|
|
|
|
|
|
|
| 57 |
|
| 58 |
// Wander steering (Reynolds-style): a circle ahead of the fish whose target point jitters
|
| 59 |
this.wanderTheta = rand(0, Math.PI * 2);
|
|
@@ -131,14 +133,14 @@ class Fish {
|
|
| 131 |
const groundY = sandAt(this.x + Math.cos(this.angle) * this.wanderDist) - this.size * 0.5;
|
| 132 |
wy += (groundY - wy) * night * 0.85;
|
| 133 |
} else if (seaweeds.length) {
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
if (d2 < bd) { bd = d2; bx = w.x; by = w.yMid; }
|
| 138 |
}
|
|
|
|
| 139 |
const k = night * 0.8;
|
| 140 |
-
wx += (
|
| 141 |
-
wy += (
|
| 142 |
}
|
| 143 |
}
|
| 144 |
|
|
@@ -168,8 +170,7 @@ class Fish {
|
|
| 168 |
}
|
| 169 |
|
| 170 |
// v7: separation steering β bend around nearby fish instead of ploughing into them.
|
| 171 |
-
//
|
| 172 |
-
// the faster we swim, the earlier and harder we steer away.
|
| 173 |
const mySpeed = this.speed * this.speedFactor;
|
| 174 |
if (mySpeed > 0.3) {
|
| 175 |
let ax = 0, ay = 0, wsum = 0;
|
|
@@ -189,6 +190,26 @@ class Fish {
|
|
| 189 |
if (wsum > 0) {
|
| 190 |
desired = lerpAngle(desired, Math.atan2(ay, ax), Math.min(0.85, wsum * 0.45));
|
| 191 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
}
|
| 193 |
|
| 194 |
// Limit turn rate so direction changes are smooth and fish-like
|
|
@@ -703,7 +724,9 @@ function updatePlants(t, dt) {
|
|
| 703 |
// ---- fish push leaves aside: fish overpower the flora ----
|
| 704 |
for (const f of fishes) {
|
| 705 |
const R = 80, R2 = R * R; // influence radius around fish
|
| 706 |
-
const
|
|
|
|
|
|
|
| 707 |
for (let i = 1; i <= w.segs; i++) {
|
| 708 |
const fl = i / w.segs;
|
| 709 |
const px = w.x + w.off[i] + Math.sin(t * w.speed + w.phase + fl * 2.6) * fl * fl * 24;
|
|
@@ -713,9 +736,10 @@ function updatePlants(t, dt) {
|
|
| 713 |
if (d2 < R2 && d2 > 0.01) {
|
| 714 |
const d = Math.sqrt(d2);
|
| 715 |
const weight = (R - d) / R * (0.35 + 0.65 * fl); // upper segments yield more
|
| 716 |
-
// shove radially away from the fish + drag along its swim direction
|
| 717 |
-
|
| 718 |
-
|
|
|
|
| 719 |
}
|
| 720 |
}
|
| 721 |
}
|
|
|
|
| 22 |
<script>
|
| 23 |
(() => {
|
| 24 |
"use strict";
|
| 25 |
+
// ============ Aquarium v9 β night buffers: spaced sleepers, calmer seaweed ==============
|
| 26 |
const canvas = document.getElementById("tank");
|
| 27 |
const ctx = canvas.getContext("2d");
|
| 28 |
let W = 0, H = 0;
|
|
|
|
| 52 |
this.angle = Math.random() < 0.5 ? rand(-0.4, 0.4) : Math.PI + rand(-0.4, 0.4);
|
| 53 |
this.hue = pick(HUES);
|
| 54 |
this.phase = rand(0, Math.PI * 2);
|
| 55 |
+
// v9: after dark, most fish bed down low in the grass β only a small share still
|
| 56 |
+
// hovers by the seaweed, and each of those keeps to its own stalk (no pile-ups)
|
| 57 |
+
this.grassSleeper = Math.random() < 0.85;
|
| 58 |
+
this.seaweedPref = -1; // chosen lazily on the first night (needs built scenery)
|
| 59 |
|
| 60 |
// Wander steering (Reynolds-style): a circle ahead of the fish whose target point jitters
|
| 61 |
this.wanderTheta = rand(0, Math.PI * 2);
|
|
|
|
| 133 |
const groundY = sandAt(this.x + Math.cos(this.angle) * this.wanderDist) - this.size * 0.5;
|
| 134 |
wy += (groundY - wy) * night * 0.85;
|
| 135 |
} else if (seaweeds.length) {
|
| 136 |
+
// v9: each seaweed-hungry fish keeps to its own stalk instead of all crowding the nearest one
|
| 137 |
+
if (this.seaweedPref < 0 || this.seaweedPref >= seaweeds.length) {
|
| 138 |
+
this.seaweedPref = (Math.random() * seaweeds.length) | 0;
|
|
|
|
| 139 |
}
|
| 140 |
+
const w = seaweeds[this.seaweedPref];
|
| 141 |
const k = night * 0.8;
|
| 142 |
+
wx += (w.x - wx) * k;
|
| 143 |
+
wy += (w.yMid - wy) * k;
|
| 144 |
}
|
| 145 |
}
|
| 146 |
|
|
|
|
| 170 |
}
|
| 171 |
|
| 172 |
// v7: separation steering β bend around nearby fish instead of ploughing into them.
|
| 173 |
+
// The faster we swim, the earlier and harder we steer away.
|
|
|
|
| 174 |
const mySpeed = this.speed * this.speedFactor;
|
| 175 |
if (mySpeed > 0.3) {
|
| 176 |
let ax = 0, ay = 0, wsum = 0;
|
|
|
|
| 190 |
if (wsum > 0) {
|
| 191 |
desired = lerpAngle(desired, Math.atan2(ay, ax), Math.min(0.85, wsum * 0.45));
|
| 192 |
}
|
| 193 |
+
} else if (night > 0.2) {
|
| 194 |
+
// v9: at rest after dark β keep a small personal buffer so sleeping fish
|
| 195 |
+
// slowly drift apart instead of piling on top of each other
|
| 196 |
+
let ax = 0, ay = 0, wsum = 0;
|
| 197 |
+
for (const o of fishes) {
|
| 198 |
+
if (o === this) continue;
|
| 199 |
+
const dx = o.x - this.x, dy = o.y - this.y;
|
| 200 |
+
const d2 = dx * dx + dy * dy;
|
| 201 |
+
const zone = (this.size + o.size) * 1.3; // tighter buffer than the swim radius
|
| 202 |
+
if (d2 < zone * zone && d2 > 0.01) {
|
| 203 |
+
const dd = Math.sqrt(d2);
|
| 204 |
+
const w = 1 - dd / zone;
|
| 205 |
+
ax -= (dx / dd) * w;
|
| 206 |
+
ay -= (dy / dd) * w;
|
| 207 |
+
wsum += w;
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
if (wsum > 0) {
|
| 211 |
+
desired = lerpAngle(desired, Math.atan2(ay, ax), Math.min(0.5, wsum * 0.3));
|
| 212 |
+
}
|
| 213 |
}
|
| 214 |
|
| 215 |
// Limit turn rate so direction changes are smooth and fish-like
|
|
|
|
| 724 |
// ---- fish push leaves aside: fish overpower the flora ----
|
| 725 |
for (const f of fishes) {
|
| 726 |
const R = 80, R2 = R * R; // influence radius around fish
|
| 727 |
+
const fSpd = f.speed * f.cruiseSpeed * f.speedFactor; // actual current speed
|
| 728 |
+
const fx = Math.cos(f.angle) * fSpd * 60; // fish velocity x (px/s)
|
| 729 |
+
const moveF = Math.min(1, fSpd / 1.2); // v9: how actively this fish is swimming
|
| 730 |
for (let i = 1; i <= w.segs; i++) {
|
| 731 |
const fl = i / w.segs;
|
| 732 |
const px = w.x + w.off[i] + Math.sin(t * w.speed + w.phase + fl * 2.6) * fl * fl * 24;
|
|
|
|
| 736 |
if (d2 < R2 && d2 > 0.01) {
|
| 737 |
const d = Math.sqrt(d2);
|
| 738 |
const weight = (R - d) / R * (0.35 + 0.65 * fl); // upper segments yield more
|
| 739 |
+
// shove radially away from the fish + drag along its swim direction.
|
| 740 |
+
// v9: a nearly-still fish only gently parts leaves β no shoving, no flinch wobble
|
| 741 |
+
w.offV[i] += ((dx / d) * 1500 * (0.25 + 0.75 * moveF) + fx * 9) * weight * dt;
|
| 742 |
+
if (weight > 0.25 && moveF > 0.35) w.touch = Math.min(1, w.touch + dt * 5);
|
| 743 |
}
|
| 744 |
}
|
| 745 |
}
|