Skip to content

Commit

Permalink
Merge branch 'main' into GH-76
Browse files Browse the repository at this point in the history
  • Loading branch information
scottwestover committed Jan 23, 2024
2 parents 1bf0f44 + 9d06947 commit 0a338ec
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 29 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"IGUANIGNITE",
"Kenney",
"kenneys",
"MONSTERDEX",
"nineslice",
"npcs",
"parabellum",
Expand Down
6 changes: 3 additions & 3 deletions project-task-track.todo
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ Tools Part 1:
✔ util function for moving game objects @done(24-01-06 12:10)

Saving & Loading:
add game menu with option to save game
update menu scene with continue option to load game
on new game, we should reset the player data (pos, monsters, etc)
add game menu with option to save game @done(24-01-22 08:31)
update menu scene with continue option to load game @done(24-01-22 08:31)
on new game, we should reset the player data (pos, monsters, etc) @done(24-01-22 08:51)

Monster Party & Monster Detail Scenes:
☐ create monster party scene
Expand Down
13 changes: 3 additions & 10 deletions src/scenes/battle-scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export class BattleScene extends Phaser.Scene {
this.#activeEnemyMonster = new EnemyBattleMonster({
scene: this,
monsterDetails: {
id: 2,
monsterId: 2,
name: MONSTER_ASSET_KEYS.CARNODUSK,
assetKey: MONSTER_ASSET_KEYS.CARNODUSK,
assetFrame: 0,
Expand All @@ -83,16 +85,7 @@ export class BattleScene extends Phaser.Scene {
});
this.#activePlayerMonster = new PlayerBattleMonster({
scene: this,
monsterDetails: {
name: MONSTER_ASSET_KEYS.IGUANIGNITE,
assetKey: MONSTER_ASSET_KEYS.IGUANIGNITE,
assetFrame: 0,
currentHp: 25,
maxHp: 25,
attackIds: [2],
baseAttack: 15,
currentLevel: 5,
},
monsterDetails: dataManager.store.get(DATA_MANAGER_STORE_KEYS.MONSTERS_IN_PARTY)[0],
skipBattleAnimations: this.#skipAnimations,
});

Expand Down
18 changes: 7 additions & 11 deletions src/scenes/title-scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Controls } from '../utils/controls.js';
import { DIRECTION } from '../common/direction.js';
import { exhaustiveGuard } from '../utils/guard.js';
import { NineSlice } from '../utils/nine-slice.js';
import { DATA_MANAGER_STORE_KEYS, dataManager } from '../utils/data-manager.js';

