This commit is contained in:
2025-12-14 12:36:46 +01:00
parent 0131f1490f
commit c3dd39e1a6
6 changed files with 1105 additions and 4 deletions

View File

@@ -0,0 +1,249 @@
# 🎮 KRVAVA ŽETEV - Character Setup Guide
Vodič za ustvarjanje in dodajanje novih karakterjev v igro.
---
## 📋 Trenutne Nastavitve Igralca
### Player Character (Protagonist)
- **Sprite**: `assets/sprites/player_walking_clean.png`
- **Texture Key**: `player_protagonist`
- **Frame Size**: 256x256 pixels
- **Total Size**: 1024x1024 pixels (4x4 grid = 16 frames)
- **Scale**: 0.5 (prikazuje kot 128x128)
- **Origin**: (0.5, 1.0) - bottom center
### Animation Layout
```
Row 1 (frames 0-3): DOWN (spredaj, proti kameri)
Row 2 (frames 4-7): LEFT (levo, stranski pogled)
Row 3 (frames 8-11): RIGHT (desno, stranski pogled)
Row 4 (frames 12-15): UP (zadaj, hrbtni pogled)
```
### Animacije
- `protagonist_walk_down` - frames 0-3 @ 8 fps
- `protagonist_walk_left` - frames 4-7 @ 8 fps
- `protagonist_walk_right` - frames 8-11 @ 8 fps
- `protagonist_walk_up` - frames 12-15 @ 8 fps
- `protagonist_idle_down` - frame 0
- `protagonist_idle_left` - frame 4
- `protagonist_idle_right` - frame 8
- `protagonist_idle_up` - frame 12
---
## 🎨 Kako Ustvariti Nov Karakter
### 1. Pripravi Spritesheet Sliko
**Zahteve:**
- **Format**: PNG s transparentnim ozadjem
- **Velikost**: 1024x1024 pixels (ali 512x512 ali 2048x2048 - mora biti deljivo s 4)
- **Grid**: 4x4 (16 frames)
- **Frame Size**: 256x256 pixels (ali 128x128, 512x512)
- **Ozadje**: 100% transparentno (brez šahovnice!)
**Če imaš sliko s šahovnico**, uporabi Python script:
```bash
python tools/remove_checkerboard.py
```
### 2. Shrani Sliko v Pravilno Mapo
```
c:\novafarma\assets\sprites\[character_name]_walking.png
```
Primer:
- `zombie_walking.png`
- `merchant_walking.png`
- `knight_walking.png`
### 3. Dodaj v PreloadScene.js
Odpri: `c:\novafarma\src\scenes\PreloadScene.js`
**V preload() funkciji dodaj:**
```javascript
// Nov Karakter - [IME]
this.load.spritesheet('[character_key]', 'assets/sprites/[character_name]_walking.png', {
frameWidth: 256, // Nastavi glede na velikost frame-a
frameHeight: 256
});
```
**V createAnimations() funkciji dodaj:**
```javascript
// [CHARACTER_NAME] Walking Animations
this.anims.create({
key: '[character]_walk_down',
frames: this.anims.generateFrameNumbers('[character_key]', { start: 0, end: 3 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: '[character]_walk_left',
frames: this.anims.generateFrameNumbers('[character_key]', { start: 4, end: 7 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: '[character]_walk_right',
frames: this.anims.generateFrameNumbers('[character_key]', { start: 8, end: 11 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: '[character]_walk_up',
frames: this.anims.generateFrameNumbers('[character_key]', { start: 12, end: 15 }),
frameRate: 8,
repeat: -1
});
// Idle animations
this.anims.create({
key: '[character]_idle_down',
frames: [{ key: '[character_key]', frame: 0 }],
frameRate: 1
});
this.anims.create({
key: '[character]_idle_left',
frames: [{ key: '[character_key]', frame: 4 }],
frameRate: 1
});
this.anims.create({
key: '[character]_idle_right',
frames: [{ key: '[character_key]', frame: 8 }],
frameRate: 1
});
this.anims.create({
key: '[character]_idle_up',
frames: [{ key: '[character_key]', frame: 12 }],
frameRate: 1
});
```
### 4. Ustvari Character Class
Ustvari novo datoteko: `c:\novafarma\src\entities\[CharacterName].js`
**Template:**
```javascript
// [Character Name] Entity
class [ClassName] {
constructor(scene, gridX, gridY, offsetX = 0, offsetY = 0) {
this.scene = scene;
this.gridX = gridX;
this.gridY = gridY;
this.offsetX = offsetX;
this.offsetY = offsetY;
this.iso = new IsometricUtils(48, 24);
this.direction = 'down';
this.isMoving = false;
this.createSprite();
}
createSprite() {
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
this.sprite = this.scene.add.sprite(
screenPos.x + this.offsetX,
screenPos.y + this.offsetY,
'[character_key]',
0
);
this.sprite.setOrigin(0.5, 1.0);
this.sprite.setScale(0.5); // Nastavi glede na velikost
// Play idle animation
if (this.scene.anims.exists('[character]_idle_down')) {
this.sprite.play('[character]_idle_down');
}
}
update(delta) {
// Add character logic here
}
destroy() {
if (this.sprite) this.sprite.destroy();
}
}
```
### 5. Dodaj v GameScene.js
```javascript
// Import character
// (če uporabljaš module system)
// V create() funkciji:
this.myCharacter = new [ClassName](this, 50, 50, this.terrainSystem.offsetX, this.terrainSystem.offsetY);
// V update() funkciji:
this.myCharacter.update(delta);
```
---
## 🛠️ Python Script za Odstranitev Šahovnice
**Lokacija:** `c:\novafarma\tools\remove_checkerboard.py`
**Uporaba:**
1. Odpri `remove_checkerboard.py`
2. Spremeni `input_file` in `output_file` pot
3. Zaženi: `python tools\remove_checkerboard.py`
**Primer:**
```python
input_file = r"C:\Users\Downloads\my_character.png"
output_file = r"c:\novafarma\assets\sprites\my_character_clean.png"
```
---
## ✅ Checklist za Nov Karakter
- [ ] Ustvari/pridobi spritesheet (1024x1024, 4x4 grid, transparentno ozadje)
- [ ] Odstrani šahovnico (če je potrebno)
- [ ] Shrani v `assets/sprites/`
- [ ] Dodaj spritesheet load v `PreloadScene.js`
- [ ] Dodaj animacije v `PreloadScene.js`
- [ ] Ustvari Character class (opcijsko)
- [ ] Dodaj v `GameScene.js` (opcijsko)
- [ ] Testiraj v igri (osveži s Ctrl+R)
---
## 📐 Velikosti & Skale
| Frame Size | Total Size | Priporočen Scale | Display Size |
|------------|------------|------------------|--------------|
| 128x128 | 512x512 | 1.0 | 128x128 |
| 256x256 | 1024x1024 | 0.5 | 128x128 |
| 512x512 | 2048x2048 | 0.25 | 128x128 |
---
## 🎯 Priporočila
1. **Consistent Size**: Vsi karakterji naj imajo enako display velikost (128x128)
2. **Transparent Background**: Vedno uporabi PNG s 100% transparentnim ozadjem
3. **Frame Rate**: 8 fps je idealno za walking animacije
4. **Origin Point**: (0.5, 1.0) za bottom-center je najboljše za isometric igre
5. **Backup**: Vedno shrani original pred odstranjevanjem šahovnice
---
**Zadnja posodobitev:** 14.12.2025
**Avtor:** KRVAVA ŽETEV Team

