programing is a hard job, i have nothing to say
This commit is contained in:
parent
c6a1ae71b1
commit
b7d084439f
90
src/classes/Assets.ts
Normal file
90
src/classes/Assets.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import { CreepStatsDefinition, MissionDefinition, TowerDefinition } from './Definitions';
|
||||
|
||||
export default class Assets {
|
||||
public static async LoadAssets() {
|
||||
console.log('Loading Texture Assets');
|
||||
Assets.Button01Texture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/button_01.png',
|
||||
});
|
||||
Assets.Button02Texture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/button_02.png',
|
||||
});
|
||||
Assets.Frame01Texture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/frame_01.png',
|
||||
});
|
||||
Assets.Frame02Texture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/frame_02.png',
|
||||
});
|
||||
Assets.FrameGreenTexture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/frame_green.png',
|
||||
});
|
||||
Assets.FrameRedTexture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/frame_red.png',
|
||||
});
|
||||
Assets.FrameVioletTexture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/frame_violet.png',
|
||||
});
|
||||
Assets.HealthTexture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/heart.png',
|
||||
});
|
||||
Assets.GoldTexture = await PIXI.Assets.load({
|
||||
src: '/assets/gui/star.png',
|
||||
});
|
||||
Assets.BasicCreepTexture = await PIXI.Assets.load({
|
||||
src: '/assets/creeps/basic.jpg',
|
||||
});
|
||||
await this.LoadMissions();
|
||||
await this.LoadTowers();
|
||||
await this.LoadCreepStats();
|
||||
}
|
||||
|
||||
public static async LoadCreepStats() {
|
||||
const res = await fetch('/assets/CreepStats.json');
|
||||
const stats = await res.json();
|
||||
this.CreepStats = stats;
|
||||
}
|
||||
|
||||
private static async LoadMissions() {
|
||||
Assets.Missions = [await this.LoadMission('/assets/missions/mission_01.json')];
|
||||
}
|
||||
|
||||
private static async LoadTowers() {
|
||||
const res = await fetch('/assets/Towers.json');
|
||||
const towers = await res.json();
|
||||
Assets.Towers = towers;
|
||||
}
|
||||
|
||||
private static async LoadMission(missionUrl: string) {
|
||||
const res = await fetch(missionUrl);
|
||||
const mission = await res.json();
|
||||
await this.LoadBackground(mission.mapImage.url);
|
||||
return mission;
|
||||
}
|
||||
|
||||
private static async LoadBackground(backgroundUrl: string) {
|
||||
let index = this.MissionBackgrounds.length - 1;
|
||||
if (index == -1) index = 0;
|
||||
this.MissionBackgrounds[index] = await PIXI.Assets.load({
|
||||
src: backgroundUrl,
|
||||
});
|
||||
}
|
||||
|
||||
public static BasicCreepTexture: PIXI.Texture;
|
||||
|
||||
public static Frame01Texture: PIXI.Texture;
|
||||
public static Frame02Texture: PIXI.Texture;
|
||||
public static FrameGreenTexture: PIXI.Texture;
|
||||
public static FrameRedTexture: PIXI.Texture;
|
||||
public static FrameVioletTexture: PIXI.Texture;
|
||||
public static Button01Texture: PIXI.Texture;
|
||||
public static Button02Texture: PIXI.Texture;
|
||||
public static HealthTexture: PIXI.Texture;
|
||||
public static GoldTexture: PIXI.Texture;
|
||||
|
||||
public static MissionBackgrounds: PIXI.Texture[] = [];
|
||||
public static Missions: MissionDefinition[];
|
||||
public static Towers: TowerDefinition[];
|
||||
public static CreepStats: CreepStatsDefinition[];
|
||||
public static DebuggingEnabled: boolean = true;
|
||||
}
|
@ -1,47 +1,62 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import DynamicObject from './DynamicObject';
|
||||
import GameObject from './GameObject';
|
||||
import GuiObject from './GuiObject';
|
||||
import Scene from '../scenes/Scene';
|
||||
|
||||
export class Foundation {
|
||||
public static _PIXIApp: PIXI.Application;
|
||||
public static Master: Master;
|
||||
export class environment {
|
||||
public static app: PIXI.Application;
|
||||
public static GameMaster: GameMaster;
|
||||
public static WindowHeight: number;
|
||||
public static WindowWidth: number;
|
||||
public static AspectRatio: number = 4 / 3;
|
||||
}
|
||||
|
||||
export default class Master {
|
||||
private DynamicObjects: DynamicObject[];
|
||||
export default class GameMaster {
|
||||
public currentScene: Scene;
|
||||
private GameObjects: GameObject[];
|
||||
private ticker: PIXI.Ticker;
|
||||
public stage: PIXI.Container = new PIXI.Container({
|
||||
width: Foundation.WindowWidth,
|
||||
height: Foundation.WindowHeight,
|
||||
});
|
||||
|
||||
constructor() {
|
||||
Foundation.Master = this;
|
||||
environment.GameMaster = this;
|
||||
this.ticker = new PIXI.Ticker();
|
||||
this.ticker.maxFPS = 60;
|
||||
this.ticker.minFPS = 30;
|
||||
this.ticker.add(() => this.update(this.ticker.elapsedMS));
|
||||
}
|
||||
|
||||
public _CreateDynamicObject(object: DynamicObject) {
|
||||
this.DynamicObjects.push(object);
|
||||
public _CreateGameObject(object: GameObject) {
|
||||
this.GameObjects.push(object);
|
||||
environment.app.stage.addChild(object.container);
|
||||
}
|
||||
|
||||
public _RemoveDynamicObject(object: DynamicObject) {
|
||||
this.DynamicObjects.splice(this.DynamicObjects.indexOf(object), 1);
|
||||
public _RemoveGameObject(object: GameObject) {
|
||||
this.GameObjects.splice(this.GameObjects.indexOf(object), 1);
|
||||
environment.app.stage.removeChild(object.container);
|
||||
}
|
||||
|
||||
public RefreshStage() {
|
||||
Foundation._PIXIApp.stage.removeChildren();
|
||||
this.stage.width = Foundation.WindowWidth;
|
||||
this.stage.height = Foundation.WindowHeight;
|
||||
Foundation._PIXIApp.stage.addChild(this.stage);
|
||||
public _CreateGuiObject(object: GuiObject) {
|
||||
this.currentScene.gui.push(object);
|
||||
environment.app.stage.addChild(object.container);
|
||||
}
|
||||
|
||||
public _RemoveGuiObject(object: GuiObject) {
|
||||
this.currentScene.gui.splice(this.currentScene.gui.indexOf(object), 1);
|
||||
environment.app.stage.removeChild(object.container);
|
||||
}
|
||||
|
||||
public changeScene(newScene: Scene) {
|
||||
if (this.currentScene) {
|
||||
this.currentScene.destroy();
|
||||
}
|
||||
this.GameObjects.forEach((element) => {
|
||||
element.destroy();
|
||||
});
|
||||
this.currentScene = newScene;
|
||||
this.currentScene.init();
|
||||
}
|
||||
|
||||
public update(elapsedMS) {
|
||||
this.DynamicObjects.forEach((element) => {
|
||||
this.GameObjects.forEach((element) => {
|
||||
element.update(elapsedMS);
|
||||
});
|
||||
}
|
||||
|
84
src/classes/Definitions.ts
Normal file
84
src/classes/Definitions.ts
Normal file
@ -0,0 +1,84 @@
|
||||
export type MissionDefinition = {
|
||||
name: string;
|
||||
description: string;
|
||||
mapImage: MapImageDefinition;
|
||||
gameMap: GameMapDefinition;
|
||||
rounds: MissionRoundDefinition[];
|
||||
};
|
||||
|
||||
export type MapImageDefinition = {
|
||||
url: string;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type GameMapDefinition = {
|
||||
rows: number;
|
||||
columns: number;
|
||||
cells: TerrainType[][];
|
||||
paths: PathDefinition[];
|
||||
};
|
||||
|
||||
export type MissionRoundDefinition = {
|
||||
waves: WaveDefinition[];
|
||||
offeredGems: GemType[];
|
||||
};
|
||||
|
||||
export type WaveDefinition = {
|
||||
firstCreepSpawnTick: number;
|
||||
spawnIntervalTicks: number;
|
||||
creeps: CreepType[];
|
||||
};
|
||||
|
||||
export type CreepStatsDefinition = {
|
||||
health: number;
|
||||
speed: number;
|
||||
special: Function;
|
||||
resistance: CreepResistancesDefinition;
|
||||
};
|
||||
|
||||
export type CreepResistancesDefinition = {
|
||||
physical: number;
|
||||
divine: number;
|
||||
fire: number;
|
||||
ice: number;
|
||||
frostfire: number;
|
||||
};
|
||||
|
||||
export type TowerDefinition = {
|
||||
name: string;
|
||||
stats: TowerStatsDefinition;
|
||||
};
|
||||
|
||||
export type TowerStatsDefinition = {
|
||||
damage: number;
|
||||
cooldown: number;
|
||||
gemSlotsAmount: number;
|
||||
cost: number;
|
||||
range: number;
|
||||
};
|
||||
|
||||
export type PathDefinition = [[row: number, column: number]];
|
||||
|
||||
export enum CreepType {
|
||||
Basic = 0,
|
||||
Fast = 1,
|
||||
}
|
||||
|
||||
export enum TerrainType {
|
||||
Restricted = 0,
|
||||
Buildable = 1,
|
||||
Path = 9,
|
||||
}
|
||||
|
||||
export enum GemType {
|
||||
Fire = 0,
|
||||
Yeti = 1,
|
||||
Titalium = 2,
|
||||
Soulforge = 3,
|
||||
}
|
||||
|
||||
export enum TowerType {
|
||||
Shooting = 0,
|
||||
Circle = 1,
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import { Foundation } from './Bastion';
|
||||
import { environment } from './Bastion';
|
||||
|
||||
export default abstract class DynamicObject {
|
||||
export default abstract class GameObject {
|
||||
public readonly name: string = this.constructor.name;
|
||||
|
||||
protected _container: PIXI.Container = new PIXI.Container();
|
||||
@ -9,10 +9,10 @@ export default abstract class DynamicObject {
|
||||
protected _events: PIXI.EventEmitter = new PIXI.EventEmitter();
|
||||
|
||||
public destroy() {
|
||||
environment.GameMaster._RemoveGameObject(this);
|
||||
this._events.removeAllListeners();
|
||||
if (this._container.parent) this._container.parent.removeChild(this._container);
|
||||
this._container.destroy();
|
||||
Foundation.Master._RemoveDynamicObject(this);
|
||||
}
|
||||
|
||||
public get container(): PIXI.Container {
|
||||
@ -23,9 +23,10 @@ export default abstract class DynamicObject {
|
||||
return this._events;
|
||||
}
|
||||
|
||||
public update(elapsedMS) {}
|
||||
public abstract update(elapsedMS): void;
|
||||
|
||||
constructor() {
|
||||
Foundation.Master._CreateDynamicObject(this);
|
||||
// Define stuff that goes into this.container (visual elements), then call super().
|
||||
environment.GameMaster._CreateGameObject(this);
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import { environment } from './Bastion';
|
||||
|
||||
export default abstract class GuiObject {
|
||||
public readonly name: string = this.constructor.name;
|
||||
|
||||
protected _container: PIXI.Container;
|
||||
protected _container: PIXI.Container = new PIXI.Container();
|
||||
|
||||
protected _events: PIXI.EventEmitter = new PIXI.EventEmitter();
|
||||
|
||||
protected enabled: boolean;
|
||||
|
||||
public destroy() {
|
||||
this._events.removeAllListeners();
|
||||
if (this._container.parent) this._container.parent.removeChild(this._container);
|
||||
@ -24,18 +27,24 @@ export default abstract class GuiObject {
|
||||
public onClick(e: PIXI.FederatedPointerEvent) {
|
||||
console.warn(`[${this.name} does not implement GuiObject.onClick()]`);
|
||||
}
|
||||
|
||||
public onWheel(e: PIXI.FederatedWheelEvent) {
|
||||
console.warn(`[${this.name} does not implement GuiObject.onWheel()]`);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this._container = new PIXI.Container();
|
||||
public setEnabled(enabled: boolean) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
constructor(interactive?: boolean) {
|
||||
environment.GameMaster._CreateGuiObject(this);
|
||||
if (!interactive) return;
|
||||
this._container.interactive = true;
|
||||
this._container.onwheel = (e) => {
|
||||
this.onWheel(e);
|
||||
if (this.enabled) this.onWheel(e);
|
||||
};
|
||||
this._container.onclick = (e) => {
|
||||
this.onClick(e);
|
||||
if (this.enabled) this.onClick(e);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
60
src/classes/gui/Button.ts
Normal file
60
src/classes/gui/Button.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import GuiObject from '../GuiObject';
|
||||
import Assets from '../Assets';
|
||||
|
||||
export enum ButtonTexture {
|
||||
Button01 = 0,
|
||||
Button02 = 1,
|
||||
}
|
||||
|
||||
export default class Button extends GuiObject {
|
||||
private caption: string;
|
||||
private bounds: PIXI.Rectangle;
|
||||
private buttonTexture: PIXI.Texture;
|
||||
|
||||
private buttonSprite: PIXI.NineSliceSprite;
|
||||
private buttonText: PIXI.Text;
|
||||
|
||||
setCaption(caption: string) {
|
||||
this.caption = caption;
|
||||
this.buttonText.text = caption;
|
||||
}
|
||||
|
||||
constructor(bounds: PIXI.Rectangle, caption: string, buttonTexture: ButtonTexture, enabled: boolean = true) {
|
||||
super(true);
|
||||
if (buttonTexture == ButtonTexture.Button01) this.buttonTexture = Assets.Button01Texture;
|
||||
if (buttonTexture == ButtonTexture.Button02) this.buttonTexture = Assets.Button02Texture;
|
||||
this.caption = caption;
|
||||
this.enabled = enabled;
|
||||
this.bounds = bounds;
|
||||
this.container.x = this.bounds.x;
|
||||
this.container.y = this.bounds.y;
|
||||
this.container.width = this.bounds.width;
|
||||
this.container.height = this.bounds.height;
|
||||
this.buttonSprite = new PIXI.NineSliceSprite({
|
||||
texture: this.buttonTexture,
|
||||
leftWidth: 100,
|
||||
topHeight: 100,
|
||||
rightWidth: 100,
|
||||
bottomHeight: 100,
|
||||
});
|
||||
this.buttonSprite.x = 0;
|
||||
this.buttonSprite.y = 0;
|
||||
this.buttonSprite.width = this.bounds.width;
|
||||
this.buttonSprite.height = this.bounds.height;
|
||||
this.container.addChild(this.buttonSprite);
|
||||
this.buttonText = new PIXI.Text({
|
||||
text: this.caption,
|
||||
style: new PIXI.TextStyle({
|
||||
fill: 0xffffff,
|
||||
fontSize: 24,
|
||||
}),
|
||||
});
|
||||
this.container.addChild(this.buttonText);
|
||||
this.buttonText.anchor.set(0.5, 0.5);
|
||||
this.buttonText.x = this.bounds.width / 2;
|
||||
this.buttonText.y = this.bounds.height / 2;
|
||||
this.container.x = this.bounds.x;
|
||||
this.container.y = this.bounds.y;
|
||||
}
|
||||
}
|
21
src/main.ts
21
src/main.ts
@ -1,16 +1,17 @@
|
||||
import * as PIXI from 'pixi.js';
|
||||
import Master, { Foundation } from './classes/Bastion';
|
||||
import GameMaster, { environment } from './classes/Bastion';
|
||||
import Assets from './classes/Assets';
|
||||
|
||||
(async () => {
|
||||
const app = new PIXI.Application();
|
||||
const aspectRatio = Foundation.AspectRatio;
|
||||
const aspectRatio = environment.AspectRatio;
|
||||
const maxWidth = window.innerWidth;
|
||||
const maxHeight = window.innerHeight;
|
||||
const width = Math.min(maxWidth * 0.75, maxHeight * aspectRatio);
|
||||
const height = width / aspectRatio;
|
||||
Foundation.WindowWidth = width;
|
||||
Foundation.WindowHeight = height;
|
||||
Foundation._PIXIApp = app;
|
||||
environment.WindowWidth = width;
|
||||
environment.WindowHeight = height;
|
||||
environment.app = app;
|
||||
|
||||
await app.init({
|
||||
width: width,
|
||||
@ -19,16 +20,14 @@ import Master, { Foundation } from './classes/Bastion';
|
||||
sharedTicker: true,
|
||||
preference: 'webgl',
|
||||
});
|
||||
|
||||
document.body.appendChild(app.canvas);
|
||||
let master = new Master();
|
||||
master.RefreshStage();
|
||||
await Assets.LoadAssets();
|
||||
new GameMaster();
|
||||
window.addEventListener('resize', () => {
|
||||
const newWidth = Math.min(window.innerWidth * 0.75, window.innerHeight * aspectRatio);
|
||||
const newHeight = newWidth / aspectRatio;
|
||||
Foundation.WindowWidth = newWidth;
|
||||
Foundation.WindowHeight = newHeight;
|
||||
environment.WindowWidth = newWidth;
|
||||
environment.WindowHeight = newHeight;
|
||||
app.renderer.resize(newWidth, newHeight);
|
||||
master.RefreshStage();
|
||||
});
|
||||
})();
|
||||
|
@ -0,0 +1,9 @@
|
||||
import Button from '../classes/gui/Button';
|
||||
import Scene from './Scene';
|
||||
import * as PIXI from 'pixi.js';
|
||||
|
||||
export class MainScene extends Scene {
|
||||
public init() {
|
||||
new Button(new PIXI.Bounds(0, 0, 200, 200));
|
||||
}
|
||||
}
|
16
src/scenes/Scene.ts
Normal file
16
src/scenes/Scene.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import GuiObject from '../classes/GuiObject';
|
||||
|
||||
export default class Scene {
|
||||
public gui: GuiObject[];
|
||||
public destroy() {
|
||||
this.gui.forEach((element) => {
|
||||
element.destroy();
|
||||
});
|
||||
}
|
||||
public GetGuiObject(object: GuiObject) {
|
||||
return this.gui.find((obj) => obj == object);
|
||||
}
|
||||
public init() {
|
||||
// Definitions for scene elements.
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user