Feature: torches on stage
This commit is contained in:
parent
c944fb0f4d
commit
cdd90a4c57
@ -9,6 +9,7 @@ import { Pews } from './pews.js';
|
|||||||
import { Stage } from './stage.js';
|
import { Stage } from './stage.js';
|
||||||
import { MedievalMusicians } from './medieval-musicians.js';
|
import { MedievalMusicians } from './medieval-musicians.js';
|
||||||
import { PartyGuests } from './party-guests.js';
|
import { PartyGuests } from './party-guests.js';
|
||||||
|
import { StageTorches } from './stage-torches.js';
|
||||||
// Scene Features ^^^
|
// Scene Features ^^^
|
||||||
|
|
||||||
// --- Scene Modeling Function ---
|
// --- Scene Modeling Function ---
|
||||||
|
|||||||
117
party-cathedral/src/scene/stage-torches.js
Normal file
117
party-cathedral/src/scene/stage-torches.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { state } from '../state.js';
|
||||||
|
import { SceneFeature } from './SceneFeature.js';
|
||||||
|
import sceneFeatureManager from './SceneFeatureManager.js';
|
||||||
|
import sparkTextureUrl from '/textures/spark.png';
|
||||||
|
|
||||||
|
export class StageTorches extends SceneFeature {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.torches = [];
|
||||||
|
sceneFeatureManager.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// --- Stage Dimensions for positioning ---
|
||||||
|
const length = 40;
|
||||||
|
const naveWidth = 12;
|
||||||
|
const stageWidth = naveWidth - 1;
|
||||||
|
const stageHeight = 1.5;
|
||||||
|
const stageDepth = 5;
|
||||||
|
|
||||||
|
const torchPositions = [
|
||||||
|
new THREE.Vector3(-stageWidth / 2, stageHeight, -length / 2 + 0.5),
|
||||||
|
new THREE.Vector3(stageWidth / 2, stageHeight, -length / 2 + 0.5),
|
||||||
|
new THREE.Vector3(-stageWidth / 2, stageHeight, -length / 2 + stageDepth - 0.5),
|
||||||
|
new THREE.Vector3(stageWidth / 2, stageHeight, -length / 2 + stageDepth - 0.5),
|
||||||
|
];
|
||||||
|
|
||||||
|
torchPositions.forEach(pos => {
|
||||||
|
const torch = this.createTorch(pos);
|
||||||
|
this.torches.push(torch);
|
||||||
|
state.scene.add(torch.group);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createTorch(position) {
|
||||||
|
const torchGroup = new THREE.Group();
|
||||||
|
torchGroup.position.copy(position);
|
||||||
|
|
||||||
|
// --- Torch Holder ---
|
||||||
|
const holderMaterial = new THREE.MeshStandardMaterial({ color: 0x333333, roughness: 0.6, metalness: 0.5 });
|
||||||
|
const holderGeo = new THREE.CylinderGeometry(0.1, 0.15, 1.0, 12);
|
||||||
|
const holderMesh = new THREE.Mesh(holderGeo, holderMaterial);
|
||||||
|
holderMesh.position.y = 0.5;
|
||||||
|
holderMesh.castShadow = true;
|
||||||
|
holderMesh.receiveShadow = true;
|
||||||
|
torchGroup.add(holderMesh);
|
||||||
|
|
||||||
|
// --- Point Light ---
|
||||||
|
const pointLight = new THREE.PointLight(0xffaa44, 2.5, 8);
|
||||||
|
pointLight.position.y = 1.2;
|
||||||
|
pointLight.castShadow = true;
|
||||||
|
pointLight.shadow.mapSize.width = 128;
|
||||||
|
pointLight.shadow.mapSize.height = 128;
|
||||||
|
torchGroup.add(pointLight);
|
||||||
|
|
||||||
|
// --- Particle System for Fire ---
|
||||||
|
const particleCount = 50;
|
||||||
|
const particles = new THREE.BufferGeometry();
|
||||||
|
const positions = [];
|
||||||
|
const particleData = [];
|
||||||
|
|
||||||
|
const sparkTexture = state.loader.load(sparkTextureUrl);
|
||||||
|
const particleMaterial = new THREE.PointsMaterial({
|
||||||
|
map: sparkTexture,
|
||||||
|
color: 0xffaa00,
|
||||||
|
size: 0.5,
|
||||||
|
blending: THREE.AdditiveBlending,
|
||||||
|
transparent: true,
|
||||||
|
depthWrite: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < particleCount; i++) {
|
||||||
|
positions.push(0, 1, 0);
|
||||||
|
particleData.push({
|
||||||
|
velocity: new THREE.Vector3((Math.random() - 0.5) * 0.2, Math.random() * 1.5, (Math.random() - 0.5) * 0.2),
|
||||||
|
life: Math.random() * 1.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
particles.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
|
||||||
|
const particleSystem = new THREE.Points(particles, particleMaterial);
|
||||||
|
torchGroup.add(particleSystem);
|
||||||
|
|
||||||
|
return { group: torchGroup, light: pointLight, particles: particleSystem, particleData: particleData };
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaTime) {
|
||||||
|
this.torches.forEach(torch => {
|
||||||
|
// --- Animate Particles ---
|
||||||
|
const positions = torch.particles.geometry.attributes.position.array;
|
||||||
|
for (let i = 0; i < torch.particleData.length; i++) {
|
||||||
|
const data = torch.particleData[i];
|
||||||
|
data.life -= deltaTime;
|
||||||
|
|
||||||
|
if (data.life <= 0) {
|
||||||
|
// Reset particle
|
||||||
|
positions[i * 3] = 0;
|
||||||
|
positions[i * 3 + 1] = 1;
|
||||||
|
positions[i * 3 + 2] = 0;
|
||||||
|
data.life = Math.random() * 1.0;
|
||||||
|
} else {
|
||||||
|
// Update position
|
||||||
|
positions[i * 3] += data.velocity.x * deltaTime;
|
||||||
|
positions[i * 3 + 1] += data.velocity.y * deltaTime;
|
||||||
|
positions[i * 3 + 2] += data.velocity.z * deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
torch.particles.geometry.attributes.position.needsUpdate = true;
|
||||||
|
|
||||||
|
// --- Flicker Light ---
|
||||||
|
const flicker = Math.random() * 0.5;
|
||||||
|
torch.light.intensity = 2.0 + flicker;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new StageTorches();
|
||||||
BIN
party-cathedral/textures/spark.png
Normal file
BIN
party-cathedral/textures/spark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 950 B |
Loading…
Reference in New Issue
Block a user