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

@@ -5,32 +5,125 @@ class PreloadScene extends Phaser.Scene {
}
preload() {
console.log('📦 PreloadScene: Loading assets...');
console.log(' PreloadScene: Loading assets...');
// TODO: Tu bomo nalagali sprite-e, tile-e, audio, itd.
// Za fazo 0 pustimo prazno - samo testiramo osnovni setup
// Load ALL custom sprites
this.load.image('player_sprite', 'assets/player_sprite.png');
this.load.image('zombie_sprite', 'assets/zombie_sprite.png');
this.load.image('merchant_sprite', 'assets/merchant_sprite.png');
this.load.image('house_sprite', 'assets/house_sprite.png');
this.load.image('stone_sprite', 'assets/stone_sprite.png');
this.load.image('tree_sprite', 'assets/tree_sprite.png');
this.load.image('grass_sprite', 'assets/grass_sprite.png');
this.load.image('grass_tile', 'assets/grass_tile.png');
this.load.image('leaf_sprite', 'assets/leaf_sprite.png');
this.load.image('wheat_sprite', 'assets/wheat_sprite.png');
this.load.image('stone_texture', 'assets/stone_texture.png');
// New asset packs
this.load.image('objects_pack', 'assets/objects_pack.png');
this.load.image('walls_pack', 'assets/walls_pack.png');
this.load.image('ground_tiles', 'assets/ground_tiles.png');
this.load.image('objects_pack2', 'assets/objects_pack2.png');
this.load.image('trees_vegetation', 'assets/trees_vegetation.png');
// Wait for load completion then process transparency
this.load.once('complete', () => {
this.processAllTransparency();
});
}
processAllTransparency() {
// Process ALL sprites to remove backgrounds
const spritesToProcess = [
'player_sprite',
'zombie_sprite',
'merchant_sprite',
'house_sprite',
'stone_sprite',
'tree_sprite',
'grass_sprite',
'leaf_sprite',
'wheat_sprite',
'stone_texture'
];
spritesToProcess.forEach(spriteKey => {
this.processSpriteTransparency(spriteKey);
});
console.log('✅ All sprites transparency processed!');
}
processSpriteTransparency(spriteKey) {
if (!this.textures.exists(spriteKey)) return;
const texture = this.textures.get(spriteKey);
const source = texture.getSourceImage();
// Create canvas to process image
const canvas = document.createElement('canvas');
canvas.width = source.width;
canvas.height = source.height;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
// Draw original image
ctx.drawImage(source, 0, 0);
// Get image data
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Remove backgrounds
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Remove white/light gray backgrounds (all sprites)
if (r > 200 && g > 200 && b > 200) {
data[i + 3] = 0;
}
// Special: Remove brown/tan backgrounds (merchant sprite)
if (spriteKey === 'merchant_sprite') {
// Brown detection: R > G > B, warm tones
const isBrown = r > 100 && r > g && g > b && (r - b) > 40;
if (isBrown) {
data[i + 3] = 0;
}
}
}
// Put processed data back
ctx.putImageData(imageData, 0, 0);
// Create new texture from processed canvas
this.textures.remove(spriteKey);
this.textures.addCanvas(spriteKey, canvas);
}
create() {
console.log('✅ PreloadScene: Assets loaded!');
window.gameState.currentScene = 'PreloadScene';
// Prikaz začetnega sporočila
const width = this.cameras.main.width;
const height = this.cameras.main.height;
const title = this.add.text(width / 2, height / 2 - 50, 'NOVAFARMA', {
const title = this.add.text(width / 2, height / 2 - 50, 'KRVAVA ŽETEV', {
fontFamily: 'Courier New',
fontSize: '48px',
fill: '#00ff41',
fontStyle: 'bold'
fill: '#ff0000',
fontStyle: 'bold',
stroke: '#000000',
strokeThickness: 6
});
title.setOrigin(0.5);
const subtitle = this.add.text(width / 2, height / 2 + 10, '2.5D Isometric Survival Game', {
const subtitle = this.add.text(width / 2, height / 2 + 10, 'Zombie Roots', {
fontFamily: 'Courier New',
fontSize: '20px',
fill: '#ffffff'
fontSize: '24px',
fill: '#00ff41'
});
subtitle.setOrigin(0.5);
@@ -41,7 +134,6 @@ class PreloadScene extends Phaser.Scene {
});
instruction.setOrigin(0.5);
// Blinking effect
this.tweens.add({
targets: instruction,
alpha: 0.3,
@@ -50,10 +142,25 @@ class PreloadScene extends Phaser.Scene {
repeat: -1
});
// Pritisk SPACE za začetek igre
this.input.keyboard.once('keydown-SPACE', () => {
console.log('🎮 Starting GameScene...');
this.scene.start('GameScene');
const startGame = () => {
console.log('🎮 Starting StoryScene...');
this.input.keyboard.off('keydown');
this.input.off('pointerdown');
this.scene.start('StoryScene');
};
this.time.delayedCall(3000, () => {
startGame();
});
this.input.keyboard.on('keydown', (event) => {
if (event.code === 'Space' || event.code === 'Enter') {
startGame();
}
});
this.input.on('pointerdown', () => {
startGame();
});
}
}