From 860a10a5c3d25e2103bfa8f90f63b2a26d038a26 Mon Sep 17 00:00:00 2001 From: NovaFarma Dev Date: Mon, 8 Dec 2025 01:55:39 +0100 Subject: [PATCH] farma orodje in dnevnik --- DNEVNIK.md | 75 ++++++++++ src/utils/TextureGenerator.js | 273 ++++++++++++++++++---------------- 2 files changed, 222 insertions(+), 126 deletions(-) create mode 100644 DNEVNIK.md diff --git a/DNEVNIK.md b/DNEVNIK.md new file mode 100644 index 0000000..f19cad1 --- /dev/null +++ b/DNEVNIK.md @@ -0,0 +1,75 @@ +# 📔 DNEVNIK RAZVOJA: KRVAVA ŽETEV (NOVA FARMA) + +## 📅 Začetek Projekta +**Datum začetka:** 5. December 2025 +**Lokacija:** Nova Farma (c:\novafarma) +**Engine:** Phaser 3 + Custom Antigravity Engine +**Stil:** 2.5D Izometrični Pixel Art / Voxel + +--- + +## 🧟‍♂️ Koncept Igre & Zgodba + +### Naslov: Krvava Žetev (Zombie Roots) + +**Zgodba:** +Svet, kakršnega smo poznali, je propadel. Nisi vojak, nisi heroj – si kmet. Tvoja naloga ni zgolj preživeti, ampak ponovno pognati korenine civilizacije. Prebudiš se na zapuščeni kmetiji sredi opustošene dežele. Čez dan je svet varljiv: sonce sije na ruševine, trava raste in narava si jemlje nazaj, kar je njeno. + +A ko pade noč, pridejo oni. **Prekleti.** + +Tvoj cilj je obnoviti kmetijo, pridelati hrano (ki je zdaj najvrednejša valuta) in zgraditi obrambo. Trgovali boste z redkimi preživelimi trgovci, ki si upajo potovati med naselbinami. + +**Ključne Mehanike:** +* **Farming (Kmetovanje):** Realistična rast pridelkov (koruza, pšenica, itd.). Vsaka rastlina ima svoj cikel. +* **Survival (Preživetje):** Lakota, žeja in spanje. +* **Combat (Boj):** Brani svojo letino pred nočnimi napadi zombijev. +* **Economy (Ekonomija):** Prodajaj pridelke za zlato, kupuj boljša orodja in semena. + +--- + +## 🛠️ Dosedanji Napredek (Feature Log) + +### Faza 1: Temelji (5. - 6. Dec 2025) +- [x] Vzpostavitev projekta (Node.js, Electron). +- [x] Implementacija **Antigravity Engine** (modularni sistem). +- [x] **Proceduralno Generiranje Sveta:** Uporaba Perlin Noise za ustvarjanje neskončnega, razgibanega terena (trava, voda, pesek). +- [x] Izometrična kamera in gibanje igralca. + +### Faza 2: Sistemi Igre (6. - 7. Dec 2025) +- [x] **Farming System:** + - Oranje zemlje z motiko. + - Sajenje semen. + - Faze rasti (seme -> kalček -> rastlina -> zrelo). + - Žetev pridelkov. +- [x] **Inventory System:** + - Delujoč inventar z zlaganjem (stacking). + - Drag & Drop (še v delu) / Slot selection. +- [x] **Time & Weather System:** + - Cikel dan/noč z vizualno zatemnitvijo. + - Dež (zvočni in vizualni efekti), ki namaka zemljo. + +### Faza 3: Poliranje in Realizem (8. Dec 2025 - Danes) +- [x] **Statistika in XP:** + - Dodan sistem izkušenj (XP). Igralec dobiva XP za sekanje dreves, rudarjenje in pobiranje pridelkov. + - Prikaz Levela in XP vrstice v HUD-u. +- [x] **Novi Pridelki:** + - **Pšenica:** Standardni pridelek, raste srednje hitro. + - **Koruza:** Visoka rast, počasnejša, a večji donos. + - Unikatne teksture za vsako fazo rasti. +- [x] **3D Voxel Orodja:** + - Proceduralno generirana orodja v 3D "Minecraft" stilu. + - Sekira, Kramp, Motika, Meč, Zalivalka - vsa imajo volumen in senčenje. +- [x] **Zvok:** + - Proceduralno generirani zvočni effekti (kopanje, sekanje, koraki). + - Popravek manjkajočih zvokov (`playDig`). + +--- + +## 🔮 Vizija za Naprej (TODO) +1. **Napredni NPC-ji:** Trgovci, ki pridejo le ob določenih dnevih. +2. **Gradnja Baze:** Postavljanje ograj in stolpov za obrambo. +3. **Razširitev Sveta:** Dodajanje novih biomov (gozd, puščava). +4. **Save System:** Shranjevanje napredka v datoteko. + +--- +*Zadnja posodobitev: 8. December 2025 ob 01:55* diff --git a/src/utils/TextureGenerator.js b/src/utils/TextureGenerator.js index 39da111..0167e08 100644 --- a/src/utils/TextureGenerator.js +++ b/src/utils/TextureGenerator.js @@ -136,23 +136,41 @@ class TextureGenerator { } static createCropSprite(scene, key, stage = 4) { - if (scene.textures.exists(key)) return; + if (scene.textures.exists(key)) scene.textures.remove(key); // FORCE REFRESH to see updates + const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); - ctx.fillStyle = '#228B22'; // Stem - const h = stage * 5; - ctx.fillRect(14, 32 - h, 4, h); + // Improved Wheat Visuals + const startY = 32; + // 1. Stems (Green -> Yellowish) + ctx.fillStyle = (stage < 3) ? '#32CD32' : '#DAA520'; + const h = stage * 6; + + // Draw distinct stalks + ctx.fillRect(10, startY - h, 2, h); // Left stalk + ctx.fillRect(16, startY - h, 2, h); // Center stalk + ctx.fillRect(22, startY - h, 2, h); // Right stalk + + // 2. Heads (Wheat ears) - Stage 3 & 4 if (stage >= 3) { - ctx.fillStyle = '#FFD700'; // Wheat head - ctx.beginPath(); ctx.arc(16, 32 - h, 6, 0, Math.PI * 2); ctx.fill(); + ctx.fillStyle = '#FFD700'; // Gold + // Left head + ctx.beginPath(); ctx.ellipse(11, startY - h, 3, 5, -0.2, 0, Math.PI * 2); ctx.fill(); + // Center head + ctx.beginPath(); ctx.ellipse(17, startY - h - 2, 3, 6, 0, 0, Math.PI * 2); ctx.fill(); + // Right head + ctx.beginPath(); ctx.ellipse(23, startY - h, 3, 5, 0.2, 0, Math.PI * 2); ctx.fill(); } - if (stage === 5) { // Withered + + // 3. Withered + if (stage === 5) { ctx.fillStyle = '#8B4513'; - ctx.fillRect(14, 20, 4, 12); + ctx.fillRect(10, 24, 14, 8); // Dead pile } + canvas.refresh(); } @@ -384,138 +402,104 @@ class TextureGenerator { } static createToolSprites(scene) { - // --- REALISTIC TOOLS (Procedural Generation) --- + // --- 3D VOXEL TOOLS --- - // 1. AXE (Sekira) - if (!scene.textures.exists('item_axe')) { - const c = scene.textures.createCanvas('item_axe', 32, 32); + const refresh = (key) => { + if (scene.textures.exists(key)) scene.textures.remove(key); + const c = scene.textures.createCanvas(key, 32, 32); const ctx = c.getContext(); ctx.clearRect(0, 0, 32, 32); + return { c, ctx }; + }; - // Handle (Wood) - ctx.fillStyle = '#8B4513'; - ctx.fillRect(14, 12, 4, 18); - - // Head (Metal) - ctx.fillStyle = '#708090'; // SlateGray - ctx.beginPath(); - ctx.moveTo(16, 12); - ctx.lineTo(24, 6); // Top edge - ctx.lineTo(24, 18); // Bottom edge - ctx.lineTo(16, 14); // Back to handle - ctx.fill(); - - // Edge (Sharp) - ctx.fillStyle = '#C0C0C0'; // Silver - ctx.fillRect(23, 6, 2, 12); - - c.refresh(); - } - - // 2. PICKAXE (Kramp) - if (!scene.textures.exists('item_pickaxe')) { - const c = scene.textures.createCanvas('item_pickaxe', 32, 32); - const ctx = c.getContext(); - ctx.clearRect(0, 0, 32, 32); + // Helper: Draw 3D Pixel/Block + const drawBlock = (ctx, x, y, color) => { + ctx.fillStyle = color; + ctx.fillRect(x, y, 2, 2); // Front + ctx.fillStyle = 'rgba(0,0,0,0.3)'; // Side shadow + ctx.fillRect(x + 2, y, 1, 2); + ctx.fillRect(x, y + 2, 3, 1); + }; + // 1. AXE (3D) + { + const { c, ctx } = refresh('item_axe'); // Handle - ctx.fillStyle = '#8B4513'; - ctx.fillRect(14, 10, 4, 20); - - // Head (Curved Metal) - ctx.fillStyle = '#696969'; // DimGray - ctx.beginPath(); - ctx.moveTo(6, 14); // Left tip - ctx.quadraticCurveTo(16, 4, 26, 14); // Curve over handle - ctx.lineTo(26, 16); - ctx.quadraticCurveTo(16, 8, 6, 16); - ctx.fill(); - - // Tips - ctx.fillStyle = '#DCDCDC'; - ctx.fillRect(5, 14, 2, 2); - ctx.fillRect(25, 14, 2, 2); - - c.refresh(); - } - - // 3. HOE (Motika) - if (!scene.textures.exists('item_hoe')) { - const c = scene.textures.createCanvas('item_hoe', 32, 32); - const ctx = c.getContext(); - ctx.clearRect(0, 0, 32, 32); - - // Handle - ctx.fillStyle = '#8B4513'; - ctx.fillRect(14, 6, 4, 24); - + for (let i = 0; i < 8; i++) drawBlock(ctx, 12 + i, 20 - i * 2, '#8B4513'); // Head - ctx.fillStyle = '#778899'; // LightSlateGray - ctx.fillRect(12, 6, 10, 4); // Top bar - ctx.fillRect(12, 6, 4, 8); // Blade down - - // Blade Edge - ctx.fillStyle = '#C0C0C0'; - ctx.fillRect(12, 12, 4, 2); - + for (let x = 0; x < 3; x++) { + for (let y = 0; y < 4; y++) { + drawBlock(ctx, 18 + x * 2, 6 + y * 2, '#708090'); // Gray Metal + } + } + drawBlock(ctx, 24, 8, '#C0C0C0'); // Edge + drawBlock(ctx, 24, 10, '#C0C0C0'); c.refresh(); } - // 4. SWORD (Meč) - if (!scene.textures.exists('item_sword')) { - const c = scene.textures.createCanvas('item_sword', 32, 32); - const ctx = c.getContext(); - ctx.clearRect(0, 0, 32, 32); - + // 2. PICKAXE (3D) + { + const { c, ctx } = refresh('item_pickaxe'); // Handle - ctx.fillStyle = '#8B4513'; - ctx.fillRect(15, 24, 2, 6); - // Pommel - ctx.fillStyle = '#FFD700'; // Gold - ctx.fillRect(14, 29, 4, 2); + for (let i = 0; i < 8; i++) drawBlock(ctx, 14, 8 + i * 2, '#8B4513'); + // Head (Arc) + drawBlock(ctx, 6, 10, '#696969'); + drawBlock(ctx, 8, 8, '#696969'); + drawBlock(ctx, 10, 6, '#696969'); + drawBlock(ctx, 12, 6, '#696969'); + drawBlock(ctx, 14, 6, '#696969'); // Center + drawBlock(ctx, 16, 6, '#696969'); + drawBlock(ctx, 18, 6, '#696969'); + drawBlock(ctx, 20, 8, '#696969'); + drawBlock(ctx, 22, 10, '#696969'); + c.refresh(); + } + // 3. HOE (3D) + { + const { c, ctx } = refresh('item_hoe'); + // Handle + for (let i = 0; i < 9; i++) drawBlock(ctx, 14 + i, 4 + i * 2, '#8B4513'); + // Head + drawBlock(ctx, 12, 4, '#778899'); + drawBlock(ctx, 14, 4, '#778899'); + drawBlock(ctx, 16, 6, '#778899'); + drawBlock(ctx, 16, 8, '#778899'); // Blade + c.refresh(); + } + + // 4. SWORD (3D) + { + const { c, ctx } = refresh('item_sword'); + // Handle + drawBlock(ctx, 14, 24, '#8B4513'); + drawBlock(ctx, 14, 26, '#8B4513'); // Guard - ctx.fillStyle = '#FFD700'; - ctx.fillRect(11, 22, 10, 2); - + drawBlock(ctx, 10, 22, '#FFD700'); + drawBlock(ctx, 12, 22, '#FFD700'); + drawBlock(ctx, 14, 22, '#FFD700'); + drawBlock(ctx, 16, 22, '#FFD700'); + drawBlock(ctx, 18, 22, '#FFD700'); // Blade - ctx.fillStyle = '#C0C0C0'; // Silver - ctx.fillRect(14, 4, 4, 18); - - // Blood Groove / Shine - ctx.fillStyle = '#F0F8FF'; // AliceBlue - ctx.fillRect(15, 4, 2, 18); - + for (let i = 0; i < 8; i++) drawBlock(ctx, 14, 6 + i * 2, '#C0C0C0'); c.refresh(); } - // 5. WATERING CAN (Zalivalka) - if (!scene.textures.exists('item_watering_can')) { - const c = scene.textures.createCanvas('item_watering_can', 32, 32); - const ctx = c.getContext(); - ctx.clearRect(0, 0, 32, 32); - - // Body - ctx.fillStyle = '#A9A9A9'; // DarkGray - ctx.fillRect(8, 12, 16, 14); - - // Handle - ctx.strokeStyle = '#696969'; - ctx.lineWidth = 2; - ctx.beginPath(); - ctx.moveTo(8, 14); - ctx.quadraticCurveTo(4, 10, 8, 6); - ctx.lineTo(20, 6); - ctx.stroke(); + // 5. WATERING CAN (3D) + { + const { c, ctx } = refresh('item_watering_can'); + // Body 3x3 blocks + for (let x = 0; x < 4; x++) + for (let y = 0; y < 3; y++) + drawBlock(ctx, 10 + x * 2, 14 + y * 2, '#A9A9A9'); // Spout - ctx.fillStyle = '#A9A9A9'; - ctx.beginPath(); - ctx.moveTo(24, 16); - ctx.lineTo(30, 10); - ctx.lineTo(28, 20); - ctx.fill(); - + drawBlock(ctx, 18, 12, '#A9A9A9'); + drawBlock(ctx, 20, 10, '#A9A9A9'); + // Handle + drawBlock(ctx, 8, 12, '#696969'); + drawBlock(ctx, 8, 10, '#696969'); + drawBlock(ctx, 10, 8, '#696969'); c.refresh(); } } @@ -537,14 +521,51 @@ class TextureGenerator { const it = typeof item === 'string' ? item : item.name; const color = typeof item === 'string' ? 'gold' : item.color; const k = (it.startsWith('item_')) ? it : 'item_' + it; - if (!scene.textures.exists(k)) { - const c = scene.textures.createCanvas(k, 32, 32); - const x = c.getContext(); - x.clearRect(0, 0, 32, 32); + + if (scene.textures.exists(k)) scene.textures.remove(k); // FORCE REFRESH + + const c = scene.textures.createCanvas(k, 32, 32); + const x = c.getContext(); + x.clearRect(0, 0, 32, 32); + + // SPECIAL ICONS + if (it === 'corn') { + // Corn Cob + x.fillStyle = '#228B22'; // Husk + x.beginPath(); x.ellipse(16, 16, 6, 12, 0, 0, Math.PI * 2); x.fill(); + x.fillStyle = '#FFD700'; // Kernels + x.beginPath(); x.ellipse(16, 16, 3, 8, 0, 0, Math.PI * 2); x.fill(); + } + else if (it === 'wheat') { + // Wheat Sheaf + x.strokeStyle = '#FFD700'; + x.lineWidth = 2; + x.beginPath(); + x.moveTo(12, 28); x.lineTo(20, 4); // Stalk 1 + x.moveTo(16, 28); x.lineTo(16, 4); // Stalk 2 + x.moveTo(20, 28); x.lineTo(12, 4); // Stalk 3 + x.stroke(); + // Tie + x.fillStyle = '#DAA520'; + x.fillRect(13, 22, 6, 3); + } + else if (it.includes('seeds')) { + // Seed Bag + x.fillStyle = '#DEB887'; // Burlywood bag + x.beginPath(); + x.moveTo(10, 8); x.lineTo(22, 8); // Top + x.lineTo(26, 26); x.lineTo(6, 26); // Bottom + x.fill(); + // Label/Dots + x.fillStyle = color; + x.beginPath(); x.arc(16, 18, 4, 0, Math.PI * 2); x.fill(); + } + else { + // Default Circle x.fillStyle = color; x.beginPath(); x.arc(16, 16, 10, 0, Math.PI * 2); x.fill(); - c.refresh(); } + c.refresh(); }); }