svet
134
SESSION_FOREST_OPTIMIZATION.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# 🌲 Sesija: Optimizacija Gozda - 12. December 2025
|
||||
|
||||
## 📋 Povzetek Sesije
|
||||
|
||||
### 🎯 Cilj
|
||||
Generirati 100x100 mapo z **Stardew Valley stilom gozda** z vijolčnimi in sadnimi drevesi ter zapuščenimi hišami.
|
||||
|
||||
### ✅ Dosežki
|
||||
|
||||
#### 1. **Velikost Mape**
|
||||
- ✅ Spremenjena na **100x100** tiles
|
||||
- ✅ Celoten teren: `GRASS_FULL`
|
||||
- ✅ Farm: 8x8 na (50,50) z `DIRT` ploščicami
|
||||
|
||||
#### 2. **Drevesni Sistem**
|
||||
- ✅ **Gostota:** 1% (zelo nizka, optimizirana)
|
||||
- ✅ **Preverjanje razdalje:** Min 2 tiles med drevesi
|
||||
- ✅ **Vrste dreves:**
|
||||
- 💜 30% Vijolčna drevesa (`tree_purple`)
|
||||
- 🍎 20% Sadna drevesa (`tree_apple`, `tree_pear`, `tree_cherry`)
|
||||
- 🌳 50% Zelena/modra drevesa (`tree_green_final`, `tree_blue_final`)
|
||||
|
||||
#### 3. **Sprite-i**
|
||||
- ✅ Generirani novi sprite-i za drevesa
|
||||
- ✅ Ultra agresivno odstranjevanje ozadij (brightness > 100)
|
||||
- ✅ Čisti, transparentni sprite-i
|
||||
|
||||
#### 4. **Optimizacije**
|
||||
- ✅ Odstranjena vsa ozadja iz sprite-ov
|
||||
- ✅ Pomanjšana drevesa (scale 0.6-0.7)
|
||||
- ✅ Sistem preverjanja razdalje med drevesi
|
||||
- ✅ Čista mapa brez nepotrebnih dekoracij
|
||||
|
||||
### 🔧 Ključne Spremembe
|
||||
|
||||
#### **TerrainSystem.js**
|
||||
```javascript
|
||||
// Konstante
|
||||
const TREE_DENSITY = 0.01; // 1% gostota
|
||||
const PURPLE_TREE_CHANCE = 0.30;
|
||||
const FRUIT_TREE_CHANCE = 0.20;
|
||||
const MIN_TREE_DISTANCE_SQUARED = 2 * 2;
|
||||
|
||||
// Tracking dreves
|
||||
this.placedTrees = [];
|
||||
|
||||
// Funkcija za preverjanje razdalje
|
||||
isTreeLocationFarEnough(newX, newY) {
|
||||
// Preveri razdaljo do vseh dreves
|
||||
// Vrne true če je OK, false če preblizu
|
||||
}
|
||||
```
|
||||
|
||||
#### **GameScene.js**
|
||||
```javascript
|
||||
// Farm ploščice - DIRT namesto GRASS
|
||||
this.terrainSystem.tiles[y][x].type = 'dirt';
|
||||
this.terrainSystem.tiles[y][x].sprite.setTexture('dirt');
|
||||
```
|
||||
|
||||
#### **PreloadScene.js**
|
||||
```javascript
|
||||
// Novi sprite-i
|
||||
this.load.image('tree_purple', 'assets/tree_purple.png');
|
||||
this.load.image('tree_apple', 'assets/tree_apple.png');
|
||||
this.load.image('tree_pear', 'assets/tree_pear.png');
|
||||
this.load.image('tree_cherry', 'assets/tree_cherry.png');
|
||||
|
||||
// Ultra agresivno odstranjevanje ozadij
|
||||
processSpriteTransparency(spriteKey) {
|
||||
// Odstrani VSE svetle barve (brightness > 100)
|
||||
// Odstrani VSE sive barve
|
||||
// Odstrani VSE pastelne barve
|
||||
}
|
||||
```
|
||||
|
||||
### 🐛 Odpravljene Napake
|
||||
|
||||
1. ✅ **TypeError: Cannot read properties of null (reading 'addDecoration')**
|
||||
- Dodano preverjanje `if (this.terrainSystem)` pred klici
|
||||
|
||||
2. ✅ **ReferenceError: TILE_PAVEMENT is not defined**
|
||||
- Dodane manjkajoče konstante za rudnik
|
||||
|
||||
3. ✅ **Cannot read properties of null (reading 'getTile')**
|
||||
- Dodano preverjanje v OceanSystem
|
||||
|
||||
4. ✅ **Stari save file nalaga hiše**
|
||||
- Onemogočen loadGame() za testiranje
|
||||
- Odstranjena koda za generiranje hiš
|
||||
|
||||
5. ✅ **Ozadja še vedno vidna**
|
||||
- Ultra agresivno odstranjevanje (brightness > 100)
|
||||
- Python skripta za procesiranje
|
||||
|
||||
### 📊 Končna Konfiguracija
|
||||
|
||||
**Mapa:**
|
||||
- Velikost: 100x100
|
||||
- Teren: Zelena trava (`grass_full`)
|
||||
- Farm: 8x8 dirt ploščice na (50,50)
|
||||
|
||||
**Drevesa:**
|
||||
- Gostota: 1%
|
||||
- Min. razdalja: 2 tiles
|
||||
- Vijolčna: 30%
|
||||
- Sadna: 20%
|
||||
- Zelena/modra: 50%
|
||||
|
||||
**Dekoracije:**
|
||||
- Grmički: 0%
|
||||
- Rože: 0%
|
||||
- Skale: 0%
|
||||
- Hiše: 0%
|
||||
|
||||
### 🎯 Naslednji Koraki
|
||||
|
||||
1. **Testiranje v igri** - Vizualno preverjanje gozda
|
||||
2. **Dodatne izboljšave** - Po potrebi prilagoditev gostote
|
||||
3. **Interakcije** - Sekanje dreves, nabiranje sadja
|
||||
4. **Zapuščene hiše** - Ponovno dodati če želeno
|
||||
|
||||
### 📝 Opombe
|
||||
|
||||
- Save sistem je ponovno omogočen
|
||||
- Vsi sprite-i imajo transparentna ozadja
|
||||
- Sistem preverjanja razdalje preprečuje prekrivanje
|
||||
- Optimizirana gostota za boljšo vidnost
|
||||
|
||||
---
|
||||
|
||||
**Datum:** 12. December 2025
|
||||
**Trajanje:** ~1.5 ure
|
||||
**Status:** ✅ Uspešno zaključeno
|
||||
BIN
assets/tree_apple.png
Normal file
|
After Width: | Height: | Size: 916 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 129 KiB |
BIN
assets/tree_cherry.png
Normal file
|
After Width: | Height: | Size: 988 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 177 KiB |
BIN
assets/tree_pear.png
Normal file
|
After Width: | Height: | Size: 986 KiB |
BIN
assets/tree_purple.png
Normal file
|
After Width: | Height: | Size: 898 KiB |
18
clear_all_saves.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// CLEAR ALL SAVE FILES
|
||||
console.log('🗑️ Clearing ALL save files...');
|
||||
|
||||
// Clear main save
|
||||
localStorage.removeItem('novafarma_savefile');
|
||||
|
||||
// Clear all slots
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
localStorage.removeItem(`novafarma_save_slot${i}`);
|
||||
localStorage.removeItem(`novafarma_slot${i}_meta`);
|
||||
}
|
||||
|
||||
// Clear other saves
|
||||
localStorage.removeItem('novafarma_save');
|
||||
localStorage.removeItem('novafarma_achievement_progress');
|
||||
|
||||
console.log('✅ All saves cleared! Reload page (F4) for fresh start.');
|
||||
console.log('📝 Remaining keys:', Object.keys(localStorage).filter(k => k.includes('novafarma')));
|
||||
3
clear_save.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// Clear localStorage save file
|
||||
localStorage.removeItem('novafarma_savefile');
|
||||
console.log('✅ Save file cleared! Reload page (F4) for fresh start.');
|
||||
@@ -23,7 +23,9 @@
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"canvas": "^3.2.0",
|
||||
"phaser": "^3.80.1"
|
||||
"express": "^5.2.1",
|
||||
"phaser": "^3.80.1",
|
||||
"socket.io": "^4.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^33.2.1"
|
||||
|
||||
78
remove_backgrounds.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from PIL import Image
|
||||
import os
|
||||
|
||||
# Lista slik za procesiranje
|
||||
images_to_process = [
|
||||
'assets/tree_purple.png',
|
||||
'assets/tree_apple.png',
|
||||
'assets/tree_pear.png',
|
||||
'assets/tree_cherry.png'
|
||||
]
|
||||
|
||||
def remove_background(image_path):
|
||||
"""Odstrani ozadje iz slike - naredi transparentno"""
|
||||
try:
|
||||
# Naloži sliko
|
||||
img = Image.open(image_path).convert('RGBA')
|
||||
data = img.getdata()
|
||||
|
||||
new_data = []
|
||||
for item in data:
|
||||
r, g, b, a = item
|
||||
|
||||
# Izračunaj brightness in grayscale
|
||||
brightness = (r + g + b) / 3
|
||||
is_grayscale = abs(r - g) < 20 and abs(g - b) < 20 and abs(r - b) < 20
|
||||
|
||||
# Odstrani:
|
||||
# 1. Vse sive barve (šahovsko ozadje)
|
||||
# 2. Vse svetle barve (brightness > 150)
|
||||
# 3. Bele barve
|
||||
# 4. Pastelne barve (nizka saturacija)
|
||||
|
||||
should_remove = False
|
||||
|
||||
# Sive barve
|
||||
if is_grayscale and brightness > 80:
|
||||
should_remove = True
|
||||
|
||||
# Svetle barve
|
||||
if brightness > 150:
|
||||
should_remove = True
|
||||
|
||||
# Bele
|
||||
if r > 240 and g > 240 and b > 240:
|
||||
should_remove = True
|
||||
|
||||
# Pastelne (nizka saturacija)
|
||||
max_rgb = max(r, g, b)
|
||||
min_rgb = min(r, g, b)
|
||||
saturation = 0 if max_rgb == 0 else (max_rgb - min_rgb) / max_rgb
|
||||
|
||||
if saturation < 0.3 and brightness > 120:
|
||||
should_remove = True
|
||||
|
||||
if should_remove:
|
||||
new_data.append((r, g, b, 0)) # Transparentno
|
||||
else:
|
||||
new_data.append(item) # Ohrani original
|
||||
|
||||
# Posodobi sliko
|
||||
img.putdata(new_data)
|
||||
|
||||
# Shrani
|
||||
img.save(image_path)
|
||||
print(f'✅ Processed: {image_path}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Error processing {image_path}: {e}')
|
||||
|
||||
# Procesiraj vse slike
|
||||
print('🎨 Removing backgrounds from tree sprites...')
|
||||
for img_path in images_to_process:
|
||||
if os.path.exists(img_path):
|
||||
remove_background(img_path)
|
||||
else:
|
||||
print(f'⚠️ File not found: {img_path}')
|
||||
|
||||
print('✅ Done! All backgrounds removed.')
|
||||
@@ -208,14 +208,19 @@ class GameScene extends Phaser.Scene {
|
||||
this.signposts = [];
|
||||
|
||||
// Path markers (using fence sprites as signposts)
|
||||
const pathMarkers = [
|
||||
{ x: 35, y: 35, label: '→ City' },
|
||||
{ x: 50, y: 50, label: '← Farm' },
|
||||
];
|
||||
// ONLY if terrainSystem was successfully initialized
|
||||
if (this.terrainSystem) {
|
||||
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 });
|
||||
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 });
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ TerrainSystem not initialized - skipping signposts');
|
||||
}
|
||||
|
||||
// Kamera sledi igralcu z gladko interpolacijo (lerp 0.1)
|
||||
@@ -280,8 +285,8 @@ class GameScene extends Phaser.Scene {
|
||||
// Initialize Save System
|
||||
this.saveSystem = new SaveSystem(this);
|
||||
|
||||
// Auto-load if available
|
||||
this.saveSystem.loadGame();
|
||||
// Auto-load if available (DISABLED in SaveSystem!)
|
||||
this.saveSystem.loadGame(); // Vrne false - ne naloži save-a!
|
||||
|
||||
// Debug Text
|
||||
this.add.text(10, 10, 'NovaFarma Alpha v0.6', { font: '16px monospace', fill: '#ffffff' })
|
||||
@@ -738,11 +743,11 @@ class GameScene extends Phaser.Scene {
|
||||
if (this.terrainSystem.decorationsMap.has(key)) {
|
||||
this.terrainSystem.removeDecoration(x, y);
|
||||
}
|
||||
// Make it grass or dirt - USE CORRECT TERRAIN TYPE OBJECT
|
||||
// Make it DIRT for farming
|
||||
if (this.terrainSystem.tiles[y] && this.terrainSystem.tiles[y][x]) {
|
||||
this.terrainSystem.tiles[y][x].type = this.terrainSystem.terrainTypes.GRASS_FULL;
|
||||
this.terrainSystem.tiles[y][x].type = 'dirt';
|
||||
if (this.terrainSystem.tiles[y][x].sprite) {
|
||||
this.terrainSystem.tiles[y][x].sprite.setTexture('grass');
|
||||
this.terrainSystem.tiles[y][x].sprite.setTexture('dirt');
|
||||
this.terrainSystem.tiles[y][x].sprite.setTint(0xffffff); // Clear tint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,13 @@ class PreloadScene extends Phaser.Scene {
|
||||
this.load.image('tree_blue_final', 'assets/tree_blue_final.png');
|
||||
this.load.image('tree_dead_final', 'assets/tree_dead_final.png');
|
||||
|
||||
// STARDEW VALLEY FOREST TREES (NEW!)
|
||||
this.load.image('tree_purple', 'assets/tree_purple.png');
|
||||
this.load.image('tree_apple', 'assets/tree_apple.png');
|
||||
this.load.image('tree_pear', 'assets/tree_pear.png');
|
||||
this.load.image('tree_cherry', 'assets/tree_cherry.png');
|
||||
this.load.image('tree_sapling', 'assets/tree_green_final.png'); // Reuse green as sapling
|
||||
|
||||
// NEW transparent tree/rock assets
|
||||
this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); // Keep for backup
|
||||
|
||||
@@ -53,6 +60,9 @@ class PreloadScene extends Phaser.Scene {
|
||||
this.load.image('merchant_new', 'assets/merchant_new.png');
|
||||
this.load.image('elite_zombie', 'assets/elite_zombie.png');
|
||||
|
||||
// Fence old for abandoned houses
|
||||
this.load.image('fence_old', 'assets/fence_isometric.png'); // Reuse fence for old houses
|
||||
|
||||
// AI-Generated NPC Sprites (with cache-busting)
|
||||
const cacheBust = Date.now();
|
||||
this.load.image('cow', `assets/cow.png?v=${cacheBust}`);
|
||||
@@ -191,6 +201,13 @@ class PreloadScene extends Phaser.Scene {
|
||||
'tree_blue_final',
|
||||
'tree_dead_final',
|
||||
|
||||
// STARDEW VALLEY FOREST TREES
|
||||
'tree_purple',
|
||||
'tree_apple',
|
||||
'tree_pear',
|
||||
'tree_cherry',
|
||||
'tree_sapling',
|
||||
|
||||
// NEW transparent assets
|
||||
'tree_blue_new',
|
||||
'tree_green_new',
|
||||
@@ -203,6 +220,7 @@ class PreloadScene extends Phaser.Scene {
|
||||
'flowers_new',
|
||||
'hill_sprite',
|
||||
'fence',
|
||||
'fence_old',
|
||||
'gravestone',
|
||||
// City content
|
||||
'chest',
|
||||
@@ -288,43 +306,51 @@ class PreloadScene extends Phaser.Scene {
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const data = imageData.data;
|
||||
|
||||
// Remove backgrounds - IMPROVED CHECKBOARD DETECTION
|
||||
// Remove backgrounds - ULTRA AGGRESSIVE MODE!
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const r = data[i];
|
||||
const g = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
const a = data[i + 3];
|
||||
|
||||
// Remove ALL grayscale colors (checkboard pattern)
|
||||
// Checkboard has both light (204,204,204) and dark (153,153,153) squares
|
||||
const isGrayscale = Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && Math.abs(r - b) < 15;
|
||||
// Skip if already transparent
|
||||
if (a === 0) continue;
|
||||
|
||||
if (isGrayscale) {
|
||||
// ULTRA-AGGRESSIVE: Remove ALL grays from 100-240
|
||||
const isAnyGray = r >= 100 && r <= 240;
|
||||
|
||||
if (isAnyGray) {
|
||||
data[i + 3] = 0; // Make transparent
|
||||
}
|
||||
}
|
||||
|
||||
// AGGRESSIVE: Remove ALL light backgrounds (AI-generated sprites)
|
||||
const brightness = (r + g + b) / 3;
|
||||
const isVeryLight = brightness > 170 && Math.abs(r - g) < 50 && Math.abs(g - b) < 50;
|
||||
|
||||
if (isVeryLight) {
|
||||
// 1. Remove ALL grayscale colors (ANY shade of gray)
|
||||
const isGrayscale = Math.abs(r - g) < 20 && Math.abs(g - b) < 20 && Math.abs(r - b) < 20;
|
||||
if (isGrayscale && brightness > 80) {
|
||||
data[i + 3] = 0; // Make transparent
|
||||
continue;
|
||||
}
|
||||
|
||||
// ULTRA AGGRESSIVE: Remove PURE WHITE backgrounds
|
||||
const isWhite = r > 240 && g > 240 && b > 240;
|
||||
if (isWhite) {
|
||||
// 2. Remove ALL light/bright backgrounds (AI-generated sprites)
|
||||
if (brightness > 150) {
|
||||
data[i + 3] = 0; // Make transparent
|
||||
continue;
|
||||
}
|
||||
|
||||
// ULTRA AGGRESSIVE: Remove OFF-WHITE backgrounds (cream, beige)
|
||||
const isOffWhite = brightness > 230 && Math.abs(r - g) < 20 && Math.abs(g - b) < 20;
|
||||
if (isOffWhite) {
|
||||
data[i + 3] = 0; // Make transparent
|
||||
// 3. Remove PURE WHITE
|
||||
if (r > 240 && g > 240 && b > 240) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. Remove OFF-WHITE / CREAM / BEIGE
|
||||
if (brightness > 200 && Math.abs(r - g) < 30 && Math.abs(g - b) < 30) {
|
||||
data[i + 3] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5. Remove PASTEL colors (low saturation, high brightness)
|
||||
const maxRGB = Math.max(r, g, b);
|
||||
const minRGB = Math.min(r, g, b);
|
||||
const saturation = maxRGB === 0 ? 0 : (maxRGB - minRGB) / maxRGB;
|
||||
|
||||
if (saturation < 0.3 && brightness > 120) {
|
||||
data[i + 3] = 0; // Remove low-saturation backgrounds
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special: Remove brown/tan backgrounds (merchant sprite)
|
||||
|
||||
@@ -26,7 +26,7 @@ class OceanSystem {
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
if (!this.scene.player) return;
|
||||
if (!this.scene.player || !this.scene.terrainSystem) return;
|
||||
|
||||
const playerPos = this.scene.player.getPosition();
|
||||
const tile = this.scene.terrainSystem.getTile(playerPos.x, playerPos.y);
|
||||
@@ -83,6 +83,8 @@ class OceanSystem {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.scene.terrainSystem) return;
|
||||
|
||||
// Check if on water or near water?
|
||||
// Actually, let's allow "deploying" boat anywhere, but only moving fast on water?
|
||||
// OR: Only allow deploying on water tile.
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
// ========================================================
|
||||
// NOVE GLOBALNE KONSTANTE ZA LOKACIJE
|
||||
// STARDEW VALLEY STYLE FOREST MAP - 100x100
|
||||
// ========================================================
|
||||
const MAP_SIZE = 100; // 100x100 velika mapa!
|
||||
const FARM_SIZE = 8; // 8x8 MICRO FARM - Začetek igre!
|
||||
const FARM_CENTER_X = 50; // Center mape (50,50)
|
||||
const FARM_CENTER_Y = 50; // Center mape (50,50)
|
||||
|
||||
const CITY_SIZE = 15;
|
||||
const CITY_START_X = 65; // Desni del mape (npr. med 65 in 80)
|
||||
const CITY_START_Y = 65;
|
||||
// Zapuščene hiše lokacije - ODSTRANJENO ZA TESTIRANJE!
|
||||
const ABANDONED_HOUSES = [
|
||||
// { x: 25, y: 25, size: 5 },
|
||||
// { x: 75, y: 30, size: 6 },
|
||||
// { x: 40, y: 75, size: 4 }
|
||||
]; // PRAZNO - brez hiš!
|
||||
|
||||
// ========================================================
|
||||
// NOVE KONSTANTE ZA RUDNIK IN RUDE
|
||||
// GOZD KONSTANTE - STARDEW VALLEY STYLE (OPTIMIZIRANO)
|
||||
// ========================================================
|
||||
const TILE_STONE_ORE = 82; // ID za navadni kamen (Ore Tile)
|
||||
const TILE_IRON_ORE = 83; // ID za železovo rudo
|
||||
const TILE_PAVEMENT = 16; // ID za prehodno ploščico (tla rudnika)
|
||||
const TILE_MINE_WALL = 81; // ID za zid rudnika (Solid/Kolizija)
|
||||
|
||||
// ID-ji Virov
|
||||
const ITEM_STONE = 20; // ID za kamen, ki ga igralec dobi
|
||||
const ITEM_IRON = 21; // ID za železo
|
||||
|
||||
const TREE_DENSITY_THRESHOLD = 0.45; // Višja vrednost = manj gosto (manj gozda)
|
||||
const TREE_DENSITY = 0.01; // 1% chance za drevo (zelo nizka gostota)
|
||||
const PURPLE_TREE_CHANCE = 0.30; // 30% vijolčnih dreves
|
||||
const FRUIT_TREE_CHANCE = 0.20; // 20% sadnih dreves
|
||||
const ROCK_DENSITY_THRESHOLD = 0.60; // Prag za skupine skal
|
||||
|
||||
// ========================================================
|
||||
// RUDNIK KONSTANTE (za terrainTypes)
|
||||
// ========================================================
|
||||
const TILE_PAVEMENT = 16; // ID za prehodno ploščico
|
||||
const TILE_MINE_WALL = 81; // ID za zid rudnika
|
||||
const TILE_STONE_ORE = 82; // ID za navadni kamen
|
||||
const TILE_IRON_ORE = 83; // ID za železovo rudo
|
||||
|
||||
// Terrain Generator System
|
||||
class TerrainSystem {
|
||||
constructor(scene, width = 100, height = 100) {
|
||||
@@ -127,10 +132,35 @@ class TerrainSystem {
|
||||
this.generatedChunks = new Set();
|
||||
this.chunkSize = 10;
|
||||
|
||||
// FOREST GENERATION: Tracking postavljenih dreves za preverjanje razdalje
|
||||
this.placedTrees = []; // Seznam vseh postavljenih dreves { x, y }
|
||||
this.MIN_TREE_DISTANCE_SQUARED = 2 * 2; // Minimalna razdalja med drevesi (2 tiles)
|
||||
|
||||
// Init tiles array with NULLs
|
||||
this.tiles = Array.from({ length: this.height }, () => Array(this.width).fill(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Preveri, ali je nova lokacija (newX, newY) dovolj oddaljena od vseh
|
||||
* že postavljenih dreves. Uporablja kvadrat razdalje za hitrejšo optimizacijo.
|
||||
*/
|
||||
isTreeLocationFarEnough(newX, newY) {
|
||||
for (let i = 0; i < this.placedTrees.length; i++) {
|
||||
const existingTree = this.placedTrees[i];
|
||||
|
||||
// Izračunaj kvadrat razdalje
|
||||
const dx = newX - existingTree.x;
|
||||
const dy = newY - existingTree.y;
|
||||
const distanceSq = (dx * dx) + (dy * dy);
|
||||
|
||||
// Če je razdalja manjša od zahtevane minimalne razdalje, zavrni lokacijo
|
||||
if (distanceSq < this.MIN_TREE_DISTANCE_SQUARED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true; // Lokacija je dovolj oddaljena
|
||||
}
|
||||
|
||||
createTileTextures() {
|
||||
const tileWidth = 48;
|
||||
const tileHeight = 60;
|
||||
@@ -373,186 +403,87 @@ class TerrainSystem {
|
||||
for (let y = startY; y < endY; y++) {
|
||||
for (let x = startX; x < endX; x++) {
|
||||
|
||||
// --- PER TILE GENERATION LOGIC (Moved from old loop) ---
|
||||
const nx = x * 0.1;
|
||||
const ny = y * 0.1;
|
||||
const elevation = this.noise.noise(nx, ny);
|
||||
|
||||
// SIMPLE TERRAIN - samo grass (brez elevation/stone/hills)
|
||||
let terrainType = this.terrainTypes.GRASS_FULL;
|
||||
|
||||
// Edges of WORLD -也 grass
|
||||
// (removed elevation-based terrain - user wants clean platform)
|
||||
// --- STARDEW VALLEY FOREST GENERATION ---
|
||||
let terrainType = this.terrainTypes.GRASS_FULL; // Vsa mapa je trava!
|
||||
|
||||
// Farm Override - ZELENA PLATFORMA!
|
||||
if (Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 && Math.abs(y - FARM_CENTER_Y) <= FARM_SIZE / 2) {
|
||||
terrainType = this.terrainTypes.GRASS_FULL; // ZELENA TRAVA!
|
||||
terrainType = this.terrainTypes.GRASS_FULL;
|
||||
}
|
||||
|
||||
// RIVER Override - VIJUGAST POTOK!
|
||||
// River gre diagonalno skozi mapo z sinusnim vijuganjem
|
||||
const riverCenterY = 50; // Center Y pozicija za river
|
||||
const riverWidth = 3; // Širina potoka (3 tiles)
|
||||
const waveAmplitude = 8; // Amplituda vijuganja
|
||||
const waveFrequency = 0.1; // Frekvenca vijuganja
|
||||
|
||||
// Izračun vijugaste poti
|
||||
const riverOffset = Math.sin(x * waveFrequency) * waveAmplitude;
|
||||
const riverY = riverCenterY + riverOffset;
|
||||
|
||||
// Če je tile znotraj river area
|
||||
if (Math.abs(y - riverY) <= riverWidth / 2) {
|
||||
terrainType = this.terrainTypes.WATER; // VODA!
|
||||
}
|
||||
|
||||
// City Override - DISABLED (User request: no walls)
|
||||
// if (x >= CITY_START_X && x < CITY_START_X + CITY_SIZE &&
|
||||
// y >= CITY_START_Y && y < CITY_START_Y + CITY_SIZE) {
|
||||
// const isEdge = (x === CITY_START_X ||
|
||||
// x === CITY_START_X + CITY_SIZE - 1 ||
|
||||
// y === CITY_START_Y ||
|
||||
// y === CITY_START_Y + CITY_SIZE - 1);
|
||||
// if (isEdge) {
|
||||
// terrainType = { name: 'WALL_EDGE', color: 0x505050, solid: true };
|
||||
// } else {
|
||||
// terrainType = this.terrainTypes.PAVEMENT;
|
||||
// if (Math.random() < 0.15) {
|
||||
// terrainType = this.terrainTypes.RUINS;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Zapuščene hiše - DIRT tiles
|
||||
let isHouse = false;
|
||||
ABANDONED_HOUSES.forEach(house => {
|
||||
if (x >= house.x && x < house.x + house.size &&
|
||||
y >= house.y && y < house.y + house.size) {
|
||||
terrainType = this.terrainTypes.DIRT; // Hiša na DIRT
|
||||
isHouse = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Create Tile Data
|
||||
this.tiles[y][x] = {
|
||||
type: terrainType.name,
|
||||
texture: terrainType.name === 'water' ? 'water_frame_0' : terrainType.name, // Water tiles get animated frame!
|
||||
texture: terrainType.name,
|
||||
hasDecoration: false,
|
||||
hasCrop: false,
|
||||
solid: terrainType.solid || false
|
||||
solid: terrainType.solid || false,
|
||||
isHouse: isHouse
|
||||
};
|
||||
|
||||
// Track water tiles za animacijo
|
||||
if (terrainType.name === 'water') {
|
||||
this.waterTiles.push(this.tiles[y][x]);
|
||||
}
|
||||
|
||||
// Track valid positions for decorations
|
||||
if (terrainType.name !== 'water' && terrainType.name !== 'sand' && terrainType.name !== 'stone' && !terrainType.solid) {
|
||||
// Exclude Farm/City from random decor logic
|
||||
// Track valid positions for decorations (TREES!)
|
||||
if (terrainType.name === 'grass_full' && !isHouse) {
|
||||
const isFarm = Math.abs(x - FARM_CENTER_X) <= (FARM_SIZE / 2 + 2) && Math.abs(y - FARM_CENTER_Y) <= (FARM_SIZE / 2 + 2);
|
||||
const isCity = x >= CITY_START_X - 2 && x < CITY_START_X + CITY_SIZE + 2 && y >= CITY_START_Y - 2 && y < CITY_START_Y + CITY_SIZE + 2;
|
||||
|
||||
if (!isFarm && !isCity) {
|
||||
if (!isFarm) {
|
||||
validPositions.push({ x, y });
|
||||
}
|
||||
}
|
||||
|
||||
// Direct Placement Calls (Trees/Rocks) - legacy method support
|
||||
// this.placeTree(x, y, terrainType.name); // Optional: keep this if preferred over random batch
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- CHUNK DECORATION PASS ---
|
||||
// DISABLED - User wants clean platform (no trees, rocks, flowers)
|
||||
|
||||
// 1. Random Decorations - DISABLED
|
||||
// validPositions.forEach(pos => {
|
||||
// // Trees
|
||||
// if (Math.random() < 0.05) {
|
||||
// this.placeTree(pos.x, pos.y, 'grass');
|
||||
// }
|
||||
// // Rocks
|
||||
// if (Math.random() < 0.02) {
|
||||
// this.placeRock(pos.x, pos.y, 'grass');
|
||||
// }
|
||||
// // Flowers
|
||||
// if (Math.random() < 0.05) {
|
||||
// const flowers = ['flower_red', 'flower_yellow', 'flower_blue'];
|
||||
// const flowerType = flowers[Math.floor(Math.random() * flowers.length)];
|
||||
// this.addDecoration(pos.x, pos.y, flowerType);
|
||||
// }
|
||||
// // Path Stones
|
||||
// if (Math.random() < 0.02) {
|
||||
// this.addDecoration(pos.x, pos.y, 'path_stone');
|
||||
// }
|
||||
// });
|
||||
|
||||
// MICRO FARM FENCE (8x8 starting area) - DISABLED FOR NOW
|
||||
// Will be added properly later
|
||||
// --- STARDEW VALLEY FOREST DECORATION PASS ---
|
||||
const farmMinX = FARM_CENTER_X - FARM_SIZE / 2;
|
||||
const farmMaxX = FARM_CENTER_X + FARM_SIZE / 2;
|
||||
const farmMinY = FARM_CENTER_Y - FARM_SIZE / 2;
|
||||
const farmMaxY = FARM_CENTER_Y + FARM_SIZE / 2;
|
||||
|
||||
// DECORATIONS: Flowers & Bushes on grass tiles (random)
|
||||
for (let y = startY; y < endY; y++) {
|
||||
for (let x = startX; x < endX; x++) {
|
||||
const tile = this.tiles[y][x]; // Corrected access to this.tiles
|
||||
// DREVESA - 3% gostota z preverjanjem razdalje!
|
||||
validPositions.forEach(pos => {
|
||||
const rand = Math.random();
|
||||
|
||||
// Only on grass tiles, outside farm area
|
||||
if (tile && tile.type === 'GRASS_FULL' && // Changed 'grass' to 'GRASS_FULL' to match terrainType.name
|
||||
(x < farmMinX || x > farmMaxX || y < farmMinY || y > farmMaxY)) {
|
||||
|
||||
const rand = Math.random();
|
||||
|
||||
// 10% chance for flowers
|
||||
if (rand < 0.10) {
|
||||
const flowerTypes = ['flowers_new', 'flowers_pink_isometric'];
|
||||
const randomType = flowerTypes[Math.floor(Math.random() * flowerTypes.length)];
|
||||
this.addDecoration(x, y, randomType);
|
||||
}
|
||||
// 8% chance for grass patches (visual variety)
|
||||
else if (rand >= 0.10 && rand < 0.18) {
|
||||
this.addDecoration(x, y, 'grass_sprite');
|
||||
}
|
||||
// 5% chance for bushes
|
||||
else if (rand >= 0.18 && rand < 0.23) {
|
||||
this.addDecoration(x, y, 'bush_small');
|
||||
}
|
||||
// 3% chance for small rocks
|
||||
else if (rand >= 0.23 && rand < 0.26) {
|
||||
const rockTypes = ['rock_small', 'rock_2'];
|
||||
const randomRock = rockTypes[Math.floor(Math.random() * rockTypes.length)];
|
||||
this.addDecoration(x, y, randomRock);
|
||||
}
|
||||
// 3% chance za drevo
|
||||
if (rand < TREE_DENSITY) {
|
||||
// PREVERJANJE RAZDALJE: Ali je ta lokacija dovolj oddaljena?
|
||||
if (!this.isTreeLocationFarEnough(pos.x, pos.y)) {
|
||||
return; // Preskoči to lokacijo - preblizu drugim drevesom!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this chunk contains farm border
|
||||
if (cx * this.chunkSize <= farmMaxX && (cx + 1) * this.chunkSize >= farmMinX &&
|
||||
cy * this.chunkSize <= farmMaxY && (cy + 1) * this.chunkSize >= farmMinY) {
|
||||
const treeRand = Math.random();
|
||||
let treeType;
|
||||
|
||||
// Top border (y = farmMinY)
|
||||
if (startY <= farmMinY && endY > farmMinY) {
|
||||
for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) {
|
||||
this.addDecoration(x, farmMinY, 'fence_isometric');
|
||||
// 30% VIJOLČNA DREVESA
|
||||
if (treeRand < PURPLE_TREE_CHANCE) {
|
||||
treeType = 'tree_purple';
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom border (y = farmMaxY)
|
||||
if (startY <= farmMaxY && endY > farmMaxY) {
|
||||
for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) {
|
||||
this.addDecoration(x, farmMaxY, 'fence_isometric');
|
||||
// 20% SADNA DREVESA
|
||||
else if (treeRand < PURPLE_TREE_CHANCE + FRUIT_TREE_CHANCE) {
|
||||
const fruitTypes = ['tree_apple', 'tree_pear', 'tree_cherry'];
|
||||
treeType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
|
||||
}
|
||||
}
|
||||
|
||||
// Left border (x = farmMinX)
|
||||
if (startX <= farmMinX && endX > farmMinX) {
|
||||
for (let y = Math.max(startY, farmMinY); y <= Math.min(endY - 1, farmMaxY); y++) {
|
||||
this.addDecoration(farmMinX, y, 'fence_isometric');
|
||||
// 50% NAVADNA DREVESA
|
||||
else {
|
||||
const normalTrees = ['tree_green_final', 'tree_blue_final', 'tree_sapling'];
|
||||
treeType = normalTrees[Math.floor(Math.random() * normalTrees.length)];
|
||||
}
|
||||
}
|
||||
|
||||
// Right border (x = farmMaxX)
|
||||
if (startX <= farmMaxX && endX > farmMaxX) {
|
||||
for (let y = Math.max(startY, farmMinY); y <= Math.min(endY - 1, farmMaxY); y++) {
|
||||
this.addDecoration(farmMaxX, y, 'fence_isometric');
|
||||
}
|
||||
// DODAJ DREVO
|
||||
this.addDecoration(pos.x, pos.y, treeType);
|
||||
this.placedTrees.push({ x: pos.x, y: pos.y });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// KONEC generateChunk
|
||||
}
|
||||
|
||||
updateChunks(camera) {
|
||||
@@ -777,18 +708,22 @@ class TerrainSystem {
|
||||
|
||||
let scale = 1.0;
|
||||
|
||||
if (type === 'rock_1' || type === 'rock_2') scale = 1.5; // Povečano (bilo 0.5)
|
||||
// POMANJŠANA DREVESA - Stardew Valley stil
|
||||
if (type === 'rock_1' || type === 'rock_2') scale = 1.0; // Zmanjšano
|
||||
else if (type === 'tree_green_new' || type === 'tree_blue_new' || type === 'tree_dead_new') scale = 0.04;
|
||||
else if (type === 'flowers_new') scale = 0.02;
|
||||
else if (type === 'fence') scale = 0.025;
|
||||
else if (type === 'gravestone') scale = 0.03;
|
||||
else if (type === 'hill_sprite') scale = 0.025;
|
||||
else if (type.includes('_final')) scale = 1.0; // New Final Trees
|
||||
else if (type.includes('_final')) scale = 0.7; // POMANJŠANO - final trees
|
||||
else if (type.includes('purple') || type.includes('apple') || type.includes('pear') || type.includes('cherry')) {
|
||||
scale = 0.6; // POMANJŠANO - novi sadni in vijolčni
|
||||
}
|
||||
else {
|
||||
// Old Assets (Low Res)
|
||||
if (type.includes('tree')) scale = 1.2 + Math.random() * 0.4;
|
||||
else if (type.includes('rock')) scale = 0.8;
|
||||
else scale = 1.0;
|
||||
if (type.includes('tree')) scale = 0.7 + Math.random() * 0.2; // POMANJŠANO (bilo 1.2-1.6)
|
||||
else if (type.includes('rock')) scale = 0.6; // POMANJŠANO
|
||||
else scale = 0.8; // POMANJŠANO
|
||||
}
|
||||
|
||||
// Calculate Plant Day for Saplings (Growth System)
|
||||
|
||||
77
ultra_remove_bg.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from PIL import Image
|
||||
import os
|
||||
|
||||
# Lista slik za procesiranje
|
||||
images_to_process = [
|
||||
'assets/tree_purple.png',
|
||||
'assets/tree_apple.png',
|
||||
'assets/tree_pear.png',
|
||||
'assets/tree_cherry.png',
|
||||
'assets/tree_green_final.png',
|
||||
'assets/tree_blue_final.png',
|
||||
'assets/tree_dead_final.png'
|
||||
]
|
||||
|
||||
def ultra_remove_background(image_path):
|
||||
"""ULTRA AGRESIVNO odstranjevanje ozadja"""
|
||||
try:
|
||||
# Naloži sliko
|
||||
img = Image.open(image_path).convert('RGBA')
|
||||
data = img.getdata()
|
||||
|
||||
new_data = []
|
||||
for item in data:
|
||||
r, g, b, a = item
|
||||
|
||||
# Če je že transparentno, ohrani
|
||||
if a == 0:
|
||||
new_data.append(item)
|
||||
continue
|
||||
|
||||
# Izračunaj brightness
|
||||
brightness = (r + g + b) / 3
|
||||
|
||||
# ULTRA AGRESIVNO: Odstrani VSE kar je svetlejše od 100
|
||||
# To bo odstranilo VSE šahovske kvadratke
|
||||
if brightness > 100:
|
||||
new_data.append((r, g, b, 0)) # Transparentno
|
||||
continue
|
||||
|
||||
# Odstrani VSE sive barve (ne glede na brightness)
|
||||
is_grayscale = abs(r - g) < 25 and abs(g - b) < 25 and abs(r - b) < 25
|
||||
if is_grayscale:
|
||||
new_data.append((r, g, b, 0)) # Transparentno
|
||||
continue
|
||||
|
||||
# Ohrani samo temne, nasičene barve (drevesa)
|
||||
max_rgb = max(r, g, b)
|
||||
min_rgb = min(r, g, b)
|
||||
saturation = 0 if max_rgb == 0 else (max_rgb - min_rgb) / max_rgb
|
||||
|
||||
# Če je nizka saturacija (pastelno) -> odstrani
|
||||
if saturation < 0.2:
|
||||
new_data.append((r, g, b, 0))
|
||||
continue
|
||||
|
||||
# Ohrani pixel
|
||||
new_data.append(item)
|
||||
|
||||
# Posodobi sliko
|
||||
img.putdata(new_data)
|
||||
|
||||
# Shrani
|
||||
img.save(image_path)
|
||||
print(f'✅ ULTRA Processed: {image_path}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'❌ Error processing {image_path}: {e}')
|
||||
|
||||
# Procesiraj vse slike
|
||||
print('🔥 ULTRA AGGRESSIVE background removal...')
|
||||
for img_path in images_to_process:
|
||||
if os.path.exists(img_path):
|
||||
ultra_remove_background(img_path)
|
||||
else:
|
||||
print(f'⚠️ File not found: {img_path}')
|
||||
|
||||
print('✅ Done! All backgrounds ULTRA removed.')
|
||||