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",
|
"type": "commonjs",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas": "^3.2.0",
|
"canvas": "^3.2.0",
|
||||||
"phaser": "^3.80.1"
|
"express": "^5.2.1",
|
||||||
|
"phaser": "^3.80.1",
|
||||||
|
"socket.io": "^4.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^33.2.1"
|
"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,6 +208,8 @@ class GameScene extends Phaser.Scene {
|
|||||||
this.signposts = [];
|
this.signposts = [];
|
||||||
|
|
||||||
// Path markers (using fence sprites as signposts)
|
// Path markers (using fence sprites as signposts)
|
||||||
|
// ONLY if terrainSystem was successfully initialized
|
||||||
|
if (this.terrainSystem) {
|
||||||
const pathMarkers = [
|
const pathMarkers = [
|
||||||
{ x: 35, y: 35, label: '→ City' },
|
{ x: 35, y: 35, label: '→ City' },
|
||||||
{ x: 50, y: 50, label: '← Farm' },
|
{ x: 50, y: 50, label: '← Farm' },
|
||||||
@@ -217,6 +219,9 @@ class GameScene extends Phaser.Scene {
|
|||||||
this.terrainSystem.addDecoration(marker.x, marker.y, 'fence');
|
this.terrainSystem.addDecoration(marker.x, marker.y, 'fence');
|
||||||
this.signposts.push({ gridX: marker.x, gridY: marker.y, label: marker.label });
|
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)
|
// Kamera sledi igralcu z gladko interpolacijo (lerp 0.1)
|
||||||
this.cameras.main.startFollow(this.player.sprite, true, 0.1, 0.1);
|
this.cameras.main.startFollow(this.player.sprite, true, 0.1, 0.1);
|
||||||
@@ -280,8 +285,8 @@ class GameScene extends Phaser.Scene {
|
|||||||
// Initialize Save System
|
// Initialize Save System
|
||||||
this.saveSystem = new SaveSystem(this);
|
this.saveSystem = new SaveSystem(this);
|
||||||
|
|
||||||
// Auto-load if available
|
// Auto-load if available (DISABLED in SaveSystem!)
|
||||||
this.saveSystem.loadGame();
|
this.saveSystem.loadGame(); // Vrne false - ne naloži save-a!
|
||||||
|
|
||||||
// Debug Text
|
// Debug Text
|
||||||
this.add.text(10, 10, 'NovaFarma Alpha v0.6', { font: '16px monospace', fill: '#ffffff' })
|
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)) {
|
if (this.terrainSystem.decorationsMap.has(key)) {
|
||||||
this.terrainSystem.removeDecoration(x, y);
|
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]) {
|
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) {
|
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
|
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_blue_final', 'assets/tree_blue_final.png');
|
||||||
this.load.image('tree_dead_final', 'assets/tree_dead_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
|
// NEW transparent tree/rock assets
|
||||||
this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); // Keep for backup
|
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('merchant_new', 'assets/merchant_new.png');
|
||||||
this.load.image('elite_zombie', 'assets/elite_zombie.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)
|
// AI-Generated NPC Sprites (with cache-busting)
|
||||||
const cacheBust = Date.now();
|
const cacheBust = Date.now();
|
||||||
this.load.image('cow', `assets/cow.png?v=${cacheBust}`);
|
this.load.image('cow', `assets/cow.png?v=${cacheBust}`);
|
||||||
@@ -191,6 +201,13 @@ class PreloadScene extends Phaser.Scene {
|
|||||||
'tree_blue_final',
|
'tree_blue_final',
|
||||||
'tree_dead_final',
|
'tree_dead_final',
|
||||||
|
|
||||||
|
// STARDEW VALLEY FOREST TREES
|
||||||
|
'tree_purple',
|
||||||
|
'tree_apple',
|
||||||
|
'tree_pear',
|
||||||
|
'tree_cherry',
|
||||||
|
'tree_sapling',
|
||||||
|
|
||||||
// NEW transparent assets
|
// NEW transparent assets
|
||||||
'tree_blue_new',
|
'tree_blue_new',
|
||||||
'tree_green_new',
|
'tree_green_new',
|
||||||
@@ -203,6 +220,7 @@ class PreloadScene extends Phaser.Scene {
|
|||||||
'flowers_new',
|
'flowers_new',
|
||||||
'hill_sprite',
|
'hill_sprite',
|
||||||
'fence',
|
'fence',
|
||||||
|
'fence_old',
|
||||||
'gravestone',
|
'gravestone',
|
||||||
// City content
|
// City content
|
||||||
'chest',
|
'chest',
|
||||||
@@ -288,43 +306,51 @@ class PreloadScene extends Phaser.Scene {
|
|||||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
const data = imageData.data;
|
const data = imageData.data;
|
||||||
|
|
||||||
// Remove backgrounds - IMPROVED CHECKBOARD DETECTION
|
// Remove backgrounds - ULTRA AGGRESSIVE MODE!
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
const r = data[i];
|
const r = data[i];
|
||||||
const g = data[i + 1];
|
const g = data[i + 1];
|
||||||
const b = data[i + 2];
|
const b = data[i + 2];
|
||||||
|
const a = data[i + 3];
|
||||||
|
|
||||||
// Remove ALL grayscale colors (checkboard pattern)
|
// Skip if already transparent
|
||||||
// Checkboard has both light (204,204,204) and dark (153,153,153) squares
|
if (a === 0) continue;
|
||||||
const isGrayscale = Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && Math.abs(r - b) < 15;
|
|
||||||
|
|
||||||
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 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
|
data[i + 3] = 0; // Make transparent
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULTRA AGGRESSIVE: Remove PURE WHITE backgrounds
|
// 2. Remove ALL light/bright backgrounds (AI-generated sprites)
|
||||||
const isWhite = r > 240 && g > 240 && b > 240;
|
if (brightness > 150) {
|
||||||
if (isWhite) {
|
|
||||||
data[i + 3] = 0; // Make transparent
|
data[i + 3] = 0; // Make transparent
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULTRA AGGRESSIVE: Remove OFF-WHITE backgrounds (cream, beige)
|
// 3. Remove PURE WHITE
|
||||||
const isOffWhite = brightness > 230 && Math.abs(r - g) < 20 && Math.abs(g - b) < 20;
|
if (r > 240 && g > 240 && b > 240) {
|
||||||
if (isOffWhite) {
|
data[i + 3] = 0;
|
||||||
data[i + 3] = 0; // Make transparent
|
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)
|
// Special: Remove brown/tan backgrounds (merchant sprite)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class OceanSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(time, delta) {
|
update(time, delta) {
|
||||||
if (!this.scene.player) return;
|
if (!this.scene.player || !this.scene.terrainSystem) return;
|
||||||
|
|
||||||
const playerPos = this.scene.player.getPosition();
|
const playerPos = this.scene.player.getPosition();
|
||||||
const tile = this.scene.terrainSystem.getTile(playerPos.x, playerPos.y);
|
const tile = this.scene.terrainSystem.getTile(playerPos.x, playerPos.y);
|
||||||
@@ -83,6 +83,8 @@ class OceanSystem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.scene.terrainSystem) return;
|
||||||
|
|
||||||
// Check if on water or near water?
|
// Check if on water or near water?
|
||||||
// Actually, let's allow "deploying" boat anywhere, but only moving fast on water?
|
// Actually, let's allow "deploying" boat anywhere, but only moving fast on water?
|
||||||
// OR: Only allow deploying on water tile.
|
// 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_SIZE = 8; // 8x8 MICRO FARM - Začetek igre!
|
||||||
const FARM_CENTER_X = 50; // Center mape (50,50)
|
const FARM_CENTER_X = 50; // Center mape (50,50)
|
||||||
const FARM_CENTER_Y = 50; // Center mape (50,50)
|
const FARM_CENTER_Y = 50; // Center mape (50,50)
|
||||||
|
|
||||||
const CITY_SIZE = 15;
|
// Zapuščene hiše lokacije - ODSTRANJENO ZA TESTIRANJE!
|
||||||
const CITY_START_X = 65; // Desni del mape (npr. med 65 in 80)
|
const ABANDONED_HOUSES = [
|
||||||
const CITY_START_Y = 65;
|
// { 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 TREE_DENSITY = 0.01; // 1% chance za drevo (zelo nizka gostota)
|
||||||
const TILE_IRON_ORE = 83; // ID za železovo rudo
|
const PURPLE_TREE_CHANCE = 0.30; // 30% vijolčnih dreves
|
||||||
const TILE_PAVEMENT = 16; // ID za prehodno ploščico (tla rudnika)
|
const FRUIT_TREE_CHANCE = 0.20; // 20% sadnih dreves
|
||||||
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 ROCK_DENSITY_THRESHOLD = 0.60; // Prag za skupine skal
|
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
|
// Terrain Generator System
|
||||||
class TerrainSystem {
|
class TerrainSystem {
|
||||||
constructor(scene, width = 100, height = 100) {
|
constructor(scene, width = 100, height = 100) {
|
||||||
@@ -127,10 +132,35 @@ class TerrainSystem {
|
|||||||
this.generatedChunks = new Set();
|
this.generatedChunks = new Set();
|
||||||
this.chunkSize = 10;
|
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
|
// Init tiles array with NULLs
|
||||||
this.tiles = Array.from({ length: this.height }, () => Array(this.width).fill(null));
|
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() {
|
createTileTextures() {
|
||||||
const tileWidth = 48;
|
const tileWidth = 48;
|
||||||
const tileHeight = 60;
|
const tileHeight = 60;
|
||||||
@@ -373,186 +403,87 @@ class TerrainSystem {
|
|||||||
for (let y = startY; y < endY; y++) {
|
for (let y = startY; y < endY; y++) {
|
||||||
for (let x = startX; x < endX; x++) {
|
for (let x = startX; x < endX; x++) {
|
||||||
|
|
||||||
// --- PER TILE GENERATION LOGIC (Moved from old loop) ---
|
// --- STARDEW VALLEY FOREST GENERATION ---
|
||||||
const nx = x * 0.1;
|
let terrainType = this.terrainTypes.GRASS_FULL; // Vsa mapa je trava!
|
||||||
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)
|
|
||||||
|
|
||||||
// Farm Override - ZELENA PLATFORMA!
|
// Farm Override - ZELENA PLATFORMA!
|
||||||
if (Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 && Math.abs(y - FARM_CENTER_Y) <= FARM_SIZE / 2) {
|
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!
|
// Zapuščene hiše - DIRT tiles
|
||||||
// River gre diagonalno skozi mapo z sinusnim vijuganjem
|
let isHouse = false;
|
||||||
const riverCenterY = 50; // Center Y pozicija za river
|
ABANDONED_HOUSES.forEach(house => {
|
||||||
const riverWidth = 3; // Širina potoka (3 tiles)
|
if (x >= house.x && x < house.x + house.size &&
|
||||||
const waveAmplitude = 8; // Amplituda vijuganja
|
y >= house.y && y < house.y + house.size) {
|
||||||
const waveFrequency = 0.1; // Frekvenca vijuganja
|
terrainType = this.terrainTypes.DIRT; // Hiša na DIRT
|
||||||
|
isHouse = true;
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// Create Tile Data
|
// Create Tile Data
|
||||||
this.tiles[y][x] = {
|
this.tiles[y][x] = {
|
||||||
type: terrainType.name,
|
type: terrainType.name,
|
||||||
texture: terrainType.name === 'water' ? 'water_frame_0' : terrainType.name, // Water tiles get animated frame!
|
texture: terrainType.name,
|
||||||
hasDecoration: false,
|
hasDecoration: false,
|
||||||
hasCrop: false,
|
hasCrop: false,
|
||||||
solid: terrainType.solid || false
|
solid: terrainType.solid || false,
|
||||||
|
isHouse: isHouse
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track water tiles za animacijo
|
// Track valid positions for decorations (TREES!)
|
||||||
if (terrainType.name === 'water') {
|
if (terrainType.name === 'grass_full' && !isHouse) {
|
||||||
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
|
|
||||||
const isFarm = Math.abs(x - FARM_CENTER_X) <= (FARM_SIZE / 2 + 2) && Math.abs(y - FARM_CENTER_Y) <= (FARM_SIZE / 2 + 2);
|
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) {
|
||||||
|
|
||||||
if (!isFarm && !isCity) {
|
|
||||||
validPositions.push({ x, y });
|
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 ---
|
// --- STARDEW VALLEY FOREST 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
|
|
||||||
const farmMinX = FARM_CENTER_X - FARM_SIZE / 2;
|
const farmMinX = FARM_CENTER_X - FARM_SIZE / 2;
|
||||||
const farmMaxX = FARM_CENTER_X + FARM_SIZE / 2;
|
const farmMaxX = FARM_CENTER_X + FARM_SIZE / 2;
|
||||||
const farmMinY = FARM_CENTER_Y - FARM_SIZE / 2;
|
const farmMinY = FARM_CENTER_Y - FARM_SIZE / 2;
|
||||||
const farmMaxY = FARM_CENTER_Y + FARM_SIZE / 2;
|
const farmMaxY = FARM_CENTER_Y + FARM_SIZE / 2;
|
||||||
|
|
||||||
// DECORATIONS: Flowers & Bushes on grass tiles (random)
|
// DREVESA - 3% gostota z preverjanjem razdalje!
|
||||||
for (let y = startY; y < endY; y++) {
|
validPositions.forEach(pos => {
|
||||||
for (let x = startX; x < endX; x++) {
|
|
||||||
const tile = this.tiles[y][x]; // Corrected access to this.tiles
|
|
||||||
|
|
||||||
// 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();
|
const rand = Math.random();
|
||||||
|
|
||||||
// 10% chance for flowers
|
// 3% chance za drevo
|
||||||
if (rand < 0.10) {
|
if (rand < TREE_DENSITY) {
|
||||||
const flowerTypes = ['flowers_new', 'flowers_pink_isometric'];
|
// PREVERJANJE RAZDALJE: Ali je ta lokacija dovolj oddaljena?
|
||||||
const randomType = flowerTypes[Math.floor(Math.random() * flowerTypes.length)];
|
if (!this.isTreeLocationFarEnough(pos.x, pos.y)) {
|
||||||
this.addDecoration(x, y, randomType);
|
return; // Preskoči to lokacijo - preblizu drugim drevesom!
|
||||||
}
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this chunk contains farm border
|
const treeRand = Math.random();
|
||||||
if (cx * this.chunkSize <= farmMaxX && (cx + 1) * this.chunkSize >= farmMinX &&
|
let treeType;
|
||||||
cy * this.chunkSize <= farmMaxY && (cy + 1) * this.chunkSize >= farmMinY) {
|
|
||||||
|
|
||||||
// Top border (y = farmMinY)
|
// 30% VIJOLČNA DREVESA
|
||||||
if (startY <= farmMinY && endY > farmMinY) {
|
if (treeRand < PURPLE_TREE_CHANCE) {
|
||||||
for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) {
|
treeType = 'tree_purple';
|
||||||
this.addDecoration(x, farmMinY, '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)];
|
||||||
|
}
|
||||||
|
// 50% NAVADNA DREVESA
|
||||||
|
else {
|
||||||
|
const normalTrees = ['tree_green_final', 'tree_blue_final', 'tree_sapling'];
|
||||||
|
treeType = normalTrees[Math.floor(Math.random() * normalTrees.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom border (y = farmMaxY)
|
// DODAJ DREVO
|
||||||
if (startY <= farmMaxY && endY > farmMaxY) {
|
this.addDecoration(pos.x, pos.y, treeType);
|
||||||
for (let x = Math.max(startX, farmMinX); x <= Math.min(endX - 1, farmMaxX); x++) {
|
this.placedTrees.push({ x: pos.x, y: pos.y });
|
||||||
this.addDecoration(x, farmMaxY, 'fence_isometric');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Left border (x = farmMinX)
|
// KONEC generateChunk
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateChunks(camera) {
|
updateChunks(camera) {
|
||||||
@@ -777,18 +708,22 @@ class TerrainSystem {
|
|||||||
|
|
||||||
let scale = 1.0;
|
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 === '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 === 'flowers_new') scale = 0.02;
|
||||||
else if (type === 'fence') scale = 0.025;
|
else if (type === 'fence') scale = 0.025;
|
||||||
else if (type === 'gravestone') scale = 0.03;
|
else if (type === 'gravestone') scale = 0.03;
|
||||||
else if (type === 'hill_sprite') scale = 0.025;
|
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 {
|
else {
|
||||||
// Old Assets (Low Res)
|
// Old Assets (Low Res)
|
||||||
if (type.includes('tree')) scale = 1.2 + Math.random() * 0.4;
|
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.8;
|
else if (type.includes('rock')) scale = 0.6; // POMANJŠANO
|
||||||
else scale = 1.0;
|
else scale = 0.8; // POMANJŠANO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate Plant Day for Saplings (Growth System)
|
// 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.')
|
||||||