This commit is contained in:
2025-12-08 01:00:56 +01:00
parent 7834aee111
commit 9c61c3b56d
20 changed files with 675 additions and 129 deletions

View File

@@ -368,28 +368,10 @@ class Player {
const key = `${targetX},${targetY}`;
if (terrainSystem.decorationsMap.has(key)) {
const decor = terrainSystem.decorationsMap.get(key);
// Vsi trdni objekti - igralec ne more hoditi skozi njih
const solidTypes = [
'tree', 'stone', 'bush', 'wall', 'ruin', 'fence', 'house', 'gravestone',
'rock_asset', 'rock_1', 'rock_2', 'rock_small', // Kamni
'tree_green_final', 'tree_blue_final', 'tree_dead_final', // Drevesa
'chest', 'spawner', // City struktury
'signpost_city', 'signpost_farm', 'signpost_both', // Signposti
'arena' // Arena
];
// Check ali je tip solid - case-insensitive
const typeLower = (decor.type || '').toLowerCase();
const isSolid = solidTypes.includes(decor.type) ||
typeLower.includes('tree') ||
typeLower.includes('sapling') ||
typeLower.includes('rock') ||
typeLower.includes('stone') ||
typeLower.includes('signpost') ||
typeLower.includes('hill');
if (isSolid) {
console.log('⛔ BLOCKED:', decor.type);
// Preverimo decor.solid property (set by TerrainSystem.addDecoration)
if (decor.solid === true) {
console.log('⛔ BLOCKED by solid decoration:', decor.type);
isPassable = false;
}
}

View File

@@ -56,7 +56,7 @@ const config = {
clearBeforeRender: true,
powerPreference: 'high-performance',
// Eksplicitna NEAREST_NEIGHBOR filtracija
mipmapFilter: 'LINEAR_MIPMAP_LINEAR',
mipmapFilter: 'NEAREST',
batchSize: 4096
},
physics: {

View File

@@ -102,6 +102,21 @@ class GameScene extends Phaser.Scene {
this.terrainSystem.placeStructure(65, 64, 'signpost_farm'); // Pri mestu "← Farm"
this.terrainSystem.placeStructure(45, 40, 'signpost_both'); // Na križišču
// DAMAGED CITY WALLS - vizualni markerji mesta (porušeni zidovi)
console.log('🏚️ Placing Damaged City Walls...');
// Delno porušeni zidovi okoli city perimetra
const wallPositions = [
[65, 65], [70, 65], [75, 65], // Top wall
[65, 79], [70, 79], [75, 79], // Bottom wall
[65, 70], [65, 75], // Left wall
[79, 70], [79, 75] // Right wall
];
wallPositions.forEach(([wx, wy]) => {
if (Math.random() < 0.7) { // 70% chance per segment (gaps for realism)
this.terrainSystem.placeStructure(wx, wy, 'wall_damaged');
}
});
// Initialize Pathfinding (Worker)
console.log('🗺️ Initializing Pathfinding...');
this.pathfinding = new PathfindingSystem(this);
@@ -358,6 +373,9 @@ class GameScene extends Phaser.Scene {
);
}
}
// Run Antigravity Engine Update
this.Antigravity_Update(delta);
}
spawnNightZombie() {
@@ -464,19 +482,40 @@ class GameScene extends Phaser.Scene {
// 2. Place starter resources (chest s semeni)
this.terrainSystem.placeStructure(farmX + 3, farmY + 3, 'chest');
// 3. Place fence around farm (optional)
const fencePositions = [
[farmX - farmRadius, farmY - farmRadius],
[farmX + farmRadius, farmY - farmRadius],
[farmX - farmRadius, farmY + farmRadius],
[farmX + farmRadius, farmY + farmRadius]
];
fencePositions.forEach(([fx, fy]) => {
if (fx >= 0 && fx < 100 && fy >= 0 && fy < 100) {
this.terrainSystem.placeStructure(fx, fy, 'fence');
// 3. Place FULL FENCE around farm
console.log('🚧 Building Farm Fence...');
const minX = farmX - farmRadius;
const maxX = farmX + farmRadius;
const minY = farmY - farmRadius;
const maxY = farmY + farmRadius;
// Top and bottom horizontal fences
for (let x = minX; x <= maxX; x++) {
if (x >= 0 && x < 100) {
this.terrainSystem.placeStructure(x, minY, 'fence_full'); // Top
this.terrainSystem.placeStructure(x, maxY, 'fence_full'); // Bottom
}
});
}
// Left and right vertical fences
for (let y = minY; y <= maxY; y++) {
if (y >= 0 && y < 100) {
this.terrainSystem.placeStructure(minX, y, 'fence_full'); // Left
this.terrainSystem.placeStructure(maxX, y, 'fence_full'); // Right
}
}
console.log('✅ Farm Area Initialized at (20,20)');
}
// ========================================================
// ANTIGRAVITY ENGINE UPDATE
// ========================================================
Antigravity_Update(delta) {
// Globalni update klic
if (window.Antigravity) {
window.Antigravity.Update(this, delta);
}
}
}

View File

@@ -56,6 +56,18 @@ class PreloadScene extends Phaser.Scene {
this.load.image('fence', 'assets/fence.png');
this.load.image('gravestone', 'assets/gravestone.png');
// City content assets
this.load.image('chest', 'assets/chest.png');
this.load.image('spawner', 'assets/spawner.png');
this.load.image('signpost_city', 'assets/signpost_city.png');
this.load.image('signpost_farm', 'assets/signpost_farm.png');
this.load.image('signpost_both', 'assets/signpost_both.png');
this.load.image('city_wall', 'assets/city_wall.png');
this.load.image('road_tile', 'assets/road_tile.png');
this.load.image('farm_zone', 'assets/farm_zone.png');
this.load.image('fence_full', 'assets/fence_full.png');
this.load.image('wall_damaged', 'assets/wall_damaged.png');
// Voxel stil asset-i (2.5D)
this.load.image('tree_voxel_green', 'assets/tree_voxel_green.png');
this.load.image('tree_voxel_blue', 'assets/tree_voxel_blue.png');
@@ -130,6 +142,12 @@ class PreloadScene extends Phaser.Scene {
'hill_sprite',
'fence',
'gravestone',
// City content
'chest',
'spawner',
'signpost_city',
'signpost_farm',
'signpost_both',
// Voxel stil
'tree_voxel_green',
'tree_voxel_blue',

View File

@@ -0,0 +1,56 @@
/**
* ANTIGRAVITY ENGINE
* Core system for NovaFarma
*/
window.Antigravity = {
Config: {
Tileset: {
Spacing: 0,
Margin: 0,
TextureFilter: 'NEAREST'
}
},
Rendering: {
/**
* Zagotavlja pravilno globinsko razvrščanje (Depth Sorting) vseh spritov
* @param {Phaser.Scene} scene
*/
depthSortSprites: function (scene) {
// 1. Player Depth
if (scene.player && scene.player.sprite) {
scene.player.updateDepth();
}
// 2. NPC Depth
if (scene.npcs) {
scene.npcs.forEach(npc => {
if (npc && npc.sprite && npc.sprite.visible) {
npc.updateDepth(); // Vsak NPC ima svojo metodo
}
});
}
// 3. Projectiles / Particles (če bi jih imeli ločene)
// ...
}
},
Physics: {
checkCollisions: function (scene) {
// Placeholder za centraliziran collision logic
}
},
/**
* Glavni update loop za Engine
* @param {Phaser.Scene} scene
* @param {number} delta
*/
Update: function (scene, delta) {
this.Rendering.depthSortSprites(scene);
}
};
console.log('🌌 Antigravity Engine Initialized', window.Antigravity.Config);

View File

@@ -21,6 +21,9 @@ 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 ROCK_DENSITY_THRESHOLD = 0.60; // Prag za skupine skal
// Terrain Generator System
class TerrainSystem {
constructor(scene, width = 100, height = 100) {
@@ -121,65 +124,86 @@ class TerrainSystem {
createTileTextures() {
const tileWidth = 48;
const tileHeight = 60;
const P = 2; // PADDING (Margin) za preprečevanje črt
const types = Object.values(this.terrainTypes);
types.forEach((type) => {
if (this.scene.textures.exists(type.name)) return;
const graphics = this.scene.make.graphics({ x: 0, y: 0, add: false });
const x = 0;
const midX = 24;
const midY = 12;
const bottomY = 24;
// Koordinate z upoštevanjem paddinga
const xs = P;
const xe = 48 + P;
const midX = 24 + P;
const topY = P;
const midY = 12 + P;
const bottomY = 24 + P;
const depth = 20;
graphics.fillStyle(0x8B4513);
// 1. STRANICE (Faces)
// Left Face
const cLeft = 0x8B4513;
graphics.fillStyle(cLeft);
graphics.beginPath();
graphics.moveTo(midX, bottomY);
graphics.lineTo(midX, bottomY + depth);
graphics.lineTo(x, midY + depth);
graphics.lineTo(x, midY);
graphics.lineTo(xs, midY + depth);
graphics.lineTo(xs, midY);
graphics.closePath();
graphics.fill();
graphics.lineStyle(2, cLeft); // Overdraw
graphics.strokePath();
graphics.fillStyle(0x6B3410);
// Right Face
const cRight = 0x6B3410;
graphics.fillStyle(cRight);
graphics.beginPath();
graphics.moveTo(x + 48, midY);
graphics.lineTo(x + 48, midY + depth);
graphics.moveTo(xe, midY);
graphics.lineTo(xe, midY + depth);
graphics.lineTo(midX, bottomY + depth);
graphics.lineTo(midX, bottomY);
graphics.closePath();
graphics.fill();
graphics.fillStyle(type.color);
graphics.beginPath();
graphics.moveTo(midX, 0);
graphics.lineTo(x + 48, midY);
graphics.lineTo(midX, bottomY);
graphics.lineTo(x, midY);
graphics.closePath();
graphics.fill();
graphics.lineStyle(1, 0xffffff, 0.15);
graphics.beginPath();
graphics.moveTo(x, midY);
graphics.lineTo(midX, 0);
graphics.lineTo(x + 48, midY);
graphics.lineStyle(2, cRight);
graphics.strokePath();
// 2. ZGORNJA PLOSKEV (Top Face)
graphics.fillStyle(type.color);
graphics.beginPath();
graphics.moveTo(xs, midY);
graphics.lineTo(midX, topY);
graphics.lineTo(xe, midY);
graphics.lineTo(midX, bottomY);
graphics.closePath();
graphics.fill();
graphics.lineStyle(2, type.color); // Overdraw
graphics.strokePath();
// Highlight
graphics.lineStyle(1, 0xffffff, 0.15);
graphics.beginPath();
graphics.moveTo(xs, midY);
graphics.lineTo(midX, topY);
graphics.lineTo(xe, midY);
graphics.strokePath();
// 3. DETAJLI
if (type.name.includes('grass')) {
graphics.fillStyle(Phaser.Display.Color.IntegerToColor(type.color).lighten(10).color);
for (let i = 0; i < 8; i++) {
const rx = x + 10 + Math.random() * 28;
const ry = 4 + Math.random() * 16;
const rx = xs + 10 + Math.random() * 28;
const ry = topY + 4 + Math.random() * 16;
graphics.fillRect(rx, ry, 2, 2);
}
}
if (type.name.includes('stone') || type.name.includes('ruins')) {
graphics.fillStyle(0x444444);
for (let i = 0; i < 6; i++) {
const rx = x + 8 + Math.random() * 30;
const ry = 4 + Math.random() * 16;
const rx = xs + 8 + Math.random() * 30;
const ry = topY + 4 + Math.random() * 16;
graphics.fillRect(rx, ry, 3, 3);
}
}
@@ -187,12 +211,12 @@ class TerrainSystem {
if (type.name.includes('pavement')) {
graphics.lineStyle(1, 0x555555, 0.5);
graphics.beginPath();
graphics.moveTo(x + 12, midY + 6);
graphics.lineTo(x + 36, midY - 6);
graphics.moveTo(xs + 12, midY + 6);
graphics.lineTo(xs + 36, midY - 6);
graphics.strokePath();
}
graphics.generateTexture(type.name, tileWidth, tileHeight);
graphics.generateTexture(type.name, tileWidth + P * 2, tileHeight + P * 2);
graphics.destroy();
});
}
@@ -357,22 +381,27 @@ class TerrainSystem {
if (isFarm || isCity) return;
// 2. Noise for clustering (Forests)
// Offset inputs to decouple from terrain height noise
const noiseVal = this.noise.noise(x * 0.1 + 123.45, y * 0.1 + 678.90);
// 3. Selection Logic (Scattered & Saplings focus)
// KLJUČNO PREVERJANJE: Ali tu že stoji drug Sprite?
const key = `${x},${y}`;
if (this.decorationsMap.has(key)) return;
if (this.tiles[y][x].hasDecoration) return;
// 3. Selection Logic
let shouldPlace = false;
let type = window.SPRITE_TREE_HEALTHY || 'tree_green_final';
// Bolj enakomerna porazdelitev (Scattered)
// Noise uporabimo le za rahlo variacijo, ne za stroge gruče
let chance = 0.015; // 1.5% base chance (zelo redko)
if (noiseVal > 0.30) chance = 0.03; // Malo večja gostota v "gozdu"
if (Math.random() < chance) {
// USER LOGIC: Gostota 40% če smo nad pragom (Gozd)
if (noiseVal > TREE_DENSITY_THRESHOLD && Math.random() < 0.4) {
shouldPlace = true;
}
// Fallback: Redka posamična drevesa (1.5%)
else if (Math.random() < 0.015) {
shouldPlace = true;
}
if (shouldPlace) {
// Variants Logic
const r = Math.random();
// 50% možnosti, da je drevo komaj začelo rasti (Sapling)
@@ -395,26 +424,24 @@ class TerrainSystem {
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) return;
// Če je že dekoracija (drevo), ne dajaj kamna
// KLJUČNO PREVERJANJE: Ali tu že stoji drug Sprite?
const key = `${x},${y}`;
if (this.decorationsMap.has(key)) return;
if (this.tiles[y][x].hasDecoration) return;
// Noise for Rock Clusters
const noiseVal = this.noise.noise(x * 0.15 + 99.99, y * 0.15 + 88.88);
let shouldPlace = false;
let type = 'rock_1'; // Default
let type = 'rock_asset'; // Default lep kamen
let chance = 0.01; // 1% Scattered chance
if (noiseVal > 0.45) { // Rock Cluster Area
chance = 0.30; // High density in cluster
}
if (Math.random() < chance) {
// USER LOGIC: Gostota 40% če smo nad pragom (Skalovje)
if (noiseVal > ROCK_DENSITY_THRESHOLD && Math.random() < 0.4) {
shouldPlace = true;
}
// Fallback: Redke posamične skale (1%)
else if (Math.random() < 0.01) {
shouldPlace = true;
// Variants - "Lepi kamni" (rock_asset)
// Odstranili smo nedokončane velike kamne
type = 'rock_asset';
}
if (shouldPlace) {
@@ -505,6 +532,24 @@ class TerrainSystem {
if (!w) plantDay = 1 - Math.floor(Math.random() * 2);
}
// Determine if decoration is SOLID (blocking movement)
const typeLower = type.toLowerCase();
const isSolid = typeLower.includes('tree') ||
typeLower.includes('sapling') ||
typeLower.includes('rock') ||
typeLower.includes('stone') ||
typeLower.includes('fence') ||
typeLower.includes('wall') ||
typeLower.includes('signpost') ||
typeLower.includes('hill') ||
typeLower.includes('chest') ||
typeLower.includes('spawner') ||
typeLower.includes('ruin') ||
typeLower.includes('arena') ||
typeLower.includes('house') ||
typeLower.includes('gravestone') ||
typeLower.includes('bush');
const decorData = {
gridX: gridX,
gridY: gridY,
@@ -513,7 +558,8 @@ class TerrainSystem {
maxHp: 10,
hp: 10,
scale: scale,
plantDay: plantDay // Added for Growth System
plantDay: plantDay, // Added for Growth System
solid: isSolid // TRDNOST (collision blocking)
};
this.decorations.push(decorData);
this.decorationsMap.set(key, decorData);
@@ -611,7 +657,7 @@ class TerrainSystem {
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.setPosition(Math.round(screenPos.x + this.offsetX), Math.round(screenPos.y + this.offsetY));
sprite.setDepth(this.iso.getDepth(x, y, this.iso.LAYER_FLOOR)); // Tiles = Floor
this.visibleTiles.set(key, sprite);
}
@@ -624,7 +670,7 @@ class TerrainSystem {
const sprite = this.decorationPool.get();
const screenPos = this.iso.toScreen(x, y);
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY - voxelOffset);
sprite.setPosition(Math.round(screenPos.x + this.offsetX), Math.round(screenPos.y + this.offsetY - voxelOffset));
if (decor.type.includes('house') || decor.type.includes('market') || decor.type.includes('structure')) {
sprite.setOrigin(0.5, 0.8);
@@ -652,7 +698,7 @@ class TerrainSystem {
if (!this.visibleCrops.has(key)) {
const sprite = this.cropPool.get();
const screenPos = this.iso.toScreen(x, y);
sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY - voxelOffset);
sprite.setPosition(Math.round(screenPos.x + this.offsetX), Math.round(screenPos.y + this.offsetY - voxelOffset));
sprite.setTexture(`crop_stage_${crop.stage}`);
sprite.setOrigin(0.5, 1);
// Layer Objects (da igralec hodi okoli njih)