FAZA 17: 2.5D Minecraft-Style Terrain + Y-Layer Stacking + Custom Sprites
COMPLETED FEATURES: Custom Sprite Integration: - Player, Zombie, Merchant sprites (0.2 scale) - 11 custom sprites + 5 asset packs loaded - Auto-transparency processing (white/brown removal) - Gravestone system with atlas extraction 2.5D Minecraft-Style Terrain: - Volumetric blocks with 25px thickness - Strong left/right side shading (30%/50% darker) - Minecraft-style texture patterns (grass, dirt, stone) - Crisp black outlines for definition Y-Layer Stacking System: - GRASS_FULL: All green (elevation > 0.7) - GRASS_TOP: Green top + brown sides (elevation 0.4-0.7) - DIRT: All brown (elevation < 0.4) - Dynamic terrain depth based on height Floating Island World Edge: - Stone cliff walls at map borders - 2-tile transition zone - Elevation flattening for cliff drop-off effect - 100x100 world with defined boundaries Performance & Polish: - Canvas renderer for pixel-perfect sharpness - CSS image-rendering: crisp-edges - willReadFrequently optimization - No Canvas2D warnings Technical: - 3D volumetric trees and rocks - Hybrid rendering (2.5D terrain + 2D characters) - Procedural texture generation - Y-layer aware terrain type selection
This commit is contained in:
112
src/systems/BuildingSystem.js
Normal file
112
src/systems/BuildingSystem.js
Normal file
@@ -0,0 +1,112 @@
|
||||
class BuildingSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.isBuildMode = false;
|
||||
this.selectedBuilding = 'fence'; // fence, wall, house
|
||||
|
||||
this.buildingsData = {
|
||||
fence: { name: 'Fence', cost: { wood: 2 }, w: 1, h: 1 },
|
||||
wall: { name: 'Stone Wall', cost: { stone: 2 }, w: 1, h: 1 },
|
||||
house: { name: 'House', cost: { wood: 20, stone: 20, gold: 50 }, w: 1, h: 1 } // Visual is bigger but anchor is 1 tile
|
||||
};
|
||||
|
||||
// Textures init
|
||||
if (!this.scene.textures.exists('struct_fence')) TextureGenerator.createStructureSprite(this.scene, 'struct_fence', 'fence');
|
||||
if (!this.scene.textures.exists('struct_wall')) TextureGenerator.createStructureSprite(this.scene, 'struct_wall', 'wall');
|
||||
if (!this.scene.textures.exists('struct_house')) TextureGenerator.createStructureSprite(this.scene, 'struct_house', 'house');
|
||||
}
|
||||
|
||||
toggleBuildMode() {
|
||||
this.isBuildMode = !this.isBuildMode;
|
||||
console.log(`🔨 Build Mode: ${this.isBuildMode}`);
|
||||
|
||||
// Update UI
|
||||
const uiScene = this.scene.scene.get('UIScene');
|
||||
if (uiScene) {
|
||||
uiScene.toggleBuildMenu(this.isBuildMode);
|
||||
}
|
||||
}
|
||||
|
||||
selectBuilding(type) {
|
||||
if (this.buildingsData[type]) {
|
||||
this.selectedBuilding = type;
|
||||
console.log(`🔨 Selected: ${this.selectedBuilding}`);
|
||||
|
||||
// UI feedback?
|
||||
const uiScene = this.scene.scene.get('UIScene');
|
||||
if (uiScene) uiScene.updateBuildSelection(type);
|
||||
}
|
||||
}
|
||||
|
||||
tryBuild(gridX, gridY) {
|
||||
if (!this.isBuildMode) return false;
|
||||
|
||||
const building = this.buildingsData[this.selectedBuilding];
|
||||
const inv = this.scene.inventorySystem;
|
||||
const terrain = this.scene.terrainSystem;
|
||||
|
||||
// 1. Check Cost
|
||||
if (building.cost.wood) {
|
||||
if (!inv.hasItem('wood', building.cost.wood)) {
|
||||
console.log('❌ Not enough Wood!');
|
||||
this.showFloatingText('Need Wood!', gridX, gridY, '#FF0000');
|
||||
return true; // We handled the click, even if failed
|
||||
}
|
||||
}
|
||||
if (building.cost.stone) {
|
||||
if (!inv.hasItem('stone', building.cost.stone)) {
|
||||
console.log('❌ Not enough Stone!');
|
||||
this.showFloatingText('Need Stone!', gridX, gridY, '#FF0000');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (building.cost.gold) {
|
||||
if (inv.gold < building.cost.gold) {
|
||||
console.log('❌ Not enough Gold!');
|
||||
this.showFloatingText('Need Gold!', gridX, gridY, '#FF0000');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check Space
|
||||
const tile = terrain.getTile(gridX, gridY);
|
||||
if (!tile || tile.type === 'water' || tile.hasDecoration || tile.hasCrop || tile.hasBuilding) {
|
||||
console.log('❌ Space occupied!');
|
||||
this.showFloatingText('Occupied!', gridX, gridY, '#FF0000');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. Consume Resources
|
||||
if (building.cost.wood) inv.removeItem('wood', building.cost.wood);
|
||||
if (building.cost.stone) inv.removeItem('stone', building.cost.stone);
|
||||
if (building.cost.gold) {
|
||||
inv.gold -= building.cost.gold;
|
||||
inv.updateUI();
|
||||
}
|
||||
|
||||
// 4. Place Building
|
||||
// Using decorations layer for now, but marking as building
|
||||
// Need to add texture to TerrainSystem pool?
|
||||
// Or better: TerrainSystem should handle 'placing structure'
|
||||
|
||||
// Let's modify TerrainSystem to support 'structures' better or just hack decorations
|
||||
const success = terrain.placeStructure(gridX, gridY, `struct_${this.selectedBuilding}`);
|
||||
if (success) {
|
||||
this.showFloatingText(`Built ${building.name}!`, gridX, gridY, '#00FF00');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
showFloatingText(text, gridX, gridY, color) {
|
||||
const iso = new IsometricUtils(48, 24);
|
||||
const pos = iso.toScreen(gridX, gridY);
|
||||
const popup = this.scene.add.text(
|
||||
pos.x + this.scene.terrainOffsetX,
|
||||
pos.y + this.scene.terrainOffsetY - 40,
|
||||
text,
|
||||
{ fontSize: '14px', fill: color, stroke: '#000', strokeThickness: 3 }
|
||||
).setOrigin(0.5);
|
||||
this.scene.tweens.add({ targets: popup, y: popup.y - 30, alpha: 0, duration: 2000, onComplete: () => popup.destroy() });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user