From c3dd39e1a637815de868b77edd048cf940fbdbdf Mon Sep 17 00:00:00 2001 From: NovaFarma Dev Date: Sun, 14 Dec 2025 12:36:46 +0100 Subject: [PATCH] test --- docs/CHARACTER_SETUP_GUIDE.md | 249 +++++++++++++++++ docs/CRAFTING_GUIDE.md | 489 ++++++++++++++++++++++++++++++++++ docs/Z_SORTING_GUIDE.md | 312 ++++++++++++++++++++++ src/data/CraftingRecipes.js | 25 ++ src/entities/Player.js | 10 +- src/scenes/GameScene.js | 24 ++ 6 files changed, 1105 insertions(+), 4 deletions(-) create mode 100644 docs/CHARACTER_SETUP_GUIDE.md create mode 100644 docs/CRAFTING_GUIDE.md create mode 100644 docs/Z_SORTING_GUIDE.md diff --git a/docs/CHARACTER_SETUP_GUIDE.md b/docs/CHARACTER_SETUP_GUIDE.md new file mode 100644 index 0000000..4d8cc14 --- /dev/null +++ b/docs/CHARACTER_SETUP_GUIDE.md @@ -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 diff --git a/docs/CRAFTING_GUIDE.md b/docs/CRAFTING_GUIDE.md new file mode 100644 index 0000000..45b96a0 --- /dev/null +++ b/docs/CRAFTING_GUIDE.md @@ -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` diff --git a/docs/Z_SORTING_GUIDE.md b/docs/Z_SORTING_GUIDE.md new file mode 100644 index 0000000..7ada098 --- /dev/null +++ b/docs/Z_SORTING_GUIDE.md @@ -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 diff --git a/src/data/CraftingRecipes.js b/src/data/CraftingRecipes.js index 901f83c..145c465 100644 --- a/src/data/CraftingRecipes.js +++ b/src/data/CraftingRecipes.js @@ -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.' } }; diff --git a/src/entities/Player.js b/src/entities/Player.js index ff19f35..0c37736 100644 --- a/src/entities/Player.js +++ b/src/entities/Player.js @@ -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() { diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index 3617d61..135267d 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -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);