/** @type {Phaser.Types.GameObjects.Text.TextStyle} */
const MENU_TEXT_STYLE = Object.freeze({
Expand Down Expand Up @@ -62,7 +63,7 @@ export class TitleScene extends Phaser.Scene {
console.log(`[${TitleScene.name}:create] invoked`);

this.#selectedMenuOption = MAIN_MENU_OPTIONS.NEW_GAME;
this.#isContinueButtonEnabled = false;
this.#isContinueButtonEnabled = dataManager.store.get(DATA_MANAGER_STORE_KEYS.GAME_STARTED) || false;

// create title scene background
this.add.image(0, 0, TITLE_ASSET_KEYS.BACKGROUND).setOrigin(0).setScale(0.58);
Expand Down Expand Up @@ -112,21 +113,16 @@ export class TitleScene extends Phaser.Scene {

// add in fade effects
this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
if (this.#selectedMenuOption === MAIN_MENU_OPTIONS.NEW_GAME) {
// TODO: enhance with logic to reset game once we implement saving/loading data
this.scene.start(SCENE_KEYS.WORLD_SCENE);
if (this.#selectedMenuOption === MAIN_MENU_OPTIONS.OPTIONS) {
this.scene.start(SCENE_KEYS.OPTIONS_SCENE);
return;
}

if (this.#selectedMenuOption === MAIN_MENU_OPTIONS.CONTINUE) {
this.scene.start(SCENE_KEYS.WORLD_SCENE);
return;
if (this.#selectedMenuOption === MAIN_MENU_OPTIONS.NEW_GAME) {
dataManager.startNewGame();
}

if (this.#selectedMenuOption === MAIN_MENU_OPTIONS.OPTIONS) {
this.scene.start(SCENE_KEYS.OPTIONS_SCENE);
return;
}
this.scene.start(SCENE_KEYS.WORLD_SCENE);
});

this.#controls = new Controls(this);
Expand Down
56 changes: 51 additions & 5 deletions src/scenes/world-scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getTargetPositionFromGameObjectPositionAndDirection } from '../utils/gr
import { CANNOT_READ_SIGN_TEXT, SAMPLE_TEXT } from '../utils/text-utils.js';
import { DialogUi } from '../world/dialog-ui.js';
import { NPC } from '../world/characters/npc.js';
import { Menu } from '../world/menu/menu.js';

/**
* @typedef TiledObjectProperty
Expand Down Expand Up @@ -57,6 +58,8 @@ export class WorldScene extends Phaser.Scene {
#npcs;
/** @type {NPC | undefined} */
#npcPlayerIsInteractingWith;
/** @type {Menu} */
#menu;

constructor() {
super({
Expand Down Expand Up @@ -159,7 +162,11 @@ export class WorldScene extends Phaser.Scene {
// create dialog ui
this.#dialogUi = new DialogUi(this, 1280);

// create menu
this.#menu = new Menu(this);

this.cameras.main.fadeIn(1000, 0, 0, 0);
dataManager.store.set(DATA_MANAGER_STORE_KEYS.GAME_STARTED, true);
}

/**
Expand All @@ -172,15 +179,54 @@ export class WorldScene extends Phaser.Scene {
return;
}

const selectedDirection = this.#controls.getDirectionKeyPressedDown();
if (selectedDirection !== DIRECTION.NONE && !this.#isPlayerInputLocked()) {
this.#player.moveCharacter(selectedDirection);
const wasSpaceKeyPressed = this.#controls.wasSpaceKeyPressed();
const selectedDirectionHeldDown = this.#controls.getDirectionKeyPressedDown();
const selectedDirectionPressedOnce = this.#controls.getDirectionKeyJustPressed();
if (selectedDirectionHeldDown !== DIRECTION.NONE && !this.#isPlayerInputLocked()) {
this.#player.moveCharacter(selectedDirectionHeldDown);
}

if (this.#controls.wasSpaceKeyPressed() && !this.#player.isMoving) {
if (wasSpaceKeyPressed && !this.#player.isMoving && !this.#menu.isVisible) {
this.#handlePlayerInteraction();
}

if (this.#controls.wasEnterKeyPressed() && !this.#player.isMoving) {
if (this.#dialogUi.isVisible) {
return;
}

if (this.#menu.isVisible) {
this.#menu.hide();
return;
}

this.#menu.show();
}

if (this.#menu.isVisible) {
if (selectedDirectionPressedOnce !== DIRECTION.NONE) {
this.#menu.handlePlayerInput(selectedDirectionPressedOnce);
}

if (wasSpaceKeyPressed) {
this.#menu.handlePlayerInput('OK');

if (this.#menu.selectedMenuOption === 'SAVE') {
this.#menu.hide();
dataManager.saveData();
this.#dialogUi.showDialogModal(['Game progress has been saved']);
} else if (this.#menu.selectedMenuOption === 'EXIT') {
this.#menu.hide();
}

// TODO: handle other selected menu options
}

if (this.#controls.wasBackKeyPressed()) {
this.#menu.hide();
}
}

this.#player.update(time);

this.#npcs.forEach((npc) => {
Expand Down Expand Up @@ -281,7 +327,7 @@ export class WorldScene extends Phaser.Scene {
}

#isPlayerInputLocked() {
return this.#dialogUi.isVisible;
return this.#controls.isInputLocked || this.#dialogUi.isVisible || this.#menu.isVisible;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/types/typedef.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Phaser from '../lib/phaser.js';
/**
* @typedef Monster
* @type {object}
* @property {number} id the unique identifier for this monster
* @property {number} monsterId the unique identifier for this monster type
* @property {string} name the name of the monster
* @property {string} assetKey the name of the asset key that should be used for this monster
* @property {number} [assetFrame=0] if the asset key is tied to a spritesheet, this frame will be used, defaults to 0
Expand Down
11 changes: 11 additions & 0 deletions src/utils/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ export class Controls {
#cursorKeys;
/** @type {boolean} */
#lockPlayerInput;
/** @type {Phaser.Input.Keyboard.Key | undefined} */
#enterKey;

/**
* @param {Phaser.Scene} scene the Phaser 3 Scene the cursor keys will be created in
*/
constructor(scene) {
this.#scene = scene;
this.#cursorKeys = this.#scene.input.keyboard?.createCursorKeys();
this.#enterKey = this.#scene.input.keyboard?.addKey(Phaser.Input.Keyboard.KeyCodes.ENTER);
this.#lockPlayerInput = false;
}

Expand All @@ -28,6 +31,14 @@ export class Controls {
this.#lockPlayerInput = val;
}

/** @returns {boolean} */
wasEnterKeyPressed() {
if (this.#enterKey === undefined) {
return false;
}
return Phaser.Input.Keyboard.JustDown(this.#enterKey);
}

/** @returns {boolean} */
wasSpaceKeyPressed() {
if (this.#cursorKeys === undefined) {
Expand Down
49 changes: 49 additions & 0 deletions src/utils/data-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import { DIRECTION } from '../common/direction.js';
import { TEXT_SPEED, TILE_SIZE } from '../config.js';
import { TEXT_SPEED_OPTIONS, BATTLE_SCENE_OPTIONS, BATTLE_STYLE_OPTIONS, SOUND_OPTIONS } from '../common/options.js';
import { exhaustiveGuard } from './guard.js';
import { MONSTER_ASSET_KEYS } from '../assets/asset-keys.js';

const LOCAL_STORAGE_KEY = 'MONSTER_TAMER_DATA';

/**
* @typedef MonsterData
* @type {object}
* @property {import('../types/typedef.js').Monster[]} inParty
*/

/**
* @typedef GlobalState
* @type {object}
Expand All @@ -21,6 +28,8 @@ const LOCAL_STORAGE_KEY = 'MONSTER_TAMER_DATA';
* @property {import('../common/options.js').SoundMenuOptions} options.sound
* @property {import('../common/options.js').VolumeMenuOptions} options.volume
* @property {import('../common/options.js').MenuColorOptions} options.menuColor
* @property {boolean} gameStarted
* @property {MonsterData} monsters
*/

/** @type {GlobalState} */
Expand All @@ -40,6 +49,23 @@ const initialState = {
volume: 4,
menuColor: 0,
},
gameStarted: false,
monsters: {
inParty: [
{
id: 1,
monsterId: 1,
name: MONSTER_ASSET_KEYS.IGUANIGNITE,
assetKey: MONSTER_ASSET_KEYS.IGUANIGNITE,
assetFrame: 0,
currentHp: 25,
maxHp: 25,
attackIds: [2],
baseAttack: 15,
currentLevel: 5,
},
],
},
};

export const DATA_MANAGER_STORE_KEYS = Object.freeze({
Expand All @@ -51,6 +77,8 @@ export const DATA_MANAGER_STORE_KEYS = Object.freeze({
OPTIONS_SOUND: 'OPTIONS_SOUND',
OPTIONS_VOLUME: 'OPTIONS_VOLUME',
OPTIONS_MENU_COLOR: 'OPTIONS_MENU_COLOR',
GAME_STARTED: 'GAME_STARTED',
MONSTERS_IN_PARTY: 'MONSTERS_IN_PARTY',
});

class DataManager extends Phaser.Events.EventEmitter {
Expand Down Expand Up @@ -113,6 +141,21 @@ class DataManager extends Phaser.Events.EventEmitter {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(dataToSave));
}

startNewGame() {
// get existing data before resetting all of the data, so we can persist options data
const existingData = { ...this.#dataManagerDataToGlobalStateObject() };
existingData.player.position = { ...initialState.player.position };
existingData.player.direction = initialState.player.direction;
existingData.gameStarted = initialState.gameStarted;
existingData.monsters = {
inParty: [...initialState.monsters.inParty],
};

this.#store.reset();
this.#updateDataManger(existingData);
this.saveData();
}

/**
* @returns {number}
*/
Expand Down Expand Up @@ -149,6 +192,8 @@ class DataManager extends Phaser.Events.EventEmitter {
[DATA_MANAGER_STORE_KEYS.OPTIONS_SOUND]: data.options.sound,
[DATA_MANAGER_STORE_KEYS.OPTIONS_VOLUME]: data.options.volume,
[DATA_MANAGER_STORE_KEYS.OPTIONS_MENU_COLOR]: data.options.menuColor,
[DATA_MANAGER_STORE_KEYS.GAME_STARTED]: data.gameStarted,
[DATA_MANAGER_STORE_KEYS.MONSTERS_IN_PARTY]: data.monsters.inParty,
});
}

Expand All @@ -172,6 +217,10 @@ class DataManager extends Phaser.Events.EventEmitter {
volume: this.#store.get(DATA_MANAGER_STORE_KEYS.OPTIONS_VOLUME),
menuColor: this.#store.get(DATA_MANAGER_STORE_KEYS.OPTIONS_MENU_COLOR),
},
gameStarted: this.#store.get(DATA_MANAGER_STORE_KEYS.GAME_STARTED),
monsters: {
inParty: [...this.#store.get(DATA_MANAGER_STORE_KEYS.MONSTERS_IN_PARTY)],
},
};
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/world/menu/menu-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const MENU_COLOR = Object.freeze({
1: {
main: 0x32454c,
border: 0x6d9aa8,
},
2: {
main: 0x324c3a,
border: 0x6da87d,
},
3: {
main: 0x38324c,
border: 0x796da8,
},
});
Loading

0 comments on commit 0a338ec

Please sign in to comment.