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:
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user