489
docs/CRAFTING_GUIDE.md Normal file
View File

@@ -0,0 +1,489 @@
# 🛠️ Crafting System Guide
Kompletni vodič za dodajanje in ustvarjanje crafting receptov v KRVAVA ŽETEV igri.
---
## 📖 Pregled
Igra ima **crafting sistem** ki omogoča igralcu izdelovanje:
- **Orodja** (sekira, kramp, motika)
- **Orožje** (meč, lok)
- **Zgradbe** (ograja, chest, furnace)
- **Materiale** (palica, bakla)
---
## 📂 Lokacija Datotek
```
c:\novafarma\src\data\CraftingRecipes.js ← Vsi recepti
c:\novafarma\src\systems\CraftingTiersSystem.js ← Tier sistem
```
---
## 🎯 DVA FORMATA RECEPTOV
### **Format 1: Obstoječi (Podroben)** ✅ PRIPOROČENO
```javascript
const CRAFTING_RECIPES = {
'lesena_ograda': {
id: 'lesena_ograda',
name: 'Lesena Ograda',
ingredients: [
{ item: 'wood', amount: 2 }
],
result: { item: 'lesena_ograda', amount: 5 },
category: 'buildings',
description: 'Lesena ograja za zaščito farme.'
},
'sekira_osnovna': {
id: 'sekira_osnovna',
name: 'Osnovna Sekira',
ingredients: [
{ item: 'wood', amount: 3 },
{ item: 'stone', amount: 2 }
],
result: { item: 'sekira_osnovna', amount: 1 },
category: 'tools',
description: 'Osnovno orodje za sekanje dreves.'
}
};
```
**Prednosti:**
- ✅ Podpira kategorije (tools, weapons, buildings...)
- ✅ Podpira opise
- ✅ Združljivo z obstoječim sistemom
- ✅ Enostavno razširljivo
---
### **Format 2: Enostaven/Kompakten**
```javascript
const craftingRecipes = {
'lesena_ograda': {
requires: { 'wood': 2 },
yields: 5
},
'sekira_osnovna': {
requires: {
'wood': 3,
'stone': 2
},
yields: 1
}
};
```
**Prednosti:**
- ✅ Krajši
- ✅ Hitrejši za pisanje
**Slabosti:**
- ❌ Ni kategorij
- ❌ Ni opisov
- ❌ Potreben converter
---
## 🔧 Converter Funkcija
Če želiš uporabljati enostavni format, uporabi converter:
```javascript
/**
* Pretvori enostavni format v obstoječi format
* @param {Object} simpleRecipes - Enostavni format receptov
* @returns {Object} - Obstoječi format receptov
*/
function convertToStandardFormat(simpleRecipes) {
const standardRecipes = {};
for (const [id, recipe] of Object.entries(simpleRecipes)) {
// Pretvori requires v ingredients array
const ingredients = [];
for (const [item, amount] of Object.entries(recipe.requires)) {
ingredients.push({ item, amount });
}
// Ustvari standardni format
standardRecipes[id] = {
id: id,
name: id.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
ingredients: ingredients,
result: { item: id, amount: recipe.yields },
category: 'custom',
description: `Crafted item: ${id}`
};
}
return standardRecipes;
}
// UPORABA:
const enostavniRecepti = {
'lesena_ograda': {
requires: { 'wood': 2 },
yields: 5
}
};
const standardRecepti = convertToStandardFormat(enostavniRecepti);
// Rezultat:
// {
// 'lesena_ograda': {
// id: 'lesena_ograda',
// name: 'Lesena Ograda',
// ingredients: [{ item: 'wood', amount: 2 }],
// result: { item: 'lesena_ograda', amount: 5 },
// category: 'custom',
// description: 'Crafted item: lesena_ograda'
// }
// }
```
---
## ✨ Kako Dodati Nov Recept
### **Korak 1: Odpri CraftingRecipes.js**
```
c:\novafarma\src\data\CraftingRecipes.js
```
### **Korak 2: Dodaj Nov Recept**
Najdi ustrezno kategorijo in dodaj:
```javascript
const CRAFTING_RECIPES = {
// ... obstoječi recepti ...
// ==================================
// CUSTOM RECIPES (Novi!)
// ==================================
'lesena_ograda': {
id: 'lesena_ograda',
name: 'Lesena Ograda',
ingredients: [
{ item: 'wood', amount: 2 }
],
result: { item: 'lesena_ograda', amount: 5 },
category: 'buildings',
description: 'Lesena ograja za zaščito farme.'
},
'sekira_osnovna': {
id: 'sekira_osnovna',
name: 'Osnovna Sekira',
ingredients: [
{ item: 'wood', amount: 3 },
{ item: 'stone', amount: 2 }
],
result: { item: 'sekira_osnovna', amount: 1 },
category: 'tools',
description: 'Osnovno orodje za sekanje dreves.'
}
};
```
### **Korak 3: Shrani in Osveži**
- Shrani datoteko
- Osveži igro (Ctrl+R)
- Odpri crafting menu (C tipka)
---
## 📋 Kategorije Receptov
| Kategorija | Opis | Primeri |
|------------|------|---------|
| `tools` | Orodja | Sekira, kramp, motika |
| `weapons` | Orožje | Meč, lok, kopje |
| `buildings` | Zgradbe | Ograja, chest, furnace |
| `materials` | Materiali | Palica, deska, bakla |
| `storage` | Shranjevanje | Chest, barrel |
| `workstation` | Delavnice | Furnace, anvil |
| `lighting` | Svetloba | Bakla, svetilka |
| `custom` | Po meri | Tvoji recepti |
---
## 🎮 Helper Funkcije
### **getCraftingRecipe(id)**
```javascript
const recipe = getCraftingRecipe('lesena_ograda');
console.log(recipe.name); // "Lesena Ograda"
console.log(recipe.ingredients); // [{ item: 'wood', amount: 2 }]
```
### **canCraft(id, inventory)**
```javascript
const canMake = canCraft('lesena_ograda', playerInventory);
if (canMake) {
console.log('✅ Lahko narediš ograjo!');
} else {
console.log('❌ Manjka material!');
}
```
### **craftItem(id, inventory)**
```javascript
const success = craftItem('lesena_ograda', playerInventory);
if (success) {
console.log('🔨 Izdelano!');
// Inventory: wood -= 2, lesena_ograda += 5
}
```
---
## 💡 Praktični Primeri
### **Primer 1: Enostavna Palica**
```javascript
'stick': {
id: 'stick',
name: 'Palica',
ingredients: [
{ item: 'wood', amount: 1 }
],
result: { item: 'stick', amount: 4 },
category: 'materials',
description: 'Osnoven material za crafting.'
}
```
### **Primer 2: Sekira (Več Ingredientov)**
```javascript
'stone_axe': {
id: 'stone_axe',
name: 'Kamnita Sekira',
ingredients: [
{ item: 'stone', amount: 3 },
{ item: 'stick', amount: 2 }
],
result: { item: 'stone_axe', amount: 1 },
category: 'tools',
description: 'Izboljšana sekira za hitrejše sekanje.'
}
```
### **Primer 3: Furnace (Kompleksno)**
```javascript
'furnace': {
id: 'furnace',
name: 'Peč',
ingredients: [
{ item: 'stone', amount: 8 },
{ item: 'coal', amount: 4 }
],
result: { item: 'furnace', amount: 1 },
category: 'workstation',
description: 'Topi rude v ingote.'
}
```
---
---
## 🔄 Crafting Funkcija Primerjava
### **Obstoječa Funkcija (Podroben Format)**
```javascript
/**
* Helper function to craft item (consumes ingredients)
*/
function craftItem(recipeId, playerInventory) {
if (!canCraft(recipeId, playerInventory)) {
console.warn('⚠️ Cannot craft - missing ingredients!');
return false;
}
const recipe = getCraftingRecipe(recipeId);
// Consume ingredients
for (const ingredient of recipe.ingredients) {
playerInventory.removeItem(ingredient.item, ingredient.amount);
}
// Add result
playerInventory.addItem(recipe.result.item, recipe.result.amount);
console.log(`✅ Crafted ${recipe.result.amount}x ${recipe.name}`);
return true;
}
// UPORABA:
craftItem('lesena_ograda', playerInventory);
// Rezultat: wood -= 2, lesena_ograda += 5
```
---
### **Enostavna Funkcija (Enostaven Format)**
```javascript
/**
* Poskuša izdelati določen predmet (Enostaven Format).
* @param {string} recipeKey - Ime recepta (npr. 'lesena_ograda').
*/
function craftItem(recipeKey) {
const recipe = craftingRecipes[recipeKey];
if (!recipe) {
console.error(`Recept '${recipeKey}' ne obstaja.`);
return false;
}
// Preverimo, ali imamo dovolj vseh sestavin
for (const requiredItem in recipe.requires) {
const requiredAmount = recipe.requires[requiredItem];
// Če je predmeta manj v inventarju, ne moremo craftati!
if (inventory[requiredItem] === undefined || inventory[requiredItem] < requiredAmount) {
console.warn(`Ni dovolj ${requiredItem} za izdelavo ${recipeKey}. Potrebno: ${requiredAmount}, Imate: ${inventory[requiredItem] || 0}`);
return false;
}
}
// Če pridemo sem, imamo dovolj sestavin:
// 1. Odstranimo porabljene sestavine iz inventarja
for (const requiredItem in recipe.requires) {
const requiredAmount = recipe.requires[requiredItem];
inventory[requiredItem] -= requiredAmount;
}
// 2. Dodamo izdelan predmet v inventar
addItemToInventory(recipeKey, recipe.yields);
console.log(`${recipeKey} uspešno izdelan!`);
return true;
}
// UPORABA:
craftItem('lesena_ograda');
// Rezultat: inventory.wood -= 2, inventory.lesena_ograda += 5
```
---
### **Primerjava Funkcij**
| Lastnost | Obstoječa | Enostavna |
|----------|-----------|-----------|
| Format receptov | `ingredients: [{item, amount}]` | `requires: {item: amount}` |
| Inventory sistem | Uporablja `playerInventory` objekt | Uporablja globalni `inventory` objekt |
| Preverjanje | `canCraft()` helper funkcija | Direktno v funkciji |
| Fleksibilnost | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Enostavnost | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
---
### **Kdy Uporabiti Katero?**
**Uporabi OBSTOJEČO funkcijo** če:
- ✅ Uporabljaš InventorySystem class
- ✅ Rabiš kategorije in opise
- ✅ Delaš kompleksnejšo igro
- ✅ Rabiš helper funkcije (`canCraft`, `getCraftingRecipe`)
**Uporabi ENOSTAVNO funkcijo** če:
- ✅ Imaš preprost inventory (object)
- ✅ Delaš prototip/testiranje
- ✅ Rabiš hitro implementacijo
- ✅ Ne rabiš kategorij
---
## 🔍 Debugging
### **Problem: Recept ne deluje**
```javascript
// Preveri če recept obstaja
const recipe = getCraftingRecipe('moj_recept');
if (!recipe) {
console.error('❌ Recept ne obstaja!');
}
// Preveri ingrediente
const canMake = canCraft('moj_recept', playerInventory);
console.log('Can craft:', canMake);
// Preveri inventory
console.log('Player wood:', playerInventory.getItemCount('wood'));
```
### **Problem: Material se ne porabi**
```javascript
// Poglej craftItem funkcijo v CraftingRecipes.js
// Preveri če removeItem() deluje:
playerInventory.removeItem('wood', 2);
console.log('Wood after:', playerInventory.getItemCount('wood'));
```
---
## 🎨 Best Practices
### ✅ DO:
- Uporabi smiselne ID-je (`stone_axe`, ne `item_123`)
- Dodaj opise za vse recepte
- Uporabi ustrezne kategorije
- Testiraj recepte pred objavo
### ❌ DON'T:
- Ne uporabljaj presledkov v ID-jih (`stone axe` ❌)
- Ne pozabi `yields`/`result.amount`
- Ne uporabljaj item-ov ki ne obstajajo
---
## 📊 Obstoječi Recepti
Trenutno v igri:
| Recept | Kategorija | Ingredienti |
|--------|-----------|-------------|
| Bone Pickaxe | tools | bone (3), wood (2) |
| Bone Axe | tools | bone (3), wood (2) |
| Bone Hoe | tools | bone (2), wood (2) |
| Bone Sword | weapons | bone (2), wood (1) |
| Wooden Pickaxe | tools | wood (3), stick (2) |
| Stone Pickaxe | tools | stone (3), stick (2) |
| Stick | materials | wood (1) → 4x |
| Torch | lighting | stick (1), coal (1) → 4x |
| Chest | storage | wood (8) |
| Furnace | workstation | stone (8), coal (4) |
---
## 🚀 Naslednji Koraki
1. **Odpri** `c:\novafarma\src\data\CraftingRecipes.js`
2. **Dodaj** svoje recepte v ustrezno kategorijo
3. **Shrani** datoteko
4. **Osveži** igro (Ctrl+R)
5. **Testiraj** v crafting meniju (C tipka)
---
**Zadnja posodobitev:** 14.12.2025
**Avtor:** KRVAVA ŽETEV Team
**Status:** ✅ Ready to use
**Lokacija:** `c:\novafarma\src\data\CraftingRecipes.js`

