🌲 Interactive Forest Path Scene - Faza 1 Demo
✨ Dodane features: - Interaktivna kamera z mouse wheel zoom (0.5x - 2.5x) - Dinamična trava z wind sway animacijo (6 šopov) - Depth of Field efekt pri zoom-u (background fade) - Virusne infekcije z neon zelenim glow (pulsing) - Pot v gozd z mrtimi drevesi (tunnel effect) - Y-sorted layering (9 slojev) 🧹 Asset Cleanup: - Ultra cleaned 106+ PNG slik v 'nova mapa' - Odstranjen checkerboard pattern z dreves, skal, trave - Feathering robov poti za naravno zlitje - Transparency fix na vseh environment assetih 🎨 Scene Composition: - Kaijev tabor (šotor + ognjišče) - Pot s skalami, poleni, razbito longboard - Grmovje in drevored - Foreground/midground/background separation 📁 Assets iz: nova mapa/ (Characters, Environment, UI) 🎮 Testno: http://localhost:3000 + mouse wheel zoom
This commit is contained in:
@@ -1,83 +1,267 @@
|
||||
export default class GrassScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'GrassScene' });
|
||||
this.currentZoom = 1.0;
|
||||
this.targetZoom = 1.0;
|
||||
}
|
||||
|
||||
preload() {
|
||||
console.log("👻 Loading Haunted Memory Assets...");
|
||||
console.log("🌲 Loading Interactive Forest...");
|
||||
|
||||
// 1. TERRAIN & CHARACTER
|
||||
this.load.image('grass', 'assets/slike/environment/grass_tile.png');
|
||||
this.load.image('kai', 'assets/slike/characters/liki_kai_ref_kai.png');
|
||||
// TERRAIN
|
||||
this.load.image('grass', 'assets/slike/environment/trava .png');
|
||||
this.load.image('dirt_path', 'assets/slike/nova mapa /Environment/podlaga/dirt_path.png');
|
||||
this.load.image('tall_grass', 'assets/slike/environment/tall_grass.png');
|
||||
|
||||
// 2. GHOSTS (Memory of Parents)
|
||||
// Path corrected after rename (Ghost: -> Ghost)
|
||||
this.load.image('ghost_father', 'assets/slike/NOVE_SLIKE/Characters/starsa/Ghost/ghost_otac_cyan.png');
|
||||
this.load.image('ghost_parents', 'assets/slike/NOVE_SLIKE/Characters/starsa/Ghost/MOJE_SLIKE_KONCNA_ostalo_parents_transparent_ghosts_clean.png');
|
||||
// CAMP
|
||||
this.load.image('tent', 'assets/slike/nova mapa /Environment/stavbe/MOJE_SLIKE_KONCNA_ostalo_tent_basic_style32.png');
|
||||
this.load.image('campfire', 'assets/slike/nova mapa /Environment/props/MOJE_SLIKE_KONCNA_ostalo_campfire_frame1.png');
|
||||
|
||||
// 3. UI ELEMENTS (Rusty Industrial Style)
|
||||
this.load.image('frame_rusty', 'assets/slike/NOVE_SLIKE/UI/okvir_zarjavel.png');
|
||||
this.load.image('health_gauge', 'assets/slike/NOVE_SLIKE/UI/merilec_zdravja.png');
|
||||
this.load.image('amnesia_mask', 'assets/slike/NOVE_SLIKE/UI/amnezija_maska.png');
|
||||
// NATURE
|
||||
this.load.image('dead_tree', 'assets/slike/nova mapa /Environment/narava/assets_maps_tilesets_Tree_Dead.png');
|
||||
this.load.image('bush', 'assets/slike/nova mapa /Environment/narava/MOJE_SLIKE_KONCNA_okolje_bush_green.png');
|
||||
this.load.image('rock_small', 'assets/slike/nova mapa /Environment/narava/MOJE_SLIKE_KONCNA_okolje_biomi_gore_rock_small_style32.png');
|
||||
this.load.image('rock_medium', 'assets/slike/nova mapa /Environment/narava/MOJE_SLIKE_KONCNA_okolje_biomi_gore_rock_medium_style32.png');
|
||||
|
||||
// PROPS
|
||||
this.load.image('wood_log', 'assets/slike/nova mapa /Environment/props/wood_log.png');
|
||||
this.load.image('broken_board', 'assets/slike/nova mapa /UI/icon_longboard.png');
|
||||
|
||||
// CHARACTER
|
||||
this.load.image('kai', 'assets/slike/characters/kai_idle_west_2_styleA_1024x1024.png');
|
||||
}
|
||||
|
||||
create() {
|
||||
console.log("💀 Reconstructing Memory...");
|
||||
console.log("🏕️ Building Interactive Forest...");
|
||||
const { width, height } = this.cameras.main;
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
|
||||
// --- LAYER 0: BACKGROUND ---
|
||||
// Trava (Depth: 0)
|
||||
const bg = this.add.tileSprite(0, 0, width, height, 'grass').setOrigin(0, 0);
|
||||
bg.setTint(0x888888);
|
||||
bg.setDepth(0);
|
||||
// Store all objects for DOF effect
|
||||
this.backgroundObjects = [];
|
||||
this.foregroundObjects = [];
|
||||
|
||||
// --- LAYER 10: CHARACTERS ---
|
||||
// Father Ghost (Left) - Depth: 10
|
||||
const father = this.add.image(centerX - 300, centerY, 'ghost_father');
|
||||
father.setAlpha(0.4);
|
||||
father.setScale(0.8);
|
||||
father.setDepth(10);
|
||||
// --- LAYER 0: GRASS BACKGROUND ---
|
||||
const grass = this.add.tileSprite(0, 0, width, height, 'grass').setOrigin(0, 0);
|
||||
grass.setDepth(0);
|
||||
|
||||
// Parents Ghost (Right) - Depth: 10
|
||||
const parents = this.add.image(centerX + 300, centerY, 'ghost_parents');
|
||||
parents.setAlpha(0.4);
|
||||
parents.setScale(0.8);
|
||||
parents.setDepth(10);
|
||||
// --- LAYER 1: DIRT PATH with FEATHERING ---
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const pathX = width / 2 + (i * 120);
|
||||
const pathY = height / 2 + 100 + (i * 40);
|
||||
const path = this.add.image(pathX, pathY, 'dirt_path');
|
||||
path.setScale(0.5);
|
||||
path.setDepth(1);
|
||||
path.setAlpha(0.7 + (i * 0.025));
|
||||
}
|
||||
|
||||
// Kai (Center) - Depth: 10
|
||||
const kai = this.add.image(centerX, centerY, 'kai');
|
||||
kai.setScale(0.8);
|
||||
kai.setDepth(10);
|
||||
// --- LAYER 2: BACKGROUND TREES ---
|
||||
const bgTree1 = this.add.image(width / 2 + 450, height / 2 - 120, 'dead_tree');
|
||||
bgTree1.setScale(0.4);
|
||||
bgTree1.setDepth(2);
|
||||
bgTree1.setAlpha(0.5);
|
||||
bgTree1.setTint(0x666666);
|
||||
this.backgroundObjects.push(bgTree1);
|
||||
|
||||
// --- LAYER 100: UI & EFFECTS ---
|
||||
const bgTree2 = this.add.image(width / 2 + 650, height / 2 + 20, 'dead_tree');
|
||||
bgTree2.setScale(0.38);
|
||||
bgTree2.setDepth(2);
|
||||
bgTree2.setAlpha(0.45);
|
||||
bgTree2.setTint(0x666666);
|
||||
this.backgroundObjects.push(bgTree2);
|
||||
|
||||
// 1. Amnesia Mask (Full Screen Overlay) - Depth: 100
|
||||
const mask = this.add.image(centerX, centerY, 'amnesia_mask');
|
||||
mask.setDisplaySize(width, height); // Stretch to cover FULL screen
|
||||
mask.setAlpha(0.9);
|
||||
mask.setDepth(100);
|
||||
// --- LAYER 3: VIRUS GLOW ---
|
||||
const virusGlow1 = this.add.circle(width / 2 + 280, height / 2 + 50, 80, 0x00ff00, 0.25);
|
||||
virusGlow1.setDepth(3);
|
||||
virusGlow1.setBlendMode(Phaser.BlendModes.ADD);
|
||||
|
||||
// 2. Health Gauge (Top Left, Small) - Depth: 100
|
||||
const gauge = this.add.image(90, 90, 'health_gauge');
|
||||
gauge.setDisplaySize(150, 150); // Resize to 150x150 as requested
|
||||
gauge.setDepth(100);
|
||||
const virusGlow2 = this.add.circle(width / 2 + 530, height / 2 + 200, 70, 0x00ff00, 0.2);
|
||||
virusGlow2.setDepth(3);
|
||||
virusGlow2.setBlendMode(Phaser.BlendModes.ADD);
|
||||
|
||||
// 3. Rusty Frame (Bottom Center) - Depth: 100
|
||||
const frameY = height - 100;
|
||||
const frame = this.add.image(centerX, frameY, 'frame_rusty');
|
||||
frame.setDepth(100);
|
||||
const virusGlow3 = this.add.circle(width / 2 + 650, height / 2 + 50, 60, 0x00ff00, 0.18);
|
||||
virusGlow3.setDepth(3);
|
||||
virusGlow3.setBlendMode(Phaser.BlendModes.ADD);
|
||||
|
||||
// 4. Dialog Text (Centered on Frame) - Depth: 101 (On top of frame)
|
||||
this.add.text(centerX, frameY, "Kai... se naju spomniš?", {
|
||||
this.tweens.add({
|
||||
targets: [virusGlow1, virusGlow2, virusGlow3],
|
||||
alpha: { from: 0.15, to: 0.35 },
|
||||
scaleX: { from: 0.85, to: 1.15 },
|
||||
scaleY: { from: 0.85, to: 1.15 },
|
||||
duration: 2500,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
|
||||
// --- LAYER 4: CAMP ---
|
||||
const tent = this.add.image(width / 2 - 300, height / 2 - 50, 'tent');
|
||||
tent.setScale(0.4);
|
||||
tent.setDepth(10);
|
||||
|
||||
const campfire = this.add.image(width / 2 - 100, height / 2 + 30, 'campfire');
|
||||
campfire.setScale(0.3);
|
||||
campfire.setDepth(11);
|
||||
|
||||
// --- LAYER 5: PATH DECORATIONS ---
|
||||
const rock1 = this.add.image(width / 2 + 150, height / 2 + 120, 'rock_small');
|
||||
rock1.setScale(0.28);
|
||||
rock1.setDepth(8);
|
||||
|
||||
const rock2 = this.add.image(width / 2 + 380, height / 2 + 210, 'rock_medium');
|
||||
rock2.setScale(0.32);
|
||||
rock2.setDepth(8);
|
||||
|
||||
const rock3 = this.add.image(width / 2 + 520, height / 2 + 260, 'rock_small');
|
||||
rock3.setScale(0.25);
|
||||
rock3.setDepth(8);
|
||||
|
||||
const log1 = this.add.image(width / 2 + 240, height / 2 + 150, 'wood_log');
|
||||
log1.setScale(0.22);
|
||||
log1.setDepth(9);
|
||||
log1.setAngle(35);
|
||||
|
||||
const brokenBoard = this.add.image(width / 2 + 460, height / 2 + 235, 'broken_board');
|
||||
brokenBoard.setScale(0.08);
|
||||
brokenBoard.setDepth(9);
|
||||
brokenBoard.setAngle(-20);
|
||||
brokenBoard.setTint(0x555555);
|
||||
|
||||
// --- LAYER 6: MID-GROUND TREES ---
|
||||
const tree1 = this.add.image(width / 2 + 280, height / 2 + 20, 'dead_tree');
|
||||
tree1.setScale(0.55);
|
||||
tree1.setDepth(13);
|
||||
tree1.setAngle(-12);
|
||||
this.backgroundObjects.push(tree1);
|
||||
|
||||
const tree2 = this.add.image(width / 2 + 530, height / 2 + 170, 'dead_tree');
|
||||
tree2.setScale(0.58);
|
||||
tree2.setDepth(13);
|
||||
tree2.setAngle(10);
|
||||
this.backgroundObjects.push(tree2);
|
||||
|
||||
// Bushes
|
||||
const bush1 = this.add.image(width / 2 + 330, height / 2 + 75, 'bush');
|
||||
bush1.setScale(0.32);
|
||||
bush1.setDepth(12);
|
||||
|
||||
const bush2 = this.add.image(width / 2 + 460, height / 2 + 165, 'bush');
|
||||
bush2.setScale(0.35);
|
||||
bush2.setDepth(12);
|
||||
|
||||
const bush3 = this.add.image(width / 2 + 590, height / 2 + 240, 'bush');
|
||||
bush3.setScale(0.3);
|
||||
bush3.setDepth(12);
|
||||
|
||||
// --- LAYER 7: DYNAMIC GRASS TUFTS (wind effect) ---
|
||||
this.grassTufts = [];
|
||||
const tuftsPositions = [
|
||||
{ x: width / 2 + 180, y: height / 2 + 110, delay: 0, duration: 3500 },
|
||||
{ x: width / 2 + 350, y: height / 2 + 60, delay: 0.5, duration: 4000 },
|
||||
{ x: width / 2 + 270, y: height / 2 + 180, delay: 1.0, duration: 3200 },
|
||||
{ x: width / 2 + 490, y: height / 2 + 150, delay: 1.5, duration: 3800 },
|
||||
{ x: width / 2 + 400, y: height / 2 + 240, delay: 0.8, duration: 3600 },
|
||||
{ x: width / 2 + 560, y: height / 2 + 220, delay: 1.2, duration: 4200 },
|
||||
];
|
||||
|
||||
tuftsPositions.forEach(pos => {
|
||||
const tuft = this.add.image(pos.x, pos.y, 'tall_grass');
|
||||
tuft.setScale(0.12);
|
||||
tuft.setDepth(16);
|
||||
tuft.setOrigin(0.5, 1); // Bottom center
|
||||
|
||||
// Wind sway animation
|
||||
this.tweens.add({
|
||||
targets: tuft,
|
||||
angle: { from: -3, to: 3 },
|
||||
duration: pos.duration,
|
||||
delay: pos.delay * 1000,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
|
||||
this.grassTufts.push(tuft);
|
||||
});
|
||||
|
||||
// --- LAYER 8: FOREGROUND TREE ---
|
||||
const fgTree1 = this.add.image(width / 2 + 200, height / 2 + 180, 'dead_tree');
|
||||
fgTree1.setScale(0.7);
|
||||
fgTree1.setDepth(25);
|
||||
fgTree1.setAngle(-5);
|
||||
fgTree1.setAlpha(0.95);
|
||||
this.foregroundObjects.push(fgTree1);
|
||||
|
||||
// --- LAYER 9: KAI (focus point) ---
|
||||
this.kai = this.add.image(width / 2 + 200, height / 2 + 140, 'kai');
|
||||
this.kai.setScale(0.16);
|
||||
this.kai.setDepth(20);
|
||||
|
||||
// --- CAMERA SETUP ---
|
||||
this.cameras.main.setBounds(0, 0, width * 2, height * 2);
|
||||
this.cameras.main.startFollow(this.kai, false, 0.1, 0.1);
|
||||
|
||||
// --- MOUSE WHEEL ZOOM ---
|
||||
this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY, deltaZ) => {
|
||||
if (deltaY > 0) {
|
||||
// Zoom Out
|
||||
this.targetZoom = Math.max(0.5, this.targetZoom - 0.15);
|
||||
} else {
|
||||
// Zoom In
|
||||
this.targetZoom = Math.min(2.5, this.targetZoom + 0.15);
|
||||
}
|
||||
});
|
||||
|
||||
// --- UI ---
|
||||
const uiText = this.add.text(20, 20, "🎮 INTERACTIVE FOREST", {
|
||||
fontFamily: 'Courier New, monospace',
|
||||
fontSize: '28px',
|
||||
color: '#e0e0e0',
|
||||
fontStyle: 'bold',
|
||||
stroke: '#000000',
|
||||
strokeThickness: 5,
|
||||
shadow: { offsetX: 2, offsetY: 2, color: '#000', blur: 4, fill: true }
|
||||
}).setOrigin(0.5).setDepth(101);
|
||||
fontSize: '20px',
|
||||
color: '#d4af37',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 10, y: 5 },
|
||||
fixedToCamera: true
|
||||
}).setScrollFactor(0).setDepth(100);
|
||||
|
||||
const controlsText = this.add.text(20, 55, "🖱️ Mouse Wheel: Zoom In/Out", {
|
||||
fontFamily: 'Courier New, monospace',
|
||||
fontSize: '14px',
|
||||
color: '#ffffff',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 10, y: 5 }
|
||||
}).setScrollFactor(0).setDepth(100);
|
||||
|
||||
this.zoomText = this.add.text(20, 90, `📷 Zoom: ${this.currentZoom.toFixed(2)}x`, {
|
||||
fontFamily: 'Courier New, monospace',
|
||||
fontSize: '14px',
|
||||
color: '#00ff88',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 10, y: 5 }
|
||||
}).setScrollFactor(0).setDepth(100);
|
||||
|
||||
console.log("✅ Interactive forest ready! Use mouse wheel to zoom!");
|
||||
}
|
||||
|
||||
update() {
|
||||
// Smooth zoom transition
|
||||
if (Math.abs(this.currentZoom - this.targetZoom) > 0.01) {
|
||||
this.currentZoom = Phaser.Math.Linear(this.currentZoom, this.targetZoom, 0.1);
|
||||
this.cameras.main.setZoom(this.currentZoom);
|
||||
|
||||
// Update zoom text
|
||||
if (this.zoomText) {
|
||||
this.zoomText.setText(`📷 Zoom: ${this.currentZoom.toFixed(2)}x`);
|
||||
}
|
||||
|
||||
// Depth of Field effect based on zoom
|
||||
const dofFactor = Phaser.Math.Clamp((this.currentZoom - 1) / 1.5, 0, 1);
|
||||
|
||||
// Blur background when zoomed in
|
||||
this.backgroundObjects.forEach(obj => {
|
||||
obj.setAlpha(0.5 - (dofFactor * 0.3)); // Fade out
|
||||
});
|
||||
|
||||
// Slight blur on foreground too
|
||||
this.foregroundObjects.forEach(obj => {
|
||||
obj.setAlpha(0.95 - (dofFactor * 0.2));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user