added resource loader

This commit is contained in:
Joe Weaver 2020-09-05 00:04:14 -04:00
parent bd49258d30
commit 214eba6e71
20 changed files with 439 additions and 257 deletions

View File

@ -4,13 +4,15 @@ export default class Queue<T> implements Collection{
private readonly MAX_ELEMENTS: number;
private q: Array<T>;
private head: number;
private tail: number;
private tail: number;
private size: number;
constructor(maxElements: number = 100){
this.MAX_ELEMENTS = maxElements;
this.q = new Array(this.MAX_ELEMENTS);
this.head = 0;
this.tail = 0;
this.size = 0;
}
enqueue(item: T): void{
@ -18,6 +20,7 @@ export default class Queue<T> implements Collection{
throw "Queue full - cannot add element"
}
this.size += 1;
this.q[this.tail] = item;
this.tail = (this.tail + 1) % this.MAX_ELEMENTS;
}
@ -27,6 +30,8 @@ export default class Queue<T> implements Collection{
throw "Queue empty - cannot remove element"
}
this.size -= 1;
let item = this.q[this.head];
this.head = (this.head + 1) % this.MAX_ELEMENTS;
@ -47,7 +52,13 @@ export default class Queue<T> implements Collection{
return this.head !== this.tail;
}
getSize(): number {
return this.size;
}
// TODO: This should actually delete the items in the queue instead of leaving them here
clear(): void {
this.size = 0;
this.head = this.tail;
}

View File

@ -0,0 +1,5 @@
export default class TileLayer {
public data: Array<number>;
public collidable: boolean;
public visible: boolean;
}

View File

@ -1,45 +0,0 @@
import Scene from "../Scene";
import Viewport from "../../SceneGraph/Viewport";
import Tilemap from "../../Nodes/Tilemap"
import ResourceManager from "../../ResourceManager/ResourceManager";
import { TiledTilemapData } from "../../DataTypes/Tilesets/TiledData";
import StringUtils from "../../Utils/StringUtils";
import StaticBody from "../../Physics/StaticBody";
import Vec2 from "../../DataTypes/Vec2";
export default class TilemapFactory {
private scene: Scene;
// TODO: get the resource manager OUT of here, it does not belong
private resourceManager: ResourceManager;
constructor(scene: Scene){
this.scene = scene;
this.resourceManager = ResourceManager.getInstance();
}
add<T extends Tilemap>(constr: new (...a: any) => T, path: string, ...args: any): void {
this.resourceManager.loadTilemap(path, (tilemapData: TiledTilemapData) => {
// For each of the layers in the tilemap, create a tilemap
for(let layer of tilemapData.layers){
let tilemap = new constr(tilemapData, layer);
tilemap.init(this.scene);
// Add to scene
this.scene.addTilemap(tilemap);
if(tilemap.isCollidable()){
// Register in physics as a tilemap
this.scene.physics.addTilemap(tilemap);
}
// Load images for the tilesets
tilemap.getTilesets().forEach(tileset => {
let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl();
this.resourceManager.loadImage(imagePath, (path: string, image: HTMLImageElement) => {
tileset.setImage(image);
})
});
}
});
}
}

View File

@ -1,45 +0,0 @@
import Stack from "../DataTypes/Stack";
import Scene from "./Scene";
import Viewport from "../SceneGraph/Viewport";
import Vec2 from "../DataTypes/Vec2";
export default class GameState{
private sceneStack: Stack<Scene>;
private worldSize: Vec2;
private viewport: Viewport;
constructor(viewport: Viewport){
this.sceneStack = new Stack(10);
this.worldSize = new Vec2(1600, 1000);
this.viewport = viewport;
this.viewport.setBounds(0, 0, 2560, 1280);
}
createScene(): Scene{
let scene = new Scene(this.viewport, this);
this.addScene(scene);
return scene;
}
addScene(scene: Scene): void {
this.sceneStack.push(scene);
}
removeScene(startNewTopScene: boolean = true): void {
this.sceneStack.pop();
this.sceneStack.peek().setPaused(!startNewTopScene);
}
changeScene(scene: Scene): void {
this.sceneStack.clear();
this.sceneStack.push(scene);
}
update(deltaT: number): void {
this.sceneStack.forEach((scene: Scene) => scene.update(deltaT));
}
render(ctx: CanvasRenderingContext2D): void {
this.sceneStack.forEach((scene: Scene) => scene.render(ctx));
}
}

View File

@ -2,10 +2,10 @@ import EventQueue from "../Events/EventQueue";
import InputReceiver from "../Input/InputReceiver";
import InputHandler from "../Input/InputHandler";
import Recorder from "../Playback/Recorder";
import GameState from "../GameState/GameState";
import Debug from "../Debug/Debug";
import ResourceManager from "../ResourceManager/ResourceManager";
import Viewport from "../SceneGraph/Viewport";
import SceneManager from "../Scene/SceneManager";
export default class GameLoop{
// The amount of time to spend on a physics step
@ -37,8 +37,8 @@ export default class GameLoop{
private inputHandler: InputHandler;
private inputReceiver: InputReceiver;
private recorder: Recorder;
private gameState: GameState;
private resourceManager: ResourceManager;
private sceneManager: SceneManager;
constructor(){
this.maxFPS = 60;
@ -66,8 +66,8 @@ export default class GameLoop{
this.inputReceiver = InputReceiver.getInstance();
this.inputReceiver.setViewport(this.viewport);
this.recorder = new Recorder();
this.gameState = new GameState(this.viewport);
this.resourceManager = ResourceManager.getInstance();
this.sceneManager = new SceneManager(this.viewport);
}
private initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): CanvasRenderingContext2D {
@ -83,8 +83,8 @@ export default class GameLoop{
this.simulationTimestep = Math.floor(1000/this.maxFPS);
}
getGameState(): GameState {
return this.gameState;
getSceneManager(): SceneManager {
return this.sceneManager;
}
private updateFrameCount(timestep: number): void {
@ -149,12 +149,12 @@ export default class GameLoop{
this.eventQueue.update(deltaT);
this.inputReceiver.update(deltaT);
this.recorder.update(deltaT);
this.gameState.update(deltaT);
this.sceneManager.update(deltaT);
}
render(): void {
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
this.gameState.render(this.ctx);
this.sceneManager.render(this.ctx);
Debug.render(this.ctx);
}
}

View File

@ -1,6 +1,6 @@
import GameNode from "./GameNode";
import Vec2 from "../DataTypes/Vec2";
import Scene from "../GameState/Scene";
import Layer from "../Scene/Layer";
export default abstract class CanvasNode extends GameNode{
protected size: Vec2;

View File

@ -4,14 +4,14 @@ import Vec2 from "../DataTypes/Vec2";
import Map from "../DataTypes/Map";
import Receiver from "../Events/Receiver";
import GameEvent from "../Events/GameEvent";
import Scene from "../GameState/Scene";
import Layer from "../Scene/Layer";
export default abstract class GameNode{
private eventQueue: EventQueue;
protected input: InputReceiver;
protected position: Vec2;
private receiver: Receiver;
protected scene: Scene;
protected scene: Layer;
constructor(){
this.eventQueue = EventQueue.getInstance();
@ -19,11 +19,11 @@ export default abstract class GameNode{
this.position = new Vec2(0, 0);
}
init(scene: Scene){
init(scene: Layer){
this.scene = scene;
}
getScene(): Scene {
getScene(): Layer {
return this.scene;
}

View File

@ -2,38 +2,28 @@ import Vec2 from "../DataTypes/Vec2";
import GameNode from "./GameNode";
import Tileset from "../DataTypes/Tilesets/Tileset";
import { TiledTilemapData, TiledLayerData } from "../DataTypes/Tilesets/TiledData"
import TileLayer from "../DataTypes/Tilesets/TileLayer";
/**
* Represents one layer of tiles
*/
export default abstract class Tilemap extends GameNode {
protected data: number[];
protected collisionData: number[];
protected tilesets: Tileset[];
protected tilesets: Array<Tileset>;
protected worldSize: Vec2;
protected tileSize: Vec2;
protected visible: boolean;
protected collidable: boolean;
protected scale: Vec2;
protected layers: Array<TileLayer>;
// TODO: Make this no longer be specific to Tiled
constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData) {
constructor(tilemapData: TiledTilemapData) {
super();
this.tilesets = new Array<Tileset>();
this.worldSize = new Vec2(0, 0);
this.tileSize = new Vec2(0, 0);
this.parseTilemapData(tilemapData, layerData);
this.parseTilemapData(tilemapData);
this.scale = new Vec2(4, 4);
}
isCollidable(): boolean {
return this.collidable;
}
isVisible(): boolean {
return this.visible;
}
getTilesets(): Tileset[] {
return this.tilesets;
}
@ -56,24 +46,11 @@ export default abstract class Tilemap extends GameNode {
abstract getTileAt(worldCoords: Vec2): number;
isReady(): boolean {
if(this.tilesets.length !== 0){
for(let tileset of this.tilesets){
if(!tileset.isReady()){
return false;
}
}
}
return true;
}
abstract forEachTile(func: Function): void;
/**
* Sets up the tileset using the data loaded from file
*/
// TODO: This shouldn't use tiled data specifically - it should be more general
protected abstract parseTilemapData(tilemapData: TiledTilemapData, layerData: TiledLayerData): void;
protected abstract parseTilemapData(tilemapData: TiledTilemapData): void;
abstract render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2): void;
}

View File

@ -2,27 +2,33 @@ import Tilemap from "../Tilemap";
import Vec2 from "../../DataTypes/Vec2";
import { TiledTilemapData, TiledLayerData } from "../../DataTypes/Tilesets/TiledData";
import Tileset from "../../DataTypes/Tilesets/Tileset";
import TileLayer from "../../DataTypes/Tilesets/TileLayer";
export default class OrthogonalTilemap extends Tilemap {
protected parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void {
protected parseTilemapData(tilemapData: TiledTilemapData): void {
this.worldSize.set(tilemapData.width, tilemapData.height);
this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight);
this.data = layer.data;
this.collisionData = this.data.map(tile => tile !== 0 ? 1 : 0);
this.visible = layer.visible;
this.collidable = false;
if(layer.properties){
for(let item of layer.properties){
if(item.name === "Collidable"){
this.collidable = item.value;
for(let layerData of tilemapData.layers){
let layer = new TileLayer();
layer.data = layer.data;
layer.visible = layer.visible;
layer.collidable = false;
if(layerData.properties){
for(let item of layerData.properties){
if(item.name === "Collidable"){
layer.collidable = item.value;
}
}
}
this.layers.push(layer);
}
tilemapData.tilesets.forEach(tilesetData => this.tilesets.push(new Tileset(tilesetData)));
}
// TODO - Should this even work as it currently does? The layers make things more complicated
getTileAt(worldCoords: Vec2): number {
let localCoords = this.getColRowAt(worldCoords);
if(localCoords.x < 0 || localCoords.x >= this.worldSize.x || localCoords.y < 0 || localCoords.y >= this.worldSize.y){
@ -30,23 +36,39 @@ export default class OrthogonalTilemap extends Tilemap {
return 0;
}
return this.data[localCoords.y * this.worldSize.x + localCoords.x];
// Return the top nonzero tile
let tile = 0;
for(let layer of this.layers){
if(layer.data[localCoords.y * this.worldSize.x + localCoords.x] !== 0){
tile = layer.data[localCoords.y * this.worldSize.x + localCoords.x];
}
}
return tile;
}
isTileCollidable(indexOrCol: number, row?: number): boolean {
let index = 0;
if(row){
if(indexOrCol < 0 || indexOrCol >= this.worldSize.x || row < 0 || row >= this.worldSize.y){
// There are no tiles in negative positions or out of bounds positions
return false;
}
return this.collisionData[row * this.worldSize.x + indexOrCol] === 1 && this.collidable;
index = row * this.worldSize.x + indexOrCol;
} else {
if(indexOrCol < 0 || indexOrCol >= this.collisionData.length){
if(indexOrCol < 0 || indexOrCol >= this.layers[0].data.length){
// Tiles that don't exist aren't collidable
return false;
}
return this.collisionData[indexOrCol] === 1 && this.collidable;
index = indexOrCol;
}
for(let layer of this.layers){
if(layer.data[index] !== 0 && layer.collidable){
return true;
}
}
return false;
}
// TODO: Should this throw an error if someone tries to access an out of bounds value?
@ -56,22 +78,20 @@ export default class OrthogonalTilemap extends Tilemap {
return new Vec2(col, row);
}
forEachTile(func: Function): void {
for(let i = 0; i < this.data.length; i++){
func(this.data[i], i);
}
}
update(deltaT: number): void {}
// TODO: Don't render tiles that aren't on screen
render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) {
for(let i = 0; i < this.data.length; i++){
let tileIndex = this.data[i];
for(let layer of this.layers){
if(layer.visible){
for(let i = 0; i < layer.data.length; i++){
let tileIndex = layer.data[i];
for(let tileset of this.tilesets){
if(tileset.hasTile(tileIndex)){
tileset.renderTile(ctx, tileIndex, i, this.worldSize, origin, this.scale);
for(let tileset of this.tilesets){
if(tileset.hasTile(tileIndex)){
tileset.renderTile(ctx, tileIndex, i, this.worldSize, origin, this.scale);
}
}
}
}
}

View File

@ -1,7 +1,37 @@
import Map from "../DataTypes/Map";
import Tilemap from "../Nodes/Tilemap";
import Queue from "../DataTypes/Queue";
import { TiledTilemapData } from "../DataTypes/Tilesets/TiledData";
import StringUtils from "../Utils/StringUtils";
export default class ResourceManager {
private static instance: ResourceManager;
private loading: boolean;
private constructor(){};
private imagesLoaded: number;
private imagesToLoad: number;
private imageLoadingQueue: Queue<{key: string, path: string}>;
private images: Map<HTMLImageElement>;
private tilemapsLoaded: number;
private tilemapsToLoad: number;
private tilemapLoadingQueue: Queue<{key: string, path: string}>;
private tilemaps: Map<TiledTilemapData>;
private constructor(){
this.loading = false;
this.imagesLoaded = 0;
this.imagesToLoad = 0;
this.imageLoadingQueue = new Queue();
this.images = new Map();
this.tilemapsLoaded = 0;
this.tilemapsToLoad = 0;
this.tilemapLoadingQueue = new Queue();
this.tilemaps = new Map();
};
static getInstance(): ResourceManager {
if(!this.instance){
@ -11,11 +41,128 @@ export default class ResourceManager {
return this.instance;
}
public loadTilemap(pathToTilemapJSON: string, callback: Function): void {
this.loadTextFile(pathToTilemapJSON, (fileText: string) => {
let tilemapObject = JSON.parse(fileText);
callback(tilemapObject);
public image(key: string, path: string): void {
this.imageLoadingQueue.enqueue({key: key, path: path});
}
public spritesheet(key: string, path: string, frames: {hFrames: number, vFrames: number}): void {
}
public audio(key: string, path: string): void {
}
// This one is trickier than the others because we first have to load the json file, then we have to load the images
public tilemap(key: string, path: string): void {
// Add a function that loads the tilemap to the queue
this.tilemapLoadingQueue.enqueue({key: key, path: path});
// this.tilemapLoadingQueue.enqueue((callback: Function) => {
// this.loadTilemap(path, (tilemapData: TiledTilemapData) => {
// // When the tilemap file loads, first construct the tilemap
// // TODO: Ignore multiple layers for now, but this will have to be elegantly dealt with sometime in the future
// // Count the total number of images that need to be loaded
// let tilemap = new constr(tilemapData);
// // For each of the tilesets in the tilemap, load the image
// tilemap.getTilesets().forEach(tileset => {
// let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl();
// this.loadImage(imagePath, (image: HTMLImageElement) => {
// tileset.setImage(image);
// })
// });
// this.tilemaps.add(key, tilemap);
// });
// });
}
loadResourcesFromQueue(callback: Function): void {
this.loading = true;
// Load everything in the queues. Tilemaps have to come before images because they will add new images to the queue
this.loadTilemapsFromQueue(() => {
this.loadImagesFromQueue(() => {
// Done loading
this.loading = false;
callback();
});
});
}
private loadTilemapsFromQueue(onFinishLoading: Function){
this.tilemapsToLoad = this.tilemapLoadingQueue.getSize();
this.tilemapsLoaded = 0;
while(this.tilemapLoadingQueue.hasItems()){
let tilemap = this.tilemapLoadingQueue.dequeue();
this.loadTilemap(tilemap.key, tilemap.path, onFinishLoading);
}
}
private loadTilemap(key: string, pathToTilemapJSON: string, callbackIfLast: Function): void {
this.loadTextFile(pathToTilemapJSON, (fileText: string) => {
let tilemapObject = <TiledTilemapData>JSON.parse(fileText);
// We can parse the object later - it's much faster than loading
this.tilemaps.add(key, tilemapObject);
// Grab the tileset images we need to load and add them to the imageloading queue
for(let tileset of tilemapObject.tilesets){
let key = tileset.image;
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
this.imageLoadingQueue.enqueue({key: key, path: path});
}
// Finish loading
this.finishLoadingTilemap(callbackIfLast);
});
}
private finishLoadingTilemap(callback: Function){
this.tilemapsLoaded += 1;
if(this.tilemapsLoaded === this.tilemapsToLoad){
// We're done loading tilemaps
callback();
}
}
private loadImagesFromQueue(onFinishLoading: Function): void {
this.imagesToLoad = this.imageLoadingQueue.getSize();
this.tilemapsLoaded = 0;
while(this.imageLoadingQueue.hasItems()){
let image = this.imageLoadingQueue.dequeue();
this.loadImage(image.key, image.path, onFinishLoading);
}
}
// TODO: When you switch to WebGL, make sure to make this private and make a "loadTexture" function
public loadImage(key: string, path: string, callbackIfLast: Function): void {
var image = new Image();
image.onload = () => {
// Add to loaded images
this.images.add(key, image);
// Finish image load
this.finishLoadingImage(callbackIfLast);
}
image.src = path;
}
private finishLoadingImage(callback: Function): void {
this.imagesLoaded += 1;
if(this.imagesLoaded === this.imagesToLoad ){
// We're done loading tilemaps
callback();
}
}
private loadTextFile(textFilePath: string, callback: Function): void {
@ -29,15 +176,4 @@ export default class ResourceManager {
};
xobj.send(null);
}
// TODO: When you switch to WebGL, make sure to make this private and make a "loadTexture" function
public loadImage(path: string, callback: Function): void {
var image = new Image();
image.onload = function () {
callback(path, image);
}
image.src = path;
}
}

View File

@ -1,11 +1,11 @@
import Scene from "../Scene";
import Layer from "../Layer";
import Viewport from "../../SceneGraph/Viewport";
import CanvasItem from "../../Nodes/CanvasNode"
export default class CanvasNodeFactory {
private scene: Scene;
private scene: Layer;
constructor(scene: Scene){
constructor(scene: Layer){
this.scene = scene;
}

View File

@ -1,14 +1,14 @@
import Scene from "../Scene";
import Layer from "../Layer";
import Viewport from "../../SceneGraph/Viewport";
import PhysicsNode from "../../Physics/PhysicsNode";
import PhysicsManager from "../../Physics/PhysicsManager";
import Tilemap from "../../Nodes/Tilemap";
export default class PhysicsNodeFactory {
private scene: Scene;
private scene: Layer;
private physicsManager: PhysicsManager;
constructor(scene: Scene, physicsManager: PhysicsManager){
constructor(scene: Layer, physicsManager: PhysicsManager){
this.scene = scene;
this.physicsManager = physicsManager;
}

View File

@ -0,0 +1,45 @@
import Layer from "../Layer";
import Viewport from "../../SceneGraph/Viewport";
import Tilemap from "../../Nodes/Tilemap";
import ResourceManager from "../../ResourceManager/ResourceManager";
import { TiledTilemapData } from "../../DataTypes/Tilesets/TiledData";
import StringUtils from "../../Utils/StringUtils";
import StaticBody from "../../Physics/StaticBody";
import Vec2 from "../../DataTypes/Vec2";
export default class TilemapFactory {
private scene: Layer;
// TODO: get the resource manager OUT of here, it does not belong
private resourceManager: ResourceManager;
constructor(scene: Layer){
this.scene = scene;
this.resourceManager = ResourceManager.getInstance();
}
add<T extends Tilemap>(constr: new (...a: any) => T, path: string, ...args: any): void {
// this.resourceManager.loadTilemap(path, (tilemapData: TiledTilemapData) => {
// // For each of the layers in the tilemap, create a tilemap
// for(let layer of tilemapData.layers){
// let tilemap = new constr(tilemapData, layer);
// tilemap.init(this.scene);
// // Add to scene
// this.scene.addTilemap(tilemap);
// if(tilemap.isCollidable()){
// // Register in physics as a tilemap
// this.scene.physics.addTilemap(tilemap);
// }
// // Load images for the tilesets
// tilemap.getTilesets().forEach(tileset => {
// let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl();
// this.resourceManager.loadImage(imagePath, (path: string, image: HTMLImageElement) => {
// tileset.setImage(image);
// })
// });
// }
// });
}
}

View File

@ -4,15 +4,15 @@ import SceneGraph from "../SceneGraph/SceneGraph";
import SceneGraphArray from "../SceneGraph/SceneGraphArray";
import CanvasNode from "../Nodes/CanvasNode";
import CanvasNodeFactory from "./Factories/CanvasNodeFactory";
import GameState from "./GameState";
import Scene from "./Scene";
import Tilemap from "../Nodes/Tilemap";
import TilemapFactory from "./Factories/TilemapFactory";
import PhysicsManager from "../Physics/PhysicsManager";
import PhysicsNodeFactory from "./Factories/PhysicsNodeFactory";
import MathUtils from "../Utils/MathUtils";
export default class Scene {
private gameState: GameState;
export default class Layer {
private gameState: Scene;
private viewport: Viewport
private parallax: Vec2;
private sceneGraph: SceneGraph;
@ -27,7 +27,7 @@ export default class Scene {
public tilemap: TilemapFactory;
public physics: PhysicsNodeFactory;
constructor(viewport: Viewport, gameState: GameState){
constructor(viewport: Viewport, gameState: Scene){
this.gameState = gameState;
this.viewport = viewport;
this.parallax = new Vec2(1, 1);
@ -114,9 +114,7 @@ export default class Scene {
// Render tilemaps
this.tilemaps.forEach(tilemap => {
if(tilemap.isReady() && tilemap.isVisible()){
tilemap.render(ctx, origin, size);
}
tilemap.render(ctx, origin, size);
});
// Render visible set

41
src/Scene/Scene.ts Normal file
View File

@ -0,0 +1,41 @@
import Stack from "../DataTypes/Stack";
import Layer from "./Layer";
import Viewport from "../SceneGraph/Viewport";
import Vec2 from "../DataTypes/Vec2";
export default class Scene{
private layers: Stack<Layer>;
private worldSize: Vec2;
private viewport: Viewport;
private running: boolean;
constructor(viewport: Viewport){
this.layers = new Stack(10);
this.worldSize = new Vec2(1600, 1000);
this.viewport = viewport;
this.viewport.setBounds(0, 0, 2560, 1280);
this.running = false;
}
loadScene(): void {}
unloadScene(): void {}
setRunning(running: boolean): void {
this.running = running;
}
isRunning(): boolean {
return this.isRunning();
}
start(){}
update(deltaT: number): void {
this.layers.forEach((scene: Layer) => scene.update(deltaT));
}
render(ctx: CanvasRenderingContext2D): void {
this.layers.forEach((scene: Layer) => scene.render(ctx));
}
}

39
src/Scene/SceneManager.ts Normal file
View File

@ -0,0 +1,39 @@
import Scene from "./Scene";
import ResourceManager from "../ResourceManager/ResourceManager";
import Viewport from "../SceneGraph/Viewport";
export default class SceneManager{
private currentScene: Scene;
private viewport: Viewport;
private resourceManager: ResourceManager;
constructor(viewport: Viewport){
this.resourceManager = ResourceManager.getInstance();
this.viewport = viewport;
}
public addScene<T extends Scene>(constr: new (...args: any) => T){
let scene = new constr(this.viewport);
this.currentScene = scene;
// Enqueue all scene asset loads
scene.loadScene();
// Load all assets
this.resourceManager.loadResourcesFromQueue(() => {
scene.start();
scene.setRunning(true);
})
}
public render(ctx: CanvasRenderingContext2D){
this.currentScene.render(ctx);
}
public update(deltaT: number){
if(this.currentScene.isRunning()){
this.currentScene.update(deltaT);
}
}
}

View File

@ -2,15 +2,15 @@ import Viewport from "./Viewport";
import CanvasNode from "../Nodes/CanvasNode";
import Map from "../DataTypes/Map";
import Vec2 from "../DataTypes/Vec2";
import Scene from "../GameState/Scene";
import Layer from "../Scene/Layer";
export default abstract class SceneGraph{
protected viewport: Viewport;
protected nodeMap: Map<CanvasNode>;
protected idCounter: number;
protected scene: Scene;
protected scene: Layer;
constructor(viewport: Viewport, scene: Scene){
constructor(viewport: Viewport, scene: Layer){
this.viewport = viewport;
this.scene = scene;
this.nodeMap = new Map<CanvasNode>();

View File

@ -1,13 +1,13 @@
import SceneGraph from "./SceneGraph";
import CanvasNode from "../Nodes/CanvasNode";
import Viewport from "./Viewport";
import Scene from "../GameState/Scene";
import Layer from "../Scene/Layer";
export default class SceneGraphArray extends SceneGraph{
private nodeList: Array<CanvasNode>;
private turnOffViewportCulling_demoTool: boolean;
constructor(viewport: Viewport, scene: Scene){
constructor(viewport: Viewport, scene: Layer){
super(viewport, scene);
this.nodeList = new Array<CanvasNode>();

View File

@ -9,80 +9,80 @@ import OrthogonalTilemap from "./Nodes/Tilemaps/OrthogonalTilemap";
function main(){
// Create the game object
let game = new GameLoop();
let gameState = game.getGameState();
let gameState = game.getSceneManager();
let backgroundScene = gameState.createScene();
backgroundScene.setParallax(0.5, 0.8);
backgroundScene.setAlpha(0.5);
let mainScene = gameState.createScene();
let uiLayer = gameState.createScene();
uiLayer.setParallax(0, 0);
let pauseMenu = gameState.createScene();
pauseMenu.setParallax(0, 0);
// let backgroundScene = gameState.createScene();
// backgroundScene.setParallax(0.5, 0.8);
// backgroundScene.setAlpha(0.5);
// let mainScene = gameState.createScene();
// let uiLayer = gameState.createScene();
// uiLayer.setParallax(0, 0);
// let pauseMenu = gameState.createScene();
// pauseMenu.setParallax(0, 0);
// Initialize GameObjects
let recordButton = uiLayer.canvasNode.add(Button);
recordButton.setSize(100, 50);
recordButton.setText("Record");
recordButton.setPosition(400, 30);
recordButton.onClickEventId = "record_button_press";
// // Initialize GameObjects
// let recordButton = uiLayer.canvasNode.add(Button);
// recordButton.setSize(100, 50);
// recordButton.setText("Record");
// recordButton.setPosition(400, 30);
// recordButton.onClickEventId = "record_button_press";
let stopButton = uiLayer.canvasNode.add(Button);
stopButton.setSize(100, 50);
stopButton.setText("Stop");
stopButton.setPosition(550, 30);
stopButton.onClickEventId = "stop_button_press";
// let stopButton = uiLayer.canvasNode.add(Button);
// stopButton.setSize(100, 50);
// stopButton.setText("Stop");
// stopButton.setPosition(550, 30);
// stopButton.onClickEventId = "stop_button_press";
let playButton = uiLayer.canvasNode.add(Button);
playButton.setSize(100, 50);
playButton.setText("Play");
playButton.setPosition(700, 30);
playButton.onClickEventId = "play_button_press";
// let playButton = uiLayer.canvasNode.add(Button);
// playButton.setSize(100, 50);
// playButton.setText("Play");
// playButton.setPosition(700, 30);
// playButton.onClickEventId = "play_button_press";
let cycleFramerateButton = uiLayer.canvasNode.add(Button);
cycleFramerateButton.setSize(150, 50);
cycleFramerateButton.setText("Cycle FPS");
cycleFramerateButton.setPosition(5, 400);
let i = 0;
let fps = [15, 30, 60];
cycleFramerateButton.onClick = () => {
game.setMaxFPS(fps[i]);
i = (i + 1) % 3;
}
// let cycleFramerateButton = uiLayer.canvasNode.add(Button);
// cycleFramerateButton.setSize(150, 50);
// cycleFramerateButton.setText("Cycle FPS");
// cycleFramerateButton.setPosition(5, 400);
// let i = 0;
// let fps = [15, 30, 60];
// cycleFramerateButton.onClick = () => {
// game.setMaxFPS(fps[i]);
// i = (i + 1) % 3;
// }
let pauseButton = uiLayer.canvasNode.add(Button);
pauseButton.setSize(100, 50);
pauseButton.setText("Pause");
pauseButton.setPosition(700, 400);
pauseButton.onClick = () => {
mainScene.setPaused(true);
pauseMenu.enable();
}
// let pauseButton = uiLayer.canvasNode.add(Button);
// pauseButton.setSize(100, 50);
// pauseButton.setText("Pause");
// pauseButton.setPosition(700, 400);
// pauseButton.onClick = () => {
// mainScene.setPaused(true);
// pauseMenu.enable();
// }
let modalBackground = pauseMenu.canvasNode.add(UIElement);
modalBackground.setSize(400, 200);
modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4));
modalBackground.setPosition(200, 100);
// let modalBackground = pauseMenu.canvasNode.add(UIElement);
// modalBackground.setSize(400, 200);
// modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4));
// modalBackground.setPosition(200, 100);
let resumeButton = pauseMenu.canvasNode.add(Button);
resumeButton.setSize(100, 50);
resumeButton.setText("Resume");
resumeButton.setPosition(400, 200);
resumeButton.onClick = () => {
mainScene.setPaused(false);
pauseMenu.disable();
}
// let resumeButton = pauseMenu.canvasNode.add(Button);
// resumeButton.setSize(100, 50);
// resumeButton.setText("Resume");
// resumeButton.setPosition(400, 200);
// resumeButton.onClick = () => {
// mainScene.setPaused(false);
// pauseMenu.disable();
// }
backgroundScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Background.json");
mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Platformer.json");
let player = mainScene.physics.add(Player, "platformer");
// backgroundScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Background.json");
// mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Platformer.json");
// let player = mainScene.physics.add(Player, "platformer");
// mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/TopDown.json");
// let player = mainScene.physics.add(Player, "topdown");
// // mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/TopDown.json");
// // let player = mainScene.physics.add(Player, "topdown");
mainScene.getViewport().follow(player);
// mainScene.getViewport().follow(player);
pauseMenu.disable();
// pauseMenu.disable();
game.start();
}

View File

@ -18,11 +18,11 @@
"src/Events/GameEvent.ts",
"src/Events/Receiver.ts",
"src/GameState/Factories/CanvasNodeFactory.ts",
"src/GameState/Factories/PhysicsNodeFactory.ts",
"src/GameState/Factories/TilemapFactory.ts",
"src/GameState/GameState.ts",
"src/GameState/Scene.ts",
"src/Scene/Factories/CanvasNodeFactory.ts",
"src/Scene/Factories/PhysicsNodeFactory.ts",
"src/Scene/Factories/TilemapFactory.ts",
"src/Scene/Scene.ts",
"src/Scene/Layer.ts",
"src/Input/InputHandler.ts",
"src/Input/InputReceiver.ts",