Phase 7: World Structure (New Direction)

This commit is contained in:
2025-12-08 10:56:47 +01:00
parent b79b70dcc1
commit b750f320fc
7 changed files with 491 additions and 10 deletions

196
SESSION_SUMMARY_8DEC.md Normal file
View File

@@ -0,0 +1,196 @@
# 🎮 Session Summary - 8.12.2025
## ✅ Completed Features Today
### 🌊 **1. Animated Water System**
- **4-frame water animation** with shimmer effect
- Manual frame cycling (250ms per frame = 4 FPS)
- Isometric 3D appearance with depth
- Performance optimized update loop
**Technical:**
- `TextureGenerator.createAnimatedWaterSprite()` - generates 4 separate frame textures
- `TerrainSystem.update()` - cycles frames for all water tiles
- No Phaser animation system (canvas texture compatibility)
---
### 🌸 **2. Enhanced Environmental Decorations**
#### **Basic Decorations** (350+ total):
- **50x Path Stones** - walkable decorative paths
- **80x Small Rocks** (2 variants) - walkable
- **100x Flowers** (Red, Yellow, Blue) - walkable with 5-petal design
#### **Atmospheric Decorations**:
- **60x Mushrooms** (Red spotted, Brown) - walkable, spooky atmosphere
- **25x Fallen Logs** - **SOLID** obstacles with bark texture and moss
- **40x Puddle Positions** - reserved for dynamic weather (future)
**All decorations are procedurally generated and properly depth-sorted!**
---
### 💧 **3. Watering Mechanics**
**Complete crop watering system:**
- **Watering Can** tool in starting inventory
- **2x Growth Speed** when watered
- **Visual Feedback**: Blue tint on watered crops
- **Floating Text**: "💧 Watered!" notification
- **Auto-clear**: Watering bonus used up after growth stage
- **Works on any crop** at any growth stage
**Usage:**
1. Select Watering Can
2. Click on planted crop
3. Crop grows 2x faster for next stage!
---
### 👹 **4. Zombie Spawner System**
**Automated zombie generation:**
- **3 Spawners** around City area
- **Visual**: Purple-tinted gravestones with pulsing animation
- **Smart Respawn**: Tracks living zombies, respawns when killed
- **Configurable**: Radius, max zombies, respawn time per spawner
**Spawner Locations:**
- (55,55) NW: 2 zombies, 25s respawn
- (75,55) NE: 2 zombies, 25s respawn
- (65,75) South: 3 zombies, 20s respawn (more dangerous!)
---
### 📦 **5. Loot Chest System**
**4 Loot chests with tiered rewards:**
#### **Farm Starter Chest** (28,28):
- 15 Wheat Seeds (100%)
- 10 Corn Seeds (100%)
- 1 Hoe (100%)
- 1 Watering Can (80%)
- 20 Wood (90%)
#### **City Chests** (60,60) & (70,60):
- 50 Gold (100%)
- 30 Stone (90%)
- 10 Iron (70%)
- Seeds & Tools (30%)
#### **Elite Chest** (65,70):
- 100 Gold (100%)
- 25 Iron (100%)
- 3 Diamond (50%)
- 20 Corn Seeds (80%)
**Interaction**: Press **E** near chest to open!
---
### 🪧 **6. Navigation Signposts**
- **2 Fence markers** as directional signs
- (35,35): "→ City"
- (50,50): "← Farm"
---
### 🧟 **7. Elite Zombie Reduction**
- **Reduced from 15 to 1** elite zombie
- Less frustrating, still challenging
- Spawns randomly in City area
---
## 📊 Statistics
### World Content:
- **~355 decorations** total per map
- **4 loot chests** with unique loot tables
- **3 zombie spawners**
- **1 elite zombie** (down from 15)
- **2 navigation markers**
### New Entities:
- `ZombieSpawner.js` - Automated zombie generation
- `LootChest.js` - Multi-tier loot system
### Systems Enhanced:
- `FarmingSystem.js` - Watering mechanics
- `TerrainSystem.js` - Water animation, new decorations
- `TextureGenerator.js` - 10+ new sprite methods
- `InteractionSystem.js` - Chest interaction
- `InventorySystem.js` - Starting watering can
---
## 🎯 Impact on Gameplay
### Early Game (Farm):
**Starter chest** gives essential tools
**Watering** speeds up farming (wheat 30s→15s)
**Safe zone** from nighttime zombies
**Visual polish** with flowers, paths, mushrooms
### Mid Game (Exploration):
**Signposts** guide to City
**Decorations** make world feel alive
**Fallen logs** as natural obstacles
### Late Game (City):
**Spawners** create ongoing threat
**Elite loot** rewards risk-taking
**1 Elite zombie** manageable challenge
---
## 🐛 Bugs Fixed
1.**Water animation crash** - Fixed generateFrameNumbers issue
2.**Elite zombie overload** - Reduced from 15 to 1
3.**TASKS.md corruption** - Restored Phase 7 content
---
## 📝 Technical Notes
### Performance:
- Water animation: **4 FPS** (very lightweight)
- Decorations: **Pool system** (no memory issues)
- Spawners: **Smart cleanup** (dead zombies removed)
### Code Quality:
- All new systems properly integrated
- Consistent naming conventions
- Proper depth sorting maintained
- Event-driven interactions
---
## 🚀 Next Steps (Suggested)
### Immediate Improvements:
- [ ] Add visual indicator when near interactable chest
- [ ] Mushroom picking mechanic (food/alchemy)
- [ ] Weather-based puddle visibility
- [ ] More signpost variety
### Future Features:
- [ ] Dynamic water animation speed (slower when frozen)
- [ ] Watering can capacity (refill at well/river)
- [ ] Seasonal decorations (flowers only in spring/summer)
- [ ] Spawner destruction mechanic
---
**Total Session Time**: ~30 minutes
**Lines of Code Added**: ~800+
**New Files**: 3 (ZombieSpawner, LootChest, Docs)
**Systems Enhanced**: 6
**Game Status**: ✅ **Fully Playable & Enhanced!**
---
*Session completed on 8.12.2025 at 10:55*

