added resource culling and resource saving in the ResourceManager
This commit is contained in:
parent
460d0e3643
commit
b085612908
|
@ -1,6 +1,5 @@
|
|||
import AI from "../DataTypes/Interfaces/AI";
|
||||
import StateMachine from "../DataTypes/State/StateMachine";
|
||||
import GameEvent from "../Events/GameEvent";
|
||||
import GameNode from "../Nodes/GameNode";
|
||||
|
||||
/**
|
||||
|
@ -17,6 +16,7 @@ export default class StateMachineAI extends StateMachine implements AI {
|
|||
destroy(){
|
||||
// Get rid of our reference to the owner
|
||||
delete this.owner;
|
||||
this.receiver.destroy();
|
||||
}
|
||||
|
||||
// @implemented
|
||||
|
|
|
@ -13,6 +13,9 @@ export default interface Physical {
|
|||
/** Represents whether the object is moving or not. */
|
||||
moving: boolean;
|
||||
|
||||
/** Represent whether the object is frozen from moving or not. */
|
||||
frozen: boolean;
|
||||
|
||||
/** Represents whether the object is on the ground or not. */
|
||||
onGround: boolean;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ export default class Queue<T> implements Collection {
|
|||
*/
|
||||
enqueue(item: T): void{
|
||||
if((this.tail + 1) % this.MAX_ELEMENTS === this.head){
|
||||
throw "Queue full - cannot add element"
|
||||
throw new Error("Queue full - cannot add element");
|
||||
}
|
||||
|
||||
this.size += 1;
|
||||
|
@ -51,7 +51,7 @@ export default class Queue<T> implements Collection {
|
|||
*/
|
||||
dequeue(): T {
|
||||
if(this.head === this.tail){
|
||||
throw "Queue empty - cannot remove element"
|
||||
throw new Error("Queue empty - cannot remove element");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import Collection from "./Collection";
|
|||
*/
|
||||
export default class Stack<T> implements Collection {
|
||||
/** The maximum number of elements in the Stack */
|
||||
private readonly MAX_ELEMENTS: number;
|
||||
private MAX_ELEMENTS: number;
|
||||
|
||||
/** The internal representation of the stack */
|
||||
private stack: Array<T>;
|
||||
|
|
|
@ -81,7 +81,7 @@ export default class EventQueue {
|
|||
unsubscribe(receiver: Receiver, ...events: Array<string>): void {
|
||||
this.receivers.forEach(eventName => {
|
||||
// If keys were provided, only continue if this key is one of them
|
||||
if(events !== undefined && events.indexOf(eventName) === -1) return;
|
||||
if(events.length > 0 && events.indexOf(eventName) === -1) return;
|
||||
|
||||
// Find the index of our receiver for this key
|
||||
let index = this.receivers.get(eventName).indexOf(receiver);
|
||||
|
|
|
@ -36,7 +36,12 @@ export default class Receiver {
|
|||
* @param event The event to receive
|
||||
*/
|
||||
receive(event: GameEvent): void {
|
||||
try{
|
||||
this.q.enqueue(event);
|
||||
} catch(e){
|
||||
console.warn("Receiver overflow for event " + event.toString());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
/*---------- PHYSICAL ----------*/
|
||||
hasPhysics: boolean = false;
|
||||
moving: boolean = false;
|
||||
frozen: boolean = false;
|
||||
onGround: boolean = false;
|
||||
onWall: boolean = false;
|
||||
onCeiling: boolean = false;
|
||||
|
@ -151,11 +152,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
* @param velocity The velocity with which to move the object.
|
||||
*/
|
||||
move(velocity: Vec2): void {
|
||||
if(this.frozen) return;
|
||||
this.moving = true;
|
||||
this._velocity = velocity;
|
||||
};
|
||||
|
||||
moveOnPath(speed: number, path: NavigationPath): void {
|
||||
if(this.frozen) return;
|
||||
this.path = path;
|
||||
let dir = path.getMoveDirection(this);
|
||||
this.moving = true;
|
||||
|
@ -230,6 +233,9 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
|
||||
/** Removes this object from the physics system */
|
||||
removePhysics(): void {
|
||||
// Remove this from the physics manager
|
||||
this.scene.getPhysicsManager().deregisterObject(this);
|
||||
|
||||
// Nullify all physics fields
|
||||
this.hasPhysics = false;
|
||||
this.moving = false;
|
||||
|
@ -250,9 +256,16 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
this.collisionShape = null;
|
||||
this.colliderOffset = Vec2.ZERO;
|
||||
this.sweptRect = null;
|
||||
}
|
||||
|
||||
// Remove this from the physics manager
|
||||
this.scene.getPhysicsManager().deregisterObject(this);
|
||||
/** Disables physics movement for this node */
|
||||
freeze(): void {
|
||||
this.frozen = true;
|
||||
}
|
||||
|
||||
/** Reenables physics movement for this node */
|
||||
unfreeze(): void {
|
||||
this.frozen = false;
|
||||
}
|
||||
|
||||
/** Prevents this object from participating in all collisions and triggers. It can still move. */
|
||||
|
|
|
@ -90,7 +90,6 @@ export default abstract class UIElement extends CanvasNode {
|
|||
}
|
||||
if(this.onClickEventId !== null){
|
||||
let data = {};
|
||||
console.log("Click event: " + this.onClickEventId)
|
||||
this.emitter.fireEvent(this.onClickEventId, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ export default class BasicPhysicsManager extends PhysicsManager {
|
|||
* @param options A record of options
|
||||
*/
|
||||
protected parseOptions(options: Record<string, any>): void {
|
||||
console.log("Parsing physics options: ", options);
|
||||
if(options.groupNames !== undefined && options.collisions !== undefined){
|
||||
for(let i = 0; i < options.groupNames.length; i++){
|
||||
let group = options.groupNames[i];
|
||||
|
@ -108,6 +107,7 @@ export default class BasicPhysicsManager extends PhysicsManager {
|
|||
|
||||
// @override
|
||||
deregisterObject(node: Physical): void {
|
||||
console.log("Deregistering physics object");
|
||||
if(node.isStatic){
|
||||
// Remove the node from the static list
|
||||
const index = this.staticNodes.indexOf(node);
|
||||
|
|
|
@ -33,6 +33,10 @@ export default abstract class PhysicsManager implements Updateable {
|
|||
this.groupNames = new Array();
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.receiver.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a gamenode with this physics manager
|
||||
* @param object The object to register
|
||||
|
|
|
@ -81,7 +81,6 @@ export default class ResourceManager {
|
|||
private loadonly_gl_ShaderProgramsToLoad: number;
|
||||
private loadonly_gl_ShaderLoadingQueue: Queue<KeyPath_Shader>;
|
||||
|
||||
private gl_DefaultShaderPrograms: Map<WebGLProgramType>;
|
||||
private gl_ShaderPrograms: Map<WebGLProgramType>;
|
||||
|
||||
private gl_Textures: Map<number>;
|
||||
|
@ -90,6 +89,13 @@ export default class ResourceManager {
|
|||
|
||||
private gl: WebGLRenderingContext;
|
||||
|
||||
/* ########## UNLOADING AND EXCLUSION LIST ########## */
|
||||
/** A list of resources that will be unloaded at the end of the current scene */
|
||||
private resourcesToUnload: Array<ResourceReference>;
|
||||
|
||||
/** A list of resources to keep until further notice */
|
||||
private resourcesToKeep: Array<ResourceReference>;
|
||||
|
||||
private constructor(){
|
||||
this.loading = false;
|
||||
this.justLoaded = false;
|
||||
|
@ -123,14 +129,17 @@ export default class ResourceManager {
|
|||
this.loadonly_gl_ShaderProgramsToLoad = 0;
|
||||
this.loadonly_gl_ShaderLoadingQueue = new Queue();
|
||||
|
||||
this.gl_DefaultShaderPrograms = new Map();
|
||||
this.gl_ShaderPrograms = new Map();
|
||||
|
||||
this.gl_Textures = new Map();
|
||||
this.gl_NextTextureID = 0;
|
||||
this.gl_Buffers = new Map();
|
||||
|
||||
this.resourcesToUnload = new Array();
|
||||
this.resourcesToKeep = new Array();
|
||||
};
|
||||
|
||||
/* ######################################## SINGLETON ########################################*/
|
||||
/**
|
||||
* Returns the current instance of this class or a new instance if none exist
|
||||
* @returns The resource manager
|
||||
|
@ -143,6 +152,7 @@ export default class ResourceManager {
|
|||
return this.instance;
|
||||
}
|
||||
|
||||
/* ######################################## PUBLIC FUNCTION ########################################*/
|
||||
/**
|
||||
* Activates or deactivates the use of WebGL
|
||||
* @param flag True if WebGL should be used, false otherwise
|
||||
|
@ -165,6 +175,14 @@ export default class ResourceManager {
|
|||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepImage(key: string): void {
|
||||
this.keepResource(key, ResourceType.IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a loaded image
|
||||
* @param key The key of the loaded image
|
||||
|
@ -187,6 +205,14 @@ export default class ResourceManager {
|
|||
this.loadonly_spritesheetLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepSpritesheet(key: string): void {
|
||||
this.keepResource(key, ResourceType.SPRITESHEET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a loaded spritesheet
|
||||
* @param key The key of the spritesheet to load
|
||||
|
@ -205,6 +231,14 @@ export default class ResourceManager {
|
|||
this.loadonly_audioLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepAudio(key: string): void {
|
||||
this.keepResource(key, ResourceType.AUDIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a loaded audio file
|
||||
* @param key The key of the audio file to load
|
||||
|
@ -223,6 +257,14 @@ export default class ResourceManager {
|
|||
this.loadonly_tilemapLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepTilemap(key: string): void {
|
||||
this.keepResource(key, ResourceType.TILEMAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives a loaded tilemap
|
||||
* @param key The key of the loaded tilemap
|
||||
|
@ -241,6 +283,14 @@ export default class ResourceManager {
|
|||
this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepObject(key: string): void {
|
||||
this.keepResource(key, ResourceType.JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreives a loaded object
|
||||
* @param key The key of the loaded object
|
||||
|
@ -250,6 +300,7 @@ export default class ResourceManager {
|
|||
return this.jsonObjects.get(key);
|
||||
}
|
||||
|
||||
/* ######################################## LOAD FUNCTION ########################################*/
|
||||
/**
|
||||
* Loads all resources currently in the queue
|
||||
* @param callback The function to cal when the resources are finished loading
|
||||
|
@ -293,6 +344,21 @@ export default class ResourceManager {
|
|||
callback();
|
||||
}
|
||||
|
||||
/* ######################################## UNLOAD FUNCTION ########################################*/
|
||||
|
||||
private keepResource(key: string, type: ResourceType): void {
|
||||
console.log("Keep resource...");
|
||||
for(let i = 0; i < this.resourcesToUnload.length; i++){
|
||||
let resource = this.resourcesToUnload[i];
|
||||
if(resource.key === key && resource.resourceType === type){
|
||||
console.log("Found resource " + key + " of type " + type + ". Keeping.");
|
||||
let resourceToMove = this.resourcesToUnload.splice(i, 1);
|
||||
this.resourcesToKeep.push(...resourceToMove);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes references to all resources in the resource manager
|
||||
*/
|
||||
|
@ -300,29 +366,46 @@ export default class ResourceManager {
|
|||
this.loading = false;
|
||||
this.justLoaded = false;
|
||||
|
||||
this.loadonly_imagesLoaded = 0;
|
||||
this.loadonly_imagesToLoad = 0;
|
||||
this.images.clear();
|
||||
|
||||
this.loadonly_spritesheetsLoaded = 0;
|
||||
this.loadonly_spritesheetsToLoad = 0;
|
||||
this.spritesheets.clear();
|
||||
|
||||
this.loadonly_tilemapsLoaded = 0;
|
||||
this.loadonly_tilemapsToLoad = 0;
|
||||
this.tilemaps.clear();
|
||||
|
||||
this.loadonly_audioLoaded = 0;
|
||||
this.loadonly_audioToLoad = 0;
|
||||
this.audioBuffers.clear();
|
||||
|
||||
// WebGL
|
||||
// Delete all programs through webGL
|
||||
this.gl_ShaderPrograms.forEach(key => this.gl_ShaderPrograms.get(key).delete(this.gl));
|
||||
this.gl_ShaderPrograms.clear();
|
||||
this.gl_Textures.clear();
|
||||
for(let resource of this.resourcesToUnload){
|
||||
// Unload the resource
|
||||
this.unloadResource(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private unloadResource(resource: ResourceReference): void {
|
||||
// Delete the resource itself
|
||||
switch(resource.resourceType){
|
||||
case ResourceType.IMAGE:
|
||||
this.images.delete(resource.key);
|
||||
if(this.gl_WebGLActive){
|
||||
this.gl_Textures.delete(resource.key);
|
||||
}
|
||||
break;
|
||||
case ResourceType.TILEMAP:
|
||||
this.tilemaps.delete(resource.key);
|
||||
break;
|
||||
case ResourceType.SPRITESHEET:
|
||||
this.spritesheets.delete(resource.key);
|
||||
break;
|
||||
case ResourceType.AUDIO:
|
||||
this.audioBuffers.delete(resource.key);
|
||||
break;
|
||||
case ResourceType.JSON:
|
||||
this.jsonObjects.delete(resource.key);
|
||||
break;
|
||||
case ResourceType.SHADER:
|
||||
this.gl_ShaderPrograms.get(resource.key).delete(this.gl);
|
||||
this.gl_ShaderPrograms.delete(resource.key);
|
||||
break;
|
||||
}
|
||||
|
||||
// Delete any dependencies
|
||||
for(let dependency of resource.dependencies){
|
||||
this.unloadResource(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
/* ######################################## WORK FUNCTIONS ########################################*/
|
||||
/**
|
||||
* Loads all tilemaps currently in the tilemap loading queue
|
||||
* @param onFinishLoading The function to call when loading is complete
|
||||
|
@ -355,22 +438,32 @@ export default class ResourceManager {
|
|||
|
||||
// We can parse the object later - it's much faster than loading
|
||||
this.tilemaps.add(key, tilemapObject);
|
||||
let resource = new ResourceReference(key, ResourceType.TILEMAP);
|
||||
|
||||
// Grab the tileset images we need to load and add them to the imageloading queue
|
||||
for(let tileset of tilemapObject.tilesets){
|
||||
if(tileset.image){
|
||||
let key = tileset.image;
|
||||
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
|
||||
|
||||
// Add this image as a dependency to the tilemap
|
||||
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE));
|
||||
} else if(tileset.tiles){
|
||||
for(let tile of tileset.tiles){
|
||||
let key = tile.image;
|
||||
let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key;
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
|
||||
|
||||
// Add this image as a dependency to the tilemap
|
||||
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the resource reference to the list of resource to unload
|
||||
this.resourcesToUnload.push(resource);
|
||||
|
||||
// Finish loading
|
||||
this.finishLoadingTilemap(callbackIfLast);
|
||||
});
|
||||
|
@ -422,9 +515,14 @@ export default class ResourceManager {
|
|||
// We can parse the object later - it's much faster than loading
|
||||
this.spritesheets.add(key, spritesheet);
|
||||
|
||||
let resource = new ResourceReference(key, ResourceType.SPRITESHEET);
|
||||
|
||||
// Grab the image we need to load and add it to the imageloading queue
|
||||
let path = StringUtils.getPathFromFilePath(pathToSpritesheetJSON) + spritesheet.spriteSheetImage;
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path});
|
||||
this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path, isDependency: true});
|
||||
|
||||
resource.addDependency(new ResourceReference(spritesheet.name, ResourceType.IMAGE));
|
||||
this.resourcesToUnload.push(resource);
|
||||
|
||||
// Finish loading
|
||||
this.finishLoadingSpritesheet(callbackIfLast);
|
||||
|
@ -460,7 +558,7 @@ export default class ResourceManager {
|
|||
|
||||
while(this.loadonly_imageLoadingQueue.hasItems()){
|
||||
let image = this.loadonly_imageLoadingQueue.dequeue();
|
||||
this.loadImage(image.key, image.path, onFinishLoading);
|
||||
this.loadImage(image.key, image.path, image.isDependency, onFinishLoading);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,13 +568,18 @@ export default class ResourceManager {
|
|||
* @param path The path to the image to load
|
||||
* @param callbackIfLast The function to call if this is the last image
|
||||
*/
|
||||
public loadImage(key: string, path: string, callbackIfLast: Function): void {
|
||||
public loadImage(key: string, path: string, isDependency: boolean, callbackIfLast: Function): void {
|
||||
var image = new Image();
|
||||
|
||||
image.onload = () => {
|
||||
// Add to loaded images
|
||||
this.images.add(key, image);
|
||||
|
||||
// If not a dependency, push it to the unload list. Otherwise it's managed by something else
|
||||
if(!isDependency){
|
||||
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.IMAGE));
|
||||
}
|
||||
|
||||
// If WebGL is active, create a texture
|
||||
if(this.gl_WebGLActive){
|
||||
this.createWebGLTexture(key, image);
|
||||
|
@ -539,6 +642,7 @@ export default class ResourceManager {
|
|||
audioCtx.decodeAudioData(request.response, (buffer) => {
|
||||
// Add to list of audio buffers
|
||||
this.audioBuffers.add(key, buffer);
|
||||
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.AUDIO));
|
||||
|
||||
// Finish loading sound
|
||||
this.finishLoadingAudio(callbackIfLast);
|
||||
|
@ -592,6 +696,9 @@ export default class ResourceManager {
|
|||
this.loadTextFile(path, (fileText: string) => {
|
||||
let obj = JSON.parse(fileText);
|
||||
this.jsonObjects.add(key, obj);
|
||||
|
||||
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.JSON));
|
||||
|
||||
this.finishLoadingObject(callbackIfLast);
|
||||
});
|
||||
}
|
||||
|
@ -706,6 +813,14 @@ export default class ResourceManager {
|
|||
this.loadonly_gl_ShaderLoadingQueue.enqueue(paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the resource manager to keep this resource
|
||||
* @param key The key of the resource
|
||||
*/
|
||||
public keepShader(key: string): void {
|
||||
this.keepResource(key, ResourceType.IMAGE);
|
||||
}
|
||||
|
||||
private gl_LoadShadersFromQueue(onFinishLoading: Function): void {
|
||||
this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize();
|
||||
this.loadonly_gl_ShaderProgramsLoaded = 0;
|
||||
|
@ -741,6 +856,8 @@ export default class ResourceManager {
|
|||
// Add to our map
|
||||
this.gl_ShaderPrograms.add(key, programWrapper);
|
||||
|
||||
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.SHADER));
|
||||
|
||||
// Finish loading
|
||||
this.gl_FinishLoadingShader(callbackIfLast);
|
||||
});
|
||||
|
@ -769,7 +886,7 @@ export default class ResourceManager {
|
|||
const program = this.gl.createProgram();
|
||||
if(!program) {
|
||||
// Error creating
|
||||
console.log("Failed to create program");
|
||||
console.warn("Failed to create program");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -782,7 +899,7 @@ export default class ResourceManager {
|
|||
if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){
|
||||
// Error linking
|
||||
const error = this.gl.getProgramInfoLog(program);
|
||||
console.log("Failed to link program: " + error);
|
||||
console.warn("Failed to link program: " + error);
|
||||
|
||||
// Clean up
|
||||
this.gl.deleteProgram(program);
|
||||
|
@ -810,7 +927,7 @@ export default class ResourceManager {
|
|||
|
||||
// If we couldn't create the shader, error
|
||||
if(shader === null){
|
||||
console.log("Unable to create shader");
|
||||
console.warn("Unable to create shader");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -822,7 +939,7 @@ export default class ResourceManager {
|
|||
if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){
|
||||
// Not compiled - error
|
||||
const error = this.gl.getShaderInfoLog(shader);
|
||||
console.log("Failed to compile shader: " + error);
|
||||
console.warn("Failed to compile shader: " + error);
|
||||
|
||||
// Clean up
|
||||
this.gl.deleteShader(shader);
|
||||
|
@ -871,9 +988,44 @@ export default class ResourceManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class representing a reference to a resource.
|
||||
* This is used for the exemption list to assure assets and their dependencies don't get
|
||||
* destroyed if they are still needed.
|
||||
*/
|
||||
class ResourceReference {
|
||||
key: string;
|
||||
resourceType: ResourceType;
|
||||
dependencies: Array<ResourceReference>;
|
||||
|
||||
constructor(key: string, resourceType: ResourceType){
|
||||
this.key = key;
|
||||
this.resourceType = resourceType;
|
||||
this. dependencies = new Array();
|
||||
}
|
||||
|
||||
addDependency(resource: ResourceReference): void {
|
||||
this.dependencies.push(resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum ResourceType {
|
||||
IMAGE = "IMAGE",
|
||||
TILEMAP = "TILEMAP",
|
||||
SPRITESHEET = "SPRITESHEET",
|
||||
AUDIO = "AUDIO",
|
||||
JSON = "JSON",
|
||||
SHADER = "SHADER"
|
||||
}
|
||||
|
||||
/**
|
||||
* A pair representing a key and the path of the resource to load
|
||||
*/
|
||||
class KeyPathPair {
|
||||
key: string;
|
||||
path: string;
|
||||
isDependency?: boolean = false;
|
||||
}
|
||||
|
||||
class KeyPath_Shader {
|
||||
|
|
|
@ -90,7 +90,6 @@ export default class TilemapFactory {
|
|||
}
|
||||
|
||||
if(isParallaxLayer){
|
||||
console.log("Adding parallax layer: " + layer.name)
|
||||
sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth);
|
||||
} else {
|
||||
sceneLayer = this.scene.addLayer(layer.name, depth);
|
||||
|
|
|
@ -81,9 +81,12 @@ export default class Scene implements Updateable {
|
|||
/** An interface that allows the adding of different nodes to the scene */
|
||||
public add: FactoryManager;
|
||||
|
||||
/** An interface that allows the loading of different files for use in the scene */
|
||||
/** An interface that allows the loading of different files for use in the scene. An alias for resourceManager */
|
||||
public load: ResourceManager;
|
||||
|
||||
/** An interface that allows the loading and unloading of different files for use in the scene */
|
||||
public resourceManager: ResourceManager;
|
||||
|
||||
/** The configuration options for this scene */
|
||||
public sceneOptions: SceneOptions;
|
||||
|
||||
|
@ -120,7 +123,8 @@ export default class Scene implements Updateable {
|
|||
|
||||
this.add = new FactoryManager(this, this.tilemaps);
|
||||
|
||||
this.load = ResourceManager.getInstance();
|
||||
this.load = ResourceManager.getInstance()
|
||||
this.resourceManager = this.load;
|
||||
|
||||
// Get the timer manager and clear any existing timers
|
||||
TimerManager.getInstance().clearTimers();
|
||||
|
@ -132,9 +136,6 @@ export default class Scene implements Updateable {
|
|||
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
||||
loadScene(): void {}
|
||||
|
||||
/** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */
|
||||
unloadScene(): void {}
|
||||
|
||||
/** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */
|
||||
startScene(): void {}
|
||||
|
||||
|
@ -144,6 +145,9 @@ export default class Scene implements Updateable {
|
|||
*/
|
||||
updateScene(deltaT: number): void {}
|
||||
|
||||
/** A lifecycle method that gets called on scene destruction. Specify which files you no longer need for garbage collection. */
|
||||
unloadScene(): void {}
|
||||
|
||||
update(deltaT: number): void {
|
||||
this.updateScene(deltaT);
|
||||
|
||||
|
@ -232,6 +236,12 @@ export default class Scene implements Updateable {
|
|||
node.destroy();
|
||||
}
|
||||
|
||||
for(let tilemap of this.tilemaps){
|
||||
tilemap.destroy();
|
||||
}
|
||||
|
||||
this.receiver.destroy();
|
||||
|
||||
delete this.sceneGraph;
|
||||
delete this.physicsManager;
|
||||
delete this.navManager;
|
||||
|
|
|
@ -2,6 +2,7 @@ import Scene from "./Scene";
|
|||
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||
import Viewport from "../SceneGraph/Viewport";
|
||||
import RenderingManager from "../Rendering/RenderingManager";
|
||||
import MemoryUtils from "../Utils/MemoryUtils";
|
||||
|
||||
/**
|
||||
* The SceneManager acts as an interface to create Scenes, and handles the lifecycle methods of Scenes.
|
||||
|
@ -25,6 +26,7 @@ export default class SceneManager {
|
|||
|
||||
/** For consistency, only change scenes at the beginning of the update cycle */
|
||||
protected pendingScene: Scene;
|
||||
protected pendingSceneInit: Record<string, any>;
|
||||
|
||||
/**
|
||||
* Creates a new SceneManager
|
||||
|
@ -37,6 +39,7 @@ export default class SceneManager {
|
|||
this.viewport = viewport;
|
||||
this.renderingManager = renderingManager;
|
||||
this.idCounter = 0;
|
||||
this.pendingScene = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,31 +49,47 @@ export default class SceneManager {
|
|||
* @param init An object to pass to the init function of the new scene
|
||||
*/
|
||||
public changeToScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
|
||||
console.log("Creating the new scene - change is pending until next update");
|
||||
this.pendingScene = new constr(this.viewport, this, this.renderingManager, options);
|
||||
this.pendingSceneInit = init;
|
||||
}
|
||||
|
||||
protected doSceneChange(){
|
||||
console.log("Performing scene change");
|
||||
this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
|
||||
|
||||
let scene = new constr(this.viewport, this, this.renderingManager, options);
|
||||
|
||||
if(this.currentScene){
|
||||
console.log("Destroying Old Scene");
|
||||
console.log("Unloading old scene")
|
||||
this.currentScene.unloadScene();
|
||||
|
||||
console.log("Destroying old scene");
|
||||
this.currentScene.destroy();
|
||||
}
|
||||
|
||||
this.currentScene = scene;
|
||||
console.log("Unloading old resources...");
|
||||
this.resourceManager.unloadAllResources();
|
||||
|
||||
scene.initScene(init);
|
||||
// Make the pending scene the current one
|
||||
this.currentScene = this.pendingScene;
|
||||
|
||||
// Make the pending scene null
|
||||
this.pendingScene = null;
|
||||
|
||||
// Init the scene
|
||||
this.currentScene.initScene(this.pendingSceneInit);
|
||||
|
||||
// Enqueue all scene asset loads
|
||||
scene.loadScene();
|
||||
this.currentScene.loadScene();
|
||||
|
||||
// Load all assets
|
||||
console.log("Starting Scene Load");
|
||||
this.resourceManager.loadResourcesFromQueue(() => {
|
||||
console.log("Starting Scene");
|
||||
scene.startScene();
|
||||
scene.setRunning(true);
|
||||
this.currentScene.startScene();
|
||||
this.currentScene.setRunning(true);
|
||||
});
|
||||
|
||||
this.renderingManager.setScene(scene);
|
||||
this.renderingManager.setScene(this.currentScene);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +104,9 @@ export default class SceneManager {
|
|||
* Renders the current Scene
|
||||
*/
|
||||
public render(): void {
|
||||
this.currentScene.render();
|
||||
if(this.currentScene){
|
||||
this.currentScene.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +114,11 @@ export default class SceneManager {
|
|||
* @param deltaT The timestep of the Scene
|
||||
*/
|
||||
public update(deltaT: number){
|
||||
if(this.currentScene.isRunning()){
|
||||
if(this.pendingScene !== null){
|
||||
this.doSceneChange();
|
||||
}
|
||||
|
||||
if(this.currentScene && this.currentScene.isRunning()){
|
||||
this.currentScene.update(deltaT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ export default class Viewport {
|
|||
* @param zoom The zoom level
|
||||
*/
|
||||
setZoomLevel(zoom: number): void {
|
||||
this.view.halfSize.scale(1/zoom);
|
||||
this.view.halfSize.copy(this.canvasSize.scaled(1/zoom/2));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,7 @@ export default class AudioManager {
|
|||
this.audioCtx = new AudioContext();
|
||||
console.log('Web Audio API successfully loaded');
|
||||
} catch(e) {
|
||||
console.log('Web Audio API is not supported in this browser');
|
||||
console.warn('Web Audio API is not supported in this browser');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
46
src/Wolfie2D/Utils/MemoryUtils.ts
Normal file
46
src/Wolfie2D/Utils/MemoryUtils.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import Stack from "../DataTypes/Stack";
|
||||
|
||||
export default class MemoryUtils {
|
||||
/**
|
||||
* Returns an approximate size in bytes of any object
|
||||
* @param obj The object to get the size of
|
||||
* @returns An approximation of the number of bytes in the object provided
|
||||
*/
|
||||
static approxSizeOf(obj: any): number {
|
||||
let objectList = new Array<object>();
|
||||
let stack = new Stack<any>(10000);
|
||||
stack.push(obj);
|
||||
let bytes = 0;
|
||||
|
||||
while(!stack.isEmpty()){
|
||||
let item = stack.pop();
|
||||
|
||||
// We aren't interested in counting window and document
|
||||
if(item === window || item === document) continue;
|
||||
|
||||
if((typeof item) === "boolean"){
|
||||
bytes += 4;
|
||||
} else if((typeof item) === "number"){
|
||||
bytes += 8;
|
||||
} else if((typeof item) === "string"){
|
||||
bytes += item.length;
|
||||
} else if((typeof item) === "object" && objectList.indexOf(item) === -1){
|
||||
// We haven't seen this object before - log it
|
||||
objectList.push(item);
|
||||
|
||||
// Get the number of bytes in all of its fields
|
||||
for(let field in item){
|
||||
try {
|
||||
stack.push(item[field]);
|
||||
} catch(e){
|
||||
console.log("Pushing item: ", + item[field]);
|
||||
console.warn(`Ran out of room counting memory (Stack has size ${stack.size()}) - returning current number of bytes`);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user