Feature: add rats running on a path from a hole around the room

This commit is contained in:
Dejvino 2025-11-20 18:17:11 +01:00
parent dceb37a8dd
commit 43e746a5a0
3 changed files with 97 additions and 0 deletions

View File

@ -0,0 +1,92 @@
import * as THREE from 'three';
import { state } from '../state.js';
const SLEEP_WAIT = 1;
export class Rat {
constructor(path, initialDelay) {
this.path = path;
this.speed = 0.002 + Math.random() * 0.002;
this.progress = -initialDelay; // Start with a negative progress as a delay
// The rat's body
const bodyGeo = new THREE.CapsuleGeometry(0.02, 0.07, 4, 8);
const bodyMat = new THREE.MeshPhongMaterial({ color: 0x2a1d1d, shininess: 10 });
this.mesh = new THREE.Mesh(bodyGeo, bodyMat);
this.mesh.castShadow = true;
this.mesh.rotation.z = Math.PI / 2;
this.mesh.rotation.y = Math.PI / 2;
this.mesh.position.y = 0;
this.actor = new THREE.Group();
this.actor.visible = false; // Start invisible
this.actor.add(this.mesh);
state.scene.add(this.actor);
}
update() {
this.progress += this.speed;
// If the rat has finished its path, reset with a new delay
if (this.progress > 1.0) {
this.progress = -(Math.random() * SLEEP_WAIT); // wait some seconds before going again
this.actor.visible = false;
return;
}
// Don't do anything if we are in the delay period
if (this.progress < 0) {
return;
}
// First time it becomes visible
if (!this.actor.visible) {
this.actor.visible = true;
}
// Move along the path
const position = this.path.getPointAt(this.progress);
this.actor.position.copy(position);
// Orient along the path
const tangent = this.path.getTangentAt(this.progress).normalize();
const lookAtPosition = position.clone().add(tangent);
this.actor.lookAt(lookAtPosition);
}
}
export function createRats(x, y, z, rotY) {
// --- 9.5 Rat Hole ---
const holeGeo = new THREE.CircleGeometry(0.15, 16);
const holeMat = new THREE.MeshBasicMaterial({ color: 0x000000 });
const ratHole = new THREE.Mesh(holeGeo, holeMat);
ratHole.position.set(x, y + 0.1, z);
ratHole.rotation.y = rotY;
state.scene.add(ratHole);
// Define a path for the rats to follow
const ratPath = new THREE.CatmullRomCurve3([
new THREE.Vector3(x, y, z), // Start at the hole
new THREE.Vector3(x-2.0, 0, z),
new THREE.Vector3(0, 0, 1.0),
new THREE.Vector3(-1.0, 0, 1.8),
new THREE.Vector3(-1.5, 0, 0.5),
new THREE.Vector3(0.5, 0, 0.5),
new THREE.Vector3(1.8, 0, 1.0),
new THREE.Vector3(x, y, z), // End at the hole
]);
// Create a few rats with different starting delays
state.rats.push(new Rat(ratPath, 0.5));
state.rats.push(new Rat(ratPath, 3.0));
state.rats.push(new Rat(ratPath, 5.0));
}
export function updateRats() {
if (!state.rats || state.rats.length === 0) return;
state.rats.forEach(rat => {
rat.update();
});
}

View File

@ -6,6 +6,7 @@ import { createMagicMirror } from './magic-mirror.js';
import { createFireplace } from './fireplace.js'; import { createFireplace } from './fireplace.js';
import { createTable } from './table.js'; import { createTable } from './table.js';
import { createCauldron } from './cauldron.js'; import { createCauldron } from './cauldron.js';
import { createRats } from './rat.js';
import { PictureFrame } from './PictureFrame.js'; import { PictureFrame } from './PictureFrame.js';
import painting1 from '/textures/painting1.jpg'; import painting1 from '/textures/painting1.jpg';
import painting2 from '/textures/painting2.jpg'; import painting2 from '/textures/painting2.jpg';
@ -140,6 +141,8 @@ export function createSceneObjects() {
// --- 9. Fireplace --- // --- 9. Fireplace ---
createFireplace(state.roomSize / 2 - 0.5, -1, -Math.PI / 2); createFireplace(state.roomSize / 2 - 0.5, -1, -Math.PI / 2);
createRats(state.roomSize/2 - 0.01, 0, 0.37, -Math.PI / 2);
createBookshelf(-state.roomSize/2 + 0.2, state.roomSize/2*0.2, Math.PI/2, 0); createBookshelf(-state.roomSize/2 + 0.2, state.roomSize/2*0.2, Math.PI/2, 0);
createBookshelf(-state.roomSize/2 + 0.2, state.roomSize/2*0.7, Math.PI/2, 0); createBookshelf(-state.roomSize/2 + 0.2, state.roomSize/2*0.7, Math.PI/2, 0);
createBookshelf(-state.roomSize/2 * 0.7, -state.roomSize/2+0.3, 0, 1); createBookshelf(-state.roomSize/2 * 0.7, -state.roomSize/2+0.3, 0, 1);
@ -151,6 +154,7 @@ export function createSceneObjects() {
imageUrls: [painting1, painting2], imageUrls: [painting1, painting2],
rotationY: Math.PI / 2 rotationY: Math.PI / 2
}); });
state.pictureFrames.push(pictureFrame); state.pictureFrames.push(pictureFrame);
const pictureFrame2 = new PictureFrame(state.scene, { const pictureFrame2 = new PictureFrame(state.scene, {

View File

@ -54,6 +54,7 @@ export function initState() {
loader: new THREE.TextureLoader(), loader: new THREE.TextureLoader(),
landingSurfaces: [], landingSurfaces: [],
crawlSurfaces: [], // Surfaces for spiders to crawl on crawlSurfaces: [], // Surfaces for spiders to crawl on
rats: [], // Array to hold rats
bookLevitation: { bookLevitation: {
state: 'resting', // 'resting', 'levitating', 'returning' state: 'resting', // 'resting', 'levitating', 'returning'
timer: 0, timer: 0,