312
docs/Z_SORTING_GUIDE.md Normal file
View File

@@ -0,0 +1,312 @@
# 🎯 Z-Sorting System Guide (2.5D Depth)
Vodič za obvladovanje globine objektov v 2.5D isometric igrah.
---
## 📖 Kaj je Z-Sorting?
V 2.5D isometric igrah moramo objekte **pravilno prekrivati** glede na njihovo pozicijo:
- Objekti **spredaj** (višji Y) morajo biti **nad** objekti zadaj (nižji Y)
- To se doseže z nastavitvijo **depth** vrednosti
**Primer:**
```
Drevo na Y=100 mora biti NAD karakterjem na Y=50
Karakter na Y=100 mora biti NAD drevesom na Y=50
```
---
## 🔄 DVA PRISTOPA
### **Pristop 1: Manual updateDepth()** ❌ STAR SISTEM
**Kako deluje:**
```javascript
updateDepth() {
const layerBase = 200000; // LAYER_OBJECTS
const depth = layerBase + this.sprite.y;
this.sprite.setDepth(depth);
}
```
**Klici:**
- V `update()` funkciji vsake Entity
- Ko se objekt premakne
**Prednosti:**
- ✅ Zelo natančno (vsak piksel šteje)
- ✅ Deluje z layerji (LAYER_TERRAIN, LAYER_OBJECTS, LAYER_UI)
**Slabosti:**
- ❌ Vsak objekt potrebuje svojo `updateDepth()` funkcijo
- ❌ Več kode za vzdrževanje
- ❌ Moral klicat ročno
---
### **Pristop 2: sortableObjects Group** ✅ NOV SISTEM
**Kako deluje:**
```javascript
// V create() - GameScene.js
this.sortableObjects = this.add.group();
this.sortableObjects.add(this.player.sprite);
// V update() - GameScene.js
const children = this.sortableObjects.getChildren();
children.sort((a, b) => a.y - b.y); // Sortiranje po Y
children.forEach((obj, index) => {
obj.setDepth(200000 + index);
});
```
**Prednosti:**
-**Enostavno** - samo dodaš sprite v group
-**Centralizirano** - vse na enem mestu
-**Avtomatsko** - sortira se vsak frame
**Slabosti:**
- ⚠️ Sortira VSE objekte vsak frame (lahko počasno pri 100+ objektih)
- ⚠️ Depth je samo index (0, 1, 2, 3...) ne natančen Y
---
## 🛠️ Implementacija (Korak-po-Korak)
### **Korak 1: Ustvari sortableObjects Group**
V `GameScene.js` - `create()` funkciji:
```javascript
// Po ustvarjanju playerja
this.player = new Player(this, 50, 50, offsetX, offsetY);
// 🎯 SORTABLE OBJECTS GROUP
console.log('🎯 Creating sortableObjects group...');
this.sortableObjects = this.add.group();
// Dodaj player sprite
if (this.player && this.player.sprite) {
this.sortableObjects.add(this.player.sprite);
}
```
### **Korak 2: Dodaj Z-Sorting v Update**
V `GameScene.js` - `update()` funkciji:
```javascript
update(time, delta) {
if (this.player) this.player.update(delta);
// 🎯 Z-SORTING
if (this.sortableObjects) {
const children = this.sortableObjects.getChildren();
// Sortiranje po Y koordinati
children.sort((a, b) => a.y - b.y);
// Nastavi depth glede na vrstni red
children.forEach((obj, index) => {
obj.setDepth(200000 + index); // LAYER_OBJECTS base
});
}
// ... ostali sistemi
}
```
### **Korak 3: Odstrani Manual updateDepth()**
V `Player.js` (ali drugih Entity classes):
```javascript
update(delta) {
// ❌ ODSTRANI TO:
// if (this.isMoving) {
// this.updateDepth();
// }
// ✅ Ne rabiš več - sortableObjects to naredi avtomatsko!
if (!this.isMoving) {
this.handleInput();
}
}
```
### **Korak 4: Dodaj Nove Objekte (Drevesa, NPCji, itd.)**
Ko ustvarjaš nov objekt:
```javascript
// PRIMER: Dodaj drevo
const tree = this.add.sprite(x, y, 'tree_sprite');
tree.setOrigin(0.5, 1.0);
// ✨ DODAJ V SORTABLE OBJECTS
this.sortableObjects.add(tree);
// PRIMER: Dodaj NPC
const npc = new NPC(this, gridX, gridY);
this.sortableObjects.add(npc.sprite);
```
---
## 🎮 Praktični Primeri
### **Primer 1: Player + Drevesa**
```javascript
// V create()
this.player = new Player(this, 50, 50, offsetX, offsetY);
this.sortableObjects = this.add.group();
this.sortableObjects.add(this.player.sprite);
// Dodaj 5 dreves
for (let i = 0; i < 5; i++) {
const tree = this.add.sprite(
Math.random() * 500,
Math.random() * 500,
'tree_sprite'
);
tree.setOrigin(0.5, 1.0);
this.sortableObjects.add(tree); // ✨ Avtomatično sortiranje!
}
```
### **Primer 2: Player + NPCs + Drevesa**
```javascript
// Player
this.sortableObjects.add(this.player.sprite);
// NPCs
this.npcs = [];
for (let i = 0; i < 10; i++) {
const npc = new NPC(this, randX, randY);
this.npcs.push(npc);
this.sortableObjects.add(npc.sprite); // ✨
}
// Drevesa
this.trees.forEach(tree => {
this.sortableObjects.add(tree.sprite); // ✨
});
```
---
## ⚡ Performance Tips
### **Problem: Počasno pri 100+ objektih**
Če imaš **več kot 100 objektov**, sortiranje vsak frame (60x/sekundo) je lahko počasno.
**Rešitev 1: Dirty Flag**
```javascript
update(time, delta) {
// Sortiranje samo ko potrebno, ne vsak frame
if (this.needsSorting) {
const children = this.sortableObjects.getChildren();
children.sort((a, b) => a.y - b.y);
children.forEach((obj, index) => obj.setDepth(200000 + index));
this.needsSorting = false;
}
}
// Nastavi v Player.moveToGrid() ali NPC movement
moveToGrid(targetX, targetY) {
// ... movement code
this.scene.needsSorting = true; // ✅ Označi za sortiranje
}
```
**Rešitev 2: Throttling (vsak N-ti frame)**
```javascript
update(time, delta) {
this.sortCounter = (this.sortCounter || 0) + 1;
// Sortiranje samo vsak 3. frame (namesto vsakega)
if (this.sortCounter % 3 === 0) {
const children = this.sortableObjects.getChildren();
children.sort((a, b) => a.y - b.y);
children.forEach((obj, index) => obj.setDepth(200000 + index));
}
}
```
---
## 🔍 Debugging
### **Problem: Objekti ne prekrivajo pravilno**
```javascript
// V update(), dodaj console.log
update(time, delta) {
if (this.sortableObjects) {
const children = this.sortableObjects.getChildren();
children.sort((a, b) => a.y - b.y);
children.forEach((obj, index) => {
obj.setDepth(200000 + index);
// 🔍 DEBUG
console.log(`${obj.texture.key}: Y=${obj.y}, Depth=${obj.depth}`);
});
}
}
```
### **Problem: Objekti manjkajo**
Preveri če si dodal sprite v group:
```javascript
// ✅ PRAVILNO
this.sortableObjects.add(this.player.sprite);
// ❌ NAROBE
this.sortableObjects.add(this.player); // Mora biti .sprite!
```
---
## 📊 Primerjava: Manual vs. SortableObjects
| Feature | Manual updateDepth() | sortableObjects |
|---------|---------------------|-----------------|
| **Enostavnost** | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| **Performance (< 50 obj)** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| **Performance (> 100 obj)** | ⭐⭐⭐⭐ | ⭐⭐ |
| **Natančnost** | ⭐⭐⭐⭐⭐ (pixel perfect) | ⭐⭐⭐ (index based) |
| **Vzdrževanje** | ⭐⭐ (več kode) | ⭐⭐⭐⭐⭐ (ena funkcija) |
| **Layer podpora** | ✅ Da | ⚠️ Samo eno layer |
---
## 🎯 PRIPOROČILO
### **Za KRVAVA ŽETEV:**
**Uporabljaj sortableObjects** - enostavnejše in hitrejše za razvoj
### **Kdaj Manual:**
- Zelo kompleksne igre (10+ layerjev)
- Več kot 200+ objektov
- Potrebuješ pixel-perfect depth
---
## 📚 Dodatno Branje
- [Phaser Groups Documentation](https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Group.html)
- [Isometric Depth Sorting](https://www.youtube.com/watch?v=04oQ2jOUjkU)
- [Advanced Z-Sorting Techniques](https://gamedev.stackexchange.com/questions/8/how-do-i-sort-isometric-sprites-into-the-correct-order)
---
**Zadnja posodobitev:** 14.12.2025
**Avtor:** KRVAVA ŽETEV Team
**Status:** ✅ Implementirano v GameScene.js

View File

@@ -127,6 +127,31 @@ const CRAFTING_RECIPES = {
result: { item: 'furnace', amount: 1 },
category: 'workstation',
description: 'Smelts ores into bars.'
},
// ==================================
// CUSTOM RECIPES (NEW!)
// ==================================
'lesena_ograda': {
id: 'lesena_ograda',
name: 'Lesena Ograda',
ingredients: [
{ item: 'wood', amount: 2 }
],
result: { item: 'lesena_ograda', amount: 5 },
category: 'buildings',
description: 'Lesena ograja za zaščito farme.'
},
'sekira_osnovna': {
id: 'sekira_osnovna',
name: 'Osnovna Sekira',
ingredients: [
{ item: 'wood', amount: 3 },
{ item: 'stone', amount: 2 }
],
result: { item: 'sekira_osnovna', amount: 1 },
category: 'tools',
description: 'Osnovno orodje za sekanje dreves.'
}
};

View File

@@ -222,9 +222,10 @@ class Player {
}
update(delta) {
if (this.isMoving) {
this.updateDepth();
}
// NOTE: updateDepth() disabled - using sortableObjects Z-sorting in GameScene
// if (this.isMoving) {
// this.updateDepth();
// }
if (!this.isMoving) {
this.handleInput();
@@ -506,7 +507,8 @@ class Player {
}
});
this.updateDepth();
// NOTE: updateDepth() disabled - using sortableObjects Z-sorting in GameScene
// this.updateDepth();
}
updatePosition() {

View File

@@ -338,6 +338,16 @@ class GameScene extends Phaser.Scene {
console.log('👤 Initializing player...');
this.player = new Player(this, 50, 50, this.terrainOffsetX, this.terrainOffsetY);
// 🎯 SORTABLE OBJECTS GROUP - Za 2.5D Z-Sorting
console.log('🎯 Creating sortableObjects group for Z-sorting...');
this.sortableObjects = this.add.group();
// Dodaj player sprite v sortableObjects
if (this.player && this.player.sprite) {
this.sortableObjects.add(this.player.sprite);
console.log('✅ Player added to sortableObjects');
}
// ALL NPCs REMOVED - Solo farming mode
console.log('🌾 Solo farming mode - no NPCs');
@@ -838,6 +848,20 @@ class GameScene extends Phaser.Scene {
update(time, delta) {
if (this.player) this.player.update(delta);
// 🎯 Z-SORTING: SortableObjects based on Y position
if (this.sortableObjects) {
const children = this.sortableObjects.getChildren();
// Sortiranje po Y koordinati (nižji Y = nižji depth)
children.sort((a, b) => a.y - b.y);
// Nastavi depth glede na vrstni red (index)
children.forEach((obj, index) => {
// Use LAYER_OBJECTS base + index for depth
obj.setDepth(200000 + index);
});
}
// Update Systems
if (this.terrainSystem) this.terrainSystem.update(time, delta); // Water animation!
if (this.statsSystem) this.statsSystem.update(delta);