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 * 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 {
|
export class environment {
|
||||||
public static _PIXIApp: PIXI.Application;
|
public static app: PIXI.Application;
|
||||||
public static Master: Master;
|
public static GameMaster: GameMaster;
|
||||||
public static WindowHeight: number;
|
public static WindowHeight: number;
|
||||||
public static WindowWidth: number;
|
public static WindowWidth: number;
|
||||||
public static AspectRatio: number = 4 / 3;
|
public static AspectRatio: number = 4 / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Master {
|
export default class GameMaster {
|
||||||
private DynamicObjects: DynamicObject[];
|
public currentScene: Scene;
|
||||||
|
private GameObjects: GameObject[];
|
||||||
private ticker: PIXI.Ticker;
|
private ticker: PIXI.Ticker;
|
||||||
public stage: PIXI.Container = new PIXI.Container({
|
|
||||||
width: Foundation.WindowWidth,
|
|
||||||
height: Foundation.WindowHeight,
|
|
||||||
});
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
Foundation.Master = this;
|
environment.GameMaster = this;
|
||||||
this.ticker = new PIXI.Ticker();
|
this.ticker = new PIXI.Ticker();
|
||||||
this.ticker.maxFPS = 60;
|
this.ticker.maxFPS = 60;
|
||||||
this.ticker.minFPS = 30;
|
this.ticker.minFPS = 30;
|
||||||
this.ticker.add(() => this.update(this.ticker.elapsedMS));
|
this.ticker.add(() => this.update(this.ticker.elapsedMS));
|
||||||
}
|
}
|
||||||
|
|
||||||
public _CreateDynamicObject(object: DynamicObject) {
|
public _CreateGameObject(object: GameObject) {
|
||||||
this.DynamicObjects.push(object);
|
this.GameObjects.push(object);
|
||||||
|
environment.app.stage.addChild(object.container);
|
||||||
}
|
}
|
||||||
|
|
||||||
public _RemoveDynamicObject(object: DynamicObject) {
|
public _RemoveGameObject(object: GameObject) {
|
||||||
this.DynamicObjects.splice(this.DynamicObjects.indexOf(object), 1);
|
this.GameObjects.splice(this.GameObjects.indexOf(object), 1);
|
||||||
|
environment.app.stage.removeChild(object.container);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefreshStage() {
|
public _CreateGuiObject(object: GuiObject) {
|
||||||
Foundation._PIXIApp.stage.removeChildren();
|
this.currentScene.gui.push(object);
|
||||||
this.stage.width = Foundation.WindowWidth;
|
environment.app.stage.addChild(object.container);
|
||||||
this.stage.height = Foundation.WindowHeight;
|
}
|
||||||
Foundation._PIXIApp.stage.addChild(this.stage);
|
|
||||||
|
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) {
|
public update(elapsedMS) {
|
||||||
this.DynamicObjects.forEach((element) => {
|
this.GameObjects.forEach((element) => {
|
||||||
element.update(elapsedMS);
|
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 * 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;
|
public readonly name: string = this.constructor.name;
|
||||||
|
|
||||||
protected _container: PIXI.Container = new PIXI.Container();
|
protected _container: PIXI.Container = new PIXI.Container();
|
||||||
@ -9,10 +9,10 @@ export default abstract class DynamicObject {
|
|||||||
protected _events: PIXI.EventEmitter = new PIXI.EventEmitter();
|
protected _events: PIXI.EventEmitter = new PIXI.EventEmitter();
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
environment.GameMaster._RemoveGameObject(this);
|
||||||
this._events.removeAllListeners();
|
this._events.removeAllListeners();
|
||||||
if (this._container.parent) this._container.parent.removeChild(this._container);
|
if (this._container.parent) this._container.parent.removeChild(this._container);
|
||||||
this._container.destroy();
|
this._container.destroy();
|
||||||
Foundation.Master._RemoveDynamicObject(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get container(): PIXI.Container {
|
public get container(): PIXI.Container {
|
||||||
@ -23,9 +23,10 @@ export default abstract class DynamicObject {
|
|||||||
return this._events;
|
return this._events;
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(elapsedMS) {}
|
public abstract update(elapsedMS): void;
|
||||||
|
|
||||||
constructor() {
|
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 * as PIXI from 'pixi.js';
|
||||||
|
import { environment } from './Bastion';
|
||||||
|
|
||||||
export default abstract class GuiObject {
|
export default abstract class GuiObject {
|
||||||
public readonly name: string = this.constructor.name;
|
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 _events: PIXI.EventEmitter = new PIXI.EventEmitter();
|
||||||
|
|
||||||
|
protected enabled: boolean;
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this._events.removeAllListeners();
|
this._events.removeAllListeners();
|
||||||
if (this._container.parent) this._container.parent.removeChild(this._container);
|
if (this._container.parent) this._container.parent.removeChild(this._container);
|
||||||
@ -24,18 +27,24 @@ export default abstract class GuiObject {
|
|||||||
public onClick(e: PIXI.FederatedPointerEvent) {
|
public onClick(e: PIXI.FederatedPointerEvent) {
|
||||||
console.warn(`[${this.name} does not implement GuiObject.onClick()]`);
|
console.warn(`[${this.name} does not implement GuiObject.onClick()]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onWheel(e: PIXI.FederatedWheelEvent) {
|
public onWheel(e: PIXI.FederatedWheelEvent) {
|
||||||
console.warn(`[${this.name} does not implement GuiObject.onWheel()]`);
|
console.warn(`[${this.name} does not implement GuiObject.onWheel()]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
public setEnabled(enabled: boolean) {
|
||||||
this._container = new PIXI.Container();
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(interactive?: boolean) {
|
||||||
|
environment.GameMaster._CreateGuiObject(this);
|
||||||
|
if (!interactive) return;
|
||||||
this._container.interactive = true;
|
this._container.interactive = true;
|
||||||
this._container.onwheel = (e) => {
|
this._container.onwheel = (e) => {
|
||||||
this.onWheel(e);
|
if (this.enabled) this.onWheel(e);
|
||||||
};
|
};
|
||||||
this._container.onclick = (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 * as PIXI from 'pixi.js';
|
||||||
import Master, { Foundation } from './classes/Bastion';
|
import GameMaster, { environment } from './classes/Bastion';
|
||||||
|
import Assets from './classes/Assets';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const app = new PIXI.Application();
|
const app = new PIXI.Application();
|
||||||
const aspectRatio = Foundation.AspectRatio;
|
const aspectRatio = environment.AspectRatio;
|
||||||
const maxWidth = window.innerWidth;
|
const maxWidth = window.innerWidth;
|
||||||
const maxHeight = window.innerHeight;
|
const maxHeight = window.innerHeight;
|
||||||
const width = Math.min(maxWidth * 0.75, maxHeight * aspectRatio);
|
const width = Math.min(maxWidth * 0.75, maxHeight * aspectRatio);
|
||||||
const height = width / aspectRatio;
|
const height = width / aspectRatio;
|
||||||
Foundation.WindowWidth = width;
|
environment.WindowWidth = width;
|
||||||
Foundation.WindowHeight = height;
|
environment.WindowHeight = height;
|
||||||
Foundation._PIXIApp = app;
|
environment.app = app;
|
||||||
|
|
||||||
await app.init({
|
await app.init({
|
||||||
width: width,
|
width: width,
|
||||||
@ -19,16 +20,14 @@ import Master, { Foundation } from './classes/Bastion';
|
|||||||
sharedTicker: true,
|
sharedTicker: true,
|
||||||
preference: 'webgl',
|
preference: 'webgl',
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.appendChild(app.canvas);
|
document.body.appendChild(app.canvas);
|
||||||
let master = new Master();
|
await Assets.LoadAssets();
|
||||||
master.RefreshStage();
|
new GameMaster();
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
const newWidth = Math.min(window.innerWidth * 0.75, window.innerHeight * aspectRatio);
|
const newWidth = Math.min(window.innerWidth * 0.75, window.innerHeight * aspectRatio);
|
||||||
const newHeight = newWidth / aspectRatio;
|
const newHeight = newWidth / aspectRatio;
|
||||||
Foundation.WindowWidth = newWidth;
|
environment.WindowWidth = newWidth;
|
||||||
Foundation.WindowHeight = newHeight;
|
environment.WindowHeight = newHeight;
|
||||||
app.renderer.resize(newWidth, 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