FAZA 17: 2.5D Minecraft-Style Terrain + Y-Layer Stacking + Custom Sprites

COMPLETED FEATURES:

 Custom Sprite Integration:
- Player, Zombie, Merchant sprites (0.2 scale)
- 11 custom sprites + 5 asset packs loaded
- Auto-transparency processing (white/brown removal)
- Gravestone system with atlas extraction

 2.5D Minecraft-Style Terrain:
- Volumetric blocks with 25px thickness
- Strong left/right side shading (30%/50% darker)
- Minecraft-style texture patterns (grass, dirt, stone)
- Crisp black outlines for definition

 Y-Layer Stacking System:
- GRASS_FULL: All green (elevation > 0.7)
- GRASS_TOP: Green top + brown sides (elevation 0.4-0.7)
- DIRT: All brown (elevation < 0.4)
- Dynamic terrain depth based on height

 Floating Island World Edge:
- Stone cliff walls at map borders
- 2-tile transition zone
- Elevation flattening for cliff drop-off effect
- 100x100 world with defined boundaries

 Performance & Polish:
- Canvas renderer for pixel-perfect sharpness
- CSS image-rendering: crisp-edges
- willReadFrequently optimization
- No Canvas2D warnings

 Technical:
- 3D volumetric trees and rocks
- Hybrid rendering (2.5D terrain + 2D characters)
- Procedural texture generation
- Y-layer aware terrain type selection
This commit is contained in:
2025-12-07 01:44:16 +01:00
parent 34a2d07538
commit 9eb57ed117
60 changed files with 5082 additions and 195 deletions

107
src/systems/TimeSystem.js Normal file
View File

@@ -0,0 +1,107 @@
class TimeSystem {
constructor(scene) {
this.scene = scene;
// Konfiguracija
this.fullDaySeconds = 300; // 5 minut za cel dan (real-time)
this.startTime = 8; // Začetek ob 8:00
// Stanje
this.gameTime = this.startTime; // 0 - 24
this.dayCount = 1;
// Lighting overlay
this.lightOverlay = null; // Ustvarjen bo v GameScene ali tu? Bolje tu če imamo dostop.
}
create() {
// Overlay za temo
// Uporabimo velik pravokotnik čez cel ekran, ki je fixiran na kamero
// Ampak ker imamo UIScene, je bolje da je overlay v GameScene, ampak nad vsem razen UI.
// Najlažje: canvas tinting ali graphics overlay.
// Za preprostost: Modificiramo ambient light ali tintamo igralca/teren?
// Phaser 3 ima setTint.
// Najboljši efekt za 2D: Temno moder rectangle z 'MULTIPLY' blend mode čez GameScene.
const width = this.scene.cameras.main.width * 2; // Malo večji za varnost
const height = this.scene.cameras.main.height * 2;
this.lightOverlay = this.scene.add.rectangle(0, 0, width, height, 0x000022);
this.lightOverlay.setScrollFactor(0);
this.lightOverlay.setDepth(9000); // Pod UI (UI je v drugi sceni), ampak nad igro
this.lightOverlay.setBlendMode(Phaser.BlendModes.MULTIPLY);
this.lightOverlay.setAlpha(0); // Začetek dan (0 alpha)
}
update(delta) {
// Povečaj čas
// delta je v ms.
// fullDaySeconds = 24 game hours.
// 1 game hour = fullDaySeconds / 24 seconds.
const seconds = delta / 1000;
const gameHoursPerRealSecond = 24 / this.fullDaySeconds;
this.gameTime += seconds * gameHoursPerRealSecond;
if (this.gameTime >= 24) {
this.gameTime -= 24;
this.dayCount++;
console.log(`🌞 Day ${this.dayCount} started!`);
}
this.updateLighting();
this.updateUI();
}
updateLighting() {
if (!this.lightOverlay) return;
// Izračunaj svetlobo (Alpha vrednost senc)
// 0 = Dan (Prozoren overlay)
// 0.8 = Polnoč (Temen overlay)
let alpha = 0;
const t = this.gameTime;
// Preprosta logika:
// 6:00 - 18:00 = Dan (0 alpha)
// 18:00 - 20:00 = Mrak (prehod 0 -> 0.7)
// 20:00 - 4:00 = Noč (0.7 alpha)
// 4:00 - 6:00 = Jutro (prehod 0.7 -> 0)
if (t >= 6 && t < 18) {
alpha = 0; // Dan
} else if (t >= 18 && t < 20) {
alpha = ((t - 18) / 2) * 0.7; // Mrak
} else if (t >= 20 || t < 4) {
alpha = 0.7; // Noč
} else if (t >= 4 && t < 6) {
alpha = 0.7 - ((t - 4) / 2) * 0.7; // Jutro
}
this.lightOverlay.setAlpha(alpha);
}
updateUI() {
const uiScene = this.scene.scene.get('UIScene');
if (uiScene && uiScene.clockText) {
const hours = Math.floor(this.gameTime);
const minutes = Math.floor((this.gameTime - hours) * 60);
const timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
uiScene.clockText.setText(`Day ${this.dayCount} - ${timeString}`);
}
}
getCurrentHour() {
return Math.floor(this.gameTime);
}
getGameTime() {
return this.gameTime;
}
getDayCount() {
return this.dayCount;
}
}