mapa
This commit is contained in:
@@ -51,8 +51,15 @@ class GameScene extends Phaser.Scene {
|
||||
this.terrainSystem.updateCulling(this.cameras.main);
|
||||
|
||||
// FAZA 14: Spawn Ruin (Town Project) at fixed location near player
|
||||
console.log('🏚️ Spawning Ruin...');
|
||||
console.log('🏚️ Spawning Ruin & Arena...');
|
||||
this.terrainSystem.placeStructure(55, 55, 'ruin');
|
||||
this.terrainSystem.placeStructure(75, 75, 'arena');
|
||||
|
||||
// Initialize Pathfinding (Worker)
|
||||
console.log('🗺️ Initializing Pathfinding...');
|
||||
this.pathfinding = new PathfindingSystem(this);
|
||||
this.pathfinding.updateGrid();
|
||||
|
||||
} catch (e) {
|
||||
console.error("Terrain system failed:", e);
|
||||
}
|
||||
@@ -61,8 +68,6 @@ class GameScene extends Phaser.Scene {
|
||||
console.log('👤 Initializing player...');
|
||||
this.player = new Player(this, 50, 50, this.terrainOffsetX, this.terrainOffsetY);
|
||||
|
||||
// Dodaj 3 NPCje
|
||||
console.log('🧟 Initializing NPCs...');
|
||||
// Dodaj 3 NPCje (Mixed)
|
||||
console.log('🧟 Initializing NPCs...');
|
||||
const npcTypes = ['zombie', 'villager', 'merchant'];
|
||||
@@ -81,8 +86,8 @@ class GameScene extends Phaser.Scene {
|
||||
this.npcs.push(zombie);
|
||||
}
|
||||
|
||||
// Kamera sledi igralcu z izboljšanimi nastavitvami
|
||||
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0); // Instant follow (was 0.1)
|
||||
// Kamera sledi igralcu
|
||||
this.cameras.main.startFollow(this.player.sprite, true, 1.0, 1.0);
|
||||
|
||||
// Nastavi deadzone (100px border)
|
||||
this.cameras.main.setDeadzone(100, 100);
|
||||
@@ -99,11 +104,10 @@ class GameScene extends Phaser.Scene {
|
||||
// Kamera kontrole
|
||||
this.setupCamera();
|
||||
|
||||
// Initialize Time & Stats
|
||||
// Initialize Weather System (Unified: Time + DayNight + Weather)
|
||||
// Initialize Systems
|
||||
console.log('🌦️ Initializing Unified Weather System...');
|
||||
this.weatherSystem = new WeatherSystem(this);
|
||||
this.timeSystem = this.weatherSystem; // Alias for compatibility with other systems (e.g. UIScene, Farming)
|
||||
this.timeSystem = this.weatherSystem; // Alias
|
||||
|
||||
this.statsSystem = new StatsSystem(this);
|
||||
this.inventorySystem = new InventorySystem(this);
|
||||
@@ -111,17 +115,24 @@ class GameScene extends Phaser.Scene {
|
||||
this.interactionSystem = new InteractionSystem(this);
|
||||
this.farmingSystem = new FarmingSystem(this);
|
||||
this.buildingSystem = new BuildingSystem(this);
|
||||
|
||||
// DayNightSystem removed (merged into WeatherSystem)
|
||||
this.pathfinding = new Pathfinding(this);
|
||||
this.questSystem = new QuestSystem(this);
|
||||
this.multiplayerSystem = new MultiplayerSystem(this);
|
||||
|
||||
// Initialize Sound Manager
|
||||
console.log('🎵 Initializing Sound Manager...');
|
||||
this.soundManager = new SoundManager(this);
|
||||
this.soundManager.startMusic();
|
||||
|
||||
// Initialize Parallax System
|
||||
console.log('🌄 Initializing Parallax System...');
|
||||
this.parallaxSystem = new ParallaxSystem(this);
|
||||
|
||||
// Initialize Particle Effects
|
||||
console.log('✨ Initializing Particle Effects...');
|
||||
this.particleEffects = new ParticleEffects(this);
|
||||
this.particleEffects.createFallingLeaves();
|
||||
|
||||
// Generate Item Sprites for UI
|
||||
TextureGenerator.createItemSprites(this);
|
||||
|
||||
@@ -135,7 +146,11 @@ class GameScene extends Phaser.Scene {
|
||||
// Auto-load if available
|
||||
this.saveSystem.loadGame();
|
||||
|
||||
console.log('✅ GameScene ready - FAZA 18 (Crafting & AI)!');
|
||||
// Debug Text
|
||||
this.add.text(10, 10, 'NovaFarma Alpha v0.6', { font: '16px monospace', fill: '#ffffff' })
|
||||
.setScrollFactor(0).setDepth(10000);
|
||||
|
||||
console.log('✅ GameScene ready - FAZA 20 (Full Features)!');
|
||||
}
|
||||
|
||||
setupCamera() {
|
||||
@@ -159,21 +174,11 @@ class GameScene extends Phaser.Scene {
|
||||
});
|
||||
|
||||
// Save/Load Keys
|
||||
this.input.keyboard.on('keydown-F8', () => {
|
||||
// Save
|
||||
if (this.saveSystem) {
|
||||
this.saveSystem.saveGame();
|
||||
console.log('💾 Game Saved! (F8)');
|
||||
}
|
||||
});
|
||||
this.input.keyboard.on('keydown-F8', () => this.saveGame());
|
||||
this.input.keyboard.on('keydown-F9', () => this.loadGame());
|
||||
|
||||
this.input.keyboard.on('keydown-F9', () => {
|
||||
// Load
|
||||
if (this.saveSystem) {
|
||||
this.saveSystem.loadGame();
|
||||
console.log('📂 Game Loaded! (F9)');
|
||||
}
|
||||
});
|
||||
// Spawn Boss (Debug)
|
||||
this.input.keyboard.on('keydown-K', () => this.spawnBoss());
|
||||
|
||||
// Build Mode Keys
|
||||
this.input.keyboard.on('keydown-B', () => {
|
||||
@@ -184,41 +189,73 @@ class GameScene extends Phaser.Scene {
|
||||
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('fence');
|
||||
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(0);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-TWO', () => {
|
||||
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('wall');
|
||||
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(1);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-THREE', () => {
|
||||
if (this.buildingSystem && this.buildingSystem.isBuildMode) this.buildingSystem.selectBuilding('house');
|
||||
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(2);
|
||||
});
|
||||
|
||||
// Soft Reset (F4) - Force Reload Page
|
||||
this.input.keyboard.on('keydown-F4', () => {
|
||||
console.log('🔄 Soft Reset Initiated (Force Reload)...');
|
||||
window.location.reload();
|
||||
});
|
||||
// Soft Reset (F4)
|
||||
this.input.keyboard.on('keydown-F4', () => window.location.reload());
|
||||
|
||||
// Mute Toggle (M key)
|
||||
this.input.keyboard.on('keydown-M', () => {
|
||||
if (this.soundManager) {
|
||||
this.soundManager.toggleMute();
|
||||
}
|
||||
if (this.soundManager) this.soundManager.toggleMute();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
if (this.player) this.player.update(delta);
|
||||
|
||||
// Update Systems
|
||||
// TimeSystem update removed (handled by WeatherSystem)
|
||||
if (this.statsSystem) this.statsSystem.update(delta);
|
||||
if (this.lootSystem) this.lootSystem.update(delta); // Loot System Update
|
||||
if (this.lootSystem) this.lootSystem.update(delta);
|
||||
if (this.interactionSystem) this.interactionSystem.update(delta);
|
||||
if (this.farmingSystem) this.farmingSystem.update(delta);
|
||||
// DayNight update removed (handled by WeatherSystem)
|
||||
if (this.weatherSystem) this.weatherSystem.update(delta);
|
||||
if (this.questSystem) this.questSystem.update(delta);
|
||||
if (this.multiplayerSystem) this.multiplayerSystem.update(delta);
|
||||
|
||||
// Update Parallax (foreground grass fading)
|
||||
if (this.weatherSystem) {
|
||||
this.weatherSystem.update(delta);
|
||||
|
||||
// Night Logic
|
||||
if (this.weatherSystem.isNight()) {
|
||||
const isHorde = this.weatherSystem.isHordeNight();
|
||||
const spawnInterval = isHorde ? 2000 : 10000;
|
||||
|
||||
// Check for Horde Start Warning
|
||||
if (isHorde && !this.hordeWarningShown) {
|
||||
this.showHordeWarning();
|
||||
this.hordeWarningShown = true;
|
||||
}
|
||||
|
||||
if (!this.nightSpawnTimer) this.nightSpawnTimer = 0;
|
||||
this.nightSpawnTimer += delta;
|
||||
|
||||
if (this.nightSpawnTimer > spawnInterval) {
|
||||
this.nightSpawnTimer = 0;
|
||||
this.spawnNightZombie();
|
||||
if (isHorde) {
|
||||
this.spawnNightZombie();
|
||||
this.spawnNightZombie();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.hordeWarningShown = false;
|
||||
}
|
||||
}
|
||||
|
||||
// NPC Update
|
||||
for (const npc of this.npcs) {
|
||||
npc.update(delta);
|
||||
}
|
||||
|
||||
// Parallax
|
||||
if (this.parallaxSystem && this.player) {
|
||||
const playerPos = this.player.getPosition();
|
||||
const screenPos = this.iso.toScreen(playerPos.x, playerPos.y);
|
||||
@@ -228,45 +265,34 @@ class GameScene extends Phaser.Scene {
|
||||
);
|
||||
}
|
||||
|
||||
// Update player
|
||||
if (this.player) {
|
||||
this.player.update(delta);
|
||||
}
|
||||
|
||||
// Update NPCs
|
||||
for (const npc of this.npcs) {
|
||||
npc.update(delta);
|
||||
}
|
||||
|
||||
// Update Terrain Culling
|
||||
// Terrain Culling
|
||||
if (this.terrainSystem) {
|
||||
this.terrainSystem.updateCulling(this.cameras.main);
|
||||
}
|
||||
|
||||
// Update clouds
|
||||
// Clouds
|
||||
if (this.clouds) {
|
||||
for (const cloud of this.clouds) {
|
||||
cloud.sprite.x += cloud.speed * (delta / 1000);
|
||||
if (cloud.sprite.x > this.terrainOffsetX + 2000) { // Reset far right
|
||||
if (cloud.sprite.x > this.terrainOffsetX + 2000) {
|
||||
cloud.sprite.x = this.terrainOffsetX - 2000;
|
||||
cloud.sprite.y = Phaser.Math.Between(0, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send debug info to UI Scene
|
||||
// Debug Info
|
||||
if (this.player) {
|
||||
const playerPos = this.player.getPosition();
|
||||
const cam = this.cameras.main;
|
||||
|
||||
const uiScene = this.scene.get('UIScene');
|
||||
if (uiScene && uiScene.debugText) {
|
||||
const activeCrops = this.terrainSystem && this.terrainSystem.cropsMap ? this.terrainSystem.cropsMap.size : 0;
|
||||
const dropsCount = this.lootSystem ? this.lootSystem.drops.length : 0;
|
||||
const conn = this.multiplayerSystem && this.multiplayerSystem.isConnected ? '🟢 Online' : '🔴 Offline';
|
||||
|
||||
uiScene.debugText.setText(
|
||||
`FAZA 11 - Building\n` +
|
||||
`[F5] Save | [F9] Load | [B] Build Mode\n` +
|
||||
`NovaFarma v0.6 [${conn}]\n` +
|
||||
`[F5] Save | [F9] Load | [K] Boss\n` +
|
||||
`Time: ${this.timeSystem ? this.timeSystem.gameTime.toFixed(1) : '?'}h\n` +
|
||||
`Active Crops: ${activeCrops}\n` +
|
||||
`Loot Drops: ${dropsCount}\n` +
|
||||
@@ -276,25 +302,76 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
spawnNightZombie() {
|
||||
if (!this.player || this.npcs.length > 50) return;
|
||||
|
||||
const playerPos = this.player.getPosition();
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
const distance = Phaser.Math.Between(15, 25);
|
||||
|
||||
const spawnX = Math.floor(playerPos.x + Math.cos(angle) * distance);
|
||||
const spawnY = Math.floor(playerPos.y + Math.sin(angle) * distance);
|
||||
|
||||
if (spawnX < 0 || spawnX >= 100 || spawnY < 0 || spawnY >= 100) return;
|
||||
if (Phaser.Math.Distance.Between(spawnX, spawnY, 20, 20) < 15) return;
|
||||
|
||||
const tile = this.terrainSystem.getTile(spawnX, spawnY);
|
||||
if (tile && tile.type !== 'water') {
|
||||
console.log(`🌑 Night Spawn: Zombie at ${spawnX},${spawnY}`);
|
||||
const zombie = new NPC(this, spawnX, spawnY, this.terrainOffsetX, this.terrainOffsetY, 'zombie');
|
||||
zombie.state = 'CHASE';
|
||||
this.npcs.push(zombie);
|
||||
}
|
||||
}
|
||||
|
||||
showHordeWarning() {
|
||||
console.log('🩸 BLOOD MOON RISING!');
|
||||
if (this.soundManager) this.soundManager.playDeath();
|
||||
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
const text = this.add.text(width / 2, height / 3, 'THE HORDE IS APPROACHING...', {
|
||||
fontSize: '40px', fontFamily: 'Courier New', fill: '#ff0000', fontStyle: 'bold', stroke: '#000000', strokeThickness: 6
|
||||
}).setOrigin(0.5).setScrollFactor(0).setDepth(10000);
|
||||
|
||||
this.tweens.add({
|
||||
targets: text, scale: 1.2, duration: 500, yoyo: true, repeat: 5,
|
||||
onComplete: () => {
|
||||
this.tweens.add({
|
||||
targets: text, alpha: 0, duration: 2000,
|
||||
onComplete: () => text.destroy()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createClouds() {
|
||||
if (!this.textures.exists('cloud')) TextureGenerator.createCloudSprite(this, 'cloud');
|
||||
|
||||
this.clouds = [];
|
||||
console.log('☁️ Creating parallax clouds...');
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const x = Phaser.Math.Between(-1000, 3000);
|
||||
const y = Phaser.Math.Between(-500, 1500);
|
||||
|
||||
const cloud = this.add.sprite(x, y, 'cloud');
|
||||
cloud.setAlpha(0.4);
|
||||
cloud.setScrollFactor(0.2); // Parallax effect
|
||||
cloud.setDepth(2000); // Nad vsem
|
||||
cloud.setScale(Phaser.Math.FloatBetween(2, 4)); // Veliki oblaki
|
||||
|
||||
cloud.setAlpha(0.4).setScrollFactor(0.2).setDepth(2000).setScale(Phaser.Math.FloatBetween(2, 4));
|
||||
this.clouds.push({ sprite: cloud, speed: Phaser.Math.FloatBetween(10, 30) });
|
||||
}
|
||||
}
|
||||
|
||||
spawnBoss() {
|
||||
if (!this.player) return;
|
||||
console.log('👑 SPANWING ZOMBIE KING!');
|
||||
const playerPos = this.player.getPosition();
|
||||
const spawnX = Math.floor(playerPos.x + 8);
|
||||
const spawnY = Math.floor(playerPos.y + 8);
|
||||
const boss = new Boss(this, spawnX, spawnY);
|
||||
boss.state = 'CHASE';
|
||||
this.npcs.push(boss);
|
||||
this.showHordeWarning();
|
||||
this.events.emit('show-floating-text', { x: this.player.x, y: this.player.y - 100, text: "THE KING HAS ARRIVED!", color: '#AA00FF' });
|
||||
}
|
||||
|
||||
saveGame() {
|
||||
if (this.saveSystem) this.saveSystem.saveGame();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ class PreloadScene extends Phaser.Scene {
|
||||
preload() {
|
||||
console.log('⏳ PreloadScene: Loading assets...');
|
||||
|
||||
this.createLoadingBar();
|
||||
|
||||
// Load ALL custom sprites
|
||||
this.load.image('player_sprite', 'assets/player_sprite.png');
|
||||
this.load.image('zombie_sprite', 'assets/zombie_sprite.png');
|
||||
@@ -27,6 +29,30 @@ class PreloadScene extends Phaser.Scene {
|
||||
this.load.image('objects_pack2', 'assets/objects_pack2.png');
|
||||
this.load.image('trees_vegetation', 'assets/trees_vegetation.png');
|
||||
|
||||
// User-uploaded pixel art assets (original)
|
||||
this.load.image('flowers', 'assets/flowers.png');
|
||||
this.load.image('tree_green', 'assets/tree_green.png');
|
||||
this.load.image('tree_blue', 'assets/tree_blue.png');
|
||||
this.load.image('tree_dead', 'assets/tree_dead.png');
|
||||
this.load.image('rock_asset', 'assets/rock_asset.png');
|
||||
|
||||
// NEW transparent tree/rock assets
|
||||
this.load.image('tree_blue_new', 'assets/tree_blue_new.png');
|
||||
this.load.image('tree_green_new', 'assets/tree_green_new.png');
|
||||
this.load.image('rock_1', 'assets/rock_1.png');
|
||||
this.load.image('rock_2', 'assets/rock_2.png');
|
||||
this.load.image('tree_dead_new', 'assets/tree_dead_new.png');
|
||||
this.load.image('flowers_new', 'assets/flowers_new.png');
|
||||
this.load.image('hill_sprite', 'assets/hill_sprite.png');
|
||||
this.load.image('fence', 'assets/fence.png');
|
||||
this.load.image('gravestone', 'assets/gravestone.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');
|
||||
this.load.image('tree_voxel_dead', 'assets/tree_voxel_dead.png');
|
||||
this.load.image('rock_voxel', 'assets/rock_voxel.png');
|
||||
|
||||
// Wait for load completion then process transparency
|
||||
this.load.once('complete', () => {
|
||||
this.processAllTransparency();
|
||||
@@ -69,7 +95,28 @@ class PreloadScene extends Phaser.Scene {
|
||||
'grass_sprite',
|
||||
'leaf_sprite',
|
||||
'wheat_sprite',
|
||||
'stone_texture'
|
||||
'stone_texture',
|
||||
// New pixel art assets
|
||||
'flowers',
|
||||
'tree_green',
|
||||
'tree_blue',
|
||||
'tree_dead',
|
||||
'rock_asset',
|
||||
// NEW transparent assets
|
||||
'tree_blue_new',
|
||||
'tree_green_new',
|
||||
'rock_1',
|
||||
'rock_2',
|
||||
'tree_dead_new',
|
||||
'flowers_new',
|
||||
'hill_sprite',
|
||||
'fence',
|
||||
'gravestone',
|
||||
// Voxel stil
|
||||
'tree_voxel_green',
|
||||
'tree_voxel_blue',
|
||||
'tree_voxel_dead',
|
||||
'rock_voxel'
|
||||
];
|
||||
|
||||
spritesToProcess.forEach(spriteKey => {
|
||||
@@ -127,6 +174,42 @@ class PreloadScene extends Phaser.Scene {
|
||||
this.textures.addCanvas(spriteKey, canvas);
|
||||
}
|
||||
|
||||
createLoadingBar() {
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
const progressBar = this.add.graphics();
|
||||
const progressBox = this.add.graphics();
|
||||
progressBox.fillStyle(0x222222, 0.8);
|
||||
progressBox.fillRect(width / 2 - 160, height / 2 - 25, 320, 50);
|
||||
|
||||
const loadingText = this.add.text(width / 2, height / 2 - 50, 'Loading NovaFarma...', {
|
||||
font: '20px Courier New',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
loadingText.setOrigin(0.5, 0.5);
|
||||
|
||||
const percentText = this.add.text(width / 2, height / 2, '0%', {
|
||||
font: '18px Courier New',
|
||||
fill: '#ffffff'
|
||||
});
|
||||
percentText.setOrigin(0.5, 0.5);
|
||||
|
||||
this.load.on('progress', (value) => {
|
||||
percentText.setText(parseInt(value * 100) + '%');
|
||||
progressBar.clear();
|
||||
progressBar.fillStyle(0x00ff00, 1); // Matrix Green
|
||||
progressBar.fillRect(width / 2 - 150, height / 2 - 15, 300 * value, 30);
|
||||
});
|
||||
|
||||
this.load.on('complete', () => {
|
||||
progressBar.destroy();
|
||||
progressBox.destroy();
|
||||
loadingText.destroy();
|
||||
percentText.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
console.log('✅ PreloadScene: Assets loaded!');
|
||||
window.gameState.currentScene = 'PreloadScene';
|
||||
|
||||
@@ -11,32 +11,31 @@ class StoryScene extends Phaser.Scene {
|
||||
this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0);
|
||||
|
||||
const storyText =
|
||||
`Leto 2084.
|
||||
Svet, kot smo ga poznali, je izginil.
|
||||
`LETO 2084.
|
||||
SVET JE PADEL V TEMO.
|
||||
|
||||
Virus "Zmaj-Volka" je spremenil človeštvo.
|
||||
Mesta so ruševine. Narava je divja.
|
||||
Virus je večino spremenil v pošasti.
|
||||
Mesta so grobnice.
|
||||
|
||||
Toda ti si drugačen.
|
||||
Preživel si napad. Okužen, a imun.
|
||||
Si HIBRID.
|
||||
|
||||
Zombiji te ne napadajo... čutijo te.
|
||||
Zanje si ALFA.
|
||||
Toda našel si upanje.
|
||||
Zapuščeno kmetijo na robu divjine.
|
||||
Zadnje varno zatočišče.
|
||||
|
||||
Tvoja naloga:
|
||||
1. Najdi izgubljeno sestro.
|
||||
2. Maščuj starše.
|
||||
3. Obnovi civilizacijo iz pepela.
|
||||
1. Obnovi kmetijo in preživi.
|
||||
2. Zgradi obrambo pred hordo.
|
||||
3. Najdi zdravilo in reši svet.
|
||||
|
||||
Dobrodošel v KRVAVI ŽETVI.`;
|
||||
Pripravi se... NOČ PRIHAJA.`;
|
||||
|
||||
const textObj = this.add.text(width / 2, height + 100, storyText, {
|
||||
const textObj = this.add.text(width / 2, height, storyText, {
|
||||
fontFamily: 'Courier New',
|
||||
fontSize: '24px',
|
||||
fontSize: '28px',
|
||||
fill: '#00ff41',
|
||||
align: 'center',
|
||||
lineSpacing: 10
|
||||
lineSpacing: 15,
|
||||
stroke: '#000000',
|
||||
strokeThickness: 4
|
||||
});
|
||||
textObj.setOrigin(0.5, 0);
|
||||
|
||||
@@ -44,7 +43,7 @@ Dobrodošel v KRVAVI ŽETVI.`;
|
||||
this.tweens.add({
|
||||
targets: textObj,
|
||||
y: 50,
|
||||
duration: 10000, // 10s scroll
|
||||
duration: 15000, // 15s scroll
|
||||
ease: 'Linear',
|
||||
onComplete: () => {
|
||||
this.time.delayedCall(2000, () => {
|
||||
|
||||
@@ -18,6 +18,7 @@ class UIScene extends Phaser.Scene {
|
||||
this.createStatusBars();
|
||||
this.createInventoryBar();
|
||||
this.createGoldDisplay();
|
||||
this.createVirtualJoystick();
|
||||
this.createClock();
|
||||
// this.createDebugInfo();
|
||||
this.createSettingsButton();
|
||||
@@ -471,7 +472,20 @@ class UIScene extends Phaser.Scene {
|
||||
if (!this.buildMenuContainer) {
|
||||
this.createBuildMenuInfo();
|
||||
}
|
||||
this.buildMenuContainer.setVisible(isVisible);
|
||||
|
||||
if (isVisible) {
|
||||
this.buildMenuContainer.setVisible(true);
|
||||
this.buildMenuContainer.y = -100; // Start off-screen
|
||||
this.tweens.add({
|
||||
targets: this.buildMenuContainer,
|
||||
y: 100, // Target pos
|
||||
duration: 300,
|
||||
ease: 'Back.easeOut'
|
||||
});
|
||||
} else {
|
||||
// Slide out (optional) or just hide
|
||||
this.buildMenuContainer.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
createBuildMenuInfo() {
|
||||
@@ -778,4 +792,168 @@ class UIScene extends Phaser.Scene {
|
||||
});
|
||||
this.settingsContainer.add(hitArea);
|
||||
}
|
||||
|
||||
updateQuestTracker(quest) {
|
||||
if (!this.questContainer) {
|
||||
this.createQuestTracker();
|
||||
}
|
||||
|
||||
if (!quest) {
|
||||
this.questContainer.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.questContainer.setVisible(true);
|
||||
this.questTitle.setText(quest.title.toUpperCase());
|
||||
|
||||
let objText = '';
|
||||
quest.objectives.forEach(obj => {
|
||||
const status = obj.done ? '✅' : '⬜';
|
||||
let desc = '';
|
||||
if (obj.type === 'collect') desc = `${obj.item}: ${obj.current}/${obj.amount}`;
|
||||
else if (obj.type === 'action') desc = `${obj.action}: ${obj.current}/${obj.amount}`;
|
||||
else if (obj.type === 'kill') desc = `Slay ${obj.target}: ${obj.current}/${obj.amount}`;
|
||||
|
||||
objText += `${status} ${desc}\n`;
|
||||
});
|
||||
|
||||
this.questObjectives.setText(objText);
|
||||
}
|
||||
|
||||
createQuestTracker() {
|
||||
const x = this.width - 240;
|
||||
const y = 20;
|
||||
|
||||
this.questContainer = this.add.container(x, y);
|
||||
|
||||
// BG
|
||||
const bg = this.add.graphics();
|
||||
bg.fillStyle(0x000000, 0.6);
|
||||
bg.fillRect(0, 0, 220, 100);
|
||||
bg.lineStyle(2, 0xffaa00, 0.8);
|
||||
bg.strokeRect(0, 0, 220, 100);
|
||||
this.questContainer.add(bg);
|
||||
this.questTrackerBg = bg; // ref to resize later if needed
|
||||
|
||||
// Title Header
|
||||
const header = this.add.text(10, 5, 'CURRENT QUEST', { fontSize: '10px', fill: '#aaaaaa' });
|
||||
this.questContainer.add(header);
|
||||
|
||||
// Title
|
||||
this.questTitle = this.add.text(10, 20, 'Quest Title', {
|
||||
fontSize: '16px', fill: '#ffaa00', fontStyle: 'bold'
|
||||
});
|
||||
this.questContainer.add(this.questTitle);
|
||||
|
||||
// Objectives
|
||||
this.questObjectives = this.add.text(10, 45, 'Objectives...', {
|
||||
fontSize: '14px', fill: '#ffffff', lineSpacing: 5
|
||||
});
|
||||
this.questContainer.add(this.questObjectives);
|
||||
}
|
||||
|
||||
createVirtualJoystick() {
|
||||
const x = 120;
|
||||
const y = this.height - 120;
|
||||
// Warning: this.height might not be updated on resize? Use this.scale.height or just initial.
|
||||
// UIScene is usually overlay, so simple coords ok. But resize needs handling.
|
||||
|
||||
const r = 60;
|
||||
|
||||
// Visuals
|
||||
this.joyBase = this.add.circle(x, y, r, 0xffffff, 0.1).setScrollFactor(0).setDepth(2000).setInteractive();
|
||||
this.joyStick = this.add.circle(x, y, r / 2, 0xffffff, 0.5).setScrollFactor(0).setDepth(2001);
|
||||
|
||||
this.virtualJoystick = { up: false, down: false, left: false, right: false };
|
||||
this.joyDragging = false;
|
||||
|
||||
// Events
|
||||
this.input.on('pointermove', (pointer) => {
|
||||
if (!this.joyDragging) return;
|
||||
this.updateJoystick(pointer.x, pointer.y, x, y, r);
|
||||
});
|
||||
|
||||
this.input.on('pointerup', () => {
|
||||
if (this.joyDragging) {
|
||||
this.joyDragging = false;
|
||||
this.joyStick.setPosition(x, y);
|
||||
this.virtualJoystick = { up: false, down: false, left: false, right: false };
|
||||
}
|
||||
});
|
||||
|
||||
this.joyBase.on('pointerdown', (pointer) => {
|
||||
this.joyDragging = true;
|
||||
this.updateJoystick(pointer.x, pointer.y, x, y, r);
|
||||
});
|
||||
}
|
||||
|
||||
updateJoystick(px, py, cx, cy, r) {
|
||||
const angle = Phaser.Math.Angle.Between(cx, cy, px, py);
|
||||
const dist = Math.min(r, Phaser.Math.Distance.Between(cx, cy, px, py));
|
||||
|
||||
const sx = cx + Math.cos(angle) * dist;
|
||||
const sy = cy + Math.sin(angle) * dist;
|
||||
|
||||
this.joyStick.setPosition(sx, sy);
|
||||
|
||||
// Normalize angle to degrees
|
||||
let deg = Phaser.Math.RadToDeg(angle);
|
||||
|
||||
this.virtualJoystick = { up: false, down: false, left: false, right: false };
|
||||
|
||||
// Mapping to Isometric direction keys
|
||||
// UP Key (Top-Left on screen) -> Angle -135 (-180 to -90)
|
||||
// RIGHT Key (Top-Right on screen) -> Angle -45 (-90 to 0)
|
||||
// DOWN Key (Bottom-Right on screen) -> Angle 45 (0 to 90)
|
||||
// LEFT Key (Bottom-Left on screen) -> Angle 135 (90 to 180)
|
||||
|
||||
if (deg > -170 && deg <= -80) this.virtualJoystick.up = true; // Tuned slightly
|
||||
else if (deg > -80 && deg <= 10) this.virtualJoystick.right = true;
|
||||
else if (deg > 10 && deg <= 100) this.virtualJoystick.down = true;
|
||||
else this.virtualJoystick.left = true;
|
||||
}
|
||||
|
||||
showQuestDialog(quest, onAccept) {
|
||||
const width = 400;
|
||||
const height = 250;
|
||||
const x = this.cameras.main.centerX;
|
||||
const y = this.cameras.main.centerY;
|
||||
|
||||
const container = this.add.container(x, y);
|
||||
container.setDepth(5000);
|
||||
|
||||
const bg = this.add.rectangle(0, 0, width, height, 0x222222, 0.95);
|
||||
bg.setStrokeStyle(4, 0x444444);
|
||||
|
||||
const title = this.add.text(0, -90, quest.title.toUpperCase(), { fontSize: '24px', fontStyle: 'bold', color: '#ffcc00' }).setOrigin(0.5);
|
||||
const desc = this.add.text(0, -30, quest.description, { fontSize: '16px', color: '#dddddd', align: 'center', wordWrap: { width: width - 60 } }).setOrigin(0.5);
|
||||
|
||||
let rText = "Reward: ";
|
||||
if (quest.reward.gold) rText += `${quest.reward.gold} G `;
|
||||
if (quest.reward.item) rText += `+ ${quest.reward.amount || 1} ${quest.reward.item}`;
|
||||
|
||||
const reward = this.add.text(0, 40, rText, { fontSize: '16px', color: '#00ff00', fontStyle: 'italic' }).setOrigin(0.5);
|
||||
|
||||
// Buttons
|
||||
const btnAccept = this.add.rectangle(-70, 90, 120, 40, 0x228B22).setInteractive({ useHandCursor: true });
|
||||
const txtAccept = this.add.text(-70, 90, 'ACCEPT', { fontSize: '18px', fontStyle: 'bold' }).setOrigin(0.5);
|
||||
|
||||
const btnClose = this.add.rectangle(70, 90, 120, 40, 0x8B0000).setInteractive({ useHandCursor: true });
|
||||
const txtClose = this.add.text(70, 90, 'DECLINE', { fontSize: '18px', fontStyle: 'bold' }).setOrigin(0.5);
|
||||
|
||||
btnAccept.on('pointerdown', () => {
|
||||
onAccept();
|
||||
container.destroy();
|
||||
});
|
||||
|
||||
btnClose.on('pointerdown', () => {
|
||||
container.destroy();
|
||||
});
|
||||
|
||||
container.add([bg, title, desc, reward, btnAccept, txtAccept, btnClose, txtClose]);
|
||||
|
||||
// Appear anim
|
||||
container.setScale(0);
|
||||
this.tweens.add({ targets: container, scale: 1, duration: 200, ease: 'Back.out' });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user