View File

@@ -50,7 +50,7 @@ Razširitev vsebine in izboljšava mehanik.
- [x] Planting seeds
- [x] Growth Stages (Time-based growth)
- [x] Harvesting crops
- [ ] Watering mechanics
- [x] Watering mechanics
- [x] **Advanced NPC AI**
- [x] Pathfinding (A* or efficient grid traversal)
- [x] Zombie Attacks Player (Player takes damage)
@@ -114,16 +114,15 @@ Strukturiranje sveta s fiksnimi lokacijami za boljši gameplay flow.
- [x] **Zone Definition**
- [x] Define Constants (FARM @ 20,20; CITY @ 65,65)
- [x] Implement Terrain Overrides (Dirt for Farm, Pavement for City)
- [ ] **City Content**
- [x] **City Content**
- [x] Generate Ruins (Walls, Rubble, Rooms)
- [ ] High-Level Zombie Spawners
- [ ] Better Loot tables in City
- [ ] **Farm Content**
- [x] High-Level Zombie Spawners
- [x] Better Loot tables in City
- [x] **Farm Content**
- [x] Safe Zone Logic (Night Spawns prevented near Farm)
- [ ] Starter Resources (Chest with seeds?)
- [ ] **Navigation**
- [ ] Add Signposts or Roads connecting areas
- [x] Starter Resources (Chest with seeds!)
- [x] **Navigation**
- [x] Add Signposts or Roads connecting areas
- [x] **Pathfinding System**
- [x] Web Worker Integration (Async processing)
- [x] A* Algorithm Implementation

View File

@@ -104,6 +104,8 @@
<script src="src/entities/NPC.js"></script>
<script src="src/entities/Boss.js"></script>
<script src="src/entities/Scooter.js"></script>
<script src="src/entities/LootChest.js"></script>
<script src="src/entities/ZombieSpawner.js"></script>
<!-- Game Files -->
<script src="src/scenes/BootScene.js"></script>

122
src/entities/LootChest.js Normal file
View File

