farma orodje in dnevnik
This commit is contained in:
75
DNEVNIK.md
Normal file
75
DNEVNIK.md
Normal file
@@ -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*
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user