diff --git a/public/assets/gui/button_02.png b/public/assets/gui/button_02.png new file mode 100755 index 0000000..7ef79b1 Binary files /dev/null and b/public/assets/gui/button_02.png differ diff --git a/src/base/Button.ts b/src/base/Button.ts new file mode 100644 index 0000000..e0224a8 --- /dev/null +++ b/src/base/Button.ts @@ -0,0 +1,44 @@ +import GameObject from "./GameObject"; +import * as PIXI from "pixi.js"; + +export default class Button extends GameObject { + private caption: string; + private color: PIXI.Color; + private buttonTexture: PIXI.Texture; + + setCaption(caption: string) { + this.caption = caption; + this.createButton(); + } + + constructor(caption: string, bounds: PIXI.Rectangle, color: PIXI.Color) { + super(bounds); + this.caption = caption; + this.color = color; + this.container.interactive = true; + this.buttonTexture = PIXI.Texture.from("/assets/gui/button02.png"); + this.createButton(); + } + + protected triggerBoundsChanged() { + this.createButton(); + } + + private createButton() { + this.container.removeChildren(); + const button = new PIXI.Graphics(); + button.rect(0, 0, this.bounds.width, this.bounds.height); + button.fill(this.color); + this.container.addChild(button); + const text = new PIXI.Text({ text: this.caption }); + this.container.addChild(text); + text.anchor.set(0.5, 0.5); + text.x = this.bounds.width / 2; + text.y = this.bounds.height / 2; + this._container.x = this.bounds.x; + this._container.y = this.bounds.y; + this._container.on("click", () => { + this.events.emit("click"); + }); + } +} diff --git a/src/base/Game.ts b/src/base/Game.ts new file mode 100644 index 0000000..b571856 --- /dev/null +++ b/src/base/Game.ts @@ -0,0 +1,55 @@ +import MainMenu from "../scenes/MainMenu"; +import MissionMenuSelect from "../scenes/MissionSelectMenu"; +import GameObject from "./GameObject"; +import * as PIXI from "pixi.js"; + +export default class Game extends GameObject { + private _currentScene: GameObject | null = null; + + constructor(bounds: PIXI.Rectangle) { + super(bounds); + this.onMainMenu(); + } + + private onMainMenu() { + const mainScene = new MainMenu(this.bounds); + mainScene.events.on("newGame", this.onNewGame); + mainScene.events.on("settings", this.onSettings); + this.setScene(mainScene); + } + + private onNewGame = () => { + console.log("New Game"); + const missionSelectScene = new MissionMenuSelect(this.bounds); + missionSelectScene.events.on("mission", (mission) => { + console.log("Mission selected", mission); + }); + missionSelectScene.events.on("back", () => { + this.onMainMenu(); + }); + this.setScene(missionSelectScene); + }; + + private onSettings = () => { + console.log("Settings"); + }; + + private setScene(scene: GameObject) { + if (this._currentScene) { + this.container.removeChild(this._currentScene.container); + } + this._currentScene = scene; + this.container.addChild(scene.container); + this.drawScene(); + } + + protected triggerBoundsChanged(): void { + this.drawScene(); + } + + private drawScene() { + if (this._currentScene) { + this._currentScene.setBounds(0, 0, this.bounds.width, this.bounds.height); + } + } +} diff --git a/src/base/GameObject.ts b/src/base/GameObject.ts new file mode 100644 index 0000000..12648a5 --- /dev/null +++ b/src/base/GameObject.ts @@ -0,0 +1,32 @@ +import * as PIXI from "pixi.js"; +export default abstract class GameObject { + protected _container: PIXI.Container; + + protected bounds: PIXI.Rectangle; + + private _events: PIXI.EventEmitter = new PIXI.EventEmitter(); + + public getBounds(): PIXI.Rectangle { + return this.bounds; + } + + public setBounds(x: number, y: number, width: number, height: number) { + this.bounds = new PIXI.Rectangle(x, y, width, height); + this.triggerBoundsChanged(); // GameObject implements this. + } + + public get container(): PIXI.Container { + return this._container; + } + + public get events(): PIXI.EventEmitter { + return this._events; + } + + protected abstract triggerBoundsChanged(); + + constructor(bounds: PIXI.Rectangle) { + this.bounds = bounds; + this._container = new PIXI.Container(); + } +} diff --git a/src/classes/GUI.ts b/src/classes/GUI.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/classes/Game.ts b/src/classes/Game.ts deleted file mode 100644 index a962b9c..0000000 --- a/src/classes/Game.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Renderer } from "./Renderer.ts"; -import { BaseScene, SceneType, makeSceneFromType } from "./Scenes.ts"; - -export class Game { - public Renderer: Renderer; - public currentScene: BaseScene; - constructor(sceneType: SceneType) { - this.Renderer = new Renderer(); - this.changeScene(sceneType); - } - changeScene(sceneType): void { - if (this.currentScene != undefined) this.currentScene.destroy(); - this.currentScene = makeSceneFromType(sceneType); - } -} diff --git a/src/classes/Grid.ts b/src/classes/Grid.ts deleted file mode 100644 index 012172b..0000000 --- a/src/classes/Grid.ts +++ /dev/null @@ -1,60 +0,0 @@ -import * as PIXI from "pixi.js"; -import { Tower } from "./Tower.ts"; - -export enum CellType { - Path, - NoBuild, - Build, - Undefined, -} - -export class Cell { - public x: number; - public y: number; - public type: CellType; - public tower: Tower; - constructor(x, y, type) { - this.x = x; - this.y = y; - this.type = type; - } -} - -export class Grid { - public rows: number; - public columns: number; - public gridObject: PIXI.Container; - public cells: Array; - constructor(x, y, width, height, rows, columns) { - this.rows = rows; - this.columns = columns; - this.gridObject = new PIXI.Container({ - width: width, - height: height, - x: x, - y: y, - }); - for (let y = 0; y < rows; y++) { - for (let x = 0; x < columns; x++) { - let cell = new Cell(x, y, CellType.Undefined); - this.cells.push(cell); - } - } - } - - getPixelScalingFactor() { - const pixelScaleX = this.gridObject.width / this.columns; - const pixelScaleY = this.gridObject.height / this.rows; - return pixelScaleX < pixelScaleY ? pixelScaleX : pixelScaleY; - } - - gridUnitsToPixels(amount: number): number { - return amount * this.getPixelScalingFactor(); - } - - pixelsToGridUnits(pixels: number): number { - return pixels / this.getPixelScalingFactor(); - } - - render() {} -} diff --git a/src/classes/Renderer.ts b/src/classes/Renderer.ts deleted file mode 100644 index d75bb80..0000000 --- a/src/classes/Renderer.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as PIXI from "pixi.js"; - -export class Renderer { - constructor() {} -} diff --git a/src/classes/Scenes.ts b/src/classes/Scenes.ts deleted file mode 100644 index 09c474e..0000000 --- a/src/classes/Scenes.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as PIXI from "pixi.js"; - -export function makeSceneFromType(type: SceneType) { - if (type == SceneType.MainMenu) { - return new MainMenu(); - } - if (type == SceneType.MissionSelect) { - return new MissionSelect(); - } -} - -export enum SceneType { - MainMenu, - MissionSelect, -} - -export class BaseScene { - public type: SceneType = null; - public destroy(): boolean { - return true; // return when destroyed - } -} - -export class MainMenu extends BaseScene { - public type: SceneType = SceneType.MainMenu; - public; -} - -export class MissionSelect extends BaseScene { - public type: SceneType = SceneType.MissionSelect; -} diff --git a/src/classes/Tower.ts b/src/classes/Tower.ts deleted file mode 100644 index 221d44e..0000000 --- a/src/classes/Tower.ts +++ /dev/null @@ -1 +0,0 @@ -export class Tower {} diff --git a/src/main.ts b/src/main.ts index 99ead5d..7649048 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,5 @@ import * as PIXI from "pixi.js"; -import { Game } from "./classes/Game.ts"; -import { SceneType } from "./classes/Scenes.ts"; +import Game from "./base/Game"; (async () => { const app = new PIXI.Application(); await app.init({ @@ -11,5 +10,10 @@ import { SceneType } from "./classes/Scenes.ts"; }); document.body.appendChild(app.canvas); - globalThis.Game = new Game(SceneType.MainMenu); + const game = new Game(app.screen); + app.stage.addChild(game.container); + window.addEventListener("resize", () => { + app.renderer.resize(window.innerWidth, window.innerHeight); + game.setBounds(0, 0, app.screen.width, app.screen.height); + }); })(); diff --git a/src/scenes/Base.ts b/src/scenes/Base.ts new file mode 100644 index 0000000..f731867 --- /dev/null +++ b/src/scenes/Base.ts @@ -0,0 +1,12 @@ +import * as PIXI from "pixi.js"; +import GameObject from "../base/GameObject"; +export default abstract class Scene extends GameObject { + constructor(bounds: PIXI.Rectangle) { + super(bounds); + this.createScene(); + } + protected triggerBoundsChanged() { + this.createScene(); + } + protected abstract createScene(); +} diff --git a/src/scenes/MainMenu.ts b/src/scenes/MainMenu.ts new file mode 100644 index 0000000..ffe7090 --- /dev/null +++ b/src/scenes/MainMenu.ts @@ -0,0 +1,52 @@ +import Button from "../base/Button"; +import Scene from "./Base"; +import * as PIXI from "pixi.js"; + +export default class MainMenu extends Scene { + private _newGameButton: Button; + private _settingsButton: Button; + + constructor(bounds: PIXI.Rectangle) { + super(bounds); + } + + protected createScene() { + console.log("Creating main menu scene", this.bounds); + this.container.removeChildren(); + const g = new PIXI.Graphics(); + g.rect(0, 0, this.bounds.width, this.bounds.height); + g.fill(0x000000); + this.container.addChild(g); + this._newGameButton = new Button( + "New Game", + new PIXI.Rectangle( + 100, + this.bounds.height / 2 - 80, + this.bounds.width - 200, + 60 + ), + new PIXI.Color("blue") + ); + this._newGameButton.events.on("click", () => { + this.events.emit("newGame"); + }); + this.container.addChild(this._newGameButton.container); + + this._settingsButton = new Button( + "Settings", + new PIXI.Rectangle( + 100, + this.bounds.height / 2 + 20, + this.bounds.width - 200, + 60 + ), + new PIXI.Color("gray") + ); + this._settingsButton.events.on("click", () => { + this.events.emit("settings"); + }); + this.container.addChild(this._settingsButton.container); + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + } +} diff --git a/src/scenes/MissionSelectMenu.ts b/src/scenes/MissionSelectMenu.ts new file mode 100644 index 0000000..5f9770a --- /dev/null +++ b/src/scenes/MissionSelectMenu.ts @@ -0,0 +1,47 @@ +import Button from "../base/Button"; +import Scene from "./Base"; +import * as PIXI from "pixi.js"; + +export default class MissionMenuSelect extends Scene { + private _buttons: Button[] = []; + + constructor(bounds: PIXI.Rectangle) { + super(bounds); + } + + protected createScene() { + this.container.removeChildren(); + this._buttons = []; + const g = new PIXI.Graphics(); + g.rect(0, 0, this.bounds.width, this.bounds.height); + g.fill(0x000000); + this.container.addChild(g); + this.addMission("Mission 1"); + this.addMission("Mission 2"); + this.addMission("Mission 3"); + this.addMission("Mission 4"); + this.addButton("Back", () => { + this.events.emit("back"); + }); + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + } + + private addMission(mission: string) { + this.addButton(mission, () => { + this.events.emit("mission", mission); + }); + } + + private addButton(caption: string, onClick: () => void) { + const yOffset = this._buttons.length * 80 + 100; + const button = new Button( + caption, + new PIXI.Rectangle(100, yOffset, this.bounds.width - 200, 60), + new PIXI.Color("white") + ); + button.events.on("click", onClick); + this._buttons.push(button); + this.container.addChild(button.container); + } +} diff --git a/src/scenes/SettingsMenu.ts b/src/scenes/SettingsMenu.ts new file mode 100644 index 0000000..5e2d136 --- /dev/null +++ b/src/scenes/SettingsMenu.ts @@ -0,0 +1,51 @@ +import Button from "../base/Button"; +import Scene from "./Base"; +import * as PIXI from "pixi.js"; + +export default class SettingsMenu extends Scene { + private _newGameButton: Button; + private _settingsButton: Button; + + constructor(bounds: PIXI.Rectangle) { + super(bounds); + } + + protected createScene() { + this.container.removeChildren(); + const g = new PIXI.Graphics(); + g.rect(0, 0, this.bounds.width, this.bounds.height); + g.fill(0x000000); + this.container.addChild(g); + this._newGameButton = new Button( + "New Game", + new PIXI.Rectangle( + 100, + this.bounds.height / 2 - 80, + this.bounds.width - 200, + 60 + ), + new PIXI.Color("blue") + ); + this._newGameButton.events.on("click", () => { + this.events.emit("newGame"); + }); + this.container.addChild(this._newGameButton.container); + + this._settingsButton = new Button( + "Settings", + new PIXI.Rectangle( + 100, + this.bounds.height / 2 + 20, + this.bounds.width - 200, + 60 + ), + new PIXI.Color("gray") + ); + this._settingsButton.events.on("click", () => { + this.events.emit("settings"); + }); + this.container.addChild(this._settingsButton.container); + this.container.x = this.bounds.x; + this.container.y = this.bounds.y; + } +}