stanje 4am
This commit is contained in:
BIN
assets/sprites/player_walk.png
Normal file
BIN
assets/sprites/player_walk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 705 KiB |
BIN
assets/sprites/player_walk_strip.png
Normal file
BIN
assets/sprites/player_walk_strip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
assets/sprites/raw_player.jpg
Normal file
BIN
assets/sprites/raw_player.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 437 KiB |
BIN
assets/sprites/raw_zombie.jpg
Normal file
BIN
assets/sprites/raw_zombie.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 470 KiB |
BIN
assets/sprites/zombie_walk.png
Normal file
BIN
assets/sprites/zombie_walk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 773 KiB |
BIN
assets/sprites/zombie_walk_strip.png
Normal file
BIN
assets/sprites/zombie_walk_strip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -45,7 +45,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="game-container"></div>
|
<div id="game-container"></div>
|
||||||
<div id="debug-console"
|
<div id="debug-console"
|
||||||
style="position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.8); color: red; pointer-events: none; z-index: 9999; white-space: pre-wrap;">
|
style="position: fixed; top: 0; left: 0; color: red; pointer-events: none; z-index: 9999; white-space: pre-wrap;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
77
make_spritesheet.py
Normal file
77
make_spritesheet.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
from PIL import Image
|
||||||
|
import math
|
||||||
|
|
||||||
|
def process_sheet(input_path, output_path, target_size=(64, 64)):
|
||||||
|
print(f"Processing sheet {input_path}...")
|
||||||
|
try:
|
||||||
|
img = Image.open(input_path).convert("RGBA")
|
||||||
|
|
||||||
|
# 1. Crop to main content first to remove heavy borders
|
||||||
|
bbox = img.getbbox()
|
||||||
|
if not bbox:
|
||||||
|
print("Empty image")
|
||||||
|
return
|
||||||
|
|
||||||
|
# We assume 3 cols, 2 rows roughly distributed in the bbox
|
||||||
|
# But actually, finding the exact grid in a screenshot is hard.
|
||||||
|
# Let's try to detect 6 separated blobs? No, too complex.
|
||||||
|
|
||||||
|
# Simple approach: Crop to bbox, then assume uniform grid.
|
||||||
|
content = img.crop(bbox)
|
||||||
|
w, h = content.size
|
||||||
|
|
||||||
|
cell_w = w / 3
|
||||||
|
cell_h = h / 2
|
||||||
|
|
||||||
|
frames = []
|
||||||
|
|
||||||
|
# Extract 6 frames
|
||||||
|
for row in range(2):
|
||||||
|
for col in range(3):
|
||||||
|
left = col * cell_w
|
||||||
|
top = row * cell_h
|
||||||
|
right = left + cell_w
|
||||||
|
bottom = top + cell_h
|
||||||
|
|
||||||
|
cell = content.crop((left, top, right, bottom))
|
||||||
|
|
||||||
|
# DO NOT TRIM individual cells! Use the full cell to preserve animation offset.
|
||||||
|
|
||||||
|
# Find the best scale to fit the cell into target_size
|
||||||
|
cw, ch = cell.size
|
||||||
|
scale = min(target_size[0] / cw, target_size[1] / ch)
|
||||||
|
|
||||||
|
new_w = int(cw * scale)
|
||||||
|
new_h = int(ch * scale)
|
||||||
|
|
||||||
|
resized = cell.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
|
final_frame = Image.new("RGBA", target_size, (0,0,0,0))
|
||||||
|
|
||||||
|
# Center horizontally, align BOTTOM vertically (usually better for feet)
|
||||||
|
off_x = (target_size[0] - new_w) // 2
|
||||||
|
off_y = target_size[1] - new_h
|
||||||
|
|
||||||
|
# If the original image had a lot of empty space at bottom, feet might float.
|
||||||
|
# But since we cropped 'content' to global bbox first, it should be tight enough vertically.
|
||||||
|
|
||||||
|
final_frame.paste(resized, (off_x, off_y))
|
||||||
|
|
||||||
|
frames.append(final_frame)
|
||||||
|
|
||||||
|
# Create Strip (6x1)
|
||||||
|
strip_w = target_size[0] * 6
|
||||||
|
strip_h = target_size[1]
|
||||||
|
strip = Image.new("RGBA", (strip_w, strip_h))
|
||||||
|
|
||||||
|
for i, frame in enumerate(frames):
|
||||||
|
strip.paste(frame, (i * target_size[0], 0))
|
||||||
|
|
||||||
|
strip.save(output_path)
|
||||||
|
print(f"Saved strip to {output_path}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
process_sheet("assets/sprites/player_walk.png", "assets/sprites/player_walk_strip.png")
|
||||||
|
process_sheet("assets/sprites/zombie_walk.png", "assets/sprites/zombie_walk_strip.png")
|
||||||
38
process_sprites.py
Normal file
38
process_sprites.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from PIL import Image
|
||||||
|
import os
|
||||||
|
|
||||||
|
def remove_background(input_path, output_path):
|
||||||
|
print(f"Processing {input_path}...")
|
||||||
|
try:
|
||||||
|
img = Image.open(input_path).convert("RGBA")
|
||||||
|
datas = img.getdata()
|
||||||
|
|
||||||
|
newData = []
|
||||||
|
for item in datas:
|
||||||
|
# Checkerboard colors are usually White (255,255,255) and Light Grey (e.g. 204,204,204 or similar)
|
||||||
|
# We filter out anything very bright/neutral
|
||||||
|
r, g, b, a = item
|
||||||
|
|
||||||
|
# Check for white/near white
|
||||||
|
if r > 240 and g > 240 and b > 240:
|
||||||
|
newData.append((255, 255, 255, 0)) # Transparent
|
||||||
|
# Check for grey checkerboard (often around 204-240 range)
|
||||||
|
elif r > 190 and g > 190 and b > 190 and abs(r-g) < 10 and abs(r-b) < 10:
|
||||||
|
newData.append((255, 255, 255, 0)) # Transparent
|
||||||
|
else:
|
||||||
|
newData.append(item)
|
||||||
|
|
||||||
|
img.putdata(newData)
|
||||||
|
|
||||||
|
# Save
|
||||||
|
img.save(output_path, "PNG")
|
||||||
|
print(f"Saved to {output_path}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
# Process Player
|
||||||
|
remove_background("assets/sprites/raw_player.jpg", "assets/sprites/player_walk.png")
|
||||||
|
|
||||||
|
# Process Zombie
|
||||||
|
remove_background("assets/sprites/raw_zombie.jpg", "assets/sprites/zombie_walk.png")
|
||||||
@@ -18,6 +18,7 @@ class NPC {
|
|||||||
this.gridMoveTime = 300; // ms za premik (počasneje)
|
this.gridMoveTime = 300; // ms za premik (počasneje)
|
||||||
|
|
||||||
// Stanje
|
// Stanje
|
||||||
|
this.state = 'WANDER'; // WANDER, TAMED, FOLLOW
|
||||||
this.isMoving = false;
|
this.isMoving = false;
|
||||||
this.pauseTime = 0;
|
this.pauseTime = 0;
|
||||||
this.maxPauseTime = 2000; // Pavza med premiki (2s)
|
this.maxPauseTime = 2000; // Pavza med premiki (2s)
|
||||||
@@ -32,11 +33,51 @@ class NPC {
|
|||||||
this.pauseTime = Math.random() * this.maxPauseTime;
|
this.pauseTime = Math.random() * this.maxPauseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
createSprite() {
|
tame() {
|
||||||
// Check for custom sprites first
|
if (this.state === 'TAMED' || this.type !== 'zombie') return;
|
||||||
let texKey = `npc_${this.type}`;
|
|
||||||
|
|
||||||
if (this.type === 'zombie' && this.scene.textures.exists('zombie_sprite')) {
|
this.state = 'TAMED';
|
||||||
|
console.log('🧟❤️ Zombie TAMED!');
|
||||||
|
|
||||||
|
// Visual Feedback
|
||||||
|
const headX = this.sprite.x;
|
||||||
|
const headY = this.sprite.y - 40;
|
||||||
|
|
||||||
|
const heart = this.scene.add.text(headX, headY, '❤️', { fontSize: '20px' });
|
||||||
|
heart.setOrigin(0.5);
|
||||||
|
heart.setDepth(this.sprite.depth + 100);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: heart,
|
||||||
|
y: headY - 30,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 1500,
|
||||||
|
onComplete: () => heart.destroy()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Change color slightly to indicate friend
|
||||||
|
this.sprite.setTint(0xAAFFAA);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleState() {
|
||||||
|
if (this.state === 'WANDER') {
|
||||||
|
this.tame();
|
||||||
|
} else {
|
||||||
|
// Maybe command to stay/follow?
|
||||||
|
this.state = this.state === 'FOLLOW' ? 'STAY' : 'FOLLOW';
|
||||||
|
console.log(`Command: ${this.state}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createSprite() {
|
||||||
|
let texKey = `npc_${this.type}`;
|
||||||
|
let isAnimated = false;
|
||||||
|
|
||||||
|
// Check for animated sprites first
|
||||||
|
if (this.type === 'zombie' && this.scene.textures.exists('zombie_walk')) {
|
||||||
|
texKey = 'zombie_walk';
|
||||||
|
isAnimated = true;
|
||||||
|
} else if (this.type === 'zombie' && this.scene.textures.exists('zombie_sprite')) {
|
||||||
texKey = 'zombie_sprite';
|
texKey = 'zombie_sprite';
|
||||||
} else if (this.type === 'merchant' && this.scene.textures.exists('merchant_sprite')) {
|
} else if (this.type === 'merchant' && this.scene.textures.exists('merchant_sprite')) {
|
||||||
texKey = 'merchant_sprite';
|
texKey = 'merchant_sprite';
|
||||||
@@ -52,17 +93,72 @@ class NPC {
|
|||||||
texKey
|
texKey
|
||||||
);
|
);
|
||||||
this.sprite.setOrigin(0.5, 1);
|
this.sprite.setOrigin(0.5, 1);
|
||||||
this.sprite.setScale(0.3); // Optimized for visibility
|
|
||||||
|
if (isAnimated) {
|
||||||
|
this.sprite.setScale(1.5);
|
||||||
|
} else {
|
||||||
|
this.sprite.setScale(0.3);
|
||||||
|
}
|
||||||
|
|
||||||
// Depth sorting
|
// Depth sorting
|
||||||
this.updateDepth();
|
this.updateDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... loop update ...
|
||||||
|
|
||||||
|
moveToGrid(targetX, targetY) {
|
||||||
|
// Determine facing direction before moving
|
||||||
|
const dx = targetX - this.gridX;
|
||||||
|
const dy = targetY - this.gridY;
|
||||||
|
const movingRight = (dx > 0) || (dy > 0);
|
||||||
|
this.sprite.setFlipX(!movingRight);
|
||||||
|
|
||||||
|
this.isMoving = true;
|
||||||
|
this.gridX = targetX;
|
||||||
|
this.gridY = targetY;
|
||||||
|
|
||||||
|
const targetScreen = this.iso.toScreen(targetX, targetY);
|
||||||
|
|
||||||
|
// Animation
|
||||||
|
if (this.sprite.texture.key === 'zombie_walk') {
|
||||||
|
this.sprite.play('zombie_walk_anim', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tween za smooth gibanje
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.sprite,
|
||||||
|
x: targetScreen.x + this.offsetX,
|
||||||
|
y: targetScreen.y + this.offsetY,
|
||||||
|
duration: this.gridMoveTime,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.isMoving = false;
|
||||||
|
|
||||||
|
// Stop Animation
|
||||||
|
if (this.sprite.texture.key === 'zombie_walk') {
|
||||||
|
this.sprite.stop();
|
||||||
|
this.sprite.setFrame(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Posodobi depth
|
||||||
|
this.updateDepth();
|
||||||
|
}
|
||||||
|
|
||||||
update(delta) {
|
update(delta) {
|
||||||
|
this.updateDepth(); // Continuous depth sorting
|
||||||
|
|
||||||
if (this.isMoving) {
|
if (this.isMoving) {
|
||||||
return; // Že se premika
|
return; // Že se premika
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tamed logic
|
||||||
|
if (this.state === 'TAMED' || this.state === 'FOLLOW') {
|
||||||
|
this.followPlayer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Random walk - pavza med premiki
|
// Random walk - pavza med premiki
|
||||||
this.pauseTime += delta;
|
this.pauseTime += delta;
|
||||||
|
|
||||||
@@ -72,6 +168,31 @@ class NPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
followPlayer() {
|
||||||
|
if (!this.scene.player) return;
|
||||||
|
|
||||||
|
const playerPos = this.scene.player.getPosition();
|
||||||
|
const dist = Phaser.Math.Distance.Between(this.gridX, this.gridY, playerPos.x, playerPos.y);
|
||||||
|
|
||||||
|
// Če je precej dlje, se premakni k njemu
|
||||||
|
if (dist > 2) {
|
||||||
|
const dx = Math.sign(playerPos.x - this.gridX);
|
||||||
|
const dy = Math.sign(playerPos.y - this.gridY);
|
||||||
|
|
||||||
|
// Move 1 tile towards player
|
||||||
|
let targetX = this.gridX + dx;
|
||||||
|
let targetY = this.gridY + dy;
|
||||||
|
|
||||||
|
// Avoid occupying SAME tile as player
|
||||||
|
if (targetX === playerPos.x && targetY === playerPos.y) {
|
||||||
|
if (Math.random() < 0.5) targetX = this.gridX;
|
||||||
|
else targetY = this.gridY;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveToGrid(targetX, targetY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
performRandomWalk() {
|
performRandomWalk() {
|
||||||
// Naključna smer (NSEW + možnost obstati)
|
// Naključna smer (NSEW + možnost obstati)
|
||||||
const directions = [
|
const directions = [
|
||||||
@@ -103,28 +224,7 @@ class NPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveToGrid(targetX, targetY) {
|
|
||||||
this.isMoving = true;
|
|
||||||
this.gridX = targetX;
|
|
||||||
this.gridY = targetY;
|
|
||||||
|
|
||||||
const targetScreen = this.iso.toScreen(targetX, targetY);
|
|
||||||
|
|
||||||
// Tween za smooth gibanje
|
|
||||||
this.scene.tweens.add({
|
|
||||||
targets: this.sprite,
|
|
||||||
x: targetScreen.x + this.offsetX,
|
|
||||||
y: targetScreen.y + this.offsetY,
|
|
||||||
duration: this.gridMoveTime,
|
|
||||||
ease: 'Linear',
|
|
||||||
onComplete: () => {
|
|
||||||
this.isMoving = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Posodobi depth
|
|
||||||
this.updateDepth();
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
||||||
@@ -136,8 +236,8 @@ class NPC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateDepth() {
|
updateDepth() {
|
||||||
const depth = this.iso.getDepth(this.gridX, this.gridY);
|
// Pixel perfect sorting
|
||||||
this.sprite.setDepth(depth + 1000); // +1000 da je nad terenom
|
if (this.sprite) this.sprite.setDepth(this.sprite.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPosition() {
|
getPosition() {
|
||||||
|
|||||||
@@ -31,14 +31,16 @@ class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createSprite() {
|
createSprite() {
|
||||||
// Use custom sprite if available, otherwise procedural
|
// Prefer animated sprite if available
|
||||||
let texKey = 'player';
|
let texKey = 'player_walk'; // Spritesheet
|
||||||
|
let isAnimated = this.scene.textures.exists(texKey);
|
||||||
|
|
||||||
if (this.scene.textures.exists('player_sprite')) {
|
if (!isAnimated) {
|
||||||
texKey = 'player_sprite';
|
texKey = this.scene.textures.exists('player_sprite') ? 'player_sprite' : 'player';
|
||||||
} else if (!this.scene.textures.exists(texKey)) {
|
if (!this.scene.textures.exists(texKey)) {
|
||||||
TextureGenerator.createPlayerSprite(this.scene, texKey);
|
TextureGenerator.createPlayerSprite(this.scene, texKey);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Kreira sprite
|
// Kreira sprite
|
||||||
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
||||||
@@ -48,12 +50,67 @@ class Player {
|
|||||||
texKey
|
texKey
|
||||||
);
|
);
|
||||||
this.sprite.setOrigin(0.5, 1);
|
this.sprite.setOrigin(0.5, 1);
|
||||||
this.sprite.setScale(0.3); // Optimized for visibility
|
|
||||||
|
// Scale logic
|
||||||
|
if (isAnimated) {
|
||||||
|
this.sprite.setScale(1.5); // 64px frame -> looks good around 96px total height relative to 48px tile
|
||||||
|
} else {
|
||||||
|
this.sprite.setScale(0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- HAND / HELD ITEM SPRITE ---
|
||||||
|
this.handSprite = this.scene.add.sprite(
|
||||||
|
screenPos.x + this.offsetX + 10,
|
||||||
|
screenPos.y + this.offsetY - 25, // Adjusted for new height
|
||||||
|
'item_axe'
|
||||||
|
);
|
||||||
|
this.handSprite.setOrigin(0.5, 0.5);
|
||||||
|
this.handSprite.setScale(0.25);
|
||||||
|
this.handSprite.setVisible(false);
|
||||||
|
|
||||||
// Depth sorting
|
// Depth sorting
|
||||||
this.updateDepth();
|
this.updateDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... setupControls ...
|
||||||
|
|
||||||
|
// ... update ...
|
||||||
|
|
||||||
|
moveToGrid(targetX, targetY) {
|
||||||
|
this.isMoving = true;
|
||||||
|
this.gridX = targetX;
|
||||||
|
this.gridY = targetY;
|
||||||
|
|
||||||
|
const targetScreen = this.iso.toScreen(targetX, targetY);
|
||||||
|
|
||||||
|
// Play Animation
|
||||||
|
if (this.sprite.texture.key === 'player_walk') {
|
||||||
|
this.sprite.play('player_walk_anim', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tween za smooth gibanje
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: [this.sprite, this.handSprite], // Move both
|
||||||
|
x: '+=' + (targetScreen.x + this.offsetX - this.sprite.x),
|
||||||
|
y: '+=' + (targetScreen.y + this.offsetY - this.sprite.y),
|
||||||
|
duration: this.gridMoveTime,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.isMoving = false;
|
||||||
|
this.updatePosition();
|
||||||
|
|
||||||
|
// Stop Animation
|
||||||
|
if (this.sprite.texture.key === 'player_walk') {
|
||||||
|
this.sprite.stop();
|
||||||
|
this.sprite.setFrame(0); // Idle frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Posodobi depth
|
||||||
|
this.updateDepth();
|
||||||
|
}
|
||||||
|
|
||||||
setupControls() {
|
setupControls() {
|
||||||
// WASD kontrole
|
// WASD kontrole
|
||||||
this.keys = this.scene.input.keyboard.addKeys({
|
this.keys = this.scene.input.keyboard.addKeys({
|
||||||
@@ -65,41 +122,73 @@ class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(delta) {
|
update(delta) {
|
||||||
|
this.updateDepth();
|
||||||
|
|
||||||
if (!this.isMoving) {
|
if (!this.isMoving) {
|
||||||
this.handleInput();
|
this.handleInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync Held Item with Inventory
|
||||||
|
this.updateHeldItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHeldItem() {
|
||||||
|
const uiScene = this.scene.scene.get('UIScene');
|
||||||
|
const invSys = this.scene.inventorySystem;
|
||||||
|
|
||||||
|
if (uiScene && invSys) {
|
||||||
|
const selectedIdx = uiScene.selectedSlot;
|
||||||
|
const slot = invSys.slots[selectedIdx];
|
||||||
|
|
||||||
|
if (slot && (slot.type === 'axe' || slot.type === 'pickaxe' || slot.type === 'hoe' || slot.type === 'sword')) {
|
||||||
|
const texKey = `item_${slot.type}`;
|
||||||
|
if (this.scene.textures.exists(texKey)) {
|
||||||
|
this.handSprite.setTexture(texKey);
|
||||||
|
this.handSprite.setVisible(true);
|
||||||
|
} else {
|
||||||
|
this.handSprite.setVisible(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.handSprite.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInput() {
|
handleInput() {
|
||||||
let targetX = this.gridX;
|
let targetX = this.gridX;
|
||||||
let targetY = this.gridY;
|
let targetY = this.gridY;
|
||||||
let moved = false;
|
let moved = false;
|
||||||
|
let facingRight = !this.sprite.flipX; // Keep current
|
||||||
|
|
||||||
// WASD za isometric movement
|
// WASD za isometric movement
|
||||||
if (this.keys.up.isDown) {
|
if (this.keys.up.isDown) { // North-West
|
||||||
// W = North-West v isometric view
|
|
||||||
targetX--;
|
targetX--;
|
||||||
moved = true;
|
moved = true;
|
||||||
this.direction = 'up';
|
facingRight = false; // Left-ish
|
||||||
} else if (this.keys.down.isDown) {
|
} else if (this.keys.down.isDown) { // South-East
|
||||||
// S = South-East v isometric view
|
|
||||||
targetX++;
|
targetX++;
|
||||||
moved = true;
|
moved = true;
|
||||||
this.direction = 'down';
|
facingRight = true; // Right-ish
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.keys.left.isDown) {
|
if (this.keys.left.isDown) { // South-West
|
||||||
// A = South-West v isometric view
|
targetY++; // SWAPPED: Was --
|
||||||
targetY--;
|
|
||||||
moved = true;
|
moved = true;
|
||||||
this.direction = 'left';
|
facingRight = false; // Left-ish
|
||||||
} else if (this.keys.right.isDown) {
|
} else if (this.keys.right.isDown) { // North-East
|
||||||
// D = North-East v isometric view
|
targetY--; // SWAPPED: Was ++
|
||||||
targetY++;
|
|
||||||
moved = true;
|
moved = true;
|
||||||
this.direction = 'right';
|
facingRight = true; // Right-ish
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply Facing
|
||||||
|
this.sprite.setFlipX(!facingRight);
|
||||||
|
|
||||||
|
// Update Hand Position based on facing
|
||||||
|
const handOffset = facingRight ? 10 : -10;
|
||||||
|
this.handSprite.setX(this.sprite.x + handOffset);
|
||||||
|
this.handSprite.setFlipX(!facingRight);
|
||||||
|
|
||||||
// Preveri kolizijo z robovi mape
|
// Preveri kolizijo z robovi mape
|
||||||
const terrainSystem = this.scene.terrainSystem;
|
const terrainSystem = this.scene.terrainSystem;
|
||||||
if (moved && terrainSystem) {
|
if (moved && terrainSystem) {
|
||||||
@@ -109,28 +198,7 @@ class Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveToGrid(targetX, targetY) {
|
|
||||||
this.isMoving = true;
|
|
||||||
this.gridX = targetX;
|
|
||||||
this.gridY = targetY;
|
|
||||||
|
|
||||||
const targetScreen = this.iso.toScreen(targetX, targetY);
|
|
||||||
|
|
||||||
// Tween za smooth gibanje (brez animacije za zdaj)
|
|
||||||
this.scene.tweens.add({
|
|
||||||
targets: this.sprite,
|
|
||||||
x: targetScreen.x + this.offsetX,
|
|
||||||
y: targetScreen.y + this.offsetY,
|
|
||||||
duration: this.gridMoveTime,
|
|
||||||
ease: 'Linear',
|
|
||||||
onComplete: () => {
|
|
||||||
this.isMoving = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Posodobi depth
|
|
||||||
this.updateDepth();
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
||||||
@@ -138,12 +206,24 @@ class Player {
|
|||||||
screenPos.x + this.offsetX,
|
screenPos.x + this.offsetX,
|
||||||
screenPos.y + this.offsetY
|
screenPos.y + this.offsetY
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Update hand
|
||||||
|
const facingRight = !this.sprite.flipX;
|
||||||
|
const handOffset = facingRight ? 10 : -10;
|
||||||
|
this.handSprite.setPosition(
|
||||||
|
screenPos.x + this.offsetX + handOffset,
|
||||||
|
screenPos.y + this.offsetY - 15
|
||||||
|
);
|
||||||
|
|
||||||
this.updateDepth();
|
this.updateDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDepth() {
|
updateDepth() {
|
||||||
const depth = this.iso.getDepth(this.gridX, this.gridY);
|
// Pixel-perfect depth sorting based on screen Y
|
||||||
this.sprite.setDepth(depth + 1000); // +1000 da je nad terenom
|
if (this.sprite) {
|
||||||
|
this.sprite.setDepth(this.sprite.y);
|
||||||
|
if (this.handSprite) this.handSprite.setDepth(this.sprite.y + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPosition() {
|
getPosition() {
|
||||||
@@ -159,4 +239,19 @@ class Player {
|
|||||||
this.sprite.destroy();
|
this.sprite.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dieAnimation() {
|
||||||
|
this.sprite.setTint(0xff0000);
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.sprite,
|
||||||
|
angle: 90,
|
||||||
|
duration: 500,
|
||||||
|
ease: 'Bounce.easeOut'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
respawn() {
|
||||||
|
this.sprite.clearTint();
|
||||||
|
this.sprite.angle = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,14 +50,24 @@ class GameScene extends Phaser.Scene {
|
|||||||
|
|
||||||
// Dodaj 3 NPCje
|
// Dodaj 3 NPCje
|
||||||
console.log('🧟 Initializing NPCs...');
|
console.log('🧟 Initializing NPCs...');
|
||||||
|
// Dodaj 3 NPCje (Mixed)
|
||||||
|
console.log('🧟 Initializing NPCs...');
|
||||||
const npcTypes = ['zombie', 'villager', 'merchant'];
|
const npcTypes = ['zombie', 'villager', 'merchant'];
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
const randomX = Phaser.Math.Between(20, 80);
|
const randomX = Phaser.Math.Between(40, 60); // Closer to center
|
||||||
const randomY = Phaser.Math.Between(20, 80);
|
const randomY = Phaser.Math.Between(40, 60);
|
||||||
const npc = new NPC(this, randomX, randomY, this.terrainOffsetX, this.terrainOffsetY, npcTypes[i]);
|
const npc = new NPC(this, randomX, randomY, this.terrainOffsetX, this.terrainOffsetY, npcTypes[i]);
|
||||||
this.npcs.push(npc);
|
this.npcs.push(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dodaj 10 dodatnih Zombijev!
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const randomX = Phaser.Math.Between(10, 90);
|
||||||
|
const randomY = Phaser.Math.Between(10, 90);
|
||||||
|
const zombie = new NPC(this, randomX, randomY, this.terrainOffsetX, this.terrainOffsetY, 'zombie');
|
||||||
|
this.npcs.push(zombie);
|
||||||
|
}
|
||||||
|
|
||||||
// Kamera sledi igralcu z izboljšanimi nastavitvami
|
// Kamera sledi igralcu z izboljšanimi nastavitvami
|
||||||
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0); // Instant follow (was 0.1)
|
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0); // Instant follow (was 0.1)
|
||||||
|
|
||||||
@@ -192,8 +202,8 @@ class GameScene extends Phaser.Scene {
|
|||||||
if (this.statsSystem) this.statsSystem.update(delta);
|
if (this.statsSystem) this.statsSystem.update(delta);
|
||||||
if (this.interactionSystem) this.interactionSystem.update(delta);
|
if (this.interactionSystem) this.interactionSystem.update(delta);
|
||||||
if (this.farmingSystem) this.farmingSystem.update(delta);
|
if (this.farmingSystem) this.farmingSystem.update(delta);
|
||||||
if (this.weatherSystem) this.weatherSystem.update(delta);
|
|
||||||
if (this.dayNightSystem) this.dayNightSystem.update();
|
if (this.dayNightSystem) this.dayNightSystem.update();
|
||||||
|
if (this.weatherSystem) this.weatherSystem.update(delta);
|
||||||
|
|
||||||
// Update Parallax (foreground grass fading)
|
// Update Parallax (foreground grass fading)
|
||||||
if (this.parallaxSystem && this.player) {
|
if (this.parallaxSystem && this.player) {
|
||||||
|
|||||||
@@ -30,7 +30,31 @@ class PreloadScene extends Phaser.Scene {
|
|||||||
// Wait for load completion then process transparency
|
// Wait for load completion then process transparency
|
||||||
this.load.once('complete', () => {
|
this.load.once('complete', () => {
|
||||||
this.processAllTransparency();
|
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;
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
console.log('🎞️ Animations created!');
|
||||||
}
|
}
|
||||||
|
|
||||||
processAllTransparency() {
|
processAllTransparency() {
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ class UIScene extends Phaser.Scene {
|
|||||||
this.gameScene = this.scene.get('GameScene');
|
this.gameScene = this.scene.get('GameScene');
|
||||||
|
|
||||||
// Setup UI Container
|
// Setup UI Container
|
||||||
this.width = this.cameras.main.width;
|
// Shared Overlay (DayNight + Weather)
|
||||||
this.height = this.cameras.main.height;
|
// Rendered here to be screen-space (HUD) and ignore zoom
|
||||||
|
this.overlayGraphics = this.add.graphics();
|
||||||
|
this.overlayGraphics.setDepth(-1000); // Behind UI elements
|
||||||
|
|
||||||
this.createStatusBars();
|
this.createStatusBars();
|
||||||
this.createInventoryBar();
|
this.createInventoryBar();
|
||||||
@@ -19,7 +21,33 @@ class UIScene extends Phaser.Scene {
|
|||||||
this.createClock();
|
this.createClock();
|
||||||
this.createDebugInfo();
|
this.createDebugInfo();
|
||||||
|
|
||||||
// Listen for events from GameScene if needed
|
// Resize event
|
||||||
|
this.scale.on('resize', this.resize, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
resize(gameSize) {
|
||||||
|
this.width = gameSize.width;
|
||||||
|
this.height = gameSize.height;
|
||||||
|
|
||||||
|
this.cameras.main.setViewport(0, 0, this.width, this.height);
|
||||||
|
|
||||||
|
// Re-create UI elements at new positions
|
||||||
|
this.createClock();
|
||||||
|
this.createGoldDisplay();
|
||||||
|
this.createInventoryBar();
|
||||||
|
this.createDebugInfo();
|
||||||
|
|
||||||
|
// Refresh data
|
||||||
|
if (this.gameScene) {
|
||||||
|
if (this.gameScene.inventorySystem) {
|
||||||
|
this.updateInventory(this.gameScene.inventorySystem.slots);
|
||||||
|
}
|
||||||
|
// Clock/Gold update automatically in next frame
|
||||||
|
// Overlay fixes itself via Systems
|
||||||
|
if (this.overlayGraphics) {
|
||||||
|
this.overlayGraphics.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createStatusBars() {
|
createStatusBars() {
|
||||||
@@ -81,16 +109,26 @@ class UIScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createInventoryBar() {
|
createInventoryBar() {
|
||||||
|
// Clean up
|
||||||
|
if (this.inventorySlots) {
|
||||||
|
this.inventorySlots.forEach(slot => {
|
||||||
|
if (slot.itemSprite) slot.itemSprite.destroy();
|
||||||
|
if (slot.itemText) slot.itemText.destroy();
|
||||||
|
if (slot.countText) slot.countText.destroy();
|
||||||
|
slot.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const slotCount = 9;
|
const slotCount = 9;
|
||||||
const slotSize = 48; // 48x48 sloti
|
const slotSize = 48; // 48x48 sloti
|
||||||
const padding = 5;
|
const padding = 5;
|
||||||
|
|
||||||
const totalWidth = (slotCount * slotSize) + ((slotCount - 1) * padding);
|
const totalWidth = (slotCount * slotSize) + ((slotCount - 1) * padding);
|
||||||
const startX = (this.width - totalWidth) / 2;
|
const startX = (this.scale.width - totalWidth) / 2;
|
||||||
const startY = this.height - slotSize - 20;
|
const startY = this.scale.height - slotSize - 20;
|
||||||
|
|
||||||
this.inventorySlots = [];
|
this.inventorySlots = [];
|
||||||
this.selectedSlot = 0;
|
if (this.selectedSlot === undefined) this.selectedSlot = 0;
|
||||||
|
|
||||||
for (let i = 0; i < slotCount; i++) {
|
for (let i = 0; i < slotCount; i++) {
|
||||||
const x = startX + i * (slotSize + padding);
|
const x = startX + i * (slotSize + padding);
|
||||||
@@ -220,8 +258,11 @@ class UIScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createClock() {
|
createClock() {
|
||||||
|
if (this.clockBg) this.clockBg.destroy();
|
||||||
|
if (this.clockText) this.clockText.destroy();
|
||||||
|
|
||||||
// Clock box top right
|
// Clock box top right
|
||||||
const x = this.width - 150;
|
const x = this.scale.width - 150;
|
||||||
const y = 20;
|
const y = 20;
|
||||||
|
|
||||||
// Background
|
// Background
|
||||||
@@ -231,6 +272,8 @@ class UIScene extends Phaser.Scene {
|
|||||||
bg.lineStyle(2, 0xffffff, 0.8);
|
bg.lineStyle(2, 0xffffff, 0.8);
|
||||||
bg.strokeRect(x, y, 130, 40);
|
bg.strokeRect(x, y, 130, 40);
|
||||||
|
|
||||||
|
this.clockBg = bg; // Save ref
|
||||||
|
|
||||||
this.clockText = this.add.text(x + 65, y + 20, 'Day 1 - 08:00', {
|
this.clockText = this.add.text(x + 65, y + 20, 'Day 1 - 08:00', {
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
fontFamily: 'Courier New',
|
fontFamily: 'Courier New',
|
||||||
@@ -241,7 +284,10 @@ class UIScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createGoldDisplay() {
|
createGoldDisplay() {
|
||||||
const x = this.width - 150;
|
if (this.goldBg) this.goldBg.destroy();
|
||||||
|
if (this.goldText) this.goldText.destroy();
|
||||||
|
|
||||||
|
const x = this.scale.width - 150;
|
||||||
const y = 70; // Below clock
|
const y = 70; // Below clock
|
||||||
|
|
||||||
// Background
|
// Background
|
||||||
@@ -251,6 +297,8 @@ class UIScene extends Phaser.Scene {
|
|||||||
bg.lineStyle(2, 0xFFD700, 0.8);
|
bg.lineStyle(2, 0xFFD700, 0.8);
|
||||||
bg.strokeRect(x, y, 130, 30);
|
bg.strokeRect(x, y, 130, 30);
|
||||||
|
|
||||||
|
this.goldBg = bg; // Save ref
|
||||||
|
|
||||||
this.goldText = this.add.text(x + 65, y + 15, 'GOLD: 0', {
|
this.goldText = this.add.text(x + 65, y + 15, 'GOLD: 0', {
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
fontFamily: 'Courier New',
|
fontFamily: 'Courier New',
|
||||||
@@ -267,10 +315,21 @@ class UIScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createDebugInfo() {
|
createDebugInfo() {
|
||||||
|
if (this.debugText) this.debugText.destroy();
|
||||||
|
|
||||||
|
// Use scale height to position at bottom left (above inventory?) or top left
|
||||||
|
// Original was 10, 100 (top leftish). User said "manjkajo na dnu".
|
||||||
|
// Let's put it top left but ensure it is recreated.
|
||||||
|
// Actually, user said stats missing on top/bottom.
|
||||||
|
// Debug info is usually extra.
|
||||||
|
// Let's stick to simple recreation.
|
||||||
|
|
||||||
this.debugText = this.add.text(10, 100, '', {
|
this.debugText = this.add.text(10, 100, '', {
|
||||||
fontSize: '12px',
|
fontSize: '12px',
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fill: '#00ff00'
|
fill: '#00ff00', // Green as requested before? Or White? Sticking to Green from file.
|
||||||
|
stroke: '#000000',
|
||||||
|
strokeThickness: 3
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ class DayNightSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Create lighting overlay
|
// No local overlay - using UIScene.overlayGraphics
|
||||||
this.overlay = this.scene.add.graphics();
|
|
||||||
this.overlay.setDepth(4999); // Below weather, above everything else
|
|
||||||
this.overlay.setScrollFactor(0); // Fixed to camera
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
@@ -32,17 +29,24 @@ class DayNightSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPhase(hour) {
|
getPhase(hour) {
|
||||||
if (hour >= 5 && hour < 7) return 'dawn'; // 5-7
|
if (hour >= 5 && hour < 7) return 'dawn';
|
||||||
if (hour >= 7 && hour < 18) return 'day'; // 7-18
|
if (hour >= 7 && hour < 18) return 'day';
|
||||||
if (hour >= 18 && hour < 20) return 'dusk'; // 18-20
|
if (hour >= 18 && hour < 20) return 'dusk';
|
||||||
return 'night'; // 20-5
|
return 'night';
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLighting(hour) {
|
updateLighting(hour) {
|
||||||
const width = this.scene.cameras.main.width;
|
// Get Shared Overlay from UI Scene
|
||||||
const height = this.scene.cameras.main.height;
|
const uiScene = this.scene.scene.get('UIScene');
|
||||||
|
if (!uiScene || !uiScene.overlayGraphics) return;
|
||||||
|
|
||||||
this.overlay.clear();
|
const graphics = uiScene.overlayGraphics;
|
||||||
|
|
||||||
|
// IMPORTANT: DayNight is the FIRST system to render to overlay, so it MUST CLEAR it.
|
||||||
|
graphics.clear();
|
||||||
|
|
||||||
|
const width = uiScene.scale.width;
|
||||||
|
const height = uiScene.scale.height;
|
||||||
|
|
||||||
let color = 0x000033; // Default night blue
|
let color = 0x000033; // Default night blue
|
||||||
let alpha = 0;
|
let alpha = 0;
|
||||||
@@ -72,8 +76,8 @@ class DayNightSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (alpha > 0) {
|
if (alpha > 0) {
|
||||||
this.overlay.fillStyle(color, alpha);
|
graphics.fillStyle(color, alpha);
|
||||||
this.overlay.fillRect(0, 0, width, height);
|
graphics.fillRect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ class ParallaxSystem {
|
|||||||
console.log('🌄 ParallaxSystem: Initialized');
|
console.log('🌄 ParallaxSystem: Initialized');
|
||||||
|
|
||||||
// Layer 1: Sky/Hills (Distant background)
|
// Layer 1: Sky/Hills (Distant background)
|
||||||
this.createSkyLayer();
|
// Layer 1: Sky/Hills (Disabled by request)
|
||||||
this.createDistantHills();
|
// this.createSkyLayer();
|
||||||
|
// this.createDistantHills();
|
||||||
|
|
||||||
// Layer 4: Foreground overlay (High grass patches)
|
// Layer 4: Foreground overlay (High grass patches)
|
||||||
this.createForegroundGrass();
|
this.createForegroundGrass();
|
||||||
|
|||||||
@@ -85,24 +85,41 @@ class StatsSystem {
|
|||||||
|
|
||||||
die() {
|
die() {
|
||||||
console.log('💀 Player died!');
|
console.log('💀 Player died!');
|
||||||
// Zaenkrat samo respawn / reset
|
|
||||||
|
// Trigger Player Animation
|
||||||
|
if (this.scene.player) {
|
||||||
|
this.scene.player.dieAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show Notification & Overlay in UI Scene
|
||||||
|
const uiScene = this.scene.scene.get('UIScene');
|
||||||
|
if (uiScene) {
|
||||||
|
// Full screen overlay using scale dimensions
|
||||||
|
const width = uiScene.scale.width;
|
||||||
|
const height = uiScene.scale.height;
|
||||||
|
|
||||||
|
const bg = uiScene.add.rectangle(width / 2, height / 2, width, height, 0x000000, 0.8);
|
||||||
|
|
||||||
|
const txt = uiScene.add.text(width / 2, height / 2, 'YOU DIED', {
|
||||||
|
fontSize: '64px', color: '#ff0000', fontStyle: 'bold'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
// Wait and Respawn
|
||||||
|
uiScene.time.delayedCall(3000, () => {
|
||||||
|
if (bg) bg.destroy();
|
||||||
|
if (txt) txt.destroy();
|
||||||
|
|
||||||
|
// Reset Stats
|
||||||
this.health = 100;
|
this.health = 100;
|
||||||
this.hunger = 100;
|
this.hunger = 100;
|
||||||
this.thirst = 100;
|
this.thirst = 100;
|
||||||
|
this.updateUI();
|
||||||
|
|
||||||
// Teleport to spawn
|
// Reset Player
|
||||||
const spawnX = this.scene.terrainOffsetX + 500; // Dummy
|
if (this.scene.player) {
|
||||||
const spawnY = this.scene.terrainOffsetY + 100; // Dummy
|
this.scene.player.respawn();
|
||||||
// Reset player pos...
|
}
|
||||||
// V pravi implementaciji bi klicali GameScene.respawnPlayer()
|
});
|
||||||
|
|
||||||
// Show notification
|
|
||||||
const uiScene = this.scene.scene.get('UIScene');
|
|
||||||
if (uiScene) {
|
|
||||||
const txt = uiScene.add.text(uiScene.width / 2, uiScene.height / 2, 'YOU DIED', {
|
|
||||||
fontSize: '64px', color: '#ff0000', fontStyle: 'bold'
|
|
||||||
}).setOrigin(0.5);
|
|
||||||
uiScene.time.delayedCall(2000, () => txt.destroy());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -350,6 +350,7 @@ class TerrainSystem {
|
|||||||
if (x > 5 && x < this.width - 5 && y > 5 && y < this.height - 5) {
|
if (x > 5 && x < this.width - 5 && y > 5 && y < this.height - 5) {
|
||||||
let decorType = null;
|
let decorType = null;
|
||||||
let maxHp = 1;
|
let maxHp = 1;
|
||||||
|
let scale = 1.0; // Default scale
|
||||||
|
|
||||||
if (terrainType.name.includes('grass')) { // Check ANY grass type
|
if (terrainType.name.includes('grass')) { // Check ANY grass type
|
||||||
const rand = Math.random();
|
const rand = Math.random();
|
||||||
@@ -361,6 +362,20 @@ class TerrainSystem {
|
|||||||
} else if (rand < 0.025) { // Reduced to 2.5% trees (optimum balance)
|
} else if (rand < 0.025) { // Reduced to 2.5% trees (optimum balance)
|
||||||
decorType = 'tree';
|
decorType = 'tree';
|
||||||
maxHp = 5;
|
maxHp = 5;
|
||||||
|
|
||||||
|
// TREE SIZING LOGIC
|
||||||
|
// 20% Normal (1.0)
|
||||||
|
// 60% Medium (0.6-0.8)
|
||||||
|
// 20% Tiny (0.2)
|
||||||
|
const sizeRand = Math.random();
|
||||||
|
if (sizeRand < 0.2) {
|
||||||
|
scale = 0.25; // 20% Tiny (0.25 visible enough)
|
||||||
|
} else if (sizeRand < 0.8) {
|
||||||
|
scale = 0.6 + Math.random() * 0.2; // 60% Scale 0.6-0.8
|
||||||
|
} else {
|
||||||
|
scale = 1.0; // 20% Full size
|
||||||
|
}
|
||||||
|
|
||||||
} else if (rand < 0.03) {
|
} else if (rand < 0.03) {
|
||||||
decorType = 'gravestone'; // 💀 Nagrobniki
|
decorType = 'gravestone'; // 💀 Nagrobniki
|
||||||
maxHp = 10; // Težje uničiti
|
maxHp = 10; // Težje uničiti
|
||||||
@@ -381,7 +396,8 @@ class TerrainSystem {
|
|||||||
type: decorType,
|
type: decorType,
|
||||||
id: key,
|
id: key,
|
||||||
maxHp: maxHp,
|
maxHp: maxHp,
|
||||||
hp: maxHp
|
hp: maxHp,
|
||||||
|
scale: scale // Save scale
|
||||||
};
|
};
|
||||||
|
|
||||||
this.decorations.push(decorData);
|
this.decorations.push(decorData);
|
||||||
@@ -608,7 +624,7 @@ class TerrainSystem {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite.setDepth(this.iso.getDepth(x, y));
|
sprite.setDepth(this.iso.getDepth(x, y) - 2000); // Tiles always in background
|
||||||
|
|
||||||
this.visibleTiles.set(key, sprite);
|
this.visibleTiles.set(key, sprite);
|
||||||
}
|
}
|
||||||
@@ -630,8 +646,9 @@ class TerrainSystem {
|
|||||||
cropPos.x + this.offsetX,
|
cropPos.x + this.offsetX,
|
||||||
cropPos.y + this.offsetY + this.iso.tileHeight / 2 + elevationOffset
|
cropPos.y + this.offsetY + this.iso.tileHeight / 2 + elevationOffset
|
||||||
);
|
);
|
||||||
|
// Crop depth = Y pos
|
||||||
const depth = this.iso.getDepth(x, y);
|
const depth = this.iso.getDepth(x, y);
|
||||||
sprite.setDepth(depth + 1); // Just slightly above tile
|
sprite.setDepth(depth);
|
||||||
|
|
||||||
this.visibleCrops.set(key, sprite);
|
this.visibleCrops.set(key, sprite);
|
||||||
}
|
}
|
||||||
@@ -658,8 +675,13 @@ class TerrainSystem {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const depth = this.iso.getDepth(x, y);
|
const depth = this.iso.getDepth(x, y);
|
||||||
if (decor.type === 'flower') sprite.setDepth(depth + 1);
|
// Depth strategy: Base of object sorting.
|
||||||
else sprite.setDepth(depth + 1000); // Taller objects update depth
|
// Add small offset based on type if needed, but mainly use Y
|
||||||
|
sprite.setDepth(depth);
|
||||||
|
|
||||||
|
// Apply scale if present
|
||||||
|
if (decor.scale) sprite.setScale(decor.scale);
|
||||||
|
else sprite.setScale(1);
|
||||||
|
|
||||||
sprite.flipX = (x + y) % 2 === 0;
|
sprite.flipX = (x + y) % 2 === 0;
|
||||||
|
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ class WeatherSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// Create weather overlay
|
// No local overlay - we use UI Scene
|
||||||
this.overlay = this.scene.add.graphics();
|
|
||||||
this.overlay.setDepth(5000); // Above everything but UI
|
|
||||||
this.overlay.setScrollFactor(0); // Fixed to camera
|
|
||||||
|
|
||||||
// Start with random weather
|
|
||||||
this.changeWeather();
|
this.changeWeather();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOverlay() {
|
||||||
|
const uiScene = this.scene.scene.get('UIScene');
|
||||||
|
if (uiScene && uiScene.weatherGraphics) {
|
||||||
|
return uiScene.weatherGraphics;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
changeWeather() {
|
changeWeather() {
|
||||||
// Clean up old weather
|
// Clean up old weather
|
||||||
this.clearWeather();
|
this.clearWeather();
|
||||||
@@ -61,10 +64,10 @@ class WeatherSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startRain(heavy = false) {
|
startRain(heavy = false) {
|
||||||
const width = this.scene.cameras.main.width;
|
const width = this.scene.scale.width;
|
||||||
const height = this.scene.cameras.main.height;
|
const height = this.scene.scale.height;
|
||||||
|
|
||||||
// Create rain drops
|
// Create rain drops (keep logic for drops)
|
||||||
const dropCount = heavy ? 150 : 100;
|
const dropCount = heavy ? 150 : 100;
|
||||||
|
|
||||||
for (let i = 0; i < dropCount; i++) {
|
for (let i = 0; i < dropCount; i++) {
|
||||||
@@ -77,27 +80,16 @@ class WeatherSystem {
|
|||||||
this.rainParticles.push(drop);
|
this.rainParticles.push(drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Darken screen slightly
|
// No drawing here - handled in renderWeather
|
||||||
this.overlay.clear();
|
|
||||||
this.overlay.fillStyle(0x000033, heavy ? 0.3 : 0.2);
|
|
||||||
this.overlay.fillRect(0, 0, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFog() {
|
applyFog() {
|
||||||
const width = this.scene.cameras.main.width;
|
// No drawing here - handled in renderWeather
|
||||||
const height = this.scene.cameras.main.height;
|
|
||||||
|
|
||||||
this.overlay.clear();
|
|
||||||
this.overlay.fillStyle(0xcccccc, 0.4);
|
|
||||||
this.overlay.fillRect(0, 0, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearWeather() {
|
clearWeather() {
|
||||||
// Remove all weather effects
|
|
||||||
this.rainParticles = [];
|
this.rainParticles = [];
|
||||||
if (this.overlay) {
|
// No clearing here - handled by DayNightSystem clearing the frame
|
||||||
this.overlay.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update(delta) {
|
update(delta) {
|
||||||
@@ -108,42 +100,50 @@ class WeatherSystem {
|
|||||||
this.changeWeather();
|
this.changeWeather();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update rain
|
// Always render active weather
|
||||||
|
if (this.currentWeather !== 'clear') {
|
||||||
|
this.renderWeather(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWeather(delta) {
|
||||||
|
const overlay = this.getOverlay();
|
||||||
|
if (!overlay) return;
|
||||||
|
|
||||||
|
const height = this.scene.scale.height;
|
||||||
|
const width = this.scene.scale.width;
|
||||||
|
|
||||||
|
// FOG
|
||||||
|
if (this.currentWeather === 'fog') {
|
||||||
|
overlay.fillStyle(0xcccccc, 0.4);
|
||||||
|
overlay.fillRect(0, 0, width, height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAIN / STORM
|
||||||
if (this.currentWeather === 'rain' || this.currentWeather === 'storm') {
|
if (this.currentWeather === 'rain' || this.currentWeather === 'storm') {
|
||||||
this.updateRain(delta);
|
// Update physics
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRain(delta) {
|
|
||||||
const height = this.scene.cameras.main.height;
|
|
||||||
const width = this.scene.cameras.main.width;
|
|
||||||
|
|
||||||
// Update drop positions
|
|
||||||
for (const drop of this.rainParticles) {
|
for (const drop of this.rainParticles) {
|
||||||
drop.y += (drop.speed * delta) / 1000;
|
drop.y += (drop.speed * delta) / 1000;
|
||||||
|
|
||||||
// Reset if off screen
|
|
||||||
if (drop.y > height) {
|
if (drop.y > height) {
|
||||||
drop.y = -10;
|
drop.y = -10;
|
||||||
drop.x = Math.random() * width;
|
drop.x = Math.random() * width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render rain
|
// Darken background for storm/rain (additive to DayNight)
|
||||||
this.overlay.clear();
|
|
||||||
|
|
||||||
// Background darkening
|
|
||||||
const isDark = this.currentWeather === 'storm' ? 0.3 : 0.2;
|
const isDark = this.currentWeather === 'storm' ? 0.3 : 0.2;
|
||||||
this.overlay.fillStyle(0x000033, isDark);
|
overlay.fillStyle(0x000033, isDark);
|
||||||
this.overlay.fillRect(0, 0, width, height);
|
overlay.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
// Draw drops
|
// Draw drops
|
||||||
this.overlay.lineStyle(1, 0x88aaff, 0.5);
|
overlay.lineStyle(1, 0x88aaff, 0.5);
|
||||||
for (const drop of this.rainParticles) {
|
for (const drop of this.rainParticles) {
|
||||||
this.overlay.beginPath();
|
overlay.beginPath();
|
||||||
this.overlay.moveTo(drop.x, drop.y);
|
overlay.moveTo(drop.x, drop.y);
|
||||||
this.overlay.lineTo(drop.x - 2, drop.y + drop.length);
|
overlay.lineTo(drop.x - 2, drop.y + drop.length);
|
||||||
this.overlay.strokePath();
|
overlay.strokePath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,12 @@ class IsometricUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Izračun depth (z-index) za pravilno sortiranje
|
// Izračun depth (z-index) za pravilno sortiranje
|
||||||
|
// Izračun depth (z-index)
|
||||||
|
// V Phaserju je najbolje uporabiti kar Y koordinato spritha.
|
||||||
|
// Tu vrnemo pričakovano Y pozicijo za grid celico.
|
||||||
getDepth(gridX, gridY) {
|
getDepth(gridX, gridY) {
|
||||||
return gridX + gridY;
|
// (gridX + gridY) * tileHeight/2 je točno screenY
|
||||||
|
return (gridX + gridY) * (this.tileHeight / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Izračun centerja tile-a
|
// Izračun centerja tile-a
|
||||||
|
|||||||
Reference in New Issue
Block a user