carakter
This commit is contained in:
@@ -107,15 +107,16 @@ class Player {
|
||||
this.sprite = this.scene.add.sprite(
|
||||
screenPos.x + this.offsetX,
|
||||
screenPos.y + this.offsetY,
|
||||
texKey
|
||||
texKey,
|
||||
0 // CRITICAL: Start with frame 0 (first frame only)
|
||||
);
|
||||
this.sprite.setOrigin(0.5, 0.8); // Changed from 1 to 0.8 to show legs
|
||||
this.sprite.setOrigin(0.5, 1.0); // Bottom center - new sprite has full character!
|
||||
|
||||
// Scale based on sprite type
|
||||
if (texKey === 'player_protagonist') {
|
||||
this.sprite.setScale(1.0); // Smaller protagonist sprite
|
||||
this.sprite.setScale(0.5); // 256x256 frames scaled to 128x128 display size
|
||||
} else {
|
||||
this.sprite.setScale(1.0); // Fallback sprite
|
||||
this.sprite.setScale(0.5); // Fallback sprite
|
||||
}
|
||||
|
||||
|
||||
@@ -328,39 +329,65 @@ class Player {
|
||||
|
||||
// Update Facing Direction and Last Dir
|
||||
if (moved) {
|
||||
// Keep diagonal input clean or prioritize one axis?
|
||||
// Just use the calculated dx/dy.
|
||||
// Note: If both UP and LEFT pressed, logic above overwrites dx/dy.
|
||||
// Let's refine to allow diagonal accumulation if needed, but existing logic prioritized axis.
|
||||
// Current logic: RIGHT/LEFT overwrites UP/DOWN. This is fine for now.
|
||||
|
||||
this.lastDir = { x: dx, y: dy };
|
||||
this.sprite.setFlipX(!facingRight);
|
||||
|
||||
// Play walking animation (with safety check)
|
||||
// Determine animation direction (4 directions)
|
||||
let animDir = 'down'; // default
|
||||
|
||||
// UP/DOWN (isometric: dx changes)
|
||||
if (dx < 0 && dy === 0) {
|
||||
animDir = 'up'; // Moving up (NW in isometric)
|
||||
} else if (dx > 0 && dy === 0) {
|
||||
animDir = 'down'; // Moving down (SE in isometric)
|
||||
}
|
||||
// LEFT/RIGHT (isometric: dy changes)
|
||||
else if (dy > 0 && dx === 0) {
|
||||
animDir = 'left'; // Moving left (SW in isometric)
|
||||
} else if (dy < 0 && dx === 0) {
|
||||
animDir = 'right'; // Moving right (NE in isometric)
|
||||
}
|
||||
|
||||
this.direction = animDir;
|
||||
|
||||
// Play walking animation for the direction
|
||||
if (this.sprite.anims) {
|
||||
try {
|
||||
if (this.scene.anims.exists('protagonist_walk') && !this.sprite.anims.isPlaying) {
|
||||
this.sprite.play('protagonist_walk');
|
||||
const walkAnim = `protagonist_walk_${animDir}`;
|
||||
|
||||
// Debug
|
||||
console.log(`🎬 Trying to play: ${walkAnim}`);
|
||||
console.log(`Animation exists: ${this.scene.anims.exists(walkAnim)}`);
|
||||
|
||||
if (this.scene.anims.exists(walkAnim)) {
|
||||
this.sprite.play(walkAnim, true); // Force restart animation
|
||||
console.log(`✅ Playing: ${walkAnim}`);
|
||||
} else {
|
||||
console.warn(`⚠️ Animation not found: ${walkAnim}`);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore animation errors
|
||||
console.error('Animation error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Hand offset
|
||||
const handOffset = facingRight ? 10 : -10;
|
||||
this.handSprite.setX(this.sprite.x + handOffset);
|
||||
this.handSprite.setFlipX(!facingRight);
|
||||
// Hand offset based on direction
|
||||
const handOffsets = {
|
||||
'left': -10,
|
||||
'right': 10,
|
||||
'up': 0,
|
||||
'down': 0
|
||||
};
|
||||
this.handSprite.setX(this.sprite.x + (handOffsets[animDir] || 0));
|
||||
} else {
|
||||
// Stop animation when idle (with safety check)
|
||||
// Stop animation when idle
|
||||
if (this.sprite.anims) {
|
||||
try {
|
||||
if (this.sprite.anims.isPlaying) {
|
||||
this.sprite.stop();
|
||||
}
|
||||
if (this.scene.anims.exists('protagonist_idle')) {
|
||||
this.sprite.play('protagonist_idle');
|
||||
// Play idle animation for current direction
|
||||
const idleAnim = `protagonist_idle_${this.direction}`;
|
||||
if (this.scene.anims.exists(idleAnim)) {
|
||||
this.sprite.play(idleAnim);
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore animation errors
|
||||
@@ -431,12 +458,20 @@ class Player {
|
||||
|
||||
const targetScreen = this.iso.toScreen(targetX, targetY);
|
||||
|
||||
// Play walk animation - SAFE CHECK
|
||||
if (this.sprite.texture.key === 'player_dreadlocks') {
|
||||
// Play walk animation - SAFE CHECK (updated for protagonist)
|
||||
const texKey = this.sprite.texture.key;
|
||||
|
||||
if (texKey === 'player_protagonist') {
|
||||
// KRVAVA ŽETEV: Use directional animations
|
||||
const walkAnim = `protagonist_walk_${this.direction}`;
|
||||
if (this.scene.anims.exists(walkAnim)) {
|
||||
this.sprite.play(walkAnim, true);
|
||||
}
|
||||
} else if (texKey === 'player_dreadlocks') {
|
||||
if (this.scene.anims.exists('player_dreadlocks_walk')) {
|
||||
this.sprite.play('player_dreadlocks_walk', true);
|
||||
}
|
||||
} else if (this.sprite.texture.key === 'player_walk') {
|
||||
} else if (texKey === 'player_walk') {
|
||||
if (this.scene.anims.exists('player_walk_anim')) {
|
||||
this.sprite.play('player_walk_anim', true);
|
||||
}
|
||||
@@ -452,11 +487,19 @@ class Player {
|
||||
this.isMoving = false;
|
||||
this.updatePosition();
|
||||
|
||||
// Stop animation
|
||||
if (this.sprite.texture.key === 'player_dreadlocks') {
|
||||
// Stop animation (updated for protagonist)
|
||||
if (texKey === 'player_protagonist') {
|
||||
// Play idle animation
|
||||
const idleAnim = `protagonist_idle_${this.direction}`;
|
||||
if (this.scene.anims.exists(idleAnim)) {
|
||||
this.sprite.play(idleAnim);
|
||||
} else {
|
||||
this.sprite.stop();
|
||||
}
|
||||
} else if (texKey === 'player_dreadlocks') {
|
||||
this.sprite.stop();
|
||||
this.sprite.setFrame(0);
|
||||
} else if (this.sprite.texture.key === 'player_walk') {
|
||||
} else if (texKey === 'player_walk') {
|
||||
this.sprite.stop();
|
||||
this.sprite.setFrame(0);
|
||||
}
|
||||
|
||||
@@ -350,10 +350,10 @@ class GameScene extends Phaser.Scene {
|
||||
console.log('📊 Initializing Unified Stats Panel...');
|
||||
this.unifiedStatsPanel = new UnifiedStatsPanel(this);
|
||||
|
||||
// NPC Spawner
|
||||
console.log('🧟 Initializing NPC Spawner...');
|
||||
this.npcSpawner = new NPCSpawner(this);
|
||||
this.npcSpawner.spawnInitialNPCs();
|
||||
// NPC Spawner - DISABLED (NPCs look like player duplicates)
|
||||
console.log('🧟 NPC Spawner - DISABLED');
|
||||
this.npcSpawner = null; // new NPCSpawner(this);
|
||||
// this.npcSpawner.spawnInitialNPCs();
|
||||
|
||||
// Easter Egg: Broken Scooter
|
||||
console.log('🛵 Spawning Scooter Easter Egg...');
|
||||
|
||||
@@ -131,18 +131,24 @@ class PreloadScene extends Phaser.Scene {
|
||||
|
||||
// Wait for load completion then process transparency
|
||||
this.load.once('complete', () => {
|
||||
// NOTE: Do NOT process spritesheets - they already have proper alpha!
|
||||
// Processing destroys frame definitions
|
||||
|
||||
this.processAllTransparency();
|
||||
this.createAnimations();
|
||||
});
|
||||
|
||||
// New Processed Animations (Standardized 64x64 strips)
|
||||
this.load.spritesheet('zombie_walk', 'assets/sprites/zombie_walk_strip.png', { frameWidth: 64, frameHeight: 64 });
|
||||
// NOTE: zombie_walk_strip.png is missing - commented out for now
|
||||
// this.load.spritesheet('zombie_walk', 'assets/sprites/zombie_walk_strip.png', { frameWidth: 64, frameHeight: 64 });
|
||||
|
||||
// KRVAVA ŽETEV - New Player Sprite (Protagonist with dreadlocks)
|
||||
this.load.spritesheet('player_protagonist', 'assets/sprites/player_walk_animations.png', {
|
||||
frameWidth: 128, // Adjust based on actual sprite size
|
||||
frameHeight: 128
|
||||
// KRVAVA ŽETEV - CLEAN Player Sprite (100% Clean Transparency - No Checkerboard!)
|
||||
this.load.spritesheet('player_protagonist', 'assets/sprites/player_walking_clean.png', {
|
||||
frameWidth: 256, // 256x256 per frame, 4x4 grid = 16 frames (1024x1024 total)
|
||||
frameHeight: 256
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
createAnimations() {
|
||||
@@ -163,21 +169,64 @@ class PreloadScene extends Phaser.Scene {
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// KRVAVA ŽETEV: Protagonist animations
|
||||
// KRVAVA ŽETEV: Protagonist 4-directional walking animations
|
||||
// Row 1: DOWN (frames 0-3)
|
||||
this.anims.create({
|
||||
key: 'protagonist_walk',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 0, end: 7 }),
|
||||
frameRate: 10,
|
||||
key: 'protagonist_walk_down',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 0, end: 3 }),
|
||||
frameRate: 8,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// Row 2: LEFT (frames 4-7)
|
||||
this.anims.create({
|
||||
key: 'protagonist_idle',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 8, end: 9 }),
|
||||
frameRate: 2,
|
||||
key: 'protagonist_walk_left',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 4, end: 7 }),
|
||||
frameRate: 8,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// Row 3: RIGHT (frames 8-11)
|
||||
this.anims.create({
|
||||
key: 'protagonist_walk_right',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 8, end: 11 }),
|
||||
frameRate: 8,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// Row 4: UP (frames 12-15)
|
||||
this.anims.create({
|
||||
key: 'protagonist_walk_up',
|
||||
frames: this.anims.generateFrameNumbers('player_protagonist', { start: 12, end: 15 }),
|
||||
frameRate: 8,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
// IDLE: Use first frame of each direction
|
||||
this.anims.create({
|
||||
key: 'protagonist_idle_down',
|
||||
frames: [{ key: 'player_protagonist', frame: 0 }],
|
||||
frameRate: 1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'protagonist_idle_left',
|
||||
frames: [{ key: 'player_protagonist', frame: 4 }],
|
||||
frameRate: 1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'protagonist_idle_right',
|
||||
frames: [{ key: 'player_protagonist', frame: 8 }],
|
||||
frameRate: 1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'protagonist_idle_up',
|
||||
frames: [{ key: 'player_protagonist', frame: 12 }],
|
||||
frameRate: 1
|
||||
});
|
||||
|
||||
console.log('🎞️ Animations created!');
|
||||
}
|
||||
|
||||
@@ -470,6 +519,83 @@ class PreloadScene extends Phaser.Scene {
|
||||
});
|
||||
}
|
||||
|
||||
processPlayerSpritesheet() {
|
||||
const spriteKey = 'player_protagonist';
|
||||
|
||||
if (!this.textures.exists(spriteKey)) {
|
||||
console.warn('⚠️ Player protagonist texture not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🎨 Processing player spritesheet transparency...');
|
||||
|
||||
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;
|
||||
|
||||
// ULTRA AGGRESSIVE: Remove ALL checkerboard patterns and gray backgrounds
|
||||
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;
|
||||
|
||||
// 1. Remove PERFECT GRAY (checkerboard pattern: RGB 204,204,204 and 153,153,153)
|
||||
if (r === g && g === b) {
|
||||
if (r === 204 || r === 153 || r === 192 || r === 128 || (r >= 180 && r <= 210)) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Remove ANY grayscale (R≈G≈B within 15 units)
|
||||
const isGrayscale = Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && Math.abs(r - b) < 15;
|
||||
const brightness = (r + g + b) / 3;
|
||||
|
||||
if (isGrayscale && brightness > 100) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. Remove LIGHT backgrounds (brightness > 150)
|
||||
if (brightness > 150) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. Keep ONLY colored pixels (character skin, clothing, hair)
|
||||
// Character has: blue hoodie, brown pants, brown skin
|
||||
const maxChannel = Math.max(r, g, b);
|
||||
const minChannel = Math.min(r, g, b);
|
||||
const saturation = maxChannel === 0 ? 0 : (maxChannel - minChannel) / maxChannel;
|
||||
|
||||
// If low saturation AND bright = background
|
||||
if (saturation < 0.15 && brightness > 80) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
|
||||
// Replace texture
|
||||
this.textures.remove(spriteKey);
|
||||
this.textures.addCanvas(spriteKey, canvas);
|
||||
|
||||
console.log('✅ Player spritesheet transparency processed!');
|
||||
}
|
||||
|
||||
ultraRemoveBackground(spriteKey) {
|
||||
if (!this.textures.exists(spriteKey)) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user