phase 11 koncano
This commit is contained in:
@@ -21,7 +21,7 @@ const TILE_MINE_WALL = 81; // ID za zid rudnika (Solid/Kolizija)
|
||||
const ITEM_STONE = 20; // ID za kamen, ki ga igralec dobi
|
||||
const ITEM_IRON = 21; // ID za železo
|
||||
|
||||
const TREE_DENSITY_THRESHOLD = 0.65; // Višja vrednost = manj gosto (manj gozda)
|
||||
const TREE_DENSITY_THRESHOLD = 0.45; // Višja vrednost = manj gosto (manj gozda)
|
||||
const ROCK_DENSITY_THRESHOLD = 0.60; // Prag za skupine skal
|
||||
|
||||
// Terrain Generator System
|
||||
@@ -119,6 +119,12 @@ class TerrainSystem {
|
||||
|
||||
this.offsetX = 0;
|
||||
this.offsetY = 0;
|
||||
|
||||
this.generatedChunks = new Set();
|
||||
this.chunkSize = 10;
|
||||
|
||||
// Init tiles array with NULLs
|
||||
this.tiles = Array.from({ length: this.height }, () => Array(this.width).fill(null));
|
||||
}
|
||||
|
||||
createTileTextures() {
|
||||
@@ -224,15 +230,50 @@ class TerrainSystem {
|
||||
generate() {
|
||||
this.createTileTextures();
|
||||
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
this.tiles[y] = [];
|
||||
for (let x = 0; x < this.width; x++) {
|
||||
console.log('🌍 Initializing World (Zone Streaming Mode)...');
|
||||
|
||||
// Generate ONLY the starting area (Farm)
|
||||
// Farm is at 20,20. Let's load 3x3 chunks around it.
|
||||
const centerCx = Math.floor(FARM_CENTER_X / this.chunkSize);
|
||||
const centerCy = Math.floor(FARM_CENTER_Y / this.chunkSize);
|
||||
|
||||
for (let cy = centerCy - 2; cy <= centerCy + 2; cy++) {
|
||||
for (let cx = centerCx - 2; cx <= centerCx + 2; cx++) {
|
||||
this.generateChunk(cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ World Init Complete. Loaded ${this.generatedChunks.size} chunks.`);
|
||||
}
|
||||
|
||||
generateChunk(cx, cy) {
|
||||
const key = `${cx},${cy}`;
|
||||
if (this.generatedChunks.has(key)) return;
|
||||
|
||||
// Bounds check
|
||||
if (cx < 0 || cy < 0 || cx * this.chunkSize >= this.width || cy * this.chunkSize >= this.height) return;
|
||||
|
||||
this.generatedChunks.add(key);
|
||||
// console.log(`🔄 Streaming Chunk: [${cx}, ${cy}]`);
|
||||
|
||||
const startX = cx * this.chunkSize;
|
||||
const startY = cy * this.chunkSize;
|
||||
const endX = Math.min(startX + this.chunkSize, this.width);
|
||||
const endY = Math.min(startY + this.chunkSize, this.height);
|
||||
|
||||
const validPositions = []; // Local valid positions for this chunk
|
||||
|
||||
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);
|
||||
|
||||
let terrainType = this.terrainTypes.GRASS_FULL;
|
||||
|
||||
// Edges of WORLD
|
||||
if (x < 3 || x >= this.width - 3 || y < 3 || y >= this.height - 3) {
|
||||
terrainType = this.terrainTypes.GRASS_FULL;
|
||||
} else {
|
||||
@@ -244,136 +285,108 @@ class TerrainSystem {
|
||||
else if (elevation > 0.85) terrainType = this.terrainTypes.STONE;
|
||||
}
|
||||
|
||||
// Farm Override
|
||||
if (Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 && Math.abs(y - FARM_CENTER_Y) <= FARM_SIZE / 2) {
|
||||
terrainType = this.terrainTypes.DIRT;
|
||||
}
|
||||
// CITY AREA - 15x15 območje z OBZIDJEM
|
||||
|
||||
// City Override
|
||||
if (x >= CITY_START_X && x < CITY_START_X + CITY_SIZE &&
|
||||
y >= CITY_START_Y && y < CITY_START_Y + CITY_SIZE) {
|
||||
|
||||
// Preverimo, ali smo na ROBOVIH (Obzidje)
|
||||
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) {
|
||||
// OBZIDJE - trdno, igralec ne more čez
|
||||
terrainType = { name: 'WALL_EDGE', color: 0x505050, solid: true };
|
||||
} else {
|
||||
// NOTRANJOST MESTA - tlakovci (pavement)
|
||||
terrainType = this.terrainTypes.PAVEMENT;
|
||||
// Naključne ruševine v mestu
|
||||
if (Math.random() < 0.15) {
|
||||
terrainType = this.terrainTypes.RUINS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create Tile Data
|
||||
this.tiles[y][x] = {
|
||||
type: terrainType.name,
|
||||
texture: terrainType.name,
|
||||
hasDecoration: false,
|
||||
hasCrop: false,
|
||||
solid: terrainType.solid || false // Inherits from terrain type
|
||||
solid: terrainType.solid || false
|
||||
};
|
||||
|
||||
// Place Trees dynamically during generation
|
||||
// this.placeTree(x, y, terrainType.name);
|
||||
// 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 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;
|
||||
|
||||
// Place Rocks dynamically
|
||||
// this.placeRock(x, y, terrainType.name);
|
||||
}
|
||||
}
|
||||
|
||||
let treeCount = 0;
|
||||
let rockCount = 0;
|
||||
let flowerCount = 0;
|
||||
|
||||
const validPositions = [];
|
||||
const isFarm = (x, y) => Math.abs(x - FARM_CENTER_X) <= (FARM_SIZE / 2 + 2) && Math.abs(y - FARM_CENTER_Y) <= (FARM_SIZE / 2 + 2);
|
||||
const isCity = (x, y) => x >= CITY_START_X - 2 && x < CITY_START_X + CITY_SIZE + 2 && y >= CITY_START_Y - 2 && y < CITY_START_Y + CITY_SIZE + 2;
|
||||
|
||||
for (let y = 5; y < this.height - 5; y++) {
|
||||
for (let x = 5; x < this.width - 5; x++) {
|
||||
if (isFarm(x, y) || isCity(x, y)) continue;
|
||||
|
||||
const tile = this.tiles[y][x];
|
||||
if (tile.type !== 'water' && tile.type !== 'sand' && tile.type !== 'stone') {
|
||||
validPositions.push({ x, y });
|
||||
if (!isFarm && !isCity) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// DECORATIONS - Enhanced World Details
|
||||
console.log('🌸 Adding enhanced decorations...');
|
||||
// --- CHUNK DECORATION PASS ---
|
||||
// Instead of global counts, we use probability/density per chunk
|
||||
// 10x10 = 100 tiles.
|
||||
// Approx density: 0.2 trees per tile = 20 trees per chunk.
|
||||
|
||||
// Natural Path Stones (along roads and random areas)
|
||||
let pathStoneCount = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
this.addDecoration(pos.x, pos.y, 'path_stone');
|
||||
pathStoneCount++;
|
||||
// 1. Random Decorations
|
||||
validPositions.forEach(pos => {
|
||||
// Trees
|
||||
if (Math.random() < 0.05) { // 5% chance per valid tile
|
||||
this.placeTree(pos.x, pos.y, 'grass'); // force check inside
|
||||
}
|
||||
}
|
||||
|
||||
// Small decorative rocks
|
||||
let smallRockCount = 0;
|
||||
for (let i = 0; i < 80; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
const rockType = Math.random() > 0.5 ? 'small_rock_1' : 'small_rock_2';
|
||||
this.addDecoration(pos.x, pos.y, rockType);
|
||||
smallRockCount++;
|
||||
// Rocks
|
||||
if (Math.random() < 0.02) {
|
||||
this.placeRock(pos.x, pos.y, 'grass');
|
||||
}
|
||||
}
|
||||
|
||||
// Flower clusters
|
||||
flowerCount = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
// 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);
|
||||
flowerCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Mushrooms (spooky atmosphere)
|
||||
let mushroomCount = 0;
|
||||
for (let i = 0; i < 60; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
const mushroomType = Math.random() > 0.5 ? 'mushroom_red' : 'mushroom_brown';
|
||||
this.addDecoration(pos.x, pos.y, mushroomType);
|
||||
mushroomCount++;
|
||||
// Path Stones
|
||||
if (Math.random() < 0.02) {
|
||||
this.addDecoration(pos.x, pos.y, 'path_stone');
|
||||
}
|
||||
}
|
||||
|
||||
// Fallen Logs (forest debris)
|
||||
let logCount = 0;
|
||||
for (let i = 0; i < 25; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
this.addDecoration(pos.x, pos.y, 'fallen_log');
|
||||
logCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Puddles (will appear during rain)
|
||||
this.puddlePositions = [];
|
||||
for (let i = 0; i < 40; i++) {
|
||||
const pos = validPositions[Math.floor(Math.random() * validPositions.length)];
|
||||
if (pos && !this.decorationsMap.has(`${pos.x},${pos.y}`)) {
|
||||
this.puddlePositions.push({ x: pos.x, y: pos.y });
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Decorations: ${pathStoneCount} paths, ${smallRockCount} rocks, ${flowerCount} flowers, ${mushroomCount} mushrooms, ${logCount} logs.`);
|
||||
});
|
||||
}
|
||||
|
||||
updateChunks(camera) {
|
||||
// Calculate which chunks are in view
|
||||
const view = camera.worldView;
|
||||
const buffer = 100; // Load slightly outside view
|
||||
|
||||
const p1 = this.iso.toGrid(view.x - buffer, view.y - buffer);
|
||||
const p2 = this.iso.toGrid(view.x + view.width + buffer, view.y + view.height + buffer);
|
||||
|
||||
const minCx = Math.floor(Math.min(p1.x, p2.x) / this.chunkSize);
|
||||
const maxCx = Math.ceil(Math.max(p1.x, p2.x) / this.chunkSize);
|
||||
const minCy = Math.floor(Math.min(p1.y, p2.y) / this.chunkSize);
|
||||
const maxCy = Math.ceil(Math.max(p1.y, p2.y) / this.chunkSize);
|
||||
|
||||
for (let cy = minCy; cy <= maxCy; cy++) {
|
||||
for (let cx = minCx; cx <= maxCx; cx++) {
|
||||
this.generateChunk(cx, cy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retained helper methods...
|
||||
|
||||
damageDecoration(x, y, amount) {
|
||||
const key = `${x},${y}`;
|
||||
const decor = this.decorationsMap.get(key);
|
||||
@@ -704,6 +717,8 @@ class TerrainSystem {
|
||||
}
|
||||
|
||||
updateCulling(camera) {
|
||||
this.updateChunks(camera);
|
||||
|
||||
const view = camera.worldView;
|
||||
let buffer = 200;
|
||||
if (this.scene.settings && this.scene.settings.viewDistance === 'LOW') buffer = 50;
|
||||
|
||||
Reference in New Issue
Block a user