From 6680df14f81c93eb3a23d86593bf75aecaf42aa9 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Wed, 30 Jul 2025 19:48:25 -0600 Subject: [PATCH] Refactor game state management with GlobalState class; implement score display via Interface; adjust enemy points (100 for boss, 10 for regular); add heart upgrade item in Gulch --- raw/Tile-Project-Legends.tiled-session | 4 +-- src/characters/99boy.js | 6 ++-- src/characters/player.js | 8 ++---- src/globalState.js | 40 +++++++++++++++++++++++++- src/interface.js | 16 +++++++++++ src/main.js | 15 ++++++---- src/scenes/NNDungeon.js | 5 ++++ src/scenes/gulch.js | 24 ++++++++++++++-- 8 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 src/interface.js diff --git a/raw/Tile-Project-Legends.tiled-session b/raw/Tile-Project-Legends.tiled-session index 6bc8007..e4dc453 100644 --- a/raw/Tile-Project-Legends.tiled-session +++ b/raw/Tile-Project-Legends.tiled-session @@ -21,8 +21,8 @@ "scale": 0.5, "selectedLayer": 1, "viewCenter": { - "x": 2369, - "y": 1644 + "x": 3252, + "y": 2399 } }, "NNDungeon.tmx#99boy-tiles": { diff --git a/src/characters/99boy.js b/src/characters/99boy.js index 4a93d92..e37428b 100644 --- a/src/characters/99boy.js +++ b/src/characters/99boy.js @@ -115,9 +115,10 @@ export class NNBoy extends Phaser.GameObjects.Sprite { }); if (this.health === 1) { - if (this.boss === true) { //BOSS DEFEAT + this.scene.game.globalState.addScore(100); + this.scene.interface.showScore(); this.shoots = false; this.garbage = false; this.onPatrol = false; @@ -155,7 +156,8 @@ export class NNBoy extends Phaser.GameObjects.Sprite { } }); } else { - this.scene.game.playerData.score += 1; + this.scene.game.globalState.addScore(10); + this.scene.interface.showScore(); //REGULAR ENEMY DEFEAT let dropHeart = Math.floor(Math.random() * this.dropHeartOneIn); if (dropHeart === 1) { diff --git a/src/characters/player.js b/src/characters/player.js index bbda2f5..817df2f 100644 --- a/src/characters/player.js +++ b/src/characters/player.js @@ -12,8 +12,8 @@ export class Player extends Phaser.GameObjects.Sprite { this.showHealth = false; this.healthText; this.healthImages; - this.numHearts = 3; - this.maxHearts = scene.game.playerData.maxHearts; + this.numHearts = scene.game.globalState.hearts; + this.maxHearts = scene.game.globalState.maxHearts; this.normalVelocityX = 260; this.inventory = []; this.facing = 'south'; @@ -217,9 +217,7 @@ export class Player extends Phaser.GameObjects.Sprite { .setShadow(3,3, '#333', 5) .setScrollFactor(0); this.updateHealth(); - this.livesText = this.scene.add.text(16, 64, 'Score: '+this.scene.game.playerData.score, { fontSize: '36px', fill: '#FFF' }) - .setShadow(3,3, '#333', 5) - .setScrollFactor(0); + } } diff --git a/src/globalState.js b/src/globalState.js index 906eb63..0720b49 100644 --- a/src/globalState.js +++ b/src/globalState.js @@ -5,7 +5,9 @@ export class GlobalState { maxHearts: 3, score: 0, inventory: [], - upgrades: [] + upgrades: [], + startGulchX: 950, + startGulchY: 4250, }; } @@ -45,6 +47,20 @@ export class GlobalState { this.playerData.inventory = value; } + // Add item(s) to inventory (handles positive counts only) + addToInventory(itemName, count = 1) { + if (count < 0) throw new Error("Cannot add negative count to inventory"); + if (count === 0) return; + + // Create new array with existing items + added items + this.inventory = [...this.inventory, ...Array(count).fill(itemName)]; + } + + // Return count of item in inventory (including 0 for missing items) + hasInventory(itemName) { + return this.inventory.filter(item => item === itemName).length; + } + get upgrades() { return [...this.playerData.upgrades]; // Return a copy } @@ -53,4 +69,26 @@ export class GlobalState { if (!Array.isArray(value)) throw new Error("Upgrades must be an array"); this.playerData.upgrades = value; } + + get startGulchX() { + return this.playerData.startGulchX; + } + + set startGulchX(value) { + this.playerData.startGulchX = value; + } + + get startGulchY() { + return this.playerData.startGulchY; + } + + set startGulchY(value) { + this.playerData.startGulchY = value; + } + + // Add safe score increment method (replaces manual score updates) + addScore(amount) { + if (amount < 0) throw new Error("Cannot add negative score"); + this.score += amount; + } } \ No newline at end of file diff --git a/src/interface.js b/src/interface.js new file mode 100644 index 0000000..a2fce79 --- /dev/null +++ b/src/interface.js @@ -0,0 +1,16 @@ +export class Interface { + constructor(scene) { + this.scene = scene; + } + + showScore() { + if (this.scoreText) { + this.scoreText.destroy(); + } + // Add Score + this.scoreText = this.scene.add.text(16, 64, 'Score: '+this.scene.game.globalState.score, { fontSize: '36px', fill: '#FFF' }) + .setShadow(3,3, '#333', 5) + .setScrollFactor(0); + } + +} \ No newline at end of file diff --git a/src/main.js b/src/main.js index 4f62dce..1a703e9 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,7 @@ import { MenuScene } from './scenes/MenuScene.js'; import { Gulch } from './scenes/gulch.js'; import { NNDungeon } from './scenes/NNDungeon.js'; +import { GlobalState } from './globalState.js'; const config = { type: Phaser.AUTO, @@ -26,9 +27,11 @@ const config = { const game = new Phaser.Game(config); -game.playerData = { - score: 0, - maxHearts: 3, - startGulchX: 950, - startGulchY: 4250, -} \ No newline at end of file +game.globalState = new GlobalState(); + +// game.playerData = { +// score: 0, +// maxHearts: 3, +// startGulchX: 950, +// startGulchY: 4250, +// } \ No newline at end of file diff --git a/src/scenes/NNDungeon.js b/src/scenes/NNDungeon.js index 6e9bcc2..31cd363 100644 --- a/src/scenes/NNDungeon.js +++ b/src/scenes/NNDungeon.js @@ -1,6 +1,7 @@ import { Player } from '../characters/player.js'; import { Camera } from '../misc/cameras.js'; import { NNBoy } from '../characters/99boy.js'; +import { Interface } from '../interface.js'; export class NNDungeon extends Phaser.Scene { @@ -61,6 +62,10 @@ export class NNDungeon extends Phaser.Scene { const interactiveLayer = NNDungeonMap.getObjectLayer('interactive'); //const zoneLayer = gulchMap.getObjectLayer('zone'); + // Show Score + this.interface = new Interface(this); + this.interface.showScore(); + // Add a player this.player = new Player(this, 2400, 3450); //this.player = new Player(this, 3550, 350); diff --git a/src/scenes/gulch.js b/src/scenes/gulch.js index 62a2e94..8398f4d 100644 --- a/src/scenes/gulch.js +++ b/src/scenes/gulch.js @@ -1,6 +1,7 @@ import { Player } from '../characters/player.js'; import { Camera } from '../misc/cameras.js'; import { NNBoy } from '../characters/99boy.js'; +import { Interface } from '../interface.js'; export class Gulch extends Phaser.Scene { @@ -19,7 +20,8 @@ export class Gulch extends Phaser.Scene { preload() { this.load.image('gulch-tiles', 'assets/gulch-tiles.png'); this.load.image('heart-full', 'assets/heart-full.png'); - this.load.image('heart-empty', 'assets/heart-empty.png'); + this.load.image('heart-empty', 'assets/heart-empty.png'); + this.load.image('heart-upgrade', 'assets/heart-upgrade.png'); this.load.tilemapTiledJSON('gulchMap', 'assets/gulch.json'); this.load.spritesheet('player-tiles', 'assets/player-tiles.png', { frameWidth: 100, @@ -52,8 +54,12 @@ export class Gulch extends Phaser.Scene { const enemiesLayer = gulchMap.getObjectLayer('enemies'); const zoneLayer = gulchMap.getObjectLayer('zone'); + // Show Score + this.interface = new Interface(this); + this.interface.showScore(); + // Add a player - this.player = new Player(this, this.game.playerData.startGulchX, this.game.playerData.startGulchY); + this.player = new Player(this, this.game.globalState.startGulchX, this.game.globalState.startGulchY); this.player.healthBars(true, 1, 3); zoneLayer.objects.forEach(object => { @@ -150,6 +156,20 @@ export class Gulch extends Phaser.Scene { heart.destroy(); }); + // Add level heart upgrade + if (this.game.globalState.hasInventory('gulch-heart') === 0) { + this.upgrade = this.physics.add.image(5200, 5800, 'heart-upgrade').setScale(0.2); + this.physics.add.collider(this.player, this.upgrade, (player, upgrade) => { + this.game.globalState.addToInventory('gulch-heart', 1); + this.player.maxHearts ++; + this.player.numHearts ++; + this.game.globalState.maxHearts = this.player.maxHearts; + this.game.globalState.hearts = this.player.numHearts; + this.player.updateHealth(); + upgrade.destroy(); + }); + } + //this.cameras.main.setScroll(800, 1100); this.cameras.main.setBounds(0, 3600, 1600, 900);