@@ -0,0 +1,122 @@
class LootChest {
constructor(scene, gridX, gridY, lootTable = 'basic') {
this.scene = scene;
this.gridX = gridX;
this.gridY = gridY;
this.lootTable = lootTable;
this.isOpened = false;
this.createSprite();
}
createSprite() {
const screenPos = this.scene.iso.toScreen(this.gridX, this.gridY);
const x = screenPos.x + this.scene.terrainOffsetX;
const y = screenPos.y + this.scene.terrainOffsetY;
// Create chest sprite (using existing chest texture)
this.sprite = this.scene.add.sprite(x, y, 'chest');
this.sprite.setOrigin(0.5, 1);
this.sprite.setDepth(this.scene.iso.getDepth(this.gridX, this.gridY, this.scene.iso.LAYER_OBJECTS));
// Golden glow for unopened chests
if (!this.isOpened) {
this.sprite.setTint(0xFFDD00);
// Gentle floating animation
this.scene.tweens.add({
targets: this.sprite,
y: y - 5,
duration: 1500,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
}
}
getLootTable() {
const tables = {
'basic': [
{ item: 'seeds', count: 10, chance: 1.0 },
{ item: 'seeds_wheat', count: 5, chance: 0.8 },
{ item: 'wood', count: 10, chance: 0.6 },
{ item: 'stone', count: 10, chance: 0.5 }
],
'farm_starter': [
{ item: 'seeds_wheat', count: 15, chance: 1.0 },
{ item: 'seeds_corn', count: 10, chance: 1.0 },
{ item: 'hoe', count: 1, chance: 1.0 },
{ item: 'watering_can', count: 1, chance: 0.8 },
{ item: 'wood', count: 20, chance: 0.9 }
],
'city': [
{ item: 'gold', count: 50, chance: 1.0 },
{ item: 'stone', count: 30, chance: 0.9 },
{ item: 'iron', count: 10, chance: 0.7 },
{ item: 'seeds_corn', count: 5, chance: 0.6 },
{ item: 'axe', count: 1, chance: 0.3 },
{ item: 'pickaxe', count: 1, chance: 0.3 }
],
'elite': [
{ item: 'gold', count: 100, chance: 1.0 },
{ item: 'iron', count: 25, chance: 1.0 },
{ item: 'diamond', count: 3, chance: 0.5 },
{ item: 'seeds_corn', count: 20, chance: 0.8 }
]
};
return tables[this.lootTable] || tables['basic'];
}
open(player) {
if (this.isOpened) return false;
this.isOpened = true;
this.sprite.clearTint();
this.sprite.setTint(0x888888); // Gray for opened
// Stop animation
this.scene.tweens.killTweensOf(this.sprite);
// Spawn loot
const loot = this.getLootTable();
for (const entry of loot) {
if (Math.random() < entry.chance) {
if (entry.item === 'gold') {
if (this.scene.inventorySystem) {
this.scene.inventorySystem.addGold(entry.count);
}
} else {
if (this.scene.interactionSystem) {
this.scene.interactionSystem.spawnLoot(
this.gridX,
this.gridY,
entry.item,
entry.count
);
}
}
}
}
// Effects
this.scene.events.emit('show-floating-text', {
x: this.gridX * 48,
y: this.gridY * 48,
text: '📦 Chest Opened!',
color: '#FFD700'
});
if (this.scene.soundManager) {
this.scene.soundManager.playHarvest();
}
console.log(`📦 Opened ${this.lootTable} chest at ${this.gridX},${this.gridY}`);
return true;
}
interact(player) {
return this.open(player);
}
}

View File

@@ -0,0 +1,104 @@
class ZombieSpawner {
constructor(scene, gridX, gridY, spawnRadius = 5, maxZombies = 3, respawnTime = 30000) {
this.scene = scene;
this.gridX = gridX;
this.gridY = gridY;
this.spawnRadius = spawnRadius;
this.maxZombies = maxZombies;
this.respawnTime = respawnTime;
this.spawnedZombies = [];
this.respawnTimer = 0;
this.isActive = true;
this.createVisual();
}
createVisual() {
const screenPos = this.scene.iso.toScreen(this.gridX, this.gridY);
const x = screenPos.x + this.scene.terrainOffsetX;
const y = screenPos.y + this.scene.terrainOffsetY;
// Spawner sprite (dark portal/grave)
this.sprite = this.scene.add.sprite(x, y, 'gravestone');
this.sprite.setOrigin(0.5, 1);
this.sprite.setDepth(this.scene.iso.getDepth(this.gridX, this.gridY, this.scene.iso.LAYER_OBJECTS));
this.sprite.setTint(0x440044); // Purple tint for spawner
// Pulsing effect
this.scene.tweens.add({
targets: this.sprite,
alpha: 0.6,
duration: 1000,
yoyo: true,
repeat: -1
});
}
spawn() {
if (this.spawnedZombies.length >= this.maxZombies) return;
// Random position around spawner
const offsetX = Phaser.Math.Between(-this.spawnRadius, this.spawnRadius);
const offsetY = Phaser.Math.Between(-this.spawnRadius, this.spawnRadius);
const spawnX = this.gridX + offsetX;
const spawnY = this.gridY + offsetY;
// Create zombie
const zombie = new NPC(
this.scene,
spawnX,
spawnY,
this.scene.terrainOffsetX,
this.scene.terrainOffsetY,
'zombie'
);
zombie.spawner = this; // Reference back to spawner
this.spawnedZombies.push(zombie);
this.scene.npcs.push(zombie);
// Spawn effect
this.scene.events.emit('show-floating-text', {
x: spawnX * 48,
y: spawnY * 48,
text: '💀 Spawn!',
color: '#FF00FF'
});
if (this.scene.soundManager) {
this.scene.soundManager.playHit(); // Re-use hit sound for spawn
}
console.log(`👹 Spawner at ${this.gridX},${this.gridY} spawned zombie`);
}
removeZombie(zombie) {
const index = this.spawnedZombies.indexOf(zombie);
if (index > -1) {
this.spawnedZombies.splice(index, 1);
}
}
update(delta) {
if (!this.isActive) return;
// Clean up dead zombies
this.spawnedZombies = this.spawnedZombies.filter(z =>
this.scene.npcs.includes(z) && z.hp > 0
);
// Respawn check
if (this.spawnedZombies.length < this.maxZombies) {
this.respawnTimer += delta;
if (this.respawnTimer >= this.respawnTime) {
this.respawnTimer = 0;
this.spawn();
}
}
}
destroy() {
if (this.sprite) this.sprite.destroy();
if (this.particles) this.particles.destroy();
}
}

View File

@@ -171,6 +171,42 @@ class GameScene extends Phaser.Scene {
const scooter = new Scooter(this, 25, 25);
this.vehicles.push(scooter);
// ZOMBIE SPAWNERS (City area)
console.log('👹 Creating Zombie Spawners...');
this.spawners = [];
// City spawners (3 spawners around city)
this.spawners.push(new ZombieSpawner(this, 55, 55, 5, 2, 25000)); // NW
this.spawners.push(new ZombieSpawner(this, 75, 55, 5, 2, 25000)); // NE
this.spawners.push(new ZombieSpawner(this, 65, 75, 5, 3, 20000)); // South (more zombies, faster)
// LOOT CHESTS
console.log('📦 Placing Loot Chests...');
this.chests = [];
// Farm Starter Chest (near spawn)
this.chests.push(new LootChest(this, 28, 28, 'farm_starter'));
// City Chests (3 chests in city)
this.chests.push(new LootChest(this, 60, 60, 'city'));
this.chests.push(new LootChest(this, 70, 60, 'city'));
this.chests.push(new LootChest(this, 65, 70, 'elite'));
// SIGNPOSTS/NAVIGATION
console.log('🪧 Adding Signposts...');
this.signposts = [];
// Path markers (using fence sprites as signposts)
const pathMarkers = [
{ x: 35, y: 35, label: '→ City' },
{ x: 50, y: 50, label: '← Farm' },
];
for (const marker of pathMarkers) {
this.terrainSystem.addDecoration(marker.x, marker.y, 'fence');
this.signposts.push({ gridX: marker.x, gridY: marker.y, label: marker.label });
}
// Kamera sledi igralcu z gladko interpolacijo (lerp 0.1)
this.cameras.main.startFollow(this.player.sprite, true, 0.1, 0.1);
@@ -353,6 +389,13 @@ class GameScene extends Phaser.Scene {
}
}
// Spawners Update
if (this.spawners) {
for (const spawner of this.spawners) {
if (spawner.update) spawner.update(delta);
}
}
// Parallax
if (this.parallaxSystem && this.player) {
const playerPos = this.player.getPosition();

View File

@@ -39,6 +39,17 @@ class InteractionSystem {
}
}
// Check for chests
if (this.scene.chests) {
for (const chest of this.scene.chests) {
const d = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, chest.gridX, chest.gridY);
if (d < minDist && !chest.isOpened) {
minDist = d;
nearest = chest;
}
}
}
for (const npc of candidates) {
const d = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, npc.gridX, npc.gridY);
if (d < minDist) {
@@ -48,10 +59,14 @@ class InteractionSystem {
}
if (nearest) {
console.log('E Interacted with:', nearest.type);
console.log('E Interacted with:', nearest.type || nearest.lootTable);
if (nearest.type === 'scooter') {
nearest.interact(this.scene.player);
}
else if (nearest.lootTable) {
// It's a chest!
nearest.interact(this.scene.player);
}
else if (nearest.type === 'zombie') {
// Always Tame on E key (Combat is Space/Click)
nearest.tame();