task narejeni
This commit is contained in:
@@ -258,12 +258,11 @@ class GameScene extends Phaser.Scene {
|
|||||||
if (this.player) {
|
if (this.player) {
|
||||||
const playerPos = this.player.getPosition();
|
const playerPos = this.player.getPosition();
|
||||||
const cam = this.cameras.main;
|
const cam = this.cameras.main;
|
||||||
const visibleTiles = this.terrainSystem ? this.terrainSystem.visibleTiles.size : 0;
|
|
||||||
|
|
||||||
const uiScene = this.scene.get('UIScene');
|
const uiScene = this.scene.get('UIScene');
|
||||||
if (uiScene && uiScene.debugText) {
|
if (uiScene && uiScene.debugText) {
|
||||||
const activeCrops = this.terrainSystem && this.terrainSystem.cropsMap ? this.terrainSystem.cropsMap.size : 0;
|
const activeCrops = this.terrainSystem && this.terrainSystem.cropsMap ? this.terrainSystem.cropsMap.size : 0;
|
||||||
const dropsCount = this.interactionSystem && this.interactionSystem.drops ? this.interactionSystem.drops.length : 0;
|
const dropsCount = this.lootSystem ? this.lootSystem.drops.length : 0;
|
||||||
|
|
||||||
uiScene.debugText.setText(
|
uiScene.debugText.setText(
|
||||||
`FAZA 11 - Building\n` +
|
`FAZA 11 - Building\n` +
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Terrain Generator System
|
// Terrain Generator System
|
||||||
// Generira proceduralni isometrični teren in skrbi za optimizacijo (Culling, Object Pooling)
|
// Generira proceduralni isometrični teren in skrbi za optimizacijo (Tilemap + Culling)
|
||||||
class TerrainSystem {
|
class TerrainSystem {
|
||||||
constructor(scene, width = 100, height = 100) {
|
constructor(scene, width = 100, height = 100) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
@@ -14,30 +14,10 @@ class TerrainSystem {
|
|||||||
this.decorationsMap = new Map();
|
this.decorationsMap = new Map();
|
||||||
this.cropsMap = new Map();
|
this.cropsMap = new Map();
|
||||||
|
|
||||||
this.visibleTiles = new Map();
|
|
||||||
this.visibleDecorations = new Map();
|
this.visibleDecorations = new Map();
|
||||||
this.visibleCrops = new Map();
|
this.visibleCrops = new Map();
|
||||||
|
|
||||||
// Pools
|
// Pool for Decorations (Trees, Rocks, etc.)
|
||||||
this.tilePool = {
|
|
||||||
active: [],
|
|
||||||
inactive: [],
|
|
||||||
get: () => {
|
|
||||||
if (this.tilePool.inactive.length > 0) {
|
|
||||||
const s = this.tilePool.inactive.pop();
|
|
||||||
s.setVisible(true);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
const s = this.scene.add.sprite(0, 0, 'dirt');
|
|
||||||
s.setOrigin(0.5, 0.5);
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
release: (sprite) => {
|
|
||||||
sprite.setVisible(false);
|
|
||||||
this.tilePool.inactive.push(sprite);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.decorationPool = {
|
this.decorationPool = {
|
||||||
active: [],
|
active: [],
|
||||||
inactive: [],
|
inactive: [],
|
||||||
@@ -56,6 +36,7 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Pool for Crops
|
||||||
this.cropPool = {
|
this.cropPool = {
|
||||||
active: [],
|
active: [],
|
||||||
inactive: [],
|
inactive: [],
|
||||||
@@ -74,14 +55,14 @@ class TerrainSystem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.terrainTypes = {
|
this.terrainTypes = {
|
||||||
WATER: { name: 'water', height: 0, color: 0x4444ff },
|
WATER: { name: 'water', height: 0, color: 0x4444ff, index: 0 },
|
||||||
SAND: { name: 'sand', height: 0.2, color: 0xdddd44 },
|
SAND: { name: 'sand', height: 0.2, color: 0xdddd44, index: 1 },
|
||||||
GRASS_FULL: { name: 'grass_full', height: 0.35, color: 0x44aa44 },
|
GRASS_FULL: { name: 'grass_full', height: 0.35, color: 0x44aa44, index: 2 },
|
||||||
GRASS_TOP: { name: 'grass_top', height: 0.45, color: 0x66cc66 },
|
GRASS_TOP: { name: 'grass_top', height: 0.45, color: 0x66cc66, index: 3 },
|
||||||
DIRT: { name: 'dirt', height: 0.5, color: 0x8b4513 },
|
DIRT: { name: 'dirt', height: 0.5, color: 0x8b4513, index: 4 },
|
||||||
STONE: { name: 'stone', height: 0.7, color: 0x888888 },
|
STONE: { name: 'stone', height: 0.7, color: 0x888888, index: 5 },
|
||||||
PATH: { name: 'path', height: -1, color: 0xc2b280 },
|
PATH: { name: 'path', height: -1, color: 0xc2b280, index: 6 },
|
||||||
FARMLAND: { name: 'farmland', height: -1, color: 0x5c4033 }
|
FARMLAND: { name: 'farmland', height: -1, color: 0x5c4033, index: 7 }
|
||||||
};
|
};
|
||||||
|
|
||||||
this.offsetX = 0;
|
this.offsetX = 0;
|
||||||
@@ -89,25 +70,29 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createTileTextures() {
|
createTileTextures() {
|
||||||
// Flat Grid Look (No depth)
|
// Create a single spritesheet for tiles (Tilemap Optimization)
|
||||||
|
const graphics = this.scene.make.graphics({ x: 0, y: 0, add: false });
|
||||||
|
|
||||||
const tileWidth = 48;
|
const tileWidth = 48;
|
||||||
const tileHeight = 24; // Just the diamond
|
const tileHeight = 32; // 24 for iso + 8 depth
|
||||||
const types = Object.values(this.terrainTypes);
|
const types = Object.values(this.terrainTypes);
|
||||||
|
|
||||||
types.forEach((type) => {
|
// Draw all tiles horizontally
|
||||||
if (this.scene.textures.exists(type.name)) return;
|
types.forEach((type, index) => {
|
||||||
|
// Update index just in case
|
||||||
const graphics = this.scene.make.graphics({ x: 0, y: 0, add: false });
|
type.index = index;
|
||||||
|
|
||||||
const x = 0;
|
|
||||||
const top = 0;
|
|
||||||
const midX = 24;
|
|
||||||
const midY = 12;
|
|
||||||
const bottomY = 24;
|
|
||||||
|
|
||||||
|
const x = index * tileWidth;
|
||||||
graphics.fillStyle(type.color);
|
graphics.fillStyle(type.color);
|
||||||
|
|
||||||
// Diamond Only
|
// Draw Isometic Tile (Diamond + Thickness)
|
||||||
|
const top = 0;
|
||||||
|
const midX = x + 24;
|
||||||
|
const midY = 12;
|
||||||
|
const bottomY = 24;
|
||||||
|
const depth = 8;
|
||||||
|
|
||||||
|
// Top Face
|
||||||
graphics.beginPath();
|
graphics.beginPath();
|
||||||
graphics.moveTo(midX, top);
|
graphics.moveTo(midX, top);
|
||||||
graphics.lineTo(x + 48, midY);
|
graphics.lineTo(x + 48, midY);
|
||||||
@@ -116,23 +101,52 @@ class TerrainSystem {
|
|||||||
graphics.closePath();
|
graphics.closePath();
|
||||||
graphics.fill();
|
graphics.fill();
|
||||||
|
|
||||||
// Grid Stroke (Black/Dark)
|
// Add stroke to prevent seams/gaps (Robust Fix)
|
||||||
graphics.lineStyle(1, 0x000000, 0.3);
|
graphics.lineStyle(2, type.color);
|
||||||
graphics.strokePath();
|
graphics.strokePath();
|
||||||
|
|
||||||
// Simple details
|
// Thickness (Right)
|
||||||
|
graphics.fillStyle(Phaser.Display.Color.IntegerToColor(type.color).darken(20).color);
|
||||||
|
graphics.beginPath();
|
||||||
|
graphics.moveTo(x + 48, midY);
|
||||||
|
graphics.lineTo(x + 48, midY + depth);
|
||||||
|
graphics.lineTo(midX, bottomY + depth);
|
||||||
|
graphics.lineTo(midX, bottomY);
|
||||||
|
graphics.closePath();
|
||||||
|
graphics.fill();
|
||||||
|
|
||||||
|
// Thickness (Left)
|
||||||
|
graphics.fillStyle(Phaser.Display.Color.IntegerToColor(type.color).darken(40).color);
|
||||||
|
graphics.beginPath();
|
||||||
|
graphics.moveTo(midX, bottomY);
|
||||||
|
graphics.lineTo(midX, bottomY + depth);
|
||||||
|
graphics.lineTo(x, midY + depth);
|
||||||
|
graphics.lineTo(x, midY);
|
||||||
|
graphics.closePath();
|
||||||
|
graphics.fill();
|
||||||
|
|
||||||
|
// Detail (Grass)
|
||||||
if (type.name.includes('grass')) {
|
if (type.name.includes('grass')) {
|
||||||
graphics.fillStyle(0x339933);
|
graphics.fillStyle(0x339933); // Darker green blades
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
const rx = x + 10 + Math.random() * 28;
|
const rx = x + 8 + Math.random() * 32;
|
||||||
const ry = 5 + Math.random() * 14;
|
const ry = 4 + Math.random() * 16;
|
||||||
|
graphics.fillRect(rx, ry, 2, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Detail (Dirt)
|
||||||
|
if (type.name.includes('dirt')) {
|
||||||
|
graphics.fillStyle(0x5c4033);
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const rx = x + 8 + Math.random() * 32;
|
||||||
|
const ry = 4 + Math.random() * 16;
|
||||||
graphics.fillRect(rx, ry, 2, 2);
|
graphics.fillRect(rx, ry, 2, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.generateTexture(type.name, tileWidth, tileHeight);
|
|
||||||
graphics.destroy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
graphics.generateTexture('terrain_tileset', tileWidth * types.length, tileHeight);
|
||||||
|
graphics.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
generate() {
|
generate() {
|
||||||
@@ -158,6 +172,7 @@ class TerrainSystem {
|
|||||||
hasCrop: false
|
hasCrop: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Vegetation logic (Rich World)
|
||||||
if (x > 5 && x < this.width - 5 && y > 5 && y < this.height - 5) {
|
if (x > 5 && x < this.width - 5 && y > 5 && y < this.height - 5) {
|
||||||
let decorType = null;
|
let decorType = null;
|
||||||
let maxHp = 1;
|
let maxHp = 1;
|
||||||
@@ -168,23 +183,18 @@ class TerrainSystem {
|
|||||||
if (elevation > 0.6 && rand < 0.1) {
|
if (elevation > 0.6 && rand < 0.1) {
|
||||||
decorType = 'bush';
|
decorType = 'bush';
|
||||||
maxHp = 5;
|
maxHp = 5;
|
||||||
}
|
} else if (rand < 0.15) { // Common trees
|
||||||
// Trees - Volumetric
|
|
||||||
else if (rand < 0.15) {
|
|
||||||
decorType = 'tree';
|
decorType = 'tree';
|
||||||
maxHp = 5;
|
maxHp = 5;
|
||||||
const sizeRand = Math.random();
|
const sizeRand = Math.random();
|
||||||
if (sizeRand < 0.2) scale = 0.8;
|
if (sizeRand < 0.2) scale = 0.8;
|
||||||
else if (sizeRand < 0.8) scale = 1.0 + Math.random() * 0.3;
|
else if (sizeRand < 0.8) scale = 1.0 + Math.random() * 0.3;
|
||||||
else scale = 1.3;
|
else scale = 1.3;
|
||||||
}
|
} else if (rand < 0.18) { // Rocks
|
||||||
// Rocks - Volumetric
|
decorType = 'rock';
|
||||||
else if (rand < 0.18) {
|
|
||||||
decorType = 'rock'; // 'rock' texture from TextureGenerator
|
|
||||||
maxHp = 8;
|
maxHp = 8;
|
||||||
scale = 1.5; // Big rocks
|
scale = 1.2 + Math.random() * 0.5;
|
||||||
}
|
} else if (rand < 0.19) {
|
||||||
else if (rand < 0.19) {
|
|
||||||
decorType = 'gravestone';
|
decorType = 'gravestone';
|
||||||
maxHp = 10;
|
maxHp = 10;
|
||||||
} else if (rand < 0.30) {
|
} else if (rand < 0.30) {
|
||||||
@@ -216,6 +226,31 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('✅ Terrain and decorations generated!');
|
console.log('✅ Terrain and decorations generated!');
|
||||||
|
|
||||||
|
// --- TILEMAP IMPLEMENTATION (Performance) ---
|
||||||
|
if (this.map) this.map.destroy();
|
||||||
|
this.map = this.scene.make.tilemap({
|
||||||
|
tileWidth: this.iso.tileWidth, // 48
|
||||||
|
tileHeight: this.iso.tileHeight, // 24
|
||||||
|
width: this.width,
|
||||||
|
height: this.height,
|
||||||
|
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC
|
||||||
|
});
|
||||||
|
|
||||||
|
// 48x32 tileset
|
||||||
|
const tileset = this.map.addTilesetImage('terrain_tileset', 'terrain_tileset', 48, 32);
|
||||||
|
this.layer = this.map.createBlankLayer('Ground', tileset, this.offsetX, this.offsetY);
|
||||||
|
|
||||||
|
for (let y = 0; y < this.height; y++) {
|
||||||
|
for (let x = 0; x < this.width; x++) {
|
||||||
|
const t = this.tiles[y][x];
|
||||||
|
const typeDef = Object.values(this.terrainTypes).find(tt => tt.name === t.type);
|
||||||
|
if (typeDef) {
|
||||||
|
this.layer.putTileAt(typeDef.index, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.layer.setDepth(0); // Ground level
|
||||||
}
|
}
|
||||||
|
|
||||||
damageDecoration(x, y, amount) {
|
damageDecoration(x, y, amount) {
|
||||||
@@ -284,12 +319,13 @@ class TerrainSystem {
|
|||||||
|
|
||||||
setTileType(x, y, typeName) {
|
setTileType(x, y, typeName) {
|
||||||
if (!this.tiles[y] || !this.tiles[y][x]) return;
|
if (!this.tiles[y] || !this.tiles[y][x]) return;
|
||||||
this.tiles[y][x].type = typeName;
|
const typeDef = Object.values(this.terrainTypes).find(t => t.name === typeName);
|
||||||
|
if (!typeDef) return;
|
||||||
|
|
||||||
const key = `${x},${y}`;
|
this.tiles[y][x].type = typeName;
|
||||||
if (this.visibleTiles.has(key)) {
|
// Tilemap update
|
||||||
const sprite = this.visibleTiles.get(key);
|
if (this.layer) {
|
||||||
sprite.setTexture(typeName);
|
this.layer.putTileAt(typeDef.index, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +371,7 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateCulling(camera) {
|
updateCulling(camera) {
|
||||||
|
// Culling for Decorations & Crops (Tiles controlled by Tilemap)
|
||||||
const view = camera.worldView;
|
const view = camera.worldView;
|
||||||
let buffer = 200;
|
let buffer = 200;
|
||||||
if (this.scene.settings && this.scene.settings.viewDistance === 'LOW') buffer = 50;
|
if (this.scene.settings && this.scene.settings.viewDistance === 'LOW') buffer = 50;
|
||||||
@@ -358,27 +395,12 @@ class TerrainSystem {
|
|||||||
const startY = Math.max(0, minGridY);
|
const startY = Math.max(0, minGridY);
|
||||||
const endY = Math.min(this.height, maxGridY);
|
const endY = Math.min(this.height, maxGridY);
|
||||||
|
|
||||||
const neededTileKeys = new Set();
|
|
||||||
const neededDecorKeys = new Set();
|
const neededDecorKeys = new Set();
|
||||||
const neededCropKeys = new Set();
|
const neededCropKeys = new Set();
|
||||||
|
|
||||||
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++) {
|
||||||
const key = `${x},${y}`;
|
const key = `${x},${y}`;
|
||||||
const tile = this.tiles[y][x];
|
|
||||||
|
|
||||||
// TILES
|
|
||||||
if (tile) {
|
|
||||||
neededTileKeys.add(key);
|
|
||||||
if (!this.visibleTiles.has(key)) {
|
|
||||||
const sprite = this.tilePool.get();
|
|
||||||
sprite.setTexture(tile.type);
|
|
||||||
const screenPos = this.iso.toScreen(x, y);
|
|
||||||
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY);
|
|
||||||
sprite.setDepth(this.iso.getDepth(x, y));
|
|
||||||
this.visibleTiles.set(key, sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DECORATIONS
|
// DECORATIONS
|
||||||
const decor = this.decorationsMap.get(key);
|
const decor = this.decorationsMap.get(key);
|
||||||
@@ -390,14 +412,15 @@ class TerrainSystem {
|
|||||||
|
|
||||||
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY);
|
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY);
|
||||||
|
|
||||||
if (decor.type.includes('house_sprite') || decor.type.includes('market') || decor.type.includes('structure')) {
|
// Origin adjusted for volumetric sprites
|
||||||
|
// Trees/Rocks usually look best with origin (0.5, 0.9) to sit on the ground
|
||||||
|
if (decor.type.includes('house') || decor.type.includes('market') || decor.type.includes('structure')) {
|
||||||
sprite.setOrigin(0.5, 0.8);
|
sprite.setOrigin(0.5, 0.8);
|
||||||
} else {
|
} else {
|
||||||
// Volumetric trees/rocks origin adjustment
|
sprite.setOrigin(0.5, 0.9);
|
||||||
// Usually volumetric needed (0.5, 1) or slightly different?
|
|
||||||
sprite.setOrigin(0.5, 0.9); // Slight tweak
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Texture & Scale
|
||||||
sprite.setTexture(decor.type);
|
sprite.setTexture(decor.type);
|
||||||
sprite.setScale(decor.scale || 1.0);
|
sprite.setScale(decor.scale || 1.0);
|
||||||
|
|
||||||
@@ -415,6 +438,9 @@ class TerrainSystem {
|
|||||||
const screenPos = this.iso.toScreen(x, y);
|
const screenPos = this.iso.toScreen(x, y);
|
||||||
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY);
|
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY);
|
||||||
sprite.setTexture(`crop_stage_${crop.stage}`);
|
sprite.setTexture(`crop_stage_${crop.stage}`);
|
||||||
|
// Crop origin
|
||||||
|
sprite.setOrigin(0.5, 1);
|
||||||
|
// Crop depth
|
||||||
sprite.setDepth(this.iso.getDepth(x, y) + 0.5);
|
sprite.setDepth(this.iso.getDepth(x, y) + 0.5);
|
||||||
this.visibleCrops.set(key, sprite);
|
this.visibleCrops.set(key, sprite);
|
||||||
}
|
}
|
||||||
@@ -423,13 +449,6 @@ class TerrainSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
for (const [key, sprite] of this.visibleTiles) {
|
|
||||||
if (!neededTileKeys.has(key)) {
|
|
||||||
sprite.setVisible(false);
|
|
||||||
this.tilePool.release(sprite);
|
|
||||||
this.visibleTiles.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [key, sprite] of this.visibleDecorations) {
|
for (const [key, sprite] of this.visibleDecorations) {
|
||||||
if (!neededDecorKeys.has(key)) {
|
if (!neededDecorKeys.has(key)) {
|
||||||
sprite.setVisible(false);
|
sprite.setVisible(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user