diff --git a/games/simon/.vscode/settings.json b/games/simon/.vscode/settings.json index 749f741..b96ea0a 100644 --- a/games/simon/.vscode/settings.json +++ b/games/simon/.vscode/settings.json @@ -5,7 +5,7 @@ }, "editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "cSpell.words": [ "devshareacademy", diff --git a/games/simon/project-task.todo b/games/simon/project-task.todo new file mode 100644 index 0000000..f8397a9 --- /dev/null +++ b/games/simon/project-task.todo @@ -0,0 +1,13 @@ +☐ project setup +☐ create buttons +☐ add hover events with alpha +☐ core simon logic + ☐ generate a random element in the sequence + ☐ method to handle player input + ☐ track player input until sequence match, or mismatch + ☐ reset game +☐ connect simon to core scene + ☐ add simple state for tracking game state +☐ play a sequence + ☐ change game alpha and play sound +☐ wait for player input diff --git a/games/simon/src/main.ts b/games/simon/src/main.ts index 2c25e60..c567f7b 100644 --- a/games/simon/src/main.ts +++ b/games/simon/src/main.ts @@ -1,4 +1,6 @@ import Phaser from 'phaser'; +import Simon from './simon'; +import { sleep } from './utils'; const ASSET_KEYS = { SOUND1: 'SOUND1', @@ -7,7 +9,18 @@ const ASSET_KEYS = { SOUND4: 'SOUND4', } as const; +type GameState = keyof typeof GAME_STATE; + +const GAME_STATE = { + INITIAL: 'INITIAL', + PLAYING_PATTERN: 'PLAYING_PATTERN', + WAITING_FOR_INPUT: 'WAITING_FOR_INPUT', + DONE: 'DONE', +} as const; + class Game extends Phaser.Scene { + #gameState!: GameState; + #simonGame!: Simon; #buttons!: Phaser.GameObjects.Rectangle[]; constructor() { @@ -15,7 +28,9 @@ class Game extends Phaser.Scene { } public init() { + this.#gameState = GAME_STATE.INITIAL; this.#buttons = []; + this.#simonGame = new Simon(); } public preload(): void { @@ -32,6 +47,11 @@ class Game extends Phaser.Scene { const yellowButton = this.#createButton(20, 230, 0xe6e600, 0xffff33, 2, ASSET_KEYS.SOUND3); const blueButton = this.#createButton(230, 230, 0x0066cc, 0x1589ff, 3, ASSET_KEYS.SOUND4); this.#buttons = [redButton, greenButton, yellowButton, blueButton]; + + // play sequence for player to remember and transition to wait for player input + this.#playSequence().catch(() => { + // do nothing + }); } #createButton( @@ -51,18 +71,64 @@ class Game extends Phaser.Scene { // add event listener for pointer over event (mouse hovers over element), when event fires update color and fill button.on(Phaser.Input.Events.POINTER_OVER as string, () => { - button.fillColor = hoverColor; - button.setAlpha(1); + if (this.#gameState === GAME_STATE.WAITING_FOR_INPUT) { + button.fillColor = hoverColor; + button.setAlpha(1); + } }); // add event listener for pointer out event (mouse was hovering over element and then leaves), when event fires update color and fill button.on(Phaser.Input.Events.POINTER_OUT as string, () => { - button.fillColor = color; - button.setAlpha(0.4); + if (this.#gameState === GAME_STATE.WAITING_FOR_INPUT) { + button.fillColor = color; + button.setAlpha(0.4); + } }); + // add event listener for click events, when event fires update the player moves in the simon game logic + button.on(Phaser.Input.Events.POINTER_DOWN as string, () => { + if (this.#gameState === GAME_STATE.WAITING_FOR_INPUT) { + this.sound.play(audioAssetKey); + this.#simonGame.checkPlayerMove(button.data.values.id as number); + + button.fillColor = color; + button.setAlpha(0.4); + + // check to see if game is over and go to DONE state + if (this.#simonGame.isGameOver) { + this.#gameState = GAME_STATE.DONE; + console.log('Game is over'); + return; + } + + // check if the player sequence is complete, if so go to the next round + if (this.#simonGame.isPlayerSequenceComplete) { + this.#gameState = GAME_STATE.PLAYING_PATTERN; + this.#simonGame.generateNextSequenceElement(); + this.#playSequence().catch(() => { + // do nothing + }); + } + } + }); return button; } + + async #playSequence(): Promise { + await sleep(1000); + const currentSequence = this.#simonGame.sequence; + for (const num of currentSequence) { + this.#buttons[num].fillColor = this.#buttons[num].data.values.hoverColor as number; + this.#buttons[num].setAlpha(1); + this.sound.play(this.#buttons[num].data.values.audioAssetKey as string); + await sleep(1000); + this.#buttons[num].fillColor = this.#buttons[num].data.values.color as number; + this.#buttons[num].setAlpha(0.4); + await sleep(400); + } + + this.#gameState = GAME_STATE.WAITING_FOR_INPUT; + } } const gameConfig: Phaser.Types.Core.GameConfig = { diff --git a/games/simon/src/utils.ts b/games/simon/src/utils.ts new file mode 100644 index 0000000..2cfd4c4 --- /dev/null +++ b/games/simon/src/utils.ts @@ -0,0 +1,3 @@ +export function sleep(milliseconds: number) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +}