195 lines
5.5 KiB
JavaScript
195 lines
5.5 KiB
JavaScript
// Lighting & Shadow System - Dynamic lighting and shadows
|
|
class LightingSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.shadows = new Map(); // Entity → Shadow sprite
|
|
this.lights = new Map(); // Source → Light circle
|
|
|
|
console.log('💡 LightingSystem initialized');
|
|
}
|
|
|
|
// Create shadow for an entity (player, NPC, etc.)
|
|
createShadow(entity, offsetY = 10, width = 30, height = 15) {
|
|
if (!entity || !entity.sprite) return null;
|
|
|
|
const shadow = this.scene.add.ellipse(
|
|
entity.sprite.x,
|
|
entity.sprite.y + offsetY,
|
|
width,
|
|
height,
|
|
0x000000,
|
|
0.3
|
|
);
|
|
|
|
shadow.setDepth(entity.sprite.depth - 1); // Always below entity
|
|
this.shadows.set(entity, { shadow, offsetY, width, height });
|
|
|
|
return shadow;
|
|
}
|
|
|
|
// Update shadow position (call in entity update)
|
|
updateShadow(entity) {
|
|
const data = this.shadows.get(entity);
|
|
if (!data || !entity.sprite) return;
|
|
|
|
const { shadow, offsetY } = data;
|
|
shadow.setPosition(entity.sprite.x, entity.sprite.y + offsetY);
|
|
|
|
// Adjust shadow opacity based on time of day
|
|
if (this.scene.weatherSystem) {
|
|
const hour = this.scene.weatherSystem.getCurrentHour();
|
|
let opacity = 0.3;
|
|
|
|
if (hour >= 5 && hour < 7) {
|
|
// Dawn - weak shadow
|
|
opacity = 0.1 + ((hour - 5) / 2) * 0.2;
|
|
} else if (hour >= 7 && hour < 18) {
|
|
// Day - strong shadow
|
|
opacity = 0.3;
|
|
} else if (hour >= 18 && hour < 20) {
|
|
// Dusk - fading shadow
|
|
opacity = 0.3 - ((hour - 18) / 2) * 0.2;
|
|
} else {
|
|
// Night - very weak shadow
|
|
opacity = 0.1;
|
|
}
|
|
|
|
shadow.setAlpha(opacity);
|
|
}
|
|
}
|
|
|
|
// Remove shadow
|
|
removeShadow(entity) {
|
|
const data = this.shadows.get(entity);
|
|
if (data && data.shadow) {
|
|
data.shadow.destroy();
|
|
}
|
|
this.shadows.delete(entity);
|
|
}
|
|
|
|
// Create light source (torch, campfire, etc.)
|
|
createLight(x, y, radius = 100, color = 0xffee88, alpha = 0.3, flicker = false) {
|
|
const light = this.scene.add.circle(x, y, radius, color, alpha);
|
|
light.setBlendMode(Phaser.BlendModes.ADD);
|
|
light.setDepth(999990); // Above most things
|
|
|
|
const lightData = {
|
|
light,
|
|
radius,
|
|
color,
|
|
baseAlpha: alpha,
|
|
flicker,
|
|
flickerTimer: 0
|
|
};
|
|
|
|
this.lights.set(light, lightData);
|
|
|
|
return light;
|
|
}
|
|
|
|
// Create player torch (follows player at night)
|
|
createPlayerTorch(player) {
|
|
if (!player || !player.sprite) return null;
|
|
|
|
const torch = this.scene.add.circle(
|
|
player.sprite.x,
|
|
player.sprite.y,
|
|
80,
|
|
0xffee88,
|
|
0
|
|
);
|
|
|
|
torch.setBlendMode(Phaser.BlendModes.ADD);
|
|
torch.setDepth(999990);
|
|
|
|
this.lights.set(torch, {
|
|
light: torch,
|
|
radius: 80,
|
|
color: 0xffee88,
|
|
baseAlpha: 0.35,
|
|
flicker: true,
|
|
flickerTimer: 0,
|
|
followPlayer: player
|
|
});
|
|
|
|
return torch;
|
|
}
|
|
|
|
// Update all lights
|
|
update(delta) {
|
|
const isNight = this.scene.weatherSystem ? this.scene.weatherSystem.isNight() : false;
|
|
|
|
for (const [light, data] of this.lights) {
|
|
// Follow player if assigned
|
|
if (data.followPlayer && data.followPlayer.sprite) {
|
|
light.setPosition(
|
|
data.followPlayer.sprite.x,
|
|
data.followPlayer.sprite.y
|
|
);
|
|
|
|
// Only show torch at night
|
|
if (isNight) {
|
|
light.setAlpha(data.baseAlpha);
|
|
} else {
|
|
light.setAlpha(0); // Hidden during day
|
|
}
|
|
}
|
|
|
|
// Flicker effect
|
|
if (data.flicker) {
|
|
data.flickerTimer += delta;
|
|
if (data.flickerTimer > 50) { // Every 50ms
|
|
data.flickerTimer = 0;
|
|
const flicker = data.baseAlpha + (Math.random() * 0.1 - 0.05);
|
|
if (isNight || !data.followPlayer) {
|
|
light.setAlpha(Phaser.Math.Clamp(flicker, 0, 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update all shadows
|
|
for (const [entity, data] of this.shadows) {
|
|
this.updateShadow(entity);
|
|
}
|
|
}
|
|
|
|
// Remove light
|
|
removeLight(light) {
|
|
const data = this.lights.get(light);
|
|
if (data && data.light) {
|
|
data.light.destroy();
|
|
}
|
|
this.lights.delete(light);
|
|
}
|
|
|
|
// Create campfire effect (static light with particles)
|
|
createCampfire(x, y) {
|
|
// Light glow
|
|
const light = this.createLight(x, y, 120, 0xff6600, 0.4, true);
|
|
|
|
// Smoke particles (if ParticleEffects exists)
|
|
if (this.scene.particleEffects) {
|
|
// Add smoke rising from campfire
|
|
// (Implement in ParticleEffects system)
|
|
}
|
|
|
|
return light;
|
|
}
|
|
|
|
// Clean up
|
|
destroy() {
|
|
// Remove all shadows
|
|
for (const [entity, data] of this.shadows) {
|
|
this.removeShadow(entity);
|
|
}
|
|
|
|
// Remove all lights
|
|
for (const [light, data] of this.lights) {
|
|
this.removeLight(light);
|
|
}
|
|
|
|
console.log('💡 LightingSystem destroyed');
|
|
}
|
|
}
|