506 lines
18 KiB
JavaScript
506 lines
18 KiB
JavaScript
// Preload Scene - Nalaganje assetov
|
|
class PreloadScene extends Phaser.Scene {
|
|
constructor() {
|
|
super({ key: 'PreloadScene' });
|
|
}
|
|
|
|
preload() {
|
|
console.log('⏳ PreloadScene: Loading assets...');
|
|
|
|
this.createLoadingBar();
|
|
|
|
// 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');
|
|
|
|
// User-uploaded pixel art assets (original)
|
|
this.load.image('flowers', 'assets/flowers.png');
|
|
this.load.image('tree_green', 'assets/tree_green.png');
|
|
this.load.image('tree_blue', 'assets/tree_blue.png');
|
|
this.load.image('tree_dead', 'assets/tree_dead.png');
|
|
this.load.image('rock_asset', 'assets/rock_asset.png');
|
|
|
|
// FINAL TREES (User Uploaded)
|
|
this.load.image('tree_green_final', 'assets/tree_green_final.png');
|
|
this.load.image('tree_blue_final', 'assets/tree_blue_final.png');
|
|
this.load.image('tree_dead_final', 'assets/tree_dead_final.png');
|
|
|
|
// STARDEW VALLEY FOREST TREES (NEW!)
|
|
this.load.image('tree_purple', 'assets/tree_purple.png');
|
|
this.load.image('tree_apple', 'assets/tree_apple.png');
|
|
this.load.image('tree_pear', 'assets/tree_pear.png');
|
|
this.load.image('tree_cherry', 'assets/tree_cherry.png');
|
|
this.load.image('tree_sapling', 'assets/tree_green_final.png'); // Reuse green as sapling
|
|
|
|
// NEW transparent tree/rock assets
|
|
this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); // Keep for backup
|
|
|
|
this.load.image('tree_green_new', 'assets/tree_green_new.png');
|
|
this.load.image('rock_1', 'assets/rock_1.png');
|
|
this.load.image('rock_2', 'assets/rock_2.png');
|
|
this.load.image('rock_small', 'assets/rock_small.png');
|
|
this.load.image('tree_dead_new', 'assets/tree_dead_new.png');
|
|
this.load.image('flowers_new', 'assets/flowers_new.png');
|
|
this.load.image('merchant_new', 'assets/merchant_new.png');
|
|
this.load.image('elite_zombie', 'assets/elite_zombie.png');
|
|
|
|
// Fence old for abandoned houses
|
|
this.load.image('fence_old', 'assets/fence_isometric.png'); // Reuse fence for old houses
|
|
|
|
// AI-Generated NPC Sprites (with cache-busting)
|
|
const cacheBust = Date.now();
|
|
this.load.image('cow', `assets/cow.png?v=${cacheBust}`);
|
|
this.load.image('chicken', `assets/chicken.png?v=${cacheBust}`);
|
|
this.load.image('troll', `assets/troll.png?v=${cacheBust}`);
|
|
this.load.image('elf', `assets/elf.png?v=${cacheBust}`);
|
|
this.load.image('villager', `assets/villager.png?v=${cacheBust}`);
|
|
this.load.image('cow_mutant', `assets/cow_mutant.png?v=${cacheBust}`);
|
|
|
|
this.load.image('hill_sprite', 'assets/hill_sprite.png');
|
|
this.load.image('fence', 'assets/fence.png');
|
|
this.load.image('gravestone', 'assets/gravestone.png');
|
|
|
|
// City content assets
|
|
this.load.image('chest', 'assets/chest.png');
|
|
this.load.image('spawner', 'assets/spawner.png');
|
|
this.load.image('signpost_city', 'assets/signpost_city.png');
|
|
this.load.image('signpost_farm', 'assets/signpost_farm.png');
|
|
this.load.image('signpost_both', 'assets/signpost_both.png');
|
|
this.load.image('city_wall', 'assets/city_wall.png');
|
|
this.load.image('road_tile', 'assets/road_tile.png');
|
|
this.load.image('farm_zone', 'assets/farm_zone.png');
|
|
this.load.image('fence_full', 'assets/fence_full.png');
|
|
this.load.image('wall_damaged', 'assets/wall_damaged.png');
|
|
|
|
|
|
// Voxel stil asset-i (2.5D)
|
|
this.load.image('tree_voxel_green', 'assets/tree_voxel_green.png');
|
|
this.load.image('tree_voxel_blue', 'assets/tree_voxel_blue.png');
|
|
this.load.image('tree_voxel_dead', 'assets/tree_voxel_dead.png');
|
|
this.load.image('rock_voxel', 'assets/rock_voxel.png');
|
|
|
|
// NEW ISOMETRIC 2.5D ASSETS (Stardew Valley style)
|
|
// Buildings & Structures
|
|
this.load.image('barn_isometric', 'assets/barn_isometric.png');
|
|
this.load.image('farmhouse_isometric', 'assets/farmhouse_isometric.png');
|
|
this.load.image('fence_isometric', 'assets/fence_isometric.png');
|
|
this.load.image('bridge_isometric', 'assets/bridge_isometric.png');
|
|
this.load.image('blacksmith_workshop', 'assets/blacksmith_workshop.png');
|
|
this.load.image('ruins_building', 'assets/ruins_building.png');
|
|
|
|
// Farm & Crops
|
|
this.load.image('soil_tilled', 'assets/soil_tilled.png');
|
|
this.load.image('carrots_stages', 'assets/carrots_stages.png');
|
|
this.load.image('flowers_pink_isometric', 'assets/flowers_pink_isometric.png');
|
|
|
|
// Characters - SPRITESHEETS (6 frames @ 64x64 each)
|
|
this.load.spritesheet('player_dreadlocks', 'assets/player_dreadlocks.png', {
|
|
frameWidth: 64,
|
|
frameHeight: 64
|
|
});
|
|
this.load.spritesheet('zombie_worker', 'assets/zombie_worker.png', {
|
|
frameWidth: 64,
|
|
frameHeight: 64
|
|
});
|
|
this.load.image('grave_zombie', 'assets/grave_zombie.png');
|
|
|
|
// Fence pieces (separate parts)
|
|
this.load.image('fence_post', 'assets/fence_post.png');
|
|
this.load.image('fence_horizontal', 'assets/fence_horizontal.png');
|
|
this.load.image('fence_vertical', 'assets/fence_vertical.png');
|
|
this.load.image('fence_corner', 'assets/fence_corner.png');
|
|
|
|
// Water frames are generated procedurally in TerrainSystem.createWaterFrames()
|
|
// No need to load external files
|
|
|
|
// Wait for load completion then process transparency
|
|
this.load.once('complete', () => {
|
|
this.processAllTransparency();
|
|
this.createAnimations();
|
|
});
|
|
|
|
// New Processed Animations (Standardized 64x64 strips)
|
|
this.load.spritesheet('player_walk', 'assets/sprites/player_walk_strip.png', { frameWidth: 64, frameHeight: 64 });
|
|
this.load.spritesheet('zombie_walk', 'assets/sprites/zombie_walk_strip.png', { frameWidth: 64, frameHeight: 64 });
|
|
}
|
|
|
|
createAnimations() {
|
|
if (this.anims.exists('player_walk_anim')) return;
|
|
|
|
// Old animations
|
|
this.anims.create({
|
|
key: 'player_walk_anim',
|
|
frames: this.anims.generateFrameNumbers('player_walk', { start: 0, end: 5 }),
|
|
frameRate: 12,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'zombie_walk_anim',
|
|
frames: this.anims.generateFrameNumbers('zombie_walk', { start: 0, end: 5 }),
|
|
frameRate: 8,
|
|
repeat: -1
|
|
});
|
|
|
|
// NEW: Isometric character animations (6 frames)
|
|
this.anims.create({
|
|
key: 'player_dreadlocks_walk',
|
|
frames: this.anims.generateFrameNumbers('player_dreadlocks', { start: 0, end: 5 }),
|
|
frameRate: 10,
|
|
repeat: -1
|
|
});
|
|
|
|
this.anims.create({
|
|
key: 'zombie_worker_walk',
|
|
frames: this.anims.generateFrameNumbers('zombie_worker', { start: 0, end: 5 }),
|
|
frameRate: 8,
|
|
repeat: -1
|
|
});
|
|
|
|
console.log('🎞️ Animations created!');
|
|
}
|
|
|
|
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',
|
|
// New pixel art assets
|
|
'flowers',
|
|
'tree_green',
|
|
'tree_blue',
|
|
'tree_dead',
|
|
'rock_asset',
|
|
|
|
// FINAL TREES
|
|
'tree_green_final',
|
|
'tree_blue_final',
|
|
'tree_dead_final',
|
|
|
|
// STARDEW VALLEY FOREST TREES
|
|
'tree_purple',
|
|
'tree_apple',
|
|
'tree_pear',
|
|
'tree_cherry',
|
|
'tree_sapling',
|
|
|
|
// NEW transparent assets
|
|
'tree_blue_new',
|
|
'tree_green_new',
|
|
'rock_1',
|
|
'rock_2',
|
|
'rock_small',
|
|
'merchant_new',
|
|
'elite_zombie',
|
|
'tree_dead_new',
|
|
'flowers_new',
|
|
'hill_sprite',
|
|
'fence',
|
|
'fence_old',
|
|
'gravestone',
|
|
// City content
|
|
'chest',
|
|
'spawner',
|
|
'signpost_city',
|
|
'signpost_farm',
|
|
'signpost_both',
|
|
// Voxel stil
|
|
'tree_voxel_green',
|
|
'tree_voxel_blue',
|
|
'tree_voxel_dead',
|
|
'rock_voxel',
|
|
|
|
// NEW ISOMETRIC 2.5D ASSETS - Remove transparency
|
|
'barn_isometric',
|
|
'farmhouse_isometric',
|
|
'fence_isometric',
|
|
'bridge_isometric',
|
|
'blacksmith_workshop',
|
|
'ruins_building',
|
|
'soil_tilled',
|
|
'carrots_stages',
|
|
'flowers_pink_isometric',
|
|
// NOTE: player_dreadlocks and zombie_worker are SPRITESHEETS - don't process!
|
|
'grave_zombie',
|
|
|
|
// NEW FENCE PIECES
|
|
'fence_post',
|
|
'fence_horizontal',
|
|
'fence_vertical',
|
|
'fence_corner',
|
|
|
|
// ANIMALS & NPCs
|
|
'chicken',
|
|
'cow',
|
|
'cow_mutant',
|
|
'elf',
|
|
'troll',
|
|
'villager',
|
|
'npc_merchant',
|
|
'npc_zombie',
|
|
|
|
// STRUCTURES
|
|
'structure_house',
|
|
'wall_damaged',
|
|
'city_wall',
|
|
|
|
// MISC OBJECTS
|
|
'wheat_sprite',
|
|
'grass_sprite',
|
|
'leaf_sprite',
|
|
'stone_sprite'
|
|
];
|
|
|
|
spritesToProcess.forEach(spriteKey => {
|
|
this.processSpriteTransparency(spriteKey);
|
|
});
|
|
|
|
// ULTRA AGGRESSIVE: Fence Post only
|
|
if (this.textures.exists('fence_post')) {
|
|
this.ultraRemoveBackground('fence_post');
|
|
}
|
|
|
|
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 - ULTRA AGGRESSIVE MODE!
|
|
for (let i = 0; i < data.length; i += 4) {
|
|
const r = data[i];
|
|
const g = data[i + 1];
|
|
const b = data[i + 2];
|
|
const a = data[i + 3];
|
|
|
|
// Skip if already transparent
|
|
if (a === 0) continue;
|
|
|
|
const brightness = (r + g + b) / 3;
|
|
|
|
// 1. Remove ALL grayscale colors (ANY shade of gray)
|
|
const isGrayscale = Math.abs(r - g) < 20 && Math.abs(g - b) < 20 && Math.abs(r - b) < 20;
|
|
if (isGrayscale && brightness > 80) {
|
|
data[i + 3] = 0; // Make transparent
|
|
continue;
|
|
}
|
|
|
|
// 2. Remove ALL light/bright backgrounds (AI-generated sprites)
|
|
if (brightness > 150) {
|
|
data[i + 3] = 0; // Make transparent
|
|
continue;
|
|
}
|
|
|
|
// 3. Remove PURE WHITE
|
|
if (r > 240 && g > 240 && b > 240) {
|
|
data[i + 3] = 0;
|
|
continue;
|
|
}
|
|
|
|
// 4. Remove OFF-WHITE / CREAM / BEIGE
|
|
if (brightness > 200 && Math.abs(r - g) < 30 && Math.abs(g - b) < 30) {
|
|
data[i + 3] = 0;
|
|
continue;
|
|
}
|
|
|
|
// 5. Remove PASTEL colors (low saturation, high brightness)
|
|
const maxRGB = Math.max(r, g, b);
|
|
const minRGB = Math.min(r, g, b);
|
|
const saturation = maxRGB === 0 ? 0 : (maxRGB - minRGB) / maxRGB;
|
|
|
|
if (saturation < 0.3 && brightness > 120) {
|
|
data[i + 3] = 0; // Remove low-saturation backgrounds
|
|
continue;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
createLoadingBar() {
|
|
const width = this.cameras.main.width;
|
|
const height = this.cameras.main.height;
|
|
|
|
// Warm background (Stardew Valley style)
|
|
const bg = this.add.graphics();
|
|
bg.fillStyle(0x2d1b00, 1);
|
|
bg.fillRect(0, 0, width, height);
|
|
|
|
// Simple "LOADING" text
|
|
const title = this.add.text(width / 2, height / 2 - 80, 'LOADING', {
|
|
fontFamily: 'Georgia, serif',
|
|
fontSize: '36px',
|
|
fontStyle: 'bold',
|
|
fill: '#f4e4c1',
|
|
stroke: '#2d1b00',
|
|
strokeThickness: 4
|
|
}).setOrigin(0.5);
|
|
|
|
// Progress Bar container (wooden style)
|
|
const barWidth = 400;
|
|
const barHeight = 30;
|
|
const barX = width / 2 - barWidth / 2;
|
|
const barY = height / 2;
|
|
|
|
const progressBox = this.add.graphics();
|
|
progressBox.fillStyle(0x4a3520, 0.9);
|
|
progressBox.fillRoundedRect(barX, barY, barWidth, barHeight, 5);
|
|
progressBox.lineStyle(3, 0xd4a574, 1);
|
|
progressBox.strokeRoundedRect(barX, barY, barWidth, barHeight, 5);
|
|
|
|
const progressBar = this.add.graphics();
|
|
|
|
// Zombie sprite walking on the bar
|
|
const zombie = this.add.text(barX, barY + barHeight / 2, '🧟', {
|
|
fontSize: '32px'
|
|
}).setOrigin(0.5);
|
|
|
|
// Percentage text
|
|
const percentText = this.add.text(width / 2, barY + barHeight / 2, '0%', {
|
|
font: '16px Georgia',
|
|
fill: '#f4e4c1',
|
|
fontStyle: 'bold'
|
|
}).setOrigin(0.5);
|
|
|
|
this.load.on('progress', (value) => {
|
|
percentText.setText(parseInt(value * 100) + '%');
|
|
progressBar.clear();
|
|
progressBar.fillStyle(0x6b4423, 1);
|
|
|
|
// Smooth fill
|
|
const w = (barWidth - 10) * value;
|
|
if (w > 0) {
|
|
progressBar.fillRoundedRect(barX + 5, barY + 5, w, barHeight - 10, 2);
|
|
}
|
|
|
|
// Move zombie along the bar (moderate speed)
|
|
const zombieX = barX + (barWidth * value);
|
|
zombie.setX(zombieX);
|
|
|
|
// Gentle bounce animation
|
|
const bounce = Math.sin(value * 20) * 3;
|
|
zombie.setY(barY + barHeight / 2 + bounce);
|
|
});
|
|
|
|
this.load.on('complete', () => {
|
|
// Fade out animation
|
|
this.tweens.add({
|
|
targets: [progressBar, progressBox, percentText, title, zombie, bg],
|
|
alpha: 0,
|
|
duration: 800,
|
|
onComplete: () => {
|
|
progressBar.destroy();
|
|
progressBox.destroy();
|
|
percentText.destroy();
|
|
title.destroy();
|
|
zombie.destroy();
|
|
bg.destroy();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
create() {
|
|
console.log('✅ PreloadScene: Assets loaded!');
|
|
window.gameState.currentScene = 'PreloadScene';
|
|
|
|
// Go directly to main menu (StoryScene)
|
|
this.time.delayedCall(500, () => {
|
|
console.log('🎮 Starting StoryScene...');
|
|
this.scene.start('StoryScene');
|
|
});
|
|
}
|
|
|
|
ultraRemoveBackground(spriteKey) {
|
|
if (!this.textures.exists(spriteKey)) return;
|
|
|
|
const texture = this.textures.get(spriteKey);
|
|
const source = texture.getSourceImage();
|
|
|
|
const canvas = document.createElement('canvas');
|
|
canvas.width = source.width;
|
|
canvas.height = source.height;
|
|
const ctx = canvas.getContext('2d', { willReadFrequently: true });
|
|
|
|
ctx.drawImage(source, 0, 0);
|
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
const data = imageData.data;
|
|
|
|
// Remove EVERYTHING except brown wood colors
|
|
for (let i = 0; i < data.length; i += 4) {
|
|
const r = data[i];
|
|
const g = data[i + 1];
|
|
const b = data[i + 2];
|
|
|
|
// Keep only brown/wood colors: R > G > B and R is dominant
|
|
const isBrown = r > g && g > b && r > 80 && r < 200;
|
|
|
|
if (!isBrown) {
|
|
data[i + 3] = 0; // Make transparent
|
|
}
|
|
}
|
|
|
|
ctx.putImageData(imageData, 0, 0);
|
|
|
|
// Remove old texture and create new one from canvas
|
|
this.textures.remove(spriteKey);
|
|
this.textures.addCanvas(spriteKey, canvas);
|
|
|
|
console.log(`🔥 ULTRA removed background from ${spriteKey}`);
|
|
}
|
|
}
|