add Timers and Lines, and modified Registry
This commit is contained in:
parent
924469a2cd
commit
c241aa99bc
|
@ -50,6 +50,8 @@ export default class Graph {
|
|||
addEdge(x: number, y: number, weight?: number): void {
|
||||
let edge = new EdgeNode(y, weight);
|
||||
|
||||
|
||||
|
||||
if(this.edges[x]){
|
||||
edge.next = this.edges[x];
|
||||
}
|
||||
|
@ -69,6 +71,24 @@ export default class Graph {
|
|||
this.numEdges += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not an edge exists between two nodes.
|
||||
* This check is directional if this is a directed graph.
|
||||
* @param x The first node
|
||||
* @param y The second node
|
||||
* @returns true if an edge exists, false otherwise
|
||||
*/
|
||||
edgeExists(x: number, y: number): boolean {
|
||||
let edge = this.edges[x];
|
||||
|
||||
while(edge !== null){
|
||||
if(edge.y === y){
|
||||
return true;
|
||||
}
|
||||
edge = edge.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the edge list associated with node x
|
||||
* @param x The index of the node
|
||||
|
|
|
@ -33,4 +33,11 @@ export default interface Actor {
|
|||
* @param options An object that allows options to be pased to the activated AI
|
||||
*/
|
||||
setAIActive(active: boolean, options: Record<string, any>): void;
|
||||
|
||||
/**
|
||||
* Moves this GameNode along a path
|
||||
* @param speed The speed to move with
|
||||
* @param path The path we're moving along
|
||||
*/
|
||||
moveOnPath(speed: number, path: NavigationPath): void;
|
||||
}
|
|
@ -109,4 +109,22 @@ export default class Queue<T> implements Collection {
|
|||
i = (i + 1) % this.MAX_ELEMENTS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this queue into a string format
|
||||
* @returns A string representing this queue
|
||||
*/
|
||||
toString(): string {
|
||||
let retval = "";
|
||||
|
||||
this.forEach( (item, index) => {
|
||||
let str = item.toString()
|
||||
if(index !== 0){
|
||||
str += " -> "
|
||||
}
|
||||
retval = str + retval;
|
||||
});
|
||||
|
||||
return "Top -> " + retval;
|
||||
}
|
||||
}
|
|
@ -25,8 +25,9 @@ export default abstract class State implements Updateable {
|
|||
|
||||
/**
|
||||
* A method that is called when this state is entered. Use this to initialize any variables before updates occur.
|
||||
* @param options Information to pass to this state
|
||||
*/
|
||||
abstract onEnter(): void;
|
||||
abstract onEnter(options: Record<string, any>): void;
|
||||
|
||||
/**
|
||||
* A lifecycle method that handles an input event, such as taking damage.
|
||||
|
@ -42,11 +43,13 @@ export default abstract class State implements Updateable {
|
|||
* @param stateName The name of the state to transition to
|
||||
*/
|
||||
protected finished(stateName: string): void {
|
||||
console.log("Finished");
|
||||
this.parent.changeState(stateName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A lifecycle method is called when the state is ending.
|
||||
* @returns info to pass to the next state
|
||||
*/
|
||||
abstract onExit(): void;
|
||||
abstract onExit(): Record<string, any>;
|
||||
}
|
|
@ -67,9 +67,10 @@ export default class StateMachine implements Updateable {
|
|||
* Initializes this state machine with an initial state and sets it running
|
||||
* @param initialState The name of initial state of the state machine
|
||||
*/
|
||||
initialize(initialState: string): void {
|
||||
initialize(initialState: string, options: Record<string, any> = {}): void {
|
||||
this.stack.push(this.stateMap.get(initialState));
|
||||
this.currentState = this.stack.peek();
|
||||
this.currentState.onEnter(options);
|
||||
this.setActive(true);
|
||||
}
|
||||
|
||||
|
@ -88,7 +89,7 @@ export default class StateMachine implements Updateable {
|
|||
*/
|
||||
changeState(state: string): void {
|
||||
// Exit the current state
|
||||
this.currentState.onExit();
|
||||
let options = this.currentState.onExit();
|
||||
|
||||
// Make sure the correct state is at the top of the stack
|
||||
if(state === "previous"){
|
||||
|
@ -109,7 +110,7 @@ export default class StateMachine implements Updateable {
|
|||
}
|
||||
|
||||
// Enter the new state
|
||||
this.currentState.onEnter();
|
||||
this.currentState.onEnter(options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,6 +125,12 @@ export default class StateMachine implements Updateable {
|
|||
|
||||
// @implemented
|
||||
update(deltaT: number): void {
|
||||
// Distribute events
|
||||
while(this.receiver.hasNextEvent()){
|
||||
let event = this.receiver.getNextEvent();
|
||||
this.handleEvent(event);
|
||||
}
|
||||
|
||||
// Delegate the update to the current state
|
||||
this.currentState.update(deltaT);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,10 @@ export default class Vec2 {
|
|||
* @returns A new vector that is the unit vector for this one
|
||||
*/
|
||||
normalized(): Vec2 {
|
||||
if(this.isZero()){
|
||||
return this;
|
||||
}
|
||||
|
||||
let mag = this.mag();
|
||||
return new Vec2(this.x/mag, this.y/mag);
|
||||
}
|
||||
|
@ -235,6 +239,23 @@ export default class Vec2 {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the fields of this vector. Both are incremented with a, if only a is provided.
|
||||
* @param a The first number to increment by
|
||||
* @param b The second number to increment by
|
||||
* @returnss This vector after incrementing
|
||||
*/
|
||||
inc(a: number, b?: number): Vec2 {
|
||||
if(b === undefined){
|
||||
this.x += a;
|
||||
this.y += a;
|
||||
} else {
|
||||
this.x += a;
|
||||
this.y += b;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts another vector from this vector
|
||||
* @param other The Vec2 to subtract from this one
|
||||
|
|
|
@ -260,7 +260,7 @@ export default class Input {
|
|||
* @returns The mouse position stored as a Vec2
|
||||
*/
|
||||
static getMousePosition(): Vec2 {
|
||||
return Input.mousePosition;
|
||||
return Input.mousePosition.scaled(1/this.viewport.getZoomLevel());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,7 +269,7 @@ export default class Input {
|
|||
* @returns The mouse position stored as a Vec2
|
||||
*/
|
||||
static getGlobalMousePosition(): Vec2 {
|
||||
return Input.mousePosition.clone().add(Input.viewport.getOrigin());
|
||||
return Input.mousePosition.clone().scale(1/this.viewport.getZoomLevel()).add(Input.viewport.getOrigin());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ import GameLoop from "./GameLoop";
|
|||
import FixedUpdateGameLoop from "./FixedUpdateGameLoop";
|
||||
import EnvironmentInitializer from "./EnvironmentInitializer";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
import Registry from "../Registry/Registry";
|
||||
import RegistryManager from "../Registry/RegistryManager";
|
||||
import WebGLRenderer from "../Rendering/WebGLRenderer";
|
||||
import Scene from "../Scene/Scene";
|
||||
|
||||
|
@ -139,7 +139,7 @@ export default class Game {
|
|||
this.loop.doRender = () => this.render();
|
||||
|
||||
// Preload registry items
|
||||
Registry.preload();
|
||||
RegistryManager.preload();
|
||||
|
||||
// Load the items with the resource manager
|
||||
this.resourceManager.loadResourcesFromQueue(() => {
|
||||
|
@ -185,6 +185,11 @@ export default class Game {
|
|||
|
||||
this.sceneManager.render();
|
||||
|
||||
// Hacky debug mode
|
||||
if(Input.isKeyJustPressed("g")){
|
||||
this.showDebug = !this.showDebug;
|
||||
}
|
||||
|
||||
// Debug render
|
||||
if(this.showDebug){
|
||||
Debug.render();
|
||||
|
|
|
@ -109,7 +109,6 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
inRelativeCoordinates(point: Vec2): Vec2 {
|
||||
let origin = this.scene.getViewTranslation(this);
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
return point.clone().sub(origin).scale(zoom);
|
||||
}
|
||||
|
||||
|
@ -137,6 +136,14 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
this._velocity = velocity;
|
||||
};
|
||||
|
||||
moveOnPath(speed: number, path: NavigationPath): void {
|
||||
this.path = path;
|
||||
let dir = path.getMoveDirection(this);
|
||||
this.moving = true;
|
||||
this.pathfinding = true;
|
||||
this._velocity = dir.scale(speed);
|
||||
}
|
||||
|
||||
// @implemented
|
||||
/**
|
||||
* @param velocity The velocity with which the object will move.
|
||||
|
@ -146,6 +153,8 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
this.position.add(this._velocity);
|
||||
if(this.pathfinding){
|
||||
this.path.handlePathProgress(this);
|
||||
this.path = null;
|
||||
this.pathfinding = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,7 +275,9 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
// @implemented
|
||||
setAIActive(active: boolean, options: Record<string, any>): void {
|
||||
this.aiActive = active;
|
||||
this.ai.activate(options);
|
||||
if(this.aiActive){
|
||||
this.ai.activate(options);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------- TWEENABLE PROPERTIES ----------*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export enum GraphicType {
|
||||
POINT = "POINT",
|
||||
RECT = "RECT",
|
||||
LINE = "LINE",
|
||||
}
|
33
src/Wolfie2D/Nodes/Graphics/Line.ts
Normal file
33
src/Wolfie2D/Nodes/Graphics/Line.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import Graphic from "../Graphic";
|
||||
|
||||
export default class Line extends Graphic {
|
||||
protected _end: Vec2;
|
||||
thickness: number;
|
||||
|
||||
constructor(start: Vec2, end: Vec2){
|
||||
super();
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.thickness = 2;
|
||||
|
||||
// Does this really have a meaning for lines?
|
||||
this.size.set(5, 5);
|
||||
}
|
||||
|
||||
set start(pos: Vec2){
|
||||
this.position = pos;
|
||||
}
|
||||
|
||||
get start(): Vec2 {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
set end(pos: Vec2){
|
||||
this._end = pos;
|
||||
}
|
||||
|
||||
get end(): Vec2 {
|
||||
return this._end;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ export default abstract class Tilemap extends CanvasNode {
|
|||
|
||||
let tilecount = 0;
|
||||
for(let tileset of tilesets){
|
||||
tilecount += tileset.getTileCount();
|
||||
tilecount += tileset.getTileCount() + 1;
|
||||
}
|
||||
|
||||
this.collisionMap = new Array(tilecount);
|
||||
|
|
|
@ -19,9 +19,8 @@ export default class NavigationPath {
|
|||
*/
|
||||
constructor(path: Stack<Vec2>){
|
||||
this.path = path;
|
||||
console.log(path.toString())
|
||||
this.currentMoveDirection = Vec2.ZERO;
|
||||
this.distanceThreshold = 20;
|
||||
this.distanceThreshold = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,4 +51,8 @@ export default class NavigationPath {
|
|||
this.path.pop();
|
||||
}
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.path.toString()
|
||||
}
|
||||
}
|
21
src/Wolfie2D/Registry/Registries/Registry.ts
Normal file
21
src/Wolfie2D/Registry/Registries/Registry.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import Map from "../../DataTypes/Map";
|
||||
|
||||
export default abstract class Registry<T> extends Map<T>{
|
||||
|
||||
/** Preloads registry data */
|
||||
public abstract preload(): void;
|
||||
|
||||
/**
|
||||
* Registers an item and preloads any necessary files
|
||||
* @param key The key to register this item with
|
||||
* @param args Any additional arguments needed for registration
|
||||
*/
|
||||
public abstract registerAndPreloadItem(key: string, ...args: any): void;
|
||||
|
||||
/**
|
||||
* Registers an item and preloads any necessary files
|
||||
* @param key The key to register this item with
|
||||
* @param args Any aditional arguments needed for registration
|
||||
*/
|
||||
public abstract registerItem(key: string, ...args: any): void;
|
||||
}
|
|
@ -5,11 +5,12 @@ import PointShaderType from "../../Rendering/WebGLRendering/ShaderTypes/PointSha
|
|||
import RectShaderType from "../../Rendering/WebGLRendering/ShaderTypes/RectShaderType";
|
||||
import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType";
|
||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||
import Registry from "./Registry";
|
||||
|
||||
/**
|
||||
* A registry that handles shaders
|
||||
*/
|
||||
export default class ShaderRegistry extends Map<ShaderType> {
|
||||
export default class ShaderRegistry extends Registry<ShaderType> {
|
||||
|
||||
// Shader names
|
||||
public static POINT_SHADER = "point";
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
import ShaderRegistry from "./Registries/ShaderRegistry";
|
||||
|
||||
/**
|
||||
* The Registry is the system's way of converting classes and types into string
|
||||
* representations for use elsewhere in the application.
|
||||
* It allows classes to be accessed without explicitly using constructors in code,
|
||||
* and for resources to be loaded at Game creation time.
|
||||
*/
|
||||
export default class Registry {
|
||||
|
||||
public static shaders = new ShaderRegistry();
|
||||
|
||||
static preload(){
|
||||
this.shaders.preload();
|
||||
}
|
||||
}
|
31
src/Wolfie2D/Registry/RegistryManager.ts
Normal file
31
src/Wolfie2D/Registry/RegistryManager.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import Map from "../DataTypes/Map";
|
||||
import Registry from "./Registries/Registry";
|
||||
import ShaderRegistry from "./Registries/ShaderRegistry";
|
||||
|
||||
/**
|
||||
* The Registry is the system's way of converting classes and types into string
|
||||
* representations for use elsewhere in the application.
|
||||
* It allows classes to be accessed without explicitly using constructors in code,
|
||||
* and for resources to be loaded at Game creation time.
|
||||
*/
|
||||
export default class RegistryManager {
|
||||
|
||||
public static shaders = new ShaderRegistry();
|
||||
|
||||
/** Additional custom registries to add to the registry manager */
|
||||
protected static registries: Map<Registry<any>> = new Map();
|
||||
|
||||
static preload(){
|
||||
this.shaders.preload();
|
||||
|
||||
this.registries.forEach((key: string) => this.registries.get(key).preload());
|
||||
}
|
||||
|
||||
static addCustomRegistry(name: string, registry: Registry<any>){
|
||||
this.registries.add(name, registry);
|
||||
}
|
||||
|
||||
static getRegistry(key: string){
|
||||
return this.registries.get(key);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,8 @@ import TextInput from "../Nodes/UIElements/TextInput";
|
|||
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
import Color from "../Utils/Color";
|
||||
import Line from "../Nodes/Graphics/Line";
|
||||
import Debug from "../Debug/Debug";
|
||||
|
||||
/**
|
||||
* An implementation of the RenderingManager class using CanvasRenderingContext2D.
|
||||
|
@ -112,9 +114,19 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
}
|
||||
|
||||
// Render the uiLayers on top of everything else
|
||||
uiLayers.forEach(key => {
|
||||
if(!uiLayers.get(key).isHidden())
|
||||
uiLayers.get(key).getItems().forEach(node => this.renderNode(<CanvasNode>node))
|
||||
let sortedUILayers = new Array<UILayer>();
|
||||
|
||||
uiLayers.forEach(key => sortedUILayers.push(uiLayers.get(key)));
|
||||
|
||||
sortedUILayers = sortedUILayers.sort((ui1, ui2) => ui1.getDepth() - ui2.getDepth());
|
||||
|
||||
sortedUILayers.forEach(uiLayer => {
|
||||
if(!uiLayer.isHidden())
|
||||
uiLayer.getItems().forEach(node => {
|
||||
if((<CanvasNode>node).visible){
|
||||
this.renderNode(<CanvasNode>node)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -141,7 +153,7 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
this.ctx.setTransform(xScale, 0, 0, yScale, (node.position.x - this.origin.x)*this.zoom, (node.position.y - this.origin.y)*this.zoom);
|
||||
this.ctx.rotate(-node.rotation);
|
||||
let globalAlpha = this.ctx.globalAlpha;
|
||||
this.ctx.globalAlpha = node.alpha;
|
||||
this.ctx.globalAlpha = ((<any>node).color ? (<any>node).color.a : 1) * node.alpha;
|
||||
|
||||
if(node instanceof AnimatedSprite){
|
||||
this.renderAnimatedSprite(<AnimatedSprite>node);
|
||||
|
@ -205,6 +217,8 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
protected renderGraphic(graphic: Graphic): void {
|
||||
if(graphic instanceof Point){
|
||||
this.graphicRenderer.renderPoint(<Point>graphic, this.zoom);
|
||||
} else if(graphic instanceof Line){
|
||||
this.graphicRenderer.renderLine(<Line>graphic, this.origin, this.zoom);
|
||||
} else if(graphic instanceof Rect){
|
||||
this.graphicRenderer.renderRect(<Rect>graphic, this.zoom);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import Line from "../../Nodes/Graphics/Line";
|
||||
import Point from "../../Nodes/Graphics/Point";
|
||||
import Rect from "../../Nodes/Graphics/Rect";
|
||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||
|
@ -38,6 +40,16 @@ export default class GraphicRenderer {
|
|||
point.size.x*zoom, point.size.y*zoom);
|
||||
}
|
||||
|
||||
renderLine(line: Line, origin: Vec2, zoom: number): void {
|
||||
this.ctx.strokeStyle = line.color.toStringRGBA();
|
||||
this.ctx.lineWidth = line.thickness;
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(0, 0);
|
||||
this.ctx.lineTo((line.end.x - line.start.x)*zoom, (line.end.y - line.start.y)*zoom);
|
||||
this.ctx.closePath();
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a rect
|
||||
* @param rect The rect to render
|
||||
|
|
|
@ -13,7 +13,7 @@ import Tilemap from "../Nodes/Tilemap";
|
|||
import UIElement from "../Nodes/UIElement";
|
||||
import Label from "../Nodes/UIElements/Label";
|
||||
import ShaderRegistry from "../Registry/Registries/ShaderRegistry";
|
||||
import Registry from "../Registry/Registry";
|
||||
import RegistryManager from "../Registry/RegistryManager";
|
||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||
import ParallaxLayer from "../Scene/Layers/ParallaxLayer";
|
||||
import UILayer from "../Scene/Layers/UILayer";
|
||||
|
@ -106,13 +106,13 @@ export default class WebGLRenderer extends RenderingManager {
|
|||
}
|
||||
|
||||
protected renderSprite(sprite: Sprite): void {
|
||||
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||
let shader = RegistryManager.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||
shader.render(this.gl, options);
|
||||
}
|
||||
|
||||
protected renderAnimatedSprite(sprite: AnimatedSprite): void {
|
||||
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||
let shader = RegistryManager.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||
shader.render(this.gl, options);
|
||||
}
|
||||
|
@ -120,11 +120,11 @@ export default class WebGLRenderer extends RenderingManager {
|
|||
protected renderGraphic(graphic: Graphic): void {
|
||||
|
||||
if(graphic instanceof Point){
|
||||
let shader = Registry.shaders.get(ShaderRegistry.POINT_SHADER);
|
||||
let shader = RegistryManager.shaders.get(ShaderRegistry.POINT_SHADER);
|
||||
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||
shader.render(this.gl, options);
|
||||
} else if(graphic instanceof Rect) {
|
||||
let shader = Registry.shaders.get(ShaderRegistry.RECT_SHADER);
|
||||
let shader = RegistryManager.shaders.get(ShaderRegistry.RECT_SHADER);
|
||||
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||
shader.render(this.gl, options);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ export default class WebGLRenderer extends RenderingManager {
|
|||
|
||||
protected renderUIElement(uiElement: UIElement): void {
|
||||
if(uiElement instanceof Label){
|
||||
let shader = Registry.shaders.get(ShaderRegistry.LABEL_SHADER);
|
||||
let shader = RegistryManager.shaders.get(ShaderRegistry.LABEL_SHADER);
|
||||
let options = this.addOptions(shader.getOptions(uiElement), uiElement);
|
||||
shader.render(this.gl, options);
|
||||
|
||||
|
@ -158,7 +158,7 @@ export default class WebGLRenderer extends RenderingManager {
|
|||
}
|
||||
|
||||
protected renderCustom(node: CanvasNode): void {
|
||||
let shader = Registry.shaders.get(node.customShaderKey);
|
||||
let shader = RegistryManager.shaders.get(node.customShaderKey);
|
||||
let options = this.addOptions(shader.getOptions(node), node);
|
||||
shader.render(this.gl, options);
|
||||
}
|
||||
|
|
|
@ -69,6 +69,11 @@ export default class ResourceManager {
|
|||
/** The total number of "types" of things that need to be loaded (i.e. images and tilemaps) */
|
||||
private loadonly_typesToLoad: number;
|
||||
|
||||
private loadonly_jsonLoaded: number;
|
||||
private loadonly_jsonToLoad: number;
|
||||
private loadonly_jsonLoadingQueue: Queue<KeyPathPair>;
|
||||
private jsonObjects: Map<Record<string, any>>;
|
||||
|
||||
/* ########## INFORMATION SPECIAL TO WEBGL ########## */
|
||||
private gl_WebGLActive: boolean;
|
||||
|
||||
|
@ -109,6 +114,11 @@ export default class ResourceManager {
|
|||
this.loadonly_audioLoadingQueue = new Queue();
|
||||
this.audioBuffers = new Map();
|
||||
|
||||
this.loadonly_jsonLoaded = 0;
|
||||
this.loadonly_jsonToLoad = 0;
|
||||
this.loadonly_jsonLoadingQueue = new Queue();
|
||||
this.jsonObjects = new Map();
|
||||
|
||||
this.loadonly_gl_ShaderProgramsLoaded = 0;
|
||||
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
||||
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
||||
|
@ -222,6 +232,24 @@ export default class ResourceManager {
|
|||
return this.tilemaps.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an object from a json file.
|
||||
* @param key The key to associate with the loaded object
|
||||
* @param path The path to the json file to load
|
||||
*/
|
||||
public object(key: string, path: string){
|
||||
this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives a loaded object
|
||||
* @param key The key of the loaded object
|
||||
* @returns The object data associated with the key
|
||||
*/
|
||||
public getObject(key: string){
|
||||
return this.jsonObjects.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all resources currently in the queue
|
||||
* @param callback The function to cal when the resources are finished loading
|
||||
|
@ -240,15 +268,18 @@ export default class ResourceManager {
|
|||
console.log("Loaded Images");
|
||||
this.loadAudioFromQueue(() => {
|
||||
console.log("Loaded Audio");
|
||||
|
||||
if(this.gl_WebGLActive){
|
||||
this.gl_LoadShadersFromQueue(() => {
|
||||
console.log("Loaded Shaders");
|
||||
this.loadObjectsFromQueue(() => {
|
||||
console.log("Loaded Objects");
|
||||
|
||||
if(this.gl_WebGLActive){
|
||||
this.gl_LoadShadersFromQueue(() => {
|
||||
console.log("Loaded Shaders");
|
||||
this.finishLoading(callback);
|
||||
});
|
||||
} else {
|
||||
this.finishLoading(callback);
|
||||
});
|
||||
} else {
|
||||
this.finishLoading(callback);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -303,6 +334,7 @@ export default class ResourceManager {
|
|||
// If no items to load, we're finished
|
||||
if(this.loadonly_tilemapsToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_tilemapLoadingQueue.hasItems()){
|
||||
|
@ -368,6 +400,7 @@ export default class ResourceManager {
|
|||
// If no items to load, we're finished
|
||||
if(this.loadonly_spritesheetsToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_spritesheetLoadingQueue.hasItems()){
|
||||
|
@ -422,6 +455,7 @@ export default class ResourceManager {
|
|||
// If no items to load, we're finished
|
||||
if(this.loadonly_imagesToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_imageLoadingQueue.hasItems()){
|
||||
|
@ -479,6 +513,7 @@ export default class ResourceManager {
|
|||
// If no items to load, we're finished
|
||||
if(this.loadonly_audioToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_audioLoadingQueue.hasItems()){
|
||||
|
@ -527,6 +562,53 @@ export default class ResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects currently in the object loading queue
|
||||
* @param onFinishLoading The function to call when there are no more objects to load
|
||||
*/
|
||||
private loadObjectsFromQueue(onFinishLoading: Function): void {
|
||||
this.loadonly_jsonToLoad = this.loadonly_jsonLoadingQueue.getSize();
|
||||
this.loadonly_jsonLoaded = 0;
|
||||
|
||||
// If no items to load, we're finished
|
||||
if(this.loadonly_jsonToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_jsonLoadingQueue.hasItems()){
|
||||
let obj = this.loadonly_jsonLoadingQueue.dequeue();
|
||||
this.loadObject(obj.key, obj.path, onFinishLoading);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a singular object
|
||||
* @param key The key of the object to load
|
||||
* @param path The path to the object to load
|
||||
* @param callbackIfLast The function to call if this is the last object
|
||||
*/
|
||||
public loadObject(key: string, path: string, callbackIfLast: Function): void {
|
||||
this.loadTextFile(path, (fileText: string) => {
|
||||
let obj = JSON.parse(fileText);
|
||||
this.jsonObjects.add(key, obj);
|
||||
this.finishLoadingObject(callbackIfLast);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish loading an object. If this is the last object, it calls the callback function
|
||||
* @param callback The function to call if this is the last object
|
||||
*/
|
||||
private finishLoadingObject(callback: Function): void {
|
||||
this.loadonly_jsonLoaded += 1;
|
||||
|
||||
if(this.loadonly_jsonLoaded === this.loadonly_jsonToLoad){
|
||||
// We're done loading objects
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
/* ########## WEBGL SPECIFIC FUNCTIONS ########## */
|
||||
|
||||
public getTexture(key: string): number {
|
||||
|
@ -631,6 +713,7 @@ export default class ResourceManager {
|
|||
// If webGL isn'active or there are no items to load, we're finished
|
||||
if(!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0){
|
||||
onFinishLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
while(this.loadonly_gl_ShaderLoadingQueue.hasItems()){
|
||||
|
|
|
@ -13,6 +13,7 @@ import Slider from "../../Nodes/UIElements/Slider";
|
|||
import TextInput from "../../Nodes/UIElements/TextInput";
|
||||
import Rect from "../../Nodes/Graphics/Rect";
|
||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||
import Line from "../../Nodes/Graphics/Line";
|
||||
|
||||
// @ignorePage
|
||||
|
||||
|
@ -135,10 +136,13 @@ export default class CanvasNodeFactory {
|
|||
switch(type){
|
||||
case GraphicType.POINT:
|
||||
instance = this.buildPoint(options);
|
||||
break;
|
||||
break;
|
||||
case GraphicType.LINE:
|
||||
instance = this.buildLine(options);
|
||||
break;
|
||||
case GraphicType.RECT:
|
||||
instance = this.buildRect(options);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
throw `GraphicType '${type}' does not exist, or is registered incorrectly.`
|
||||
}
|
||||
|
@ -191,6 +195,13 @@ export default class CanvasNodeFactory {
|
|||
return new Point(options.position);
|
||||
}
|
||||
|
||||
buildLine(options?: Record<string, any>): Point {
|
||||
this.checkIfPropExists("Line", options, "start", Vec2, "Vec2");
|
||||
this.checkIfPropExists("Line", options, "end", Vec2, "Vec2");
|
||||
|
||||
return new Line(options.start, options.end);
|
||||
}
|
||||
|
||||
buildRect(options?: Record<string, any>): Rect {
|
||||
this.checkIfPropExists("Rect", options, "position", Vec2, "Vec2");
|
||||
this.checkIfPropExists("Rect", options, "size", Vec2, "Vec2");
|
||||
|
|
|
@ -159,6 +159,24 @@ export default class Layer {
|
|||
node.setLayer(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a node from this layer
|
||||
* @param node The node to remove
|
||||
* @returns true if the node was removed, false otherwise
|
||||
*/
|
||||
removeNode(node: GameNode): boolean {
|
||||
// Find and remove the node
|
||||
for(let i = 0; i < this.items.length; i++){
|
||||
if(this.items[i].id === node.id){
|
||||
this.items.splice(i, 1);
|
||||
node.setLayer(null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives all GameNodes from this layer
|
||||
* @returns an Array that contains all of the GameNodes in this layer.
|
||||
|
|
|
@ -23,6 +23,7 @@ import GameNode from "../Nodes/GameNode";
|
|||
import SceneOptions from "./SceneOptions";
|
||||
import RenderingManager from "../Rendering/RenderingManager";
|
||||
import Debug from "../Debug/Debug";
|
||||
import TimerManager from "../Timing/TimerManager";
|
||||
|
||||
/**
|
||||
* Scenes are the main container in the game engine.
|
||||
|
@ -119,6 +120,9 @@ export default class Scene implements Updateable {
|
|||
this.add = new FactoryManager(this, this.tilemaps);
|
||||
|
||||
this.load = ResourceManager.getInstance();
|
||||
|
||||
// Get the timer manager and clear any existing timers
|
||||
TimerManager.getInstance().clearTimers();
|
||||
}
|
||||
|
||||
/** A lifecycle method that gets called immediately after a new scene is created, before anything else. */
|
||||
|
@ -142,6 +146,9 @@ export default class Scene implements Updateable {
|
|||
update(deltaT: number): void {
|
||||
this.updateScene(deltaT);
|
||||
|
||||
// Do time updates
|
||||
TimerManager.getInstance().update(deltaT);
|
||||
|
||||
// Do all AI updates
|
||||
this.aiManager.update(deltaT);
|
||||
|
||||
|
|
80
src/Wolfie2D/Timing/Timer.ts
Normal file
80
src/Wolfie2D/Timing/Timer.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import Updateable from "../DataTypes/Interfaces/Updateable";
|
||||
import MathUtils from "../Utils/MathUtils";
|
||||
import TimerManager from "./TimerManager";
|
||||
|
||||
export default class Timer implements Updateable {
|
||||
|
||||
protected state: TimerState;
|
||||
protected onEnd: Function;
|
||||
protected loop: boolean;
|
||||
protected totalTime: number;
|
||||
protected timeLeft: number;
|
||||
|
||||
constructor(time: number, onEnd?: Function, loop: boolean = false){
|
||||
// Register this timer
|
||||
TimerManager.getInstance().addTimer(this);
|
||||
|
||||
this.totalTime = time;
|
||||
this.timeLeft = 0;
|
||||
this.onEnd = onEnd;
|
||||
this.loop = loop;
|
||||
this.state = TimerState.STOPPED;
|
||||
}
|
||||
|
||||
isStopped(){
|
||||
return this.state === TimerState.STOPPED;
|
||||
}
|
||||
|
||||
isPaused(){
|
||||
return this.state === TimerState.PAUSED;
|
||||
}
|
||||
|
||||
start(time?: number){
|
||||
if(time !== undefined){
|
||||
this.totalTime = time;
|
||||
}
|
||||
this.state = TimerState.ACTIVE;
|
||||
this.timeLeft = this.totalTime;
|
||||
}
|
||||
|
||||
pause(): void {
|
||||
this.state = TimerState.PAUSED;
|
||||
}
|
||||
|
||||
update(deltaT: number){
|
||||
if(this.state === TimerState.ACTIVE){
|
||||
this.timeLeft -= deltaT*1000;
|
||||
|
||||
if(this.timeLeft <= 0){
|
||||
this.timeLeft = MathUtils.clampLow0(this.timeLeft);
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected end(){
|
||||
// Update the state
|
||||
this.state = TimerState.STOPPED;
|
||||
|
||||
// Call the end function if there is one
|
||||
if(this.onEnd){
|
||||
this.onEnd();
|
||||
}
|
||||
|
||||
// Loop if we want to
|
||||
if(this.loop){
|
||||
this.state = TimerState.ACTIVE;
|
||||
this.timeLeft = this.totalTime;
|
||||
}
|
||||
}
|
||||
|
||||
toString(): string{
|
||||
return "Timer: " + this.state + " - Time Left: " + this.timeLeft + "ms of " + this.totalTime + "ms";
|
||||
}
|
||||
}
|
||||
|
||||
export enum TimerState {
|
||||
ACTIVE = "ACTIVE",
|
||||
PAUSED = "PAUSED",
|
||||
STOPPED = "STOPPED"
|
||||
}
|
33
src/Wolfie2D/Timing/TimerManager.ts
Normal file
33
src/Wolfie2D/Timing/TimerManager.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import Updateable from "../DataTypes/Interfaces/Updateable";
|
||||
import Timer from "./Timer";
|
||||
|
||||
export default class TimerManager implements Updateable {
|
||||
|
||||
protected timers: Array<Timer>;
|
||||
|
||||
constructor(){
|
||||
this.timers = new Array();
|
||||
}
|
||||
|
||||
protected static instance: TimerManager;
|
||||
|
||||
static getInstance(): TimerManager {
|
||||
if(!this.instance){
|
||||
this.instance = new TimerManager();
|
||||
}
|
||||
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
addTimer(timer: Timer){
|
||||
this.timers.push(timer);
|
||||
}
|
||||
|
||||
clearTimers(){
|
||||
this.timers = new Array();
|
||||
}
|
||||
|
||||
update(deltaT: number): void {
|
||||
this.timers.forEach(timer => timer.update(deltaT));
|
||||
}
|
||||
}
|
|
@ -185,4 +185,13 @@ export default class Color {
|
|||
this.a
|
||||
]);
|
||||
}
|
||||
|
||||
static fromStringHex(str: string): Color {
|
||||
let i = 0;
|
||||
if(str.charAt(0) == "#") i+= 1;
|
||||
let r = MathUtils.fromHex(str.substring(i, i+2));
|
||||
let g = MathUtils.fromHex(str.substring(i+2, i+4));
|
||||
let b = MathUtils.fromHex(str.substring(i+4, i+6));
|
||||
return new Color(r, g, b);
|
||||
}
|
||||
}
|
|
@ -49,6 +49,25 @@ export default class MathUtils {
|
|||
return MathUtils.clamp(x, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the lower end of the value of x to the range to min
|
||||
* @param x The value to be clamped
|
||||
* @param min The minimum allowed value of x
|
||||
* @returns x, if it is greater than min, otherwise min
|
||||
*/
|
||||
static clampLow(x: number, min: number): number {
|
||||
return x < min ? min : x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the lower end of the value of x to zero
|
||||
* @param x The value to be clamped
|
||||
* @returns x, if it is greater than 0, otherwise 0
|
||||
*/
|
||||
static clampLow0(x: number): number {
|
||||
return MathUtils.clampLow(x, 0);
|
||||
}
|
||||
|
||||
static clampMagnitude(v: Vec2, m: number): Vec2 {
|
||||
if(v.magSq() > m*m){
|
||||
return v.scaleTo(m);
|
||||
|
@ -104,6 +123,15 @@ export default class MathUtils {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number from a hex string
|
||||
* @param str the string containing the hex number
|
||||
* @returns the number in decimal represented by the hex string
|
||||
*/
|
||||
static fromHex(str: string): number {
|
||||
return parseInt(str, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number as a hexadecimal
|
||||
* @param num The number to convert to hex
|
||||
|
|
Loading…
Reference in New Issue
Block a user