SESSION END 23:40 - Complete visual overhaul. New folder structure (Ground/Veg/Env). Generated final assets (Style 32 Dark-Chibi). Implemented GrassScene_Clean.js with density logic. Scene PERFECT.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import GrassScene from './scenes/GrassScene.js';
|
||||
import GrassScene from './scenes/GrassScene_Clean.js';
|
||||
|
||||
const config = {
|
||||
type: Phaser.AUTO,
|
||||
|
||||
@@ -8,106 +8,153 @@ export default class GrassScene extends Phaser.Scene {
|
||||
preload() {
|
||||
console.log("🌿 Loading Environment assets...");
|
||||
|
||||
// Load assets from DEMO_FAZA1
|
||||
this.load.image('ground_dead', 'assets/DEMO_FAZA1/tla_trava_tekstura.png');
|
||||
this.load.image('grass_tall', 'assets/DEMO_FAZA1/visoka_trava.png');
|
||||
this.load.image('grass_tuft', 'assets/DEMO_FAZA1/trava_sop.png');
|
||||
// 1. DEFINICIJA POTI (ASSETS) - Absolute paths from server root
|
||||
const ASSETS = {
|
||||
ground: '/assets/DEMO_FAZA1/tla_trava_tekstura.png',
|
||||
fog: '/assets/DEMO_FAZA1/megla_ozadje.png',
|
||||
trees: {
|
||||
faza1: '/assets/DEMO_FAZA1/drevo_faza_1.png',
|
||||
faza2: '/assets/DEMO_FAZA1/drevo_faza_2.png',
|
||||
small: '/assets/DEMO_FAZA1/drevo_majhno.png',
|
||||
medium: '/assets/DEMO_FAZA1/drevo_srednje.png',
|
||||
large: '/assets/DEMO_FAZA1/drevo_veliko.png',
|
||||
dry: '/assets/DEMO_FAZA1/suho_drevo.png'
|
||||
},
|
||||
foliage: {
|
||||
clump: '/assets/DEMO_FAZA1/trava_sop.png',
|
||||
tall: '/assets/DEMO_FAZA1/visoka_trava.png'
|
||||
}
|
||||
};
|
||||
|
||||
// Trees (Growth Stages)
|
||||
this.load.image('tree_small', 'assets/DEMO_FAZA1/drevo_majhno.png');
|
||||
this.load.image('tree_medium', 'assets/DEMO_FAZA1/drevo_srednje.png');
|
||||
this.load.image('tree_large', 'assets/DEMO_FAZA1/drevo_veliko.png');
|
||||
this.load.image('tree_dead', 'assets/DEMO_FAZA1/suho_drevo.png');
|
||||
this.paths = ASSETS; // Store for reference if needed
|
||||
|
||||
// Weather
|
||||
this.load.image('fog', 'assets/DEMO_FAZA1/megla_ozadje.png');
|
||||
// Load specific images
|
||||
this.load.image('ground_dead', ASSETS.ground);
|
||||
this.load.image('fog', ASSETS.fog);
|
||||
|
||||
// GLSL Wind Shader (Inline for simplicity)
|
||||
this.windPipeline = null; // Will create in create()
|
||||
// Trees
|
||||
this.load.image('tree_faza1', ASSETS.trees.faza1);
|
||||
this.load.image('tree_faza2', ASSETS.trees.faza2);
|
||||
this.load.image('tree_small', ASSETS.trees.small);
|
||||
this.load.image('tree_medium', ASSETS.trees.medium);
|
||||
this.load.image('tree_large', ASSETS.trees.large);
|
||||
this.load.image('tree_dead', ASSETS.trees.dry);
|
||||
|
||||
// Foliage
|
||||
this.load.image('grass_tuft', ASSETS.foliage.clump);
|
||||
this.load.image('grass_tall', ASSETS.foliage.tall);
|
||||
|
||||
// Add error handling for loading
|
||||
this.load.on('loaderror', (file) => {
|
||||
console.error('File failed to load:', file.src);
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
const { width, height } = this.scale;
|
||||
|
||||
// 1. DEAD GROUND (Tiling background)
|
||||
// Uses the 'dead' texture as the base canvas
|
||||
// 2. NALOGA: Implementiraj 'tla_trava_tekstura.png' kot ponavljajočo se podlago
|
||||
this.ground = this.add.tileSprite(0, 0, width, height, 'ground_dead').setOrigin(0, 0);
|
||||
|
||||
// 2. VEGETATION GROUPS
|
||||
// Vegetation Groups
|
||||
this.trees = [];
|
||||
this.grasses = [];
|
||||
|
||||
// 3. GENERATE WORLD (Procedural placement)
|
||||
// Generate World
|
||||
this.generateVegetation(width, height);
|
||||
|
||||
// 4. WEATHER LAYERS (Fog)
|
||||
this.fog1 = this.add.tileSprite(0, 0, width, height, 'fog').setOrigin(0, 0).setAlpha(0.2).setBlendMode(Phaser.BlendModes.ADD);
|
||||
this.fog2 = this.add.tileSprite(0, 0, width, height, 'fog').setOrigin(0, 0).setAlpha(0.15).setBlendMode(Phaser.BlendModes.ADD);
|
||||
// 2. NALOGA: Dodaj 'megla_ozadje.png' kot zgornji sloj
|
||||
this.fog1 = this.add.tileSprite(0, 0, width, height, 'fog')
|
||||
.setOrigin(0, 0)
|
||||
.setAlpha(0.3)
|
||||
.setBlendMode(Phaser.BlendModes.ADD); // Light atmosphere
|
||||
|
||||
// 5. LIGHTING / DAY-NIGHT OVERLAY
|
||||
this.fog2 = this.add.tileSprite(0, 0, width, height, 'fog')
|
||||
.setOrigin(0, 0)
|
||||
.setAlpha(0.2)
|
||||
.setBlendMode(Phaser.BlendModes.ADD);
|
||||
|
||||
// Day/Night Overlay
|
||||
this.dayNightOverlay = this.add.rectangle(0, 0, width, height, 0x000000, 0).setOrigin(0, 0).setDepth(1000);
|
||||
|
||||
// UI Info
|
||||
this.infoText = this.add.text(10, 10, 'Time: 12:00', { font: '16px monospace', fill: '#fff' }).setDepth(2000);
|
||||
this.infoText = this.add.text(20, 20, 'Time: 12:00', {
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '18px',
|
||||
fill: '#ffffff',
|
||||
stroke: '#000000',
|
||||
strokeThickness: 3
|
||||
}).setDepth(2000);
|
||||
}
|
||||
|
||||
// 2. NALOGA: Pripravi funkcijo 'spawnTree(x, y, type)'
|
||||
spawnTree(x, y, type) {
|
||||
// Map simplified names to texture keys if needed, or use direct keys
|
||||
// Types: 'tree_faza1', 'tree_faza2', 'tree_small', 'tree_medium', 'tree_large', 'tree_dead'
|
||||
|
||||
let tree = this.add.image(x, y, type);
|
||||
|
||||
// Custom scale logic based on type could go here, for now standardized or specific per tree
|
||||
if (type === 'tree_large') tree.setScale(0.8);
|
||||
else if (type === 'tree_medium') tree.setScale(0.6);
|
||||
else if (type === 'tree_small') tree.setScale(0.5);
|
||||
else tree.setScale(0.7); // Default for others
|
||||
|
||||
tree.setDepth(y); // Y-Sort
|
||||
tree.setOrigin(0.5, 0.95); // Pivot at bottom center
|
||||
|
||||
// Sway properties for update loop
|
||||
tree.swaySpeed = 0.001 + (Math.random() * 0.001);
|
||||
tree.swayOffset = Math.random() * 100;
|
||||
|
||||
this.trees.push(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
generateVegetation(w, h) {
|
||||
// Randomly place HIGH GRASS (for cutting/hiding)
|
||||
// Place Gras (Foliage)
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let x = Phaser.Math.Between(50, w - 50);
|
||||
let y = Phaser.Math.Between(50, h - 50);
|
||||
|
||||
// Swaying tall grass
|
||||
let grass = this.add.image(x, y, 'grass_tall');
|
||||
grass.setScale(0.15 + (Math.random() * 0.1)); // Random size
|
||||
grass.setDepth(y); // Y-sort
|
||||
grass.setOrigin(0.5, 1); // Anchor at bottom
|
||||
grass.setScale(0.15 + (Math.random() * 0.1));
|
||||
grass.setDepth(y);
|
||||
grass.setOrigin(0.5, 1);
|
||||
grass.swaySpeed = 0.002 + (Math.random() * 0.002);
|
||||
grass.swayOffset = Math.random() * 100;
|
||||
this.grasses.push(grass);
|
||||
}
|
||||
|
||||
// Randomly place TREES
|
||||
for (let i = 0; i < 15; i++) {
|
||||
// Place Trees using spawnTree
|
||||
const treeTypes = ['tree_faza1', 'tree_faza2', 'tree_small', 'tree_medium', 'tree_large', 'tree_dead'];
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let x = Phaser.Math.Between(50, w - 50);
|
||||
let y = Phaser.Math.Between(50, h - 50);
|
||||
let type = Phaser.Math.RND.pick(['tree_small', 'tree_medium', 'tree_large', 'tree_dead']);
|
||||
let type = Phaser.Math.RND.pick(treeTypes);
|
||||
|
||||
let tree = this.add.image(x, y, type);
|
||||
// Size adjustments based on type
|
||||
if (type === 'tree_large') tree.setScale(0.8);
|
||||
else if (type === 'tree_medium') tree.setScale(0.6);
|
||||
else tree.setScale(0.5);
|
||||
|
||||
tree.setDepth(y);
|
||||
tree.setOrigin(0.5, 0.95); // Anchor near bottom
|
||||
tree.swaySpeed = 0.001 + (Math.random() * 0.001); // Slower sway for trees
|
||||
tree.swayOffset = Math.random() * 100;
|
||||
this.trees.push(tree);
|
||||
this.spawnTree(x, y, type);
|
||||
}
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
// --- 1. WIND ANIMATION (Manual Vertex Sway Simulation) ---
|
||||
// Since we aren't using a complex shader pipeline yet, we use rotation/skew
|
||||
|
||||
// Wind Animation
|
||||
this.grasses.forEach(g => {
|
||||
// Simple sway using Sine wave
|
||||
g.rotation = Math.sin((time * g.swaySpeed) + g.swayOffset) * 0.1; // +/- 0.1 radians
|
||||
g.rotation = Math.sin((time * g.swaySpeed) + g.swayOffset) * 0.1;
|
||||
});
|
||||
|
||||
this.trees.forEach(t => {
|
||||
// Trees sway less
|
||||
t.rotation = Math.sin((time * t.swaySpeed) + t.swayOffset) * 0.03;
|
||||
});
|
||||
|
||||
// --- 2. FOG MOVEMENT ---
|
||||
// Fog Movement
|
||||
this.fog1.tilePositionX += 0.5;
|
||||
this.fog2.tilePositionX += 0.2;
|
||||
this.fog2.tilePositionX += 0.2; // Parallax
|
||||
this.fog2.tilePositionY += 0.1;
|
||||
|
||||
// --- 3. DAY/NIGHT CYCLE ---
|
||||
this.baseTime += (delta * 0.001 * this.timeSpeed); // Simulated hours
|
||||
// Day/Night Cycle
|
||||
this.baseTime += (delta * 0.001 * this.timeSpeed);
|
||||
if (this.baseTime >= 24) this.baseTime = 0;
|
||||
|
||||
this.updateLighting(this.baseTime);
|
||||
|
||||
164
src/scenes/GrassScene_Clean.js
Normal file
164
src/scenes/GrassScene_Clean.js
Normal file
@@ -0,0 +1,164 @@
|
||||
export default class GrassScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'GrassScene' });
|
||||
this.baseTime = 12; // Start at 12:00
|
||||
this.timeSpeed = 0.5;
|
||||
}
|
||||
|
||||
preload() {
|
||||
console.log("🌿 Loading Clean Assets...");
|
||||
|
||||
// 1. PATHS (Absolute from server root)
|
||||
const PATHS = {
|
||||
ground: '/assets/DEMO_FAZA1/Ground/',
|
||||
veg: '/assets/DEMO_FAZA1/Vegetation/'
|
||||
};
|
||||
|
||||
// 2. LOAD ASSETS
|
||||
// Ground
|
||||
this.load.image('ground_base', PATHS.ground + 'tla_trava_tekstura.png');
|
||||
|
||||
// Vegetation - Grass
|
||||
this.load.image('grass_tuft', PATHS.veg + 'trava_sop.png');
|
||||
this.load.image('grass_tall', PATHS.veg + 'visoka_trava.png');
|
||||
|
||||
// Vegetation - Trees (All phases)
|
||||
this.load.image('tree_f1', PATHS.veg + 'drevo_faza_1.png'); // Kalcek
|
||||
this.load.image('tree_f2', PATHS.veg + 'drevo_faza_2.png'); // Mlado
|
||||
this.load.image('tree_small', PATHS.veg + 'drevo_majhno.png');
|
||||
this.load.image('tree_medium', PATHS.veg + 'drevo_srednje.png');
|
||||
this.load.image('tree_large', PATHS.veg + 'drevo_veliko.png'); // Hero
|
||||
|
||||
// Error handling
|
||||
this.load.on('loaderror', (file) => {
|
||||
console.error('FAILED TO LOAD:', file.src);
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
const { width, height } = this.scale;
|
||||
|
||||
// 1. BACKGROUND (Tiling Sprite - Base Layer)
|
||||
this.ground = this.add.tileSprite(0, 0, width, height, 'ground_base')
|
||||
.setOrigin(0, 0);
|
||||
|
||||
// 2. VEGETATION GROUPS
|
||||
this.grasses = [];
|
||||
this.trees = [];
|
||||
|
||||
// 3. GENERATE WORLD
|
||||
this.generateGrass(width, height);
|
||||
this.generateTrees(width, height);
|
||||
|
||||
// 4. DAY/NIGHT OVERLAY
|
||||
this.dayNightOverlay = this.add.rectangle(0, 0, width, height, 0x000000, 0)
|
||||
.setOrigin(0, 0)
|
||||
.setDepth(9000); // Top layer
|
||||
|
||||
// 5. UI INFO
|
||||
this.infoText = this.add.text(20, 20, 'Time: 12:00', {
|
||||
fontFamily: 'monospace', fontSize: '24px', fill: '#ffffff', stroke: '#000000', strokeThickness: 4
|
||||
}).setDepth(10000);
|
||||
}
|
||||
|
||||
generateGrass(w, h) {
|
||||
// A) Small Tufts (Decoration) - High Density
|
||||
// "Naključno razporedi trava_sop.png za vizualno gostoto"
|
||||
for (let i = 0; i < 150; i++) {
|
||||
let x = Phaser.Math.Between(0, w);
|
||||
let y = Phaser.Math.Between(0, h);
|
||||
|
||||
let tuft = this.add.image(x, y, 'grass_tuft');
|
||||
tuft.setScale(0.3 + Math.random() * 0.2); // Random size
|
||||
tuft.setAlpha(0.9);
|
||||
tuft.setDepth(y); // Simple Y-sort
|
||||
}
|
||||
|
||||
// B) Tall Grass (Interactive) - Medium Density
|
||||
// "Postavi visoka_trava.png ... dodaj nežen sinusni efekt"
|
||||
for (let i = 0; i < 40; i++) {
|
||||
let x = Phaser.Math.Between(50, w - 50);
|
||||
let y = Phaser.Math.Between(50, h - 50);
|
||||
|
||||
let grass = this.add.image(x, y, 'grass_tall');
|
||||
grass.setScale(0.4);
|
||||
grass.setOrigin(0.5, 1); // Pivot at bottom
|
||||
grass.setDepth(y);
|
||||
|
||||
// Custom properties for wind animation
|
||||
grass.swaySpeed = 0.002 + Math.random() * 0.001;
|
||||
grass.swayOffset = Math.random() * 100;
|
||||
|
||||
this.grasses.push(grass);
|
||||
}
|
||||
}
|
||||
|
||||
generateTrees(w, h) {
|
||||
const treeTypes = ['tree_f1', 'tree_f2', 'tree_small', 'tree_medium', 'tree_large'];
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
let x = Phaser.Math.Between(50, w - 50);
|
||||
let y = Phaser.Math.Between(50, h - 50);
|
||||
|
||||
// Randomly pick a growth stage
|
||||
let type = Phaser.Math.RND.pick(treeTypes);
|
||||
|
||||
let tree = this.add.image(x, y, type);
|
||||
tree.setOrigin(0.5, 0.9); // Pivot near bottom
|
||||
tree.setDepth(y); // Sort by Y
|
||||
|
||||
// Scale adjustments to look good
|
||||
if (type === 'tree_large') tree.setScale(0.8);
|
||||
else if (type === 'tree_medium') tree.setScale(0.7);
|
||||
else tree.setScale(0.6);
|
||||
|
||||
// Subtle sway for trees too
|
||||
tree.swaySpeed = 0.0005 + Math.random() * 0.0005;
|
||||
tree.swayOffset = Math.random() * 100;
|
||||
|
||||
this.trees.push(tree);
|
||||
}
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
// 1. WIND ANIMATION
|
||||
// "Dodaj nežen sinusni efekt za plapolanje"
|
||||
this.grasses.forEach(g => {
|
||||
g.rotation = Math.sin((time * g.swaySpeed) + g.swayOffset) * 0.15; // Stronger sway for grass
|
||||
});
|
||||
|
||||
this.trees.forEach(t => {
|
||||
t.rotation = Math.sin((time * t.swaySpeed) + t.swayOffset) * 0.02; // Very subtle for trees
|
||||
});
|
||||
|
||||
// 2. DAY/NIGHT CYCLE
|
||||
this.baseTime += (delta * 0.001 * this.timeSpeed);
|
||||
if (this.baseTime >= 24) this.baseTime = 0;
|
||||
this.updateLighting(this.baseTime);
|
||||
|
||||
// Update UI
|
||||
let hour = Math.floor(this.baseTime);
|
||||
let minute = Math.floor((this.baseTime % 1) * 60).toString().padStart(2, '0');
|
||||
this.infoText.setText(`Time: ${hour}:${minute}`);
|
||||
}
|
||||
|
||||
updateLighting(hour) {
|
||||
let alpha = 0;
|
||||
let color = 0x000000;
|
||||
|
||||
// Simple Day/Night Logic
|
||||
if (hour >= 20 || hour < 5) {
|
||||
alpha = 0.7; // Night
|
||||
color = 0x000022;
|
||||
} else if (hour >= 5 && hour < 8) {
|
||||
alpha = 0.3; // Dawn
|
||||
color = 0xFF4500;
|
||||
} else if (hour >= 18 && hour < 20) {
|
||||
alpha = 0.4; // Dusk
|
||||
color = 0xFF4500;
|
||||
} else {
|
||||
alpha = 0; // Day
|
||||
}
|
||||
this.dayNightOverlay.setFillStyle(color, alpha);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user