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

View File

@@ -18,21 +18,37 @@ class GameScene extends Phaser.Scene {
// Setup kamere
this.cameras.main.setBackgroundColor('#1a1a2e');
// Initialize Isometric Utils
this.iso = new IsometricUtils();
// Inicializiraj terrain sistem - 100x100 mapa
console.log('🌍 Initializing terrain...');
this.terrainSystem = new TerrainSystem(this, 100, 100);
this.terrainSystem.generate();
try {
this.terrainSystem = new TerrainSystem(this, 100, 100);
this.terrainSystem.generate();
// Terrain offset
this.terrainOffsetX = width / 2;
this.terrainOffsetY = 100;
this.terrainContainer = this.terrainSystem.render(this.terrainOffsetX, this.terrainOffsetY);
// Terrain offset
this.terrainOffsetX = width / 2;
this.terrainOffsetY = 100;
// Dodaj igralca - spawn na sredini mape S TERRAIN OFFSETOM
// Initialization for culling
this.terrainSystem.init(this.terrainOffsetX, this.terrainOffsetY);
// Initial force update to render active tiles before first frame
this.terrainSystem.updateCulling(this.cameras.main);
// FAZA 14: Spawn Ruin (Town Project) at fixed location near player
console.log('🏚️ Spawning Ruin...');
this.terrainSystem.placeStructure(55, 55, 'ruin');
} catch (e) {
console.error("Terrain system failed:", e);
}
// Dodaj igralca
console.log('👤 Initializing player...');
this.player = new Player(this, 50, 50, this.terrainOffsetX, this.terrainOffsetY);
// Dodaj 3 NPCje - random pozicije
// Dodaj 3 NPCje
console.log('🧟 Initializing NPCs...');
const npcTypes = ['zombie', 'villager', 'merchant'];
for (let i = 0; i < 3; i++) {
@@ -42,36 +58,59 @@ class GameScene extends Phaser.Scene {
this.npcs.push(npc);
}
// Kamera sledi igralcu
this.cameras.main.startFollow(this.player.sprite, true, 0.1, 0.1);
// Kamera sledi igralcu z izboljšanimi nastavitvami
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0); // Instant follow (was 0.1)
// Nastavi deadzone (100px border)
this.cameras.main.setDeadzone(100, 100);
// Round pixels za crisp pixel art
this.cameras.main.roundPixels = true;
// Parallax oblaki
this.createClouds();
// Kamera kontrole
this.setupCamera();
// UI elementi
this.createUI();
// Initialize Time & Stats
console.log('⏳ Initializing Time & Stats...');
this.timeSystem = new TimeSystem(this);
this.timeSystem.create();
// Debug info
this.debugText = this.add.text(10, 10, '', {
fontFamily: 'Courier New',
fontSize: '12px',
fill: '#ffffff',
backgroundColor: '#000000',
padding: { x: 5, y: 3 }
});
this.debugText.setScrollFactor(0);
this.debugText.setDepth(1000);
this.statsSystem = new StatsSystem(this);
this.inventorySystem = new InventorySystem(this);
this.interactionSystem = new InteractionSystem(this);
this.farmingSystem = new FarmingSystem(this);
this.buildingSystem = new BuildingSystem(this);
// FPS counter
this.fpsText = this.add.text(10, height - 30, 'FPS: 60', {
fontFamily: 'Courier New',
fontSize: '14px',
fill: '#00ff41'
});
this.fpsText.setScrollFactor(0);
this.fpsText.setDepth(1000);
// Initialize Weather System
console.log('🌦️ Initializing Weather System...');
this.weatherSystem = new WeatherSystem(this);
console.log('✅ GameScene ready - FAZA 3!');
// Initialize Day/Night Cycle
console.log('🌅 Initializing Day/Night System...');
this.dayNightSystem = new DayNightSystem(this, this.timeSystem);
// Initialize Sound Manager
console.log('🎵 Initializing Sound Manager...');
this.soundManager = new SoundManager(this);
// Initialize Parallax System
console.log('🌄 Initializing Parallax System...');
this.parallaxSystem = new ParallaxSystem(this);
// Launch UI Scene
console.log('🖥️ Launching UI Scene...');
this.scene.launch('UIScene');
// Initialize Save System
this.saveSystem = new SaveSystem(this);
// Auto-load if available (optional, for now manual)
// this.saveSystem.loadGame();
console.log('✅ GameScene ready - FAZA 17!');
}
setupCamera() {
@@ -88,51 +127,81 @@ class GameScene extends Phaser.Scene {
cam.setZoom(newZoom);
});
// Pan kontrole (Right click + drag) - DISABLED za FAZA 2
// Player movement sedaj uporablja WASD
// Q/E za zoom
this.zoomKeys = this.input.keyboard.addKeys({
zoomIn: Phaser.Input.Keyboard.KeyCodes.Q,
zoomOut: Phaser.Input.Keyboard.KeyCodes.E
});
}
createUI() {
const width = this.cameras.main.width;
// Naslov
const title = this.add.text(width / 2, 20, 'FAZA 3: NPC-ji in Dekoracije', {
fontFamily: 'Courier New',
fontSize: '20px',
fill: '#00ff41',
fontStyle: 'bold'
});
title.setOrigin(0.5, 0);
title.setScrollFactor(0);
title.setDepth(1000);
// Kontrole info
const controlsText = this.add.text(width - 10, 10,
'Kontrole:\n' +
'WASD - Gibanje igralca\n' +
'Q/E - Zoom\n' +
'Mouse Wheel - Zoom',
{
fontFamily: 'Courier New',
fontSize: '11px',
fill: '#888888',
backgroundColor: '#000000',
padding: { x: 5, y: 3 },
align: 'right'
// Save/Load Keys
this.input.keyboard.on('keydown-F8', () => {
// Save
if (this.saveSystem) {
this.saveSystem.saveGame();
console.log('💾 Game Saved! (F8)');
}
);
controlsText.setOrigin(1, 0);
controlsText.setScrollFactor(0);
controlsText.setDepth(1000);
});
this.input.keyboard.on('keydown-F9', () => {
// Load
if (this.saveSystem) {
this.saveSystem.loadGame();
console.log('📂 Game Loaded! (F9)');
}
});
// Build Mode Keys
this.input.keyboard.on('keydown-B', () => {
if (this.buildingSystem) this.buildingSystem.toggleBuildMode();
});
this.input.keyboard.on('keydown-ONE', () => {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('fence');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(0);
});
this.input.keyboard.on('keydown-TWO', () => {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('wall');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(1);
});
this.input.keyboard.on('keydown-THREE', () => {
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('house');
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(2);
});
// Soft Reset (F4) - Force Reload Page
this.input.keyboard.on('keydown-F4', () => {
console.log('🔄 Soft Reset Initiated (Force Reload)...');
window.location.reload();
});
// Mute Toggle (M key)
this.input.keyboard.on('keydown-M', () => {
if (this.soundManager) {
this.soundManager.toggleMute();
}
});
}
update(time, delta) {
// Update Systems
if (this.timeSystem) this.timeSystem.update(delta);
if (this.statsSystem) this.statsSystem.update(delta);
if (this.interactionSystem) this.interactionSystem.update(delta);
if (this.farmingSystem) this.farmingSystem.update(delta);
if (this.weatherSystem) this.weatherSystem.update(delta);
if (this.dayNightSystem) this.dayNightSystem.update();
// Update Parallax (foreground grass fading)
if (this.parallaxSystem && this.player) {
const playerPos = this.player.getPosition();
const screenPos = this.iso.toScreen(playerPos.x, playerPos.y);
this.parallaxSystem.update(
screenPos.x + this.terrainOffsetX,
screenPos.y + this.terrainOffsetY
);
}
// Update player
if (this.player) {
this.player.update(delta);
@@ -143,32 +212,61 @@ class GameScene extends Phaser.Scene {
npc.update(delta);
}
// Update FPS
if (this.fpsText) {
this.fpsText.setText(`FPS: ${Math.round(this.game.loop.actualFps)}`);
// Update Terrain Culling
if (this.terrainSystem) {
this.terrainSystem.updateCulling(this.cameras.main);
}
// Zoom controls
const cam = this.cameras.main;
if (this.zoomKeys) {
if (this.zoomKeys.zoomIn.isDown) {
cam.setZoom(Phaser.Math.Clamp(cam.zoom + 0.01, 0.3, 2.0));
}
if (this.zoomKeys.zoomOut.isDown) {
cam.setZoom(Phaser.Math.Clamp(cam.zoom - 0.01, 0.3, 2.0));
// Update clouds
if (this.clouds) {
for (const cloud of this.clouds) {
cloud.sprite.x += cloud.speed * (delta / 1000);
if (cloud.sprite.x > this.terrainOffsetX + 2000) { // Reset far right
cloud.sprite.x = this.terrainOffsetX - 2000;
cloud.sprite.y = Phaser.Math.Between(0, 1000);
}
}
}
// Debug info update
if (this.debugText && this.player) {
// Send debug info to UI Scene
if (this.player) {
const playerPos = this.player.getPosition();
const cam = this.cameras.main;
const visibleTiles = this.terrainSystem ? this.terrainSystem.visibleTiles.size : 0;
this.debugText.setText(
`FAZA 3 - NPCs & Decorations\n` +
`Zoom: ${cam.zoom.toFixed(2)}\n` +
`Player: (${playerPos.x}, ${playerPos.y})\n` +
`NPCs: ${this.npcs.length}`
);
const uiScene = this.scene.get('UIScene');
if (uiScene && uiScene.debugText) {
const activeCrops = this.terrainSystem && this.terrainSystem.cropsMap ? this.terrainSystem.cropsMap.size : 0;
const dropsCount = this.interactionSystem && this.interactionSystem.drops ? this.interactionSystem.drops.length : 0;
uiScene.debugText.setText(
`FAZA 11 - Building\n` +
`[F5] Save | [F9] Load | [B] Build Mode\n` +
`Time: ${this.timeSystem ? this.timeSystem.gameTime.toFixed(1) : '?'}h\n` +
`Active Crops: ${activeCrops}\n` +
`Loot Drops: ${dropsCount}\n` +
`Player: (${playerPos.x}, ${playerPos.y})`
);
}
}
}
createClouds() {
if (!this.textures.exists('cloud')) TextureGenerator.createCloudSprite(this, 'cloud');
this.clouds = [];
console.log('☁️ Creating parallax clouds...');
for (let i = 0; i < 8; i++) {
const x = Phaser.Math.Between(-1000, 3000);
const y = Phaser.Math.Between(-500, 1500);
const cloud = this.add.sprite(x, y, 'cloud');
cloud.setAlpha(0.4);
cloud.setScrollFactor(0.2); // Parallax effect
cloud.setDepth(2000); // Nad vsem
cloud.setScale(Phaser.Math.FloatBetween(2, 4)); // Veliki oblaki
this.clouds.push({ sprite: cloud, speed: Phaser.Math.FloatBetween(10, 30) });
}
}
}