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 { MedievalMusicians } from './medieval-musicians.js';
|
||||
import { PartyGuests } from './party-guests.js';
|
||||
import { StageTorches } from './stage-torches.js';
|
||||
// Scene Features ^^^
|
||||
|
||||
// --- 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