Files
novafarma/nova farma TRAE/src/scenes/GrassScene_Clean.js

883 lines
34 KiB
JavaScript

export default class GrassSceneClean extends Phaser.Scene {
constructor() {
super({ key: 'GrassSceneClean' });
}
preload() {
this.load.path = 'assets/';
// --- ASSETS ---
// 1. Podlaga (Foundation) - ZAMENJANO: Trava namesto blata
this.load.image('ground_base', 'DEMO_FAZA1/tiles/trava_osnova.png');
// 2. Vodni kanali (Water)
this.load.image('water_clean_patch', 'DEMO_FAZA1/Environment/water_clean_patch.png');
// this.load.image('river_tile_seamless', 'DEMO_FAZA1/Environment/river_tile_seamless.png');
// 3. Foliage
// "Divja trava" - samo visoka trava
this.load.image('grass_wild', 'DEMO_FAZA1/Vegetation/visoka_trava.png');
this.load.image('grass_wild_v2', 'DEMO_FAZA1/Vegetation/visoka_trava_v2.png');
// 4. Items & Charts
this.load.image('hay', 'DEMO_FAZA1/Items/hay_drop_0.png');
this.load.image('trnje', 'DEMO_FAZA1/Obstacles/trnje.png');
this.load.image('toxic_fog', 'DEMO_FAZA1/VFX/toxic_fog.png');
// this.load.image('amnesia_fog', 'DEMO_FAZA1/VFX/megla_ozadje.png'); // MISSING ASSET
// Generated Assets (Slices)
// Trees
for (let i = 0; i <= 5; i++) this.load.image(`tree_adult_${i}`, `DEMO_FAZA1/Trees/tree_adult_${i}.png`);
// Environment (Dead Nature, Fence, Water)
for (let i = 0; i <= 8; i++) this.load.image(`dead_nature_${i}`, `DEMO_FAZA1/Environment/dead_nature_${i}.png`);
for (let i = 0; i <= 2; i++) this.load.image(`fence_sign_${i}`, `DEMO_FAZA1/Environment/fence_sign_${i}.png`);
// for (let i = 0; i < 16; i++) this.load.image(`water_tile_${i}`, `DEMO_FAZA1/Environment/water_tile_${i}.png`); // MISSING ASSETS
// Misc Env
this.load.image('sotor', 'DEMO_FAZA1/Environment/sotor.png');
this.load.image('campfire', 'DEMO_FAZA1/Environment/taborni_ogenj.png');
this.load.image('sign_danger', 'DEMO_FAZA1/Environment/sign_danger.png');
// Vegetation
const veg = ['bush_hiding_spot', 'drevo_faza_1', 'drevo_faza_2', 'drevo_srednje', 'drevo_veliko', 'grass_cluster_dense', 'grass_cluster_flowery', 'trava_sop'];
veg.forEach(k => this.load.image(k, `DEMO_FAZA1/Vegetation/${k}.png`));
// Ground (Path)
// for (let i = 0; i < 16; i++) {
// this.load.image(`path_tile_${i}`, `DEMO_FAZA1/Ground/path_tile_${i}.png`);
// }
// REPLACED STATIC KAI WITH SPRITE SHEET
// Frame size 256x256 based on 1024x1024 sheet
this.load.spritesheet('kai', 'DEMO_FAZA1/Characters/kai_walk_sheet.png', {
frameWidth: 256,
frameHeight: 256
}); // Loading as 'kai' to keep existing references working, but now it has frames.
// 5. UI Assets (Loaded in UIScene now to prevent duplicates)
// REMOVED
// 6. Camp Assets
this.load.image('campfire', 'DEMO_FAZA1/Environment/taborni_ogenj.png');
this.load.image('tent', 'DEMO_FAZA1/Environment/sotor.png');
this.load.image('sleeping_bag', 'DEMO_FAZA1/Items/spalna_vreca.png');
// 7. NEW: Gronk & Structures
this.load.spritesheet('gronk', 'DEMO_FAZA1/Characters/gronk_walk_sheet.png', {
frameWidth: 256,
frameHeight: 256
});
this.load.image('rain_catcher', 'DEMO_FAZA1/Structures/rain_catcher.png');
}
create() {
// --- DYNAMIC ASSETS GENERATION ---
// Generate 'hole' texture if it doesn't exist
if (!this.textures.exists('hole')) {
const holeGfx = this.make.graphics({ x: 0, y: 0, add: false });
holeGfx.fillStyle(0x111111); // Almost black
holeGfx.fillCircle(64, 64, 60);
holeGfx.generateTexture('hole', 128, 128);
}
// --- WORLD CONFIGURATION ---
const TILE_SIZE = 128; // Standard grid size
const MAP_WIDTH_TILES = 250;
const MAP_HEIGHT_TILES = 250;
const WORLD_W = MAP_WIDTH_TILES * TILE_SIZE; // 32000 px
const WORLD_H = MAP_HEIGHT_TILES * TILE_SIZE; // 32000 px
this.physics.world.setBounds(0, 0, WORLD_W, WORLD_H);
this.cameras.main.setBounds(0, 0, WORLD_W, WORLD_H);
this.cameras.main.setBackgroundColor('#3a5f0b'); // Grass Green Background
// --- ZOOM CONTROL ---
this.cameras.main.setZoom(0.8); // Default start zoom (Wider view per user request)
this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY, deltaZ) => {
// MACBOOK OPTIMIZATION: Prevent Zoom when hovering over Editor Sidebar
/* REMOVED - Editor disabled
if (this.editorEnabled) {
const SIDEBAR_W = 320;
const PALETTE_X = this.scale.width - SIDEBAR_W;
if (pointer.x > PALETTE_X) {
return; // Stop processing zoom if over sidebar
}
}
*/
// Zoom In/Out based on wheel delta
// deltaY > 0 means scroll down (zoom out), deltaY < 0 means scroll up (zoom in)
const zoomFactor = -0.001;
const newZoom = this.cameras.main.zoom + deltaY * zoomFactor;
// Clamp zoom to reasonable limits (Extended range)
this.cameras.main.setZoom(Phaser.Math.Clamp(newZoom, 0.2, 5.0));
});
// --- 1. PODLAGA (The Foundation) ---
// ZAMENJANO: Zelena barva ozadja + trava tekstura
// 1. Nastavimo barvo ozadja na temno zeleno (da se ujema s travo)
this.cameras.main.setBackgroundColor('#2d4c1e');
// FIX: Ensure background covers max zoom out (0.2)
// Viewport at 0.2 zoom is 5x larger (1920 * 5 = 9600)
const BG_W = this.scale.width * 6; // Safety margin
const BG_H = this.scale.height * 6;
// 2. Uporabimo novo sliko za tileSprite (Grass Base)
this.ground = this.add.tileSprite(this.scale.width / 2, this.scale.height / 2, BG_W, BG_H, 'ground_base');
this.ground.setScrollFactor(0); // Sticks to camera
this.ground.setDepth(-100);
// --- SCALE TEST ---
// Za testiranje velikosti teksture:
// Originalna velikost je verjetno majhna (npr. 512px).
// Če želimo, da je vzorec večji, moramo povečati setTileScale.
// Trenutno: 1.0 (Originalna velikost)
// Če je trava "preveč drobna", povečaj to številko (npr. 2.0).
// Če je trava "preveč zrnata", zmanjšaj (npr. 0.5).
this.ground.setTileScale(1.0);
// Note: We need to update tilePosition in update() loop to match camera scroll!
// --- 2. RIVER SYSTEM (REMOVED) ---
// --- NEW: STATIC WATER POND (Ribnik) ---
// Dodano nazaj na zahtevo uporabnika (posodobljen asset)
this.pond = this.add.image(WORLD_W / 2 + 400, WORLD_H / 2 + 200, 'water_clean_patch');
this.pond.setDepth(-45); // Malo nad tlemi
this.pond.setScale(1.5);
this.physics.add.existing(this.pond, true); // Static physics body
// --- CELLAR ENTRANCE (Hole) ---
// Na poziciji Kai-a (WORLD_W / 2, WORLD_H / 2)
this.hole = this.add.image(WORLD_W / 2, WORLD_H / 2, 'hole');
this.hole.setDepth(-48); // On ground, below pond/items
this.physics.add.existing(this.hole, true); // Static body for trigger
// --- REALISTIC TREE (Next to Pond) ---
// REMOVED PER USER REQUEST
/*
// Center the whole construction
// Main Head (Pipe + Splash)
// Showing V7 Asset (Aggressive Clean + Transparent Green)
this.stream = this.physics.add.staticImage(startX, startY, 'stream_final_v7');
this.stream.setOrigin(0.5, 0.5);
this.stream.setDepth(-50);
this.stream.setInteractive({ draggable: true }); // Enable Dragging
// Physics Body for Main
this.stream.body.setSize(this.stream.width * 0.8, this.stream.height * 0.2);
this.stream.body.setOffset(this.stream.width * 0.1, this.stream.height * 0.4);
// Extensions removed for reset
// for (let i = 1; i <= 3; i++) { ... }
// Collider added later after Kai creation
// --- 2.1 STREAM BURYING (Dirt Patches) ---
// "Zakopaj" potok v zemljo (masking edges)
const dirtOffsets = [
{ x: -350, y: 150 }, // Left side
{ x: 380, y: 180 }, // Right side (The "other" side?)
{ x: 0, y: 300 } // Bottom center
];
dirtOffsets.forEach((off, i) => {
let dirt = this.add.image(startX + off.x, startY + off.y, 'ground_dirt_patch');
dirt.setScale(0.8 + Math.random() * 0.4); // Random size
dirt.setAngle(Math.random() * 360); // Random rotation
dirt.setDepth(-45); // Above stream (-50), below Kai
dirt.setTint(0xdddddd); // Slightly darker to match mud
dirt.setInteractive({ draggable: true }); // Allow user to adjust!
});
*/
// --- 3. FOLIAGE (Trava) ---
this.grassGroup = this.physics.add.group({
immovable: true,
allowGravity: false
});
// INVENTAR
this.inventory = { grass: 0 };
this.inventoryText = this.add.text(20, 20, 'Trava: 0', {
fontSize: '32px',
fill: '#ffffff',
stroke: '#000000',
strokeThickness: 4
}).setScrollFactor(0).setDepth(1000); // UI always on top
// --- INTRO SEQUENCE STATE ---
this.introStarted = false;
const GRASS_COUNT = 2000; // Restored per user request
const SPREAD = 4000; // 4000px radius okoli centra
// Parametri za izločanje trave (Pond & Hole)
const pondX = WORLD_W / 2 + 400;
const pondY = WORLD_H / 2 + 200;
const pondRadius = 600; // POVEČANO: Da odstranimo travo tudi okoli ribnika (Clearance)
const holeX = WORLD_W / 2;
const holeY = WORLD_H / 2;
const holeRadius = 80; // Radius of hole
for (let i = 0; i < GRASS_COUNT; i++) {
let x = (WORLD_W / 2) + (Math.random() * SPREAD * 2 - SPREAD);
let y = (WORLD_H / 2) + (Math.random() * SPREAD * 2 - SPREAD);
// 1. PREVERJANJE: Če je trava v ribniku (Pond)
if (Phaser.Math.Distance.Between(x, y, pondX, pondY) < pondRadius) {
continue;
}
// 2. PREVERJANJE: Če je trava v luknji (Hole)
if (Phaser.Math.Distance.Between(x, y, holeX, holeY) < holeRadius) {
continue;
}
// Randomizacija - samo divja trava
let key = Math.random() > 0.5 ? 'grass_wild' : 'grass_wild_v2';
// Ustvari travo in jo dodaj v grupo
let grass = this.grassGroup.create(x, y, key);
// POMEMBNO: Origin spodaj na sredini, da raste iz tal!
grass.setOrigin(0.5, 1.0);
// Shranimo targetScale v objekt, da ga uporabimo v tweenu
grass.targetScale = 0.5 + Math.random() * 0.5;
// Začetno stanje: skrita
grass.setScale(0);
grass.setAngle(Math.random() * 20 - 10);
grass.setAlpha(0.8 + Math.random() * 0.2);
grass.setDepth(y); // Y-sort
// Physics body (circle for better feel)
if (grass.body) {
grass.body.setCircle(grass.width / 4);
grass.body.setOffset(grass.width / 4, grass.height / 2); // Adjusted for bottom origin
}
}
// --- TREE PLANTATION (Initial Phase) ---
const TREE_COUNT = 50;
for (let i = 0; i < TREE_COUNT; i++) {
let x = (WORLD_W / 2) + (Math.random() * SPREAD * 2 - SPREAD);
let y = (WORLD_H / 2) + (Math.random() * SPREAD * 2 - SPREAD);
// Avoid Pond
if (Phaser.Math.Distance.Between(x, y, pondX, pondY) < pondRadius) continue;
// Avoid Hole
if (Phaser.Math.Distance.Between(x, y, holeX, holeY) < holeRadius + 50) continue;
let tree = this.physics.add.image(x, y, 'drevo_faza_1');
tree.setOrigin(0.5, 0.95); // Base of trunk
tree.setDepth(y);
tree.setScale(0.8 + Math.random() * 0.4);
tree.body.setImmovable(true);
tree.body.setSize(40, 30);
tree.body.setOffset(tree.width/2 - 20, tree.height - 40);
}
// --- INTRO LISTENER ---
// Klik na podlago sproži rast trave in čiščenje amnezije
this.input.on('pointerdown', () => {
if (!this.introStarted) {
this.introStarted = true;
this.startIntroSequence();
}
});
// --- 4. ITEMS & OBSTACLES ---
// REMOVED PER USER REQUEST
/*
// Trnje (Thorns) - Draggable
this.trnje = this.add.image(startX - 200, startY + 100, 'trnje');
this.trnje.setScale(0.5); // Adjust scale if needed
this.trnje.setInteractive({ draggable: true });
// Trigger Amnesia Clear on interaction
this.trnje.on('pointerdown', () => {
this.clearAmnesia();
});
// --- NEW: RAIN CATCHER ---
this.rainCatcher = this.physics.add.image(startX + 150, startY + 50, 'rain_catcher');
this.rainCatcher.setScale(0.8);
this.rainCatcher.setInteractive({ draggable: true });
this.rainCatcher.setDepth(startY + 50); // Y-sort
this.rainCatcher.body.setImmovable(true);
// Collider added later with Kai
*/
// General Drag Event
// General Drag Event
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
});
// --- EDITOR MODE SYSTEM (REMOVED) ---
/*
this.editorEnabled = true; // Enabled by default per user request
this.selectedTile = 'path_tile_0';
this.editorGroup = this.add.group(); // Saved tiles
// Initialize Default State
this.selectedTile = 'path_tile_0';
// this.editorEnabled = false; // Duplicate init removed
// UI Palette (Hidden by default)
// FIX: Use viewport dimensions for UI
const VIEW_W = this.scale.width;
const VIEW_H = this.scale.height;
// --- EDITOR UI SETUP (Clean Sidebar) ---
const SIDEBAR_W = 320;
const PALETTE_X = VIEW_W - SIDEBAR_W;
// UI Container Group (for toggling visibility)
this.editorUI = this.add.group();
// 1. Sidebar Background (Clean Glass Look)
let sidebarBg = this.add.rectangle(PALETTE_X + SIDEBAR_W / 2, VIEW_H / 2, SIDEBAR_W, VIEW_H, 0x222222, 0.95)
.setScrollFactor(0).setDepth(2000).setStrokeStyle(2, 0x444444);
this.editorUI.add(sidebarBg);
// Title
let sidebarTitle = this.add.text(PALETTE_X + 20, 20, "TILES PALETTE", {
fontSize: '24px', fontFamily: 'Arial', color: '#ffffff', fontStyle: 'bold'
}).setScrollFactor(0).setDepth(2002);
this.editorUI.add(sidebarTitle);
// 2. Layer Switcher (Tabs)
this.currentLayer = 'ground';
const layerBtns = [];
const tabsY = 60;
const createLayerBtn = (label, mode, index) => {
let x = PALETTE_X + 20 + (index * 90);
let btnBg = this.add.rectangle(x + 40, tabsY + 15, 80, 30, 0x333333).setScrollFactor(0).setDepth(2002).setInteractive({ useHandCursor: true });
let txt = this.add.text(x + 10, tabsY + 5, label, { fontSize: '14px', color: '#888', fontStyle: 'bold' })
.setScrollFactor(0).setDepth(2003);
// Hit area on bg
btnBg.on('pointerdown', () => {
this.currentLayer = mode;
layerBtns.forEach(b => {
b.txt.setColor('#888');
b.bg.setFillStyle(0x333333);
});
txt.setColor('#ffffff');
btnBg.setFillStyle(0x0077ff);
});
this.editorUI.add(btnBg);
this.editorUI.add(txt);
return { txt, bg: btnBg };
};
layerBtns.push(createLayerBtn("Ground", 'ground', 0));
layerBtns.push(createLayerBtn("Deco", 'deco', 1));
layerBtns.push(createLayerBtn("Build", 'building', 2));
// Select first default
layerBtns[0].txt.setColor('#ffffff');
layerBtns[0].bg.setFillStyle(0x0077ff);
// 3. Palette Content (Scrollable)
const contentY = 120; // Below tabs
const itemContainer = this.add.container(PALETTE_X, contentY).setScrollFactor(0).setDepth(2001);
// Mask for scrolling
const maskShape = this.make.graphics();
maskShape.fillStyle(0xffffff);
maskShape.fillRect(PALETTE_X, contentY, SIDEBAR_W, VIEW_H - contentY);
const mask = maskShape.createGeometryMask();
itemContainer.setMask(mask);
// Prepare Palette Items
const paletteItems = [];
for (let i = 0; i < 16; i++) paletteItems.push(`path_tile_${i}`);
for (let i = 0; i < 16; i++) paletteItems.push(`water_tile_${i}`);
for (let i = 0; i <= 2; i++) paletteItems.push(`fence_sign_${i}`);
paletteItems.push('sign_danger');
for (let i = 0; i <= 5; i++) paletteItems.push(`tree_adult_${i}`);
for (let i = 0; i <= 8; i++) paletteItems.push(`dead_nature_${i}`);
['bush_hiding_spot', 'drevo_faza_1', 'drevo_faza_2', 'drevo_srednje', 'drevo_veliko', 'grass_cluster_dense', 'grass_cluster_flowery', 'trava_sop'].forEach(k => paletteItems.push(k));
paletteItems.push('sotor', 'campfire', 'eraser_icon');
// Grid Layout
let col = 0, row = 0;
const CELL_SZ = 90;
// Selector Highlight (Clean Blue Border)
let selector = this.add.rectangle(0, 0, 80, 80).setStrokeStyle(4, 0x00aaff).setVisible(false);
itemContainer.add(selector);
paletteItems.forEach((key) => {
let ix = 50 + (col * CELL_SZ);
let iy = 50 + (row * CELL_SZ);
let icon = this.add.image(ix, iy, key).setScale(0.3).setInteractive({ useHandCursor: true });
itemContainer.add(icon);
icon.on('pointerdown', () => {
this.selectedTile = key;
selector.setPosition(ix, iy).setVisible(true);
// Update Ghost
if (key === 'eraser_icon') {
this.ghostSprite.setVisible(false);
} else {
this.ghostSprite.setTexture(key);
this.ghostSprite.setScale(key.includes('path') || key.includes('water') ? 0.5 : 1.0); // Simple scaling logic
}
});
col++;
if (col >= 3) { col = 0; row++; }
});
// Scroll Logic
let scrollY = 0;
const MAX_SCROLL = Math.max(0, (row * CELL_SZ) + 150 - (VIEW_H - contentY));
this.input.on('wheel', (ptr, gameObjs, dx, dy, dz) => {
if (this.editorEnabled && ptr.x > PALETTE_X) {
scrollY -= dy;
if (scrollY > 0) scrollY = 0;
if (scrollY < -MAX_SCROLL) scrollY = -MAX_SCROLL;
itemContainer.y = contentY + scrollY;
}
});
// 4. Ghost Cursor
this.ghostSprite = this.add.image(0, 0, this.selectedTile)
.setAlpha(0.6).setDepth(3000).setVisible(false); // Topmost
// Toggle Visibility Helpers
const toggleEditor = (state) => {
this.editorEnabled = state;
this.editorUI.setVisible(state);
itemContainer.setVisible(state);
this.ghostSprite.setVisible(state && this.selectedTile !== 'eraser_icon');
console.log("Editor:", state);
};
toggleEditor(false); // Start hidden per user request
// Toggle Key
this.input.keyboard.on('keydown-E', () => {
toggleEditor(!this.editorEnabled);
});
this.input.on('pointermove', (pointer) => {
if (!this.editorEnabled) return;
// Hide Ghost if over UI
if (pointer.x > PALETTE_X) {
this.ghostSprite.setVisible(false);
return;
} else if (this.selectedTile !== 'eraser_icon') {
this.ghostSprite.setVisible(true);
}
// Snap calculation
const SNAP = 128;
const sx = Math.floor(pointer.worldX / SNAP) * SNAP + (SNAP / 2);
const sy = Math.floor(pointer.worldY / SNAP) * SNAP + (SNAP / 2);
this.ghostSprite.setPosition(sx, sy);
});
// Painting Logic
this.input.on('pointerdown', (pointer) => {
if (!this.editorEnabled) return;
// Ignore UI clicks
if (pointer.x > PALETTE_X) return;
// ERASER
if (this.selectedTile === 'eraser_icon') return; // Handled by object click
// Snap
const SNAP = 128;
const sx = Math.floor(pointer.worldX / SNAP) * SNAP + (SNAP / 2);
const sy = Math.floor(pointer.worldY / SNAP) * SNAP + (SNAP / 2);
// Remove existing tile at this spot to avoid stacking
let existing = this.editorGroup.getChildren().find(c => Math.abs(c.x - sx) < 10 && Math.abs(c.y - sy) < 10);
if (existing) existing.destroy();
let placedStub = this.add.image(sx, sy, this.selectedTile);
placedStub.setInteractive();
placedStub.on('pointerdown', () => {
if (this.editorEnabled && this.selectedTile === 'eraser_icon') {
const isWater = placedStub.texture.key.startsWith('water_tile_');
placedStub.destroy();
// If we deleted water, update neighbors
if (isWater) {
const neighbors = [
{ dx: 0, dy: -SNAP }, { dx: SNAP, dy: 0 }, { dx: 0, dy: SNAP }, { dx: -SNAP, dy: 0 }
];
neighbors.forEach(n => this.updateAutotile(sx + n.dx, sy + n.dy));
}
}
});
// Layer Logic
if (this.currentLayer === 'ground') {
placedStub.setDepth(-40);
placedStub.setScale(0.5); // Grid tiles
} else {
placedStub.setDepth(sy); // Y-sort
}
this.editorGroup.add(placedStub);
// AUTO-TILE UPDATE
if (this.selectedTile.startsWith('water_tile_')) {
this.updateAutotile(sx, sy);
}
});
*/
// --- PREVIOUSLY GENERATED PROPS (Draggable Example) ---
// Commented out per request "samo blatno potko"
/*
const propAssets = ['tree_adult_0', 'tree_adult_1', 'dead_nature_0'];
for (let i = 0; i < propAssets.length; i++) {
let item = this.add.image(startX + 200 + (i * 100), startY + 200, propAssets[i]);
item.setInteractive({ draggable: true });
}
*/
// --- RECONSTRUCT PATH (4x4 GRID) ---
// REMOVED PER USER REQUEST "samo blatno potko"
/*
// Image was 1024x1024, sliced into 256x256 (4 cols, 4 rows)
// Indices 0..15
let pIndex = 0;
const GRID_SZ = 256;
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
// Determine Tile Key
let key = `path_tile_${pIndex}`;
// Place it
// Center offset: -1.5 * size to center the 4x4 block
let px = startX + (c * GRID_SZ) + 200;
let py = startY + (r * GRID_SZ) + 200;
let tile = this.add.image(px, py, key);
tile.setDepth(-40); // Ground level
// Optional: make draggable? User said "naredi", maybe fixed?
// tile.setInteractive({ draggable: true });
pIndex++;
}
}
*/
// --- 5. CHAR (Kai) ---
this.kai = this.physics.add.sprite(WORLD_W / 2, WORLD_H / 2, 'kai');
// Povečava na polno velikost (256px)
this.kai.setScale(1);
this.kai.setCollideWorldBounds(true);
this.kai.setOrigin(0.5, 0.9);
// Adjust Physics Body for larger size
// Width ~40, Height ~30 (relative to scaled sprite)
this.kai.body.setSize(50, 40);
this.kai.body.setOffset(256 / 2 - 25, 256 - 40); // Pivot offset based on 256 frame
// Collider Stream <-> Kai
// this.physics.add.collider(this.kai, this.stream);
// --- NEW: GRONK (NPC) ---
// REMOVED PER USER REQUEST
/*
this.gronk = this.physics.add.sprite(startX - 150, startY - 100, 'gronk');
this.gronk.setScale(0.8); // Gronk is big!
this.gronk.setDepth(startY - 100);
this.gronk.setImmovable(true);
this.gronk.body.setSize(80, 60);
this.gronk.body.setOffset(88, 190); // Adjusted for 256x256 frame
// Gronk Animations
this.anims.create({
key: 'gronk-idle',
frames: this.anims.generateFrameNumbers('gronk', { start: 0, end: 3 }), // Using Down walk as idle for now
frameRate: 4,
repeat: -1
});
this.gronk.play('gronk-idle');
// Interaction (Say Hello)
this.gronk.setInteractive();
this.gronk.on('pointerdown', () => {
console.log("Gronk: 'Ej stari, kje si hodil? Si pozabil, da imava vajo s bendom?'");
// Future: Show Dialog Box
});
*/
// Colliders
// this.physics.add.collider(this.kai, this.rainCatcher);
// this.physics.add.collider(this.kai, this.gronk);
// --- ANIMATIONS ---
// 0-3: Down, 4-7: Left, 8-11: Right, 12-15: Up
this.anims.create({
key: 'walk-down',
frames: this.anims.generateFrameNumbers('kai', { start: 0, end: 3 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: 'walk-left',
frames: this.anims.generateFrameNumbers('kai', { start: 4, end: 7 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: 'walk-right',
frames: this.anims.generateFrameNumbers('kai', { start: 8, end: 11 }),
frameRate: 8,
repeat: -1
});
this.anims.create({
key: 'walk-up',
frames: this.anims.generateFrameNumbers('kai', { start: 12, end: 15 }),
frameRate: 8,
repeat: -1
});
// Idle
this.kai.play('walk-down');
this.kai.stop();
// Camera setup logic
this.cameras.main.startFollow(this.kai, true, 0.1, 0.1);
this.cursors = this.input.keyboard.createCursorKeys();
// Add WASD keys
this.keys = this.input.keyboard.addKeys({
up: Phaser.Input.Keyboard.KeyCodes.W,
down: Phaser.Input.Keyboard.KeyCodes.S,
left: Phaser.Input.Keyboard.KeyCodes.A,
right: Phaser.Input.Keyboard.KeyCodes.D
});
// Collider added later after Kai creation
// Collider added later after Kai creation
// --- 3. FOLIAGE (Trava - Šopi) ---
// Removed as requested
// --- 4. ITEMS (Seno) ---
// Removed as requested
// 3. COLLIDERS
// Cellar Trigger
if (this.hole) {
this.physics.add.overlap(this.kai, this.hole, (player, hole) => {
// Trigger logic (e.g., console log or event)
// console.log("Standing on cellar entrance");
});
}
if (this.stream) this.physics.add.collider(this.kai, this.stream);
// Collider with riverCollider (invisible zone) instead of rotated sprite
if (this.riverCollider) this.physics.add.collider(this.kai, this.riverCollider);
// this.physics.add.collider(this.kai, this.obstaclesGroup);
// --- ANIMATIONS ---
// 0-3: Down, 4-7: Left, 8-11: Right, 12-15: Up
// This is a duplicate animation creation block, removing it.
// this.anims.create({
// key: 'walk-down',
// frames: this.anims.generateFrameNumbers('kai', { start: 0, end: 3 }),
// frameRate: 8,
// repeat: -1
// });
// this.anims.create({
// key: 'walk-left',
// frames: this.anims.generateFrameNumbers('kai', { start: 4, end: 7 }),
// frameRate: 8,
// repeat: -1
// });
// this.anims.create({
// key: 'walk-right',
// frames: this.anims.generateFrameNumbers('kai', { start: 8, end: 11 }),
// frameRate: 8,
// repeat: -1
// });
// this.anims.create({
// key: 'walk-up',
// frames: this.anims.generateFrameNumbers('kai', { start: 12, end: 15 }),
// frameRate: 8,
// repeat: -1
// });
// Launch UI Scene
if (!this.scene.get('UIScene').scene.settings.active) {
this.scene.launch('UIScene');
}
// --- AMNESIA INIT ---
// 1. PostFX Blur (Keep it for extra effect)
this.amnesiaBlur = this.cameras.main.postFX.addBlur(0, 2, 2, 1);
// 2. Overlay Texture (Megla Pozabe)
/*
this.amnesiaOverlay = this.add.image(WORLD_W / 2, WORLD_H / 2, 'amnesia_fog');
this.amnesiaOverlay.setScrollFactor(0); // Stuck to camera
this.amnesiaOverlay.setDepth(6000); // Topmost
this.amnesiaOverlay.setAlpha(0.8);
this.amnesiaOverlay.setScale(Math.max(VIEW_W / this.amnesiaOverlay.width, VIEW_H / this.amnesiaOverlay.height)); // Cover screen
*/
// --- TOXIC FOG (Visuals) ---
// Layer 1: Pinkish (The "Toxic" Part)
/*
this.fog1 = this.add.tileSprite(0, 0, WORLD_W, WORLD_H, 'toxic_fog');
this.fog1.setOrigin(0, 0);
this.fog1.setAlpha(0.3);
this.fog1.setDepth(5000);
this.fog1.setBlendMode(Phaser.BlendModes.SCREEN); // Screen for glowing effect
this.fog1.setTint(0xff00cc); // PINK
*/
// Layer 2: Greenish (The "Radiation" Part)
/*
this.fog2 = this.add.tileSprite(0, 0, WORLD_W, WORLD_H, 'toxic_fog');
this.fog2.setOrigin(0, 0);
this.fog2.setAlpha(0.2);
this.fog2.setDepth(5001);
this.fog2.setScale(1.5);
this.fog2.setBlendMode(Phaser.BlendModes.SCREEN);
this.fog2.setTint(0x00ff00); // GREEN
*/
}
// --- INTRO SEQUENCE ---
startIntroSequence() {
console.log("Starting Intro Sequence: Grass Growth + Amnesia Clear");
// 1. Grass Growth Animation
this.grassGroup.getChildren().forEach((grass, index) => {
this.tweens.add({
targets: grass,
scaleX: grass.targetScale, // Use stored target scale
scaleY: grass.targetScale,
duration: 800 + Math.random() * 800,
delay: Math.random() * 1500, // Staggered start
ease: 'Back.out',
});
});
// 2. Clear Amnesia (Blur Fade)
this.clearAmnesia();
}
// --- AMNESIA SYSTEM ---
clearAmnesia() {
if (this.amnesiaBlur) {
this.tweens.add({
targets: [this.amnesiaBlur, this.amnesiaOverlay], // Fade both
strength: 0, // For blur
alpha: 0, // For overlay
duration: 2000,
onComplete: () => {
this.cameras.main.postFX.remove(this.amnesiaBlur);
this.amnesiaBlur = null;
if (this.amnesiaOverlay) this.amnesiaOverlay.destroy();
}
});
}
}
// --- AUTO-TILING SYSTEM (REMOVED) ---
/* Removed for cleanup */
update(time, delta) {
// --- PARALLAX & SCROLLING ---
// 1. Ground Infinite Scroll
if (this.ground) {
this.ground.tilePositionX = this.cameras.main.scrollX;
this.ground.tilePositionY = this.cameras.main.scrollY;
}
// 2. River Flow Animation (REMOVED)
/* Removed for cleanup */
// --- PLAYER MOVEMENT ---
const speed = 250;
this.kai.setVelocity(0);
let moving = false;
// Input helpers
const left = this.cursors.left.isDown || this.keys.left.isDown;
const right = this.cursors.right.isDown || this.keys.right.isDown;
const up = this.cursors.up.isDown || this.keys.up.isDown;
const down = this.cursors.down.isDown || this.keys.down.isDown;
const space = this.cursors.space.isDown;
// --- GRASS PLUCKING MECHANIC (Trganje trave) ---
if (space) {
this.physics.overlap(this.kai, this.grassGroup, (player, grass) => {
// 1. Uniči travo
grass.destroy();
// 2. Dodaj v inventar
this.inventory.grass++;
this.inventoryText.setText('Trava: ' + this.inventory.grass);
});
}
if (left) {
this.kai.setVelocityX(-speed);
this.kai.play('walk-left', true);
moving = true;
} else if (right) {
this.kai.setVelocityX(speed);
this.kai.play('walk-right', true);
moving = true;
}
if (up) {
this.kai.setVelocityY(-speed);
if (!left && !right) {
this.kai.play('walk-up', true);
}
moving = true;
} else if (down) {
this.kai.setVelocityY(speed);
if (!left && !right) {
this.kai.play('walk-down', true);
}
moving = true;
}
if (this.kai.body.velocity.length() > 0) {
this.kai.body.velocity.normalize().scale(speed);
} else {
this.kai.stop();
// Optional: reset to idle frame?
}
// --- Z-SORTING SYSTEM ---
// Player
this.kai.setDepth(this.kai.y);
}
}