base work on engine, expanded

This commit is contained in:
koneko 2024-09-22 22:58:08 +02:00
parent cc51c3831d
commit 73eba44e5e
15 changed files with 300 additions and 115 deletions

BIN
public/assets/gui/button_02.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

44
src/base/Button.ts Normal file
View File

@ -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");
});
}
}

55
src/base/Game.ts Normal file
View File

@ -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);
}
}
}

32
src/base/GameObject.ts Normal file
View File

@ -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();
}
}

View File

View File

@ -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);
}
}

View File

@ -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<Cell>;
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() {}
}

View File

@ -1,5 +0,0 @@
import * as PIXI from "pixi.js";
export class Renderer {
constructor() {}
}

View File

@ -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;
}

View File

@ -1 +0,0 @@
export class Tower {}

View File

@ -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);
});
})();

12
src/scenes/Base.ts Normal file
View File

@ -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();
}

52
src/scenes/MainMenu.ts Normal file
View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}