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 {
|
addEdge(x: number, y: number, weight?: number): void {
|
||||||
let edge = new EdgeNode(y, weight);
|
let edge = new EdgeNode(y, weight);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(this.edges[x]){
|
if(this.edges[x]){
|
||||||
edge.next = this.edges[x];
|
edge.next = this.edges[x];
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,24 @@ export default class Graph {
|
||||||
this.numEdges += 1;
|
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
|
* Gets the edge list associated with node x
|
||||||
* @param x The index of the node
|
* @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
|
* @param options An object that allows options to be pased to the activated AI
|
||||||
*/
|
*/
|
||||||
setAIActive(active: boolean, options: Record<string, any>): void;
|
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;
|
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.
|
* 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.
|
* 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
|
* @param stateName The name of the state to transition to
|
||||||
*/
|
*/
|
||||||
protected finished(stateName: string): void {
|
protected finished(stateName: string): void {
|
||||||
|
console.log("Finished");
|
||||||
this.parent.changeState(stateName);
|
this.parent.changeState(stateName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lifecycle method is called when the state is ending.
|
* 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
|
* Initializes this state machine with an initial state and sets it running
|
||||||
* @param initialState The name of initial state of the state machine
|
* @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.stack.push(this.stateMap.get(initialState));
|
||||||
this.currentState = this.stack.peek();
|
this.currentState = this.stack.peek();
|
||||||
|
this.currentState.onEnter(options);
|
||||||
this.setActive(true);
|
this.setActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ export default class StateMachine implements Updateable {
|
||||||
*/
|
*/
|
||||||
changeState(state: string): void {
|
changeState(state: string): void {
|
||||||
// Exit the current state
|
// Exit the current state
|
||||||
this.currentState.onExit();
|
let options = this.currentState.onExit();
|
||||||
|
|
||||||
// Make sure the correct state is at the top of the stack
|
// Make sure the correct state is at the top of the stack
|
||||||
if(state === "previous"){
|
if(state === "previous"){
|
||||||
|
@ -109,7 +110,7 @@ export default class StateMachine implements Updateable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter the new state
|
// Enter the new state
|
||||||
this.currentState.onEnter();
|
this.currentState.onEnter(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,6 +125,12 @@ export default class StateMachine implements Updateable {
|
||||||
|
|
||||||
// @implemented
|
// @implemented
|
||||||
update(deltaT: number): void {
|
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
|
// Delegate the update to the current state
|
||||||
this.currentState.update(deltaT);
|
this.currentState.update(deltaT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,10 @@ export default class Vec2 {
|
||||||
* @returns A new vector that is the unit vector for this one
|
* @returns A new vector that is the unit vector for this one
|
||||||
*/
|
*/
|
||||||
normalized(): Vec2 {
|
normalized(): Vec2 {
|
||||||
|
if(this.isZero()){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
let mag = this.mag();
|
let mag = this.mag();
|
||||||
return new Vec2(this.x/mag, this.y/mag);
|
return new Vec2(this.x/mag, this.y/mag);
|
||||||
}
|
}
|
||||||
|
@ -235,6 +239,23 @@ export default class Vec2 {
|
||||||
return this;
|
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
|
* Subtracts another vector from this vector
|
||||||
* @param other The Vec2 to subtract from this one
|
* @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
|
* @returns The mouse position stored as a Vec2
|
||||||
*/
|
*/
|
||||||
static getMousePosition(): 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
|
* @returns The mouse position stored as a Vec2
|
||||||
*/
|
*/
|
||||||
static getGlobalMousePosition(): 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 FixedUpdateGameLoop from "./FixedUpdateGameLoop";
|
||||||
import EnvironmentInitializer from "./EnvironmentInitializer";
|
import EnvironmentInitializer from "./EnvironmentInitializer";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
import Registry from "../Registry/Registry";
|
import RegistryManager from "../Registry/RegistryManager";
|
||||||
import WebGLRenderer from "../Rendering/WebGLRenderer";
|
import WebGLRenderer from "../Rendering/WebGLRenderer";
|
||||||
import Scene from "../Scene/Scene";
|
import Scene from "../Scene/Scene";
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ export default class Game {
|
||||||
this.loop.doRender = () => this.render();
|
this.loop.doRender = () => this.render();
|
||||||
|
|
||||||
// Preload registry items
|
// Preload registry items
|
||||||
Registry.preload();
|
RegistryManager.preload();
|
||||||
|
|
||||||
// Load the items with the resource manager
|
// Load the items with the resource manager
|
||||||
this.resourceManager.loadResourcesFromQueue(() => {
|
this.resourceManager.loadResourcesFromQueue(() => {
|
||||||
|
@ -185,6 +185,11 @@ export default class Game {
|
||||||
|
|
||||||
this.sceneManager.render();
|
this.sceneManager.render();
|
||||||
|
|
||||||
|
// Hacky debug mode
|
||||||
|
if(Input.isKeyJustPressed("g")){
|
||||||
|
this.showDebug = !this.showDebug;
|
||||||
|
}
|
||||||
|
|
||||||
// Debug render
|
// Debug render
|
||||||
if(this.showDebug){
|
if(this.showDebug){
|
||||||
Debug.render();
|
Debug.render();
|
||||||
|
|
|
@ -109,7 +109,6 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
inRelativeCoordinates(point: Vec2): Vec2 {
|
inRelativeCoordinates(point: Vec2): Vec2 {
|
||||||
let origin = this.scene.getViewTranslation(this);
|
let origin = this.scene.getViewTranslation(this);
|
||||||
let zoom = this.scene.getViewScale();
|
let zoom = this.scene.getViewScale();
|
||||||
|
|
||||||
return point.clone().sub(origin).scale(zoom);
|
return point.clone().sub(origin).scale(zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +136,14 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
this._velocity = velocity;
|
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
|
// @implemented
|
||||||
/**
|
/**
|
||||||
* @param velocity The velocity with which the object will move.
|
* @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);
|
this.position.add(this._velocity);
|
||||||
if(this.pathfinding){
|
if(this.pathfinding){
|
||||||
this.path.handlePathProgress(this);
|
this.path.handlePathProgress(this);
|
||||||
|
this.path = null;
|
||||||
|
this.pathfinding = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +275,10 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
// @implemented
|
// @implemented
|
||||||
setAIActive(active: boolean, options: Record<string, any>): void {
|
setAIActive(active: boolean, options: Record<string, any>): void {
|
||||||
this.aiActive = active;
|
this.aiActive = active;
|
||||||
|
if(this.aiActive){
|
||||||
this.ai.activate(options);
|
this.ai.activate(options);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*---------- TWEENABLE PROPERTIES ----------*/
|
/*---------- TWEENABLE PROPERTIES ----------*/
|
||||||
set positionX(value: number) {
|
set positionX(value: number) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export enum GraphicType {
|
export enum GraphicType {
|
||||||
POINT = "POINT",
|
POINT = "POINT",
|
||||||
RECT = "RECT",
|
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;
|
let tilecount = 0;
|
||||||
for(let tileset of tilesets){
|
for(let tileset of tilesets){
|
||||||
tilecount += tileset.getTileCount();
|
tilecount += tileset.getTileCount() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collisionMap = new Array(tilecount);
|
this.collisionMap = new Array(tilecount);
|
||||||
|
|
|
@ -19,9 +19,8 @@ export default class NavigationPath {
|
||||||
*/
|
*/
|
||||||
constructor(path: Stack<Vec2>){
|
constructor(path: Stack<Vec2>){
|
||||||
this.path = path;
|
this.path = path;
|
||||||
console.log(path.toString())
|
|
||||||
this.currentMoveDirection = Vec2.ZERO;
|
this.currentMoveDirection = Vec2.ZERO;
|
||||||
this.distanceThreshold = 20;
|
this.distanceThreshold = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,4 +51,8 @@ export default class NavigationPath {
|
||||||
this.path.pop();
|
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 RectShaderType from "../../Rendering/WebGLRendering/ShaderTypes/RectShaderType";
|
||||||
import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType";
|
import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType";
|
||||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||||
|
import Registry from "./Registry";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A registry that handles shaders
|
* A registry that handles shaders
|
||||||
*/
|
*/
|
||||||
export default class ShaderRegistry extends Map<ShaderType> {
|
export default class ShaderRegistry extends Registry<ShaderType> {
|
||||||
|
|
||||||
// Shader names
|
// Shader names
|
||||||
public static POINT_SHADER = "point";
|
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 AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
import Color from "../Utils/Color";
|
import Color from "../Utils/Color";
|
||||||
|
import Line from "../Nodes/Graphics/Line";
|
||||||
|
import Debug from "../Debug/Debug";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the RenderingManager class using CanvasRenderingContext2D.
|
* 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
|
// Render the uiLayers on top of everything else
|
||||||
uiLayers.forEach(key => {
|
let sortedUILayers = new Array<UILayer>();
|
||||||
if(!uiLayers.get(key).isHidden())
|
|
||||||
uiLayers.get(key).getItems().forEach(node => this.renderNode(<CanvasNode>node))
|
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.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);
|
this.ctx.rotate(-node.rotation);
|
||||||
let globalAlpha = this.ctx.globalAlpha;
|
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){
|
if(node instanceof AnimatedSprite){
|
||||||
this.renderAnimatedSprite(<AnimatedSprite>node);
|
this.renderAnimatedSprite(<AnimatedSprite>node);
|
||||||
|
@ -205,6 +217,8 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
protected renderGraphic(graphic: Graphic): void {
|
protected renderGraphic(graphic: Graphic): void {
|
||||||
if(graphic instanceof Point){
|
if(graphic instanceof Point){
|
||||||
this.graphicRenderer.renderPoint(<Point>graphic, this.zoom);
|
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){
|
} else if(graphic instanceof Rect){
|
||||||
this.graphicRenderer.renderRect(<Rect>graphic, this.zoom);
|
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 Point from "../../Nodes/Graphics/Point";
|
||||||
import Rect from "../../Nodes/Graphics/Rect";
|
import Rect from "../../Nodes/Graphics/Rect";
|
||||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||||
|
@ -38,6 +40,16 @@ export default class GraphicRenderer {
|
||||||
point.size.x*zoom, point.size.y*zoom);
|
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
|
* Renders a rect
|
||||||
* @param rect The rect to render
|
* @param rect The rect to render
|
||||||
|
|
|
@ -13,7 +13,7 @@ import Tilemap from "../Nodes/Tilemap";
|
||||||
import UIElement from "../Nodes/UIElement";
|
import UIElement from "../Nodes/UIElement";
|
||||||
import Label from "../Nodes/UIElements/Label";
|
import Label from "../Nodes/UIElements/Label";
|
||||||
import ShaderRegistry from "../Registry/Registries/ShaderRegistry";
|
import ShaderRegistry from "../Registry/Registries/ShaderRegistry";
|
||||||
import Registry from "../Registry/Registry";
|
import RegistryManager from "../Registry/RegistryManager";
|
||||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||||
import ParallaxLayer from "../Scene/Layers/ParallaxLayer";
|
import ParallaxLayer from "../Scene/Layers/ParallaxLayer";
|
||||||
import UILayer from "../Scene/Layers/UILayer";
|
import UILayer from "../Scene/Layers/UILayer";
|
||||||
|
@ -106,13 +106,13 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderSprite(sprite: Sprite): void {
|
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);
|
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderAnimatedSprite(sprite: AnimatedSprite): void {
|
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);
|
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
|
@ -120,11 +120,11 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
protected renderGraphic(graphic: Graphic): void {
|
protected renderGraphic(graphic: Graphic): void {
|
||||||
|
|
||||||
if(graphic instanceof Point){
|
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);
|
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
} else if(graphic instanceof Rect) {
|
} 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);
|
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
|
|
||||||
protected renderUIElement(uiElement: UIElement): void {
|
protected renderUIElement(uiElement: UIElement): void {
|
||||||
if(uiElement instanceof Label){
|
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);
|
let options = this.addOptions(shader.getOptions(uiElement), uiElement);
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderCustom(node: CanvasNode): void {
|
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);
|
let options = this.addOptions(shader.getOptions(node), node);
|
||||||
shader.render(this.gl, options);
|
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) */
|
/** The total number of "types" of things that need to be loaded (i.e. images and tilemaps) */
|
||||||
private loadonly_typesToLoad: number;
|
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 ########## */
|
/* ########## INFORMATION SPECIAL TO WEBGL ########## */
|
||||||
private gl_WebGLActive: boolean;
|
private gl_WebGLActive: boolean;
|
||||||
|
|
||||||
|
@ -109,6 +114,11 @@ export default class ResourceManager {
|
||||||
this.loadonly_audioLoadingQueue = new Queue();
|
this.loadonly_audioLoadingQueue = new Queue();
|
||||||
this.audioBuffers = new Map();
|
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_ShaderProgramsLoaded = 0;
|
||||||
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
||||||
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
||||||
|
@ -222,6 +232,24 @@ export default class ResourceManager {
|
||||||
return this.tilemaps.get(key);
|
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
|
* Loads all resources currently in the queue
|
||||||
* @param callback The function to cal when the resources are finished loading
|
* @param callback The function to cal when the resources are finished loading
|
||||||
|
@ -240,6 +268,8 @@ export default class ResourceManager {
|
||||||
console.log("Loaded Images");
|
console.log("Loaded Images");
|
||||||
this.loadAudioFromQueue(() => {
|
this.loadAudioFromQueue(() => {
|
||||||
console.log("Loaded Audio");
|
console.log("Loaded Audio");
|
||||||
|
this.loadObjectsFromQueue(() => {
|
||||||
|
console.log("Loaded Objects");
|
||||||
|
|
||||||
if(this.gl_WebGLActive){
|
if(this.gl_WebGLActive){
|
||||||
this.gl_LoadShadersFromQueue(() => {
|
this.gl_LoadShadersFromQueue(() => {
|
||||||
|
@ -249,6 +279,7 @@ export default class ResourceManager {
|
||||||
} else {
|
} else {
|
||||||
this.finishLoading(callback);
|
this.finishLoading(callback);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -303,6 +334,7 @@ export default class ResourceManager {
|
||||||
// If no items to load, we're finished
|
// If no items to load, we're finished
|
||||||
if(this.loadonly_tilemapsToLoad === 0){
|
if(this.loadonly_tilemapsToLoad === 0){
|
||||||
onFinishLoading();
|
onFinishLoading();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(this.loadonly_tilemapLoadingQueue.hasItems()){
|
while(this.loadonly_tilemapLoadingQueue.hasItems()){
|
||||||
|
@ -368,6 +400,7 @@ export default class ResourceManager {
|
||||||
// If no items to load, we're finished
|
// If no items to load, we're finished
|
||||||
if(this.loadonly_spritesheetsToLoad === 0){
|
if(this.loadonly_spritesheetsToLoad === 0){
|
||||||
onFinishLoading();
|
onFinishLoading();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(this.loadonly_spritesheetLoadingQueue.hasItems()){
|
while(this.loadonly_spritesheetLoadingQueue.hasItems()){
|
||||||
|
@ -422,6 +455,7 @@ export default class ResourceManager {
|
||||||
// If no items to load, we're finished
|
// If no items to load, we're finished
|
||||||
if(this.loadonly_imagesToLoad === 0){
|
if(this.loadonly_imagesToLoad === 0){
|
||||||
onFinishLoading();
|
onFinishLoading();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(this.loadonly_imageLoadingQueue.hasItems()){
|
while(this.loadonly_imageLoadingQueue.hasItems()){
|
||||||
|
@ -479,6 +513,7 @@ export default class ResourceManager {
|
||||||
// If no items to load, we're finished
|
// If no items to load, we're finished
|
||||||
if(this.loadonly_audioToLoad === 0){
|
if(this.loadonly_audioToLoad === 0){
|
||||||
onFinishLoading();
|
onFinishLoading();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(this.loadonly_audioLoadingQueue.hasItems()){
|
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 ########## */
|
/* ########## WEBGL SPECIFIC FUNCTIONS ########## */
|
||||||
|
|
||||||
public getTexture(key: string): number {
|
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 webGL isn'active or there are no items to load, we're finished
|
||||||
if(!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0){
|
if(!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0){
|
||||||
onFinishLoading();
|
onFinishLoading();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(this.loadonly_gl_ShaderLoadingQueue.hasItems()){
|
while(this.loadonly_gl_ShaderLoadingQueue.hasItems()){
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Slider from "../../Nodes/UIElements/Slider";
|
||||||
import TextInput from "../../Nodes/UIElements/TextInput";
|
import TextInput from "../../Nodes/UIElements/TextInput";
|
||||||
import Rect from "../../Nodes/Graphics/Rect";
|
import Rect from "../../Nodes/Graphics/Rect";
|
||||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||||
|
import Line from "../../Nodes/Graphics/Line";
|
||||||
|
|
||||||
// @ignorePage
|
// @ignorePage
|
||||||
|
|
||||||
|
@ -136,6 +137,9 @@ export default class CanvasNodeFactory {
|
||||||
case GraphicType.POINT:
|
case GraphicType.POINT:
|
||||||
instance = this.buildPoint(options);
|
instance = this.buildPoint(options);
|
||||||
break;
|
break;
|
||||||
|
case GraphicType.LINE:
|
||||||
|
instance = this.buildLine(options);
|
||||||
|
break;
|
||||||
case GraphicType.RECT:
|
case GraphicType.RECT:
|
||||||
instance = this.buildRect(options);
|
instance = this.buildRect(options);
|
||||||
break;
|
break;
|
||||||
|
@ -191,6 +195,13 @@ export default class CanvasNodeFactory {
|
||||||
return new Point(options.position);
|
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 {
|
buildRect(options?: Record<string, any>): Rect {
|
||||||
this.checkIfPropExists("Rect", options, "position", Vec2, "Vec2");
|
this.checkIfPropExists("Rect", options, "position", Vec2, "Vec2");
|
||||||
this.checkIfPropExists("Rect", options, "size", Vec2, "Vec2");
|
this.checkIfPropExists("Rect", options, "size", Vec2, "Vec2");
|
||||||
|
|
|
@ -159,6 +159,24 @@ export default class Layer {
|
||||||
node.setLayer(this);
|
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
|
* Retreives all GameNodes from this layer
|
||||||
* @returns an Array that contains all of the GameNodes in 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 SceneOptions from "./SceneOptions";
|
||||||
import RenderingManager from "../Rendering/RenderingManager";
|
import RenderingManager from "../Rendering/RenderingManager";
|
||||||
import Debug from "../Debug/Debug";
|
import Debug from "../Debug/Debug";
|
||||||
|
import TimerManager from "../Timing/TimerManager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scenes are the main container in the game engine.
|
* 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.add = new FactoryManager(this, this.tilemaps);
|
||||||
|
|
||||||
this.load = ResourceManager.getInstance();
|
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. */
|
/** 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 {
|
update(deltaT: number): void {
|
||||||
this.updateScene(deltaT);
|
this.updateScene(deltaT);
|
||||||
|
|
||||||
|
// Do time updates
|
||||||
|
TimerManager.getInstance().update(deltaT);
|
||||||
|
|
||||||
// Do all AI updates
|
// Do all AI updates
|
||||||
this.aiManager.update(deltaT);
|
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
|
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);
|
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 {
|
static clampMagnitude(v: Vec2, m: number): Vec2 {
|
||||||
if(v.magSq() > m*m){
|
if(v.magSq() > m*m){
|
||||||
return v.scaleTo(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
|
* Returns the number as a hexadecimal
|
||||||
* @param num The number to convert to hex
|
* @param num The number to convert to hex
|
||||||
|
|
Loading…
Reference in New Issue
Block a user