feat: bubbles, food pellets & fish feeding behavior
- Bubbles.ts: rising bubble particles from 2 air stones (near plants), wobble + growth + fade near surface, 50-mesh pool - Food.ts: auto-dropping food pellets (every 6-14s, 3-6 pieces) that float down and settle on the floor; manual drop via click - GLTFish.ts: fish now notice food within 1.2 units, seek at 1.4x speed with faster turn rate, eat pellets within 0.15 units; faster tail beat while chasing - main.ts: wires food + bubbles into render loop; click drops 4 pellets
This commit is contained in:
+17
-5
@@ -5,6 +5,8 @@ import { setupLighting } from "./scene/Lighting";
|
||||
import { createGLTFishSchool, type FishSpec } from "./scene/GLTFish";
|
||||
import { createDecor, type DecorSpec } from "./scene/Decor";
|
||||
import { createParallaxCamera } from "./scene/Camera";
|
||||
import { createBubbles } from "./scene/Bubbles";
|
||||
import { createFood } from "./scene/Food";
|
||||
|
||||
const canvas = document.querySelector<HTMLCanvasElement>("#aquarium");
|
||||
if (!canvas) {
|
||||
@@ -34,10 +36,10 @@ setupLighting(scene, renderer);
|
||||
createTank(scene);
|
||||
const water = createWater(scene);
|
||||
|
||||
// Fish — GLB models with swim animations + wandering AI.
|
||||
// Maya's tropical fish already face local +X (no orient fix). The Quaternius
|
||||
// pack is built with its long axis on +Z (nose at +Z), so it is rotated +90°
|
||||
// about Y to bring the nose onto +X.
|
||||
// Food — pellets that drop from above; fish seek and eat them.
|
||||
const food = createFood(scene);
|
||||
|
||||
// Fish — GLB models with swim animations + wandering AI + food seeking.
|
||||
const fishSpecs: FishSpec[] = [
|
||||
// Tropical (maya's-aquarium-3d)
|
||||
{ url: "models/angelfish.glb", targetLength: 0.55, speed: [0.25, 0.45] },
|
||||
@@ -52,7 +54,7 @@ const fishSpecs: FishSpec[] = [
|
||||
{ url: "models/quaternius/glb/Fish2.glb", targetLength: 0.6, speed: [0.3, 0.55], orient: { y: Math.PI / 2 } },
|
||||
{ url: "models/quaternius/glb/Fish3.glb", targetLength: 0.55, speed: [0.35, 0.6], orient: { y: Math.PI / 2 } },
|
||||
];
|
||||
const fishSchool = createGLTFishSchool(scene, fishSpecs);
|
||||
const fishSchool = createGLTFishSchool(scene, fishSpecs, food);
|
||||
|
||||
// Decor — static plants and rocks on the gravel floor (y ~ 0.05).
|
||||
const decorSpecs: DecorSpec[] = [
|
||||
@@ -64,6 +66,9 @@ const decorSpecs: DecorSpec[] = [
|
||||
];
|
||||
createDecor(scene, decorSpecs);
|
||||
|
||||
// Bubbles — rising from air stones near the plants.
|
||||
const bubbles = createBubbles(scene);
|
||||
|
||||
const parallax = createParallaxCamera(camera);
|
||||
|
||||
// Mouse tracking (normalized to -1..1)
|
||||
@@ -73,6 +78,11 @@ window.addEventListener("mousemove", (e) => {
|
||||
mouseY = (e.clientY / window.innerHeight) * 2 - 1;
|
||||
});
|
||||
|
||||
// Click to drop food.
|
||||
window.addEventListener("click", () => {
|
||||
food.dropFood(4);
|
||||
});
|
||||
|
||||
// Resize handling
|
||||
function resize(): void {
|
||||
const width = window.innerWidth;
|
||||
@@ -95,7 +105,9 @@ function animate(): void {
|
||||
const dt = Math.min((now - lastFrameTime) / 1000, 0.1);
|
||||
lastFrameTime = now;
|
||||
water.update(time);
|
||||
food.update(dt, time);
|
||||
fishSchool.update(dt, time);
|
||||
bubbles.update(dt, time);
|
||||
parallax.update(mouseX, mouseY, time, dt);
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user