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 AI from "../DataTypes/Interfaces/AI"; | ||||||
| import StateMachine from "../DataTypes/State/StateMachine"; | import StateMachine from "../DataTypes/State/StateMachine"; | ||||||
| import GameEvent from "../Events/GameEvent"; |  | ||||||
| import GameNode from "../Nodes/GameNode"; | import GameNode from "../Nodes/GameNode"; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -17,6 +16,7 @@ export default class StateMachineAI extends StateMachine implements AI { | ||||||
| 	destroy(){ | 	destroy(){ | ||||||
| 		// Get rid of our reference to the owner
 | 		// Get rid of our reference to the owner
 | ||||||
| 		delete this.owner; | 		delete this.owner; | ||||||
|  | 		this.receiver.destroy(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// @implemented
 | 	// @implemented
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,9 @@ export default interface Physical { | ||||||
|     /** Represents whether the object is moving or not. */ |     /** Represents whether the object is moving or not. */ | ||||||
|     moving: boolean; |     moving: boolean; | ||||||
| 
 | 
 | ||||||
|  |     /** Represent whether the object is frozen from moving or not. */ | ||||||
|  |     frozen: boolean; | ||||||
|  | 
 | ||||||
|     /** Represents whether the object is on the ground or not. */ |     /** Represents whether the object is on the ground or not. */ | ||||||
|     onGround: boolean; |     onGround: boolean; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ export default class Queue<T> implements Collection { | ||||||
|      */ |      */ | ||||||
|     enqueue(item: T): void{ |     enqueue(item: T): void{ | ||||||
|         if((this.tail + 1) % this.MAX_ELEMENTS === this.head){ |         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; |         this.size += 1; | ||||||
|  | @ -51,7 +51,7 @@ export default class Queue<T> implements Collection { | ||||||
|      */ |      */ | ||||||
|     dequeue(): T { |     dequeue(): T { | ||||||
|         if(this.head === this.tail){ |         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 { | export default class Stack<T> implements Collection { | ||||||
|     /** The maximum number of elements in the Stack */ |     /** The maximum number of elements in the Stack */ | ||||||
|     private readonly MAX_ELEMENTS: number; |     private MAX_ELEMENTS: number; | ||||||
|      |      | ||||||
|     /** The internal representation of the stack */ |     /** The internal representation of the stack */ | ||||||
|     private stack: Array<T>; |     private stack: Array<T>; | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ export default class EventQueue { | ||||||
|     unsubscribe(receiver: Receiver, ...events: Array<string>): void { |     unsubscribe(receiver: Receiver, ...events: Array<string>): void { | ||||||
|         this.receivers.forEach(eventName => { |         this.receivers.forEach(eventName => { | ||||||
|             // If keys were provided, only continue if this key is one of them
 |             // 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
 |             // Find the index of our receiver for this key
 | ||||||
|             let index = this.receivers.get(eventName).indexOf(receiver); |             let index = this.receivers.get(eventName).indexOf(receiver); | ||||||
|  |  | ||||||
|  | @ -36,7 +36,12 @@ export default class Receiver { | ||||||
| 	 * @param event The event to receive | 	 * @param event The event to receive | ||||||
| 	 */ | 	 */ | ||||||
| 	receive(event: GameEvent): void { | 	receive(event: GameEvent): void { | ||||||
|  | 		try{ | ||||||
| 		this.q.enqueue(event); | 		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 ----------*/ | 	/*---------- PHYSICAL ----------*/ | ||||||
| 	hasPhysics: boolean = false; | 	hasPhysics: boolean = false; | ||||||
| 	moving: boolean = false; | 	moving: boolean = false; | ||||||
|  | 	frozen: boolean = false; | ||||||
| 	onGround: boolean = false; | 	onGround: boolean = false; | ||||||
| 	onWall: boolean = false; | 	onWall: boolean = false; | ||||||
| 	onCeiling: 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. |      * @param velocity The velocity with which to move the object. | ||||||
|      */ |      */ | ||||||
| 	move(velocity: Vec2): void { | 	move(velocity: Vec2): void { | ||||||
|  | 		if(this.frozen) return; | ||||||
| 		this.moving = true; | 		this.moving = true; | ||||||
| 		this._velocity = velocity; | 		this._velocity = velocity; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	moveOnPath(speed: number, path: NavigationPath): void { | 	moveOnPath(speed: number, path: NavigationPath): void { | ||||||
|  | 		if(this.frozen) return; | ||||||
| 		this.path = path; | 		this.path = path; | ||||||
| 		let dir = path.getMoveDirection(this); | 		let dir = path.getMoveDirection(this); | ||||||
| 		this.moving = true; | 		this.moving = true; | ||||||
|  | @ -230,6 +233,9 @@ export default abstract class GameNode implements Positioned, Unique, Updateable | ||||||
| 
 | 
 | ||||||
| 	/** Removes this object from the physics system */ | 	/** Removes this object from the physics system */ | ||||||
|     removePhysics(): void { |     removePhysics(): void { | ||||||
|  | 		// Remove this from the physics manager
 | ||||||
|  | 		this.scene.getPhysicsManager().deregisterObject(this); | ||||||
|  | 
 | ||||||
| 		// Nullify all physics fields
 | 		// Nullify all physics fields
 | ||||||
| 		this.hasPhysics = false; | 		this.hasPhysics = false; | ||||||
| 		this.moving = false; | 		this.moving = false; | ||||||
|  | @ -250,9 +256,16 @@ export default abstract class GameNode implements Positioned, Unique, Updateable | ||||||
| 		this.collisionShape = null; | 		this.collisionShape = null; | ||||||
| 		this.colliderOffset = Vec2.ZERO; | 		this.colliderOffset = Vec2.ZERO; | ||||||
| 		this.sweptRect = null; | 		this.sweptRect = null; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 		// Remove this from the physics manager
 | 	/** Disables physics movement for this node */ | ||||||
| 		this.scene.getPhysicsManager().deregisterObject(this); | 	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. */ |     /** 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){ | 				if(this.onClickEventId !== null){ | ||||||
| 					let data = {}; | 					let data = {}; | ||||||
| 					console.log("Click event: " + this.onClickEventId) |  | ||||||
| 					this.emitter.fireEvent(this.onClickEventId, data); | 					this.emitter.fireEvent(this.onClickEventId, data); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -72,7 +72,6 @@ export default class BasicPhysicsManager extends PhysicsManager { | ||||||
| 	 * @param options A record of options | 	 * @param options A record of options | ||||||
| 	 */ | 	 */ | ||||||
| 	protected parseOptions(options: Record<string, any>): void { | 	protected parseOptions(options: Record<string, any>): void { | ||||||
| 		console.log("Parsing physics options: ", options); |  | ||||||
| 		if(options.groupNames !== undefined && options.collisions !== undefined){ | 		if(options.groupNames !== undefined && options.collisions !== undefined){ | ||||||
| 			for(let i = 0; i < options.groupNames.length; i++){ | 			for(let i = 0; i < options.groupNames.length; i++){ | ||||||
| 				let group = options.groupNames[i]; | 				let group = options.groupNames[i]; | ||||||
|  | @ -108,6 +107,7 @@ export default class BasicPhysicsManager extends PhysicsManager { | ||||||
| 
 | 
 | ||||||
| 	// @override
 | 	// @override
 | ||||||
| 	deregisterObject(node: Physical): void { | 	deregisterObject(node: Physical): void { | ||||||
|  | 		console.log("Deregistering physics object"); | ||||||
| 		if(node.isStatic){ | 		if(node.isStatic){ | ||||||
| 			// Remove the node from the static list
 | 			// Remove the node from the static list
 | ||||||
| 			const index = this.staticNodes.indexOf(node); | 			const index = this.staticNodes.indexOf(node); | ||||||
|  |  | ||||||
|  | @ -33,6 +33,10 @@ export default abstract class PhysicsManager implements Updateable { | ||||||
| 		this.groupNames = new Array(); | 		this.groupNames = new Array(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	destroy(): void { | ||||||
|  | 		this.receiver.destroy(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Registers a gamenode with this physics manager | 	 * Registers a gamenode with this physics manager | ||||||
| 	 * @param object The object to register | 	 * @param object The object to register | ||||||
|  |  | ||||||
|  | @ -81,7 +81,6 @@ export default class ResourceManager { | ||||||
|     private loadonly_gl_ShaderProgramsToLoad: number; |     private loadonly_gl_ShaderProgramsToLoad: number; | ||||||
|     private loadonly_gl_ShaderLoadingQueue: Queue<KeyPath_Shader>; |     private loadonly_gl_ShaderLoadingQueue: Queue<KeyPath_Shader>; | ||||||
| 
 | 
 | ||||||
|     private gl_DefaultShaderPrograms: Map<WebGLProgramType>; |  | ||||||
|     private gl_ShaderPrograms: Map<WebGLProgramType>; |     private gl_ShaderPrograms: Map<WebGLProgramType>; | ||||||
| 
 | 
 | ||||||
|     private gl_Textures: Map<number>; |     private gl_Textures: Map<number>; | ||||||
|  | @ -90,6 +89,13 @@ export default class ResourceManager { | ||||||
| 
 | 
 | ||||||
|     private gl: WebGLRenderingContext; |     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(){ |     private constructor(){ | ||||||
|         this.loading = false; |         this.loading = false; | ||||||
|         this.justLoaded = false; |         this.justLoaded = false; | ||||||
|  | @ -123,14 +129,17 @@ export default class ResourceManager { | ||||||
|         this.loadonly_gl_ShaderProgramsToLoad = 0; |         this.loadonly_gl_ShaderProgramsToLoad = 0; | ||||||
|         this.loadonly_gl_ShaderLoadingQueue = new Queue(); |         this.loadonly_gl_ShaderLoadingQueue = new Queue(); | ||||||
| 
 | 
 | ||||||
|         this.gl_DefaultShaderPrograms = new Map(); |  | ||||||
|         this.gl_ShaderPrograms = new Map(); |         this.gl_ShaderPrograms = new Map(); | ||||||
| 
 | 
 | ||||||
|         this.gl_Textures = new Map(); |         this.gl_Textures = new Map(); | ||||||
|         this.gl_NextTextureID = 0; |         this.gl_NextTextureID = 0; | ||||||
|         this.gl_Buffers = new Map(); |         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 current instance of this class or a new instance if none exist | ||||||
|      * @returns The resource manager |      * @returns The resource manager | ||||||
|  | @ -143,6 +152,7 @@ export default class ResourceManager { | ||||||
|         return this.instance; |         return this.instance; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /* ######################################## PUBLIC FUNCTION ########################################*/ | ||||||
|     /** |     /** | ||||||
|      * Activates or deactivates the use of WebGL |      * Activates or deactivates the use of WebGL | ||||||
|      * @param flag True if WebGL should be used, false otherwise |      * @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}); |         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 |      * Retrieves a loaded image | ||||||
|      * @param key The key of the 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}); |         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 |      * Retrieves a loaded spritesheet | ||||||
|      * @param key The key of the spritesheet to load |      * @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}); |         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 |      * Retrieves a loaded audio file | ||||||
|      * @param key The key of the audio file to load |      * @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}); |         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 |      * Retreives a loaded tilemap | ||||||
|      * @param key The key of the 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}); |         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 |      * Retreives a loaded object | ||||||
|      * @param key The key of the loaded object |      * @param key The key of the loaded object | ||||||
|  | @ -250,6 +300,7 @@ export default class ResourceManager { | ||||||
|         return this.jsonObjects.get(key); |         return this.jsonObjects.get(key); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /* ######################################## LOAD FUNCTION ########################################*/ | ||||||
|     /** |     /** | ||||||
|      * 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 | ||||||
|  | @ -293,6 +344,21 @@ export default class ResourceManager { | ||||||
|         callback(); |         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 |      * Deletes references to all resources in the resource manager | ||||||
|      */ |      */ | ||||||
|  | @ -300,29 +366,46 @@ export default class ResourceManager { | ||||||
|         this.loading = false; |         this.loading = false; | ||||||
|         this.justLoaded = false; |         this.justLoaded = false; | ||||||
| 
 | 
 | ||||||
|         this.loadonly_imagesLoaded = 0; |         for(let resource of this.resourcesToUnload){ | ||||||
|         this.loadonly_imagesToLoad = 0; |             // Unload the resource
 | ||||||
|         this.images.clear(); |             this.unloadResource(resource); | ||||||
| 
 |         } | ||||||
|         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(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     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 |      * Loads all tilemaps currently in the tilemap loading queue | ||||||
|      * @param onFinishLoading The function to call when loading is complete |      * @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
 |             // We can parse the object later - it's much faster than loading
 | ||||||
|             this.tilemaps.add(key, tilemapObject); |             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
 |             // Grab the tileset images we need to load and add them to the imageloading queue
 | ||||||
|             for(let tileset of tilemapObject.tilesets){ |             for(let tileset of tilemapObject.tilesets){ | ||||||
|                 if(tileset.image){ |                 if(tileset.image){ | ||||||
|                     let key = tileset.image; |                     let key = tileset.image; | ||||||
|                     let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key; |                     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){ |                 } else if(tileset.tiles){ | ||||||
|                     for(let tile of tileset.tiles){ |                     for(let tile of tileset.tiles){ | ||||||
|                         let key = tile.image; |                         let key = tile.image; | ||||||
|                         let path = StringUtils.getPathFromFilePath(pathToTilemapJSON) + key; |                         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
 |             // Finish loading
 | ||||||
|             this.finishLoadingTilemap(callbackIfLast); |             this.finishLoadingTilemap(callbackIfLast); | ||||||
|         }); |         }); | ||||||
|  | @ -422,9 +515,14 @@ export default class ResourceManager { | ||||||
|             // We can parse the object later - it's much faster than loading
 |             // We can parse the object later - it's much faster than loading
 | ||||||
|             this.spritesheets.add(key, spritesheet); |             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
 |             // Grab the image we need to load and add it to the imageloading queue
 | ||||||
|             let path = StringUtils.getPathFromFilePath(pathToSpritesheetJSON) + spritesheet.spriteSheetImage; |             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
 |             // Finish loading
 | ||||||
|             this.finishLoadingSpritesheet(callbackIfLast); |             this.finishLoadingSpritesheet(callbackIfLast); | ||||||
|  | @ -460,7 +558,7 @@ export default class ResourceManager { | ||||||
| 
 | 
 | ||||||
|         while(this.loadonly_imageLoadingQueue.hasItems()){ |         while(this.loadonly_imageLoadingQueue.hasItems()){ | ||||||
|             let image = this.loadonly_imageLoadingQueue.dequeue(); |             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 path The path to the image to load | ||||||
|      * @param callbackIfLast The function to call if this is the last image |      * @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(); |         var image = new Image(); | ||||||
| 
 | 
 | ||||||
|         image.onload = () => { |         image.onload = () => { | ||||||
|             // Add to loaded images
 |             // Add to loaded images
 | ||||||
|             this.images.add(key, image); |             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 WebGL is active, create a texture
 | ||||||
|             if(this.gl_WebGLActive){ |             if(this.gl_WebGLActive){ | ||||||
|                 this.createWebGLTexture(key, image); |                 this.createWebGLTexture(key, image); | ||||||
|  | @ -539,6 +642,7 @@ export default class ResourceManager { | ||||||
|             audioCtx.decodeAudioData(request.response, (buffer) => { |             audioCtx.decodeAudioData(request.response, (buffer) => { | ||||||
|                 // Add to list of audio buffers
 |                 // Add to list of audio buffers
 | ||||||
|                 this.audioBuffers.add(key, buffer); |                 this.audioBuffers.add(key, buffer); | ||||||
|  |                 this.resourcesToUnload.push(new ResourceReference(key, ResourceType.AUDIO)); | ||||||
| 
 | 
 | ||||||
|                 // Finish loading sound
 |                 // Finish loading sound
 | ||||||
|                 this.finishLoadingAudio(callbackIfLast); |                 this.finishLoadingAudio(callbackIfLast); | ||||||
|  | @ -592,6 +696,9 @@ export default class ResourceManager { | ||||||
|         this.loadTextFile(path, (fileText: string) => { |         this.loadTextFile(path, (fileText: string) => { | ||||||
|             let obj = JSON.parse(fileText); |             let obj = JSON.parse(fileText); | ||||||
|             this.jsonObjects.add(key, obj); |             this.jsonObjects.add(key, obj); | ||||||
|  | 
 | ||||||
|  |             this.resourcesToUnload.push(new ResourceReference(key, ResourceType.JSON)); | ||||||
|  | 
 | ||||||
|             this.finishLoadingObject(callbackIfLast); |             this.finishLoadingObject(callbackIfLast); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | @ -706,6 +813,14 @@ export default class ResourceManager { | ||||||
|         this.loadonly_gl_ShaderLoadingQueue.enqueue(paths); |         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 { |     private gl_LoadShadersFromQueue(onFinishLoading: Function): void { | ||||||
|         this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize(); |         this.loadonly_gl_ShaderProgramsToLoad = this.loadonly_gl_ShaderLoadingQueue.getSize(); | ||||||
|         this.loadonly_gl_ShaderProgramsLoaded = 0; |         this.loadonly_gl_ShaderProgramsLoaded = 0; | ||||||
|  | @ -741,6 +856,8 @@ export default class ResourceManager { | ||||||
|                 // Add to our map
 |                 // Add to our map
 | ||||||
|                 this.gl_ShaderPrograms.add(key, programWrapper); |                 this.gl_ShaderPrograms.add(key, programWrapper); | ||||||
| 
 | 
 | ||||||
|  |                 this.resourcesToUnload.push(new ResourceReference(key, ResourceType.SHADER)); | ||||||
|  | 
 | ||||||
|                 // Finish loading
 |                 // Finish loading
 | ||||||
|                 this.gl_FinishLoadingShader(callbackIfLast); |                 this.gl_FinishLoadingShader(callbackIfLast); | ||||||
|             }); |             }); | ||||||
|  | @ -769,7 +886,7 @@ export default class ResourceManager { | ||||||
|         const program = this.gl.createProgram(); |         const program = this.gl.createProgram(); | ||||||
|         if(!program) { |         if(!program) { | ||||||
|             // Error creating
 |             // Error creating
 | ||||||
|             console.log("Failed to create program"); |             console.warn("Failed to create program"); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|      |      | ||||||
|  | @ -782,7 +899,7 @@ export default class ResourceManager { | ||||||
|         if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){ |         if(!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){ | ||||||
|             // Error linking
 |             // Error linking
 | ||||||
|             const error = this.gl.getProgramInfoLog(program); |             const error = this.gl.getProgramInfoLog(program); | ||||||
|             console.log("Failed to link program: " + error); |             console.warn("Failed to link program: " + error); | ||||||
|      |      | ||||||
|             // Clean up
 |             // Clean up
 | ||||||
|             this.gl.deleteProgram(program); |             this.gl.deleteProgram(program); | ||||||
|  | @ -810,7 +927,7 @@ export default class ResourceManager { | ||||||
|      |      | ||||||
|         // If we couldn't create the shader, error
 |         // If we couldn't create the shader, error
 | ||||||
|         if(shader === null){ |         if(shader === null){ | ||||||
|             console.log("Unable to create shader"); |             console.warn("Unable to create shader"); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|      |      | ||||||
|  | @ -822,7 +939,7 @@ export default class ResourceManager { | ||||||
|         if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){ |         if(!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){ | ||||||
|             // Not compiled - error
 |             // Not compiled - error
 | ||||||
|             const error = this.gl.getShaderInfoLog(shader); |             const error = this.gl.getShaderInfoLog(shader); | ||||||
|             console.log("Failed to compile shader: " + error); |             console.warn("Failed to compile shader: " + error); | ||||||
|      |      | ||||||
|             // Clean up
 |             // Clean up
 | ||||||
|             this.gl.deleteShader(shader); |             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 { | class KeyPathPair { | ||||||
|     key: string; |     key: string; | ||||||
|     path: string; |     path: string; | ||||||
|  |     isDependency?: boolean = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class KeyPath_Shader { | class KeyPath_Shader { | ||||||
|  |  | ||||||
|  | @ -90,7 +90,6 @@ export default class TilemapFactory { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if(isParallaxLayer){ |             if(isParallaxLayer){ | ||||||
|                 console.log("Adding parallax layer: " + layer.name) |  | ||||||
|                 sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth); |                 sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1), depth); | ||||||
|             } else { |             } else { | ||||||
|                 sceneLayer = this.scene.addLayer(layer.name, depth); |                 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 */ |     /** An interface that allows the adding of different nodes to the scene */ | ||||||
|     public add: FactoryManager; |     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; |     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 */ |     /** The configuration options for this scene */ | ||||||
|     public sceneOptions: SceneOptions; |     public sceneOptions: SceneOptions; | ||||||
| 
 | 
 | ||||||
|  | @ -120,7 +123,8 @@ 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() | ||||||
|  |         this.resourceManager = this.load; | ||||||
| 
 | 
 | ||||||
|         // Get the timer manager and clear any existing timers
 |         // Get the timer manager and clear any existing timers
 | ||||||
|         TimerManager.getInstance().clearTimers(); |         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. */ |     /** 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 {} |     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. */ |     /** A lifecycle method called strictly after loadScene(). Create any game objects you wish to use in the scene here. */ | ||||||
|     startScene(): void {} |     startScene(): void {} | ||||||
| 
 | 
 | ||||||
|  | @ -144,6 +145,9 @@ export default class Scene implements Updateable { | ||||||
|      */ |      */ | ||||||
|     updateScene(deltaT: number): void {} |     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 { |     update(deltaT: number): void { | ||||||
|         this.updateScene(deltaT); |         this.updateScene(deltaT); | ||||||
| 
 | 
 | ||||||
|  | @ -232,6 +236,12 @@ export default class Scene implements Updateable { | ||||||
|             node.destroy(); |             node.destroy(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         for(let tilemap of this.tilemaps){ | ||||||
|  |             tilemap.destroy(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.receiver.destroy(); | ||||||
|  | 
 | ||||||
|         delete this.sceneGraph; |         delete this.sceneGraph; | ||||||
|         delete this.physicsManager; |         delete this.physicsManager; | ||||||
|         delete this.navManager; |         delete this.navManager; | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import Scene from "./Scene"; | ||||||
| import ResourceManager from "../ResourceManager/ResourceManager"; | import ResourceManager from "../ResourceManager/ResourceManager"; | ||||||
| import Viewport from "../SceneGraph/Viewport"; | import Viewport from "../SceneGraph/Viewport"; | ||||||
| import RenderingManager from "../Rendering/RenderingManager"; | 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. |  * 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 */ | 	/** For consistency, only change scenes at the beginning of the update cycle */ | ||||||
| 	protected pendingScene: Scene; | 	protected pendingScene: Scene; | ||||||
|  | 	protected pendingSceneInit: Record<string, any>; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a new SceneManager | 	 * Creates a new SceneManager | ||||||
|  | @ -37,6 +39,7 @@ export default class SceneManager { | ||||||
| 		this.viewport = viewport; | 		this.viewport = viewport; | ||||||
| 		this.renderingManager = renderingManager; | 		this.renderingManager = renderingManager; | ||||||
| 		this.idCounter = 0; | 		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 | 	 * @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 { | 	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); | 		this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y); | ||||||
| 		 | 		 | ||||||
| 		let scene = new constr(this.viewport, this, this.renderingManager, options); |  | ||||||
| 		 |  | ||||||
| 		if(this.currentScene){ | 		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.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
 | 		// Enqueue all scene asset loads
 | ||||||
| 		scene.loadScene(); | 		this.currentScene.loadScene(); | ||||||
| 
 | 
 | ||||||
| 		// Load all assets
 | 		// Load all assets
 | ||||||
| 		console.log("Starting Scene Load"); | 		console.log("Starting Scene Load"); | ||||||
| 		this.resourceManager.loadResourcesFromQueue(() => { | 		this.resourceManager.loadResourcesFromQueue(() => { | ||||||
| 			console.log("Starting Scene"); | 			console.log("Starting Scene"); | ||||||
| 			scene.startScene(); | 			this.currentScene.startScene(); | ||||||
| 			scene.setRunning(true); | 			this.currentScene.setRunning(true); | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		this.renderingManager.setScene(scene); | 		this.renderingManager.setScene(this.currentScene); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	/** | 	/** | ||||||
|  | @ -85,15 +104,21 @@ export default class SceneManager { | ||||||
| 	 * Renders the current Scene | 	 * Renders the current Scene | ||||||
| 	 */ | 	 */ | ||||||
| 	public render(): void { | 	public render(): void { | ||||||
|  | 		if(this.currentScene){ | ||||||
| 			this.currentScene.render(); | 			this.currentScene.render(); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Updates the current Scene | 	 * Updates the current Scene | ||||||
| 	 * @param deltaT The timestep of the Scene | 	 * @param deltaT The timestep of the Scene | ||||||
| 	 */ | 	 */ | ||||||
| 	public update(deltaT: number){ | 	public update(deltaT: number){ | ||||||
| 		if(this.currentScene.isRunning()){ | 		if(this.pendingScene !== null){ | ||||||
|  | 			this.doSceneChange(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if(this.currentScene && this.currentScene.isRunning()){ | ||||||
| 			this.currentScene.update(deltaT); | 			this.currentScene.update(deltaT); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -155,7 +155,7 @@ export default class Viewport { | ||||||
|      * @param zoom The zoom level |      * @param zoom The zoom level | ||||||
|      */ |      */ | ||||||
|     setZoomLevel(zoom: number): void { |     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();  |             this.audioCtx = new AudioContext();  | ||||||
|             console.log('Web Audio API successfully loaded'); |             console.log('Web Audio API successfully loaded'); | ||||||
|         } catch(e) { |         } 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