updated wolfie2d

This commit is contained in:
OfficialCHenry 2022-04-13 23:09:40 -04:00
parent d19a52e184
commit 1f0764087a
4 changed files with 153 additions and 323 deletions

View File

@ -247,7 +247,7 @@ export default class Input {
* @returns True if the mouse was just pressed, false otherwise * @returns True if the mouse was just pressed, false otherwise
*/ */
static isMouseJustPressed(mouseButton?: number): boolean { static isMouseJustPressed(mouseButton?: number): boolean {
if (mouseButton) { if (mouseButton !== undefined) {
return Input.mouseJustPressed && !Input.mouseDisabled && mouseButton == this.mouseButtonPressed; return Input.mouseJustPressed && !Input.mouseDisabled && mouseButton == this.mouseButtonPressed;
} }
return Input.mouseJustPressed && !Input.mouseDisabled; return Input.mouseJustPressed && !Input.mouseDisabled;
@ -260,7 +260,7 @@ export default class Input {
* @returns True if the mouse is currently pressed, false otherwise * @returns True if the mouse is currently pressed, false otherwise
*/ */
static isMousePressed(mouseButton?: number): boolean { static isMousePressed(mouseButton?: number): boolean {
if (mouseButton) { if (mouseButton !== undefined) {
return Input.mousePressed && !Input.mouseDisabled && mouseButton == this.mouseButtonPressed; return Input.mousePressed && !Input.mouseDisabled && mouseButton == this.mouseButtonPressed;
} }
return Input.mousePressed && !Input.mouseDisabled; return Input.mousePressed && !Input.mouseDisabled;
@ -299,14 +299,12 @@ export default class Input {
return Input.mousePosition.clone().scale(1 / this.viewport.getZoomLevel()).add(Input.viewport.getOrigin()); return Input.mousePosition.clone().scale(1 / this.viewport.getZoomLevel()).add(Input.viewport.getOrigin());
} }
// -- MODIFIED BY HENRY -> added a scaling
/** /**
* Gets the position of the last mouse press * Gets the position of the last mouse press
* @returns The mouse position stored as a Vec2 * @returns The mouse position stored as a Vec2
*/ */
static getMousePressPosition(): Vec2 { static getMousePressPosition(): Vec2 {
return Input.mousePressPosition.scaled(1 / this.viewport.getZoomLevel()); return Input.getMousePosition();
} }
/** /**

View File

@ -84,6 +84,7 @@ export default abstract class UIElement extends CanvasNode {
let clickPos = Input.getMousePressPosition(); let clickPos = Input.getMousePressPosition();
if(this.contains(clickPos.x, clickPos.y) && this.visible && !this.layer.isHidden()){ if(this.contains(clickPos.x, clickPos.y) && this.visible && !this.layer.isHidden()){
this.isClicked = true; this.isClicked = true;
if(this.onClick !== null){ if(this.onClick !== null){
this.onClick(); this.onClick();
} }

View File

@ -15,7 +15,7 @@ export default class UIElementRenderer {
protected scene: Scene; protected scene: Scene;
protected ctx: CanvasRenderingContext2D; protected ctx: CanvasRenderingContext2D;
constructor(ctx: CanvasRenderingContext2D) { constructor(ctx: CanvasRenderingContext2D){
this.resourceManager = ResourceManager.getInstance(); this.resourceManager = ResourceManager.getInstance();
this.ctx = ctx; this.ctx = ctx;
} }
@ -33,81 +33,33 @@ export default class UIElementRenderer {
* @param label The label to render * @param label The label to render
*/ */
renderLabel(label: Label): void { renderLabel(label: Label): void {
// // If the size is unassigned (by the user or automatically) assign it
// label.handleInitialSizing(this.ctx);
// // Grab the global alpha so we can adjust it for this render
// let previousAlpha = this.ctx.globalAlpha;
// // Get the font and text position in label
// this.ctx.font = label.getFontString();
// let offset = label.calculateTextOffset(this.ctx);
// // Stroke and fill a rounded rect and give it text
// this.ctx.globalAlpha = label.backgroundColor.a;
// this.ctx.fillStyle = label.calculateBackgroundColor().toStringRGBA();
// this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2,
// label.size.x, label.size.y, label.borderRadius);
// this.ctx.strokeStyle = label.calculateBorderColor().toStringRGBA();
// this.ctx.globalAlpha = label.borderColor.a;
// this.ctx.lineWidth = label.borderWidth;
// this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2,
// label.size.x, label.size.y, label.borderRadius);
// this.ctx.fillStyle = label.calculateTextColor();
// this.ctx.globalAlpha = label.textColor.a;
// this.ctx.fillText(label.text, offset.x - label.size.x/2, offset.y - label.size.y/2);
// this.ctx.globalAlpha = previousAlpha;
// If the size is unassigned (by the user or automatically) assign it // If the size is unassigned (by the user or automatically) assign it
let lines = label.text.split('\n');
let tempText = label.text;
if (lines.length > 1) {
let max = 0;
let maxLengthIndex = 0;
for (let i = 0; i < lines.length; i++) {
if (lines[i].length > max) {
max = lines[i].length;
maxLengthIndex = i;
}
}
label.text = lines[maxLengthIndex];
}
label.handleInitialSizing(this.ctx); label.handleInitialSizing(this.ctx);
// Grab the global alpha so we can adjust it for this render
let previousAlpha = this.ctx.globalAlpha; // Grab the global alpha so we can adjust it for this render
let previousAlpha = this.ctx.globalAlpha;
// Get the font and text position in label // Get the font and text position in label
this.ctx.font = label.getFontString(); this.ctx.font = label.getFontString();
let offset = label.calculateTextOffset(this.ctx); let offset = label.calculateTextOffset(this.ctx);
// Stroke and fill a rounded rect and give it text // Stroke and fill a rounded rect and give it text
this.ctx.globalAlpha = label.backgroundColor.a; this.ctx.globalAlpha = label.backgroundColor.a;
this.ctx.fillStyle = label.calculateBackgroundColor().toStringRGBA(); this.ctx.fillStyle = label.calculateBackgroundColor().toStringRGBA();
this.ctx.fillRoundedRect(-label.size.x / 2, -label.size.y / 2, this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2,
label.size.x, label.size.y, label.borderRadius); label.size.x, label.size.y, label.borderRadius);
this.ctx.strokeStyle = label.calculateBorderColor().toStringRGBA();
this.ctx.globalAlpha = label.borderColor.a;
this.ctx.lineWidth = label.borderWidth;
this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2,
label.size.x, label.size.y, label.borderRadius);
this.ctx.strokeStyle = label.calculateBorderColor().toStringRGBA(); this.ctx.fillStyle = label.calculateTextColor();
this.ctx.globalAlpha = label.borderColor.a; this.ctx.globalAlpha = label.textColor.a;
this.ctx.lineWidth = label.borderWidth; this.ctx.fillText(label.text, offset.x - label.size.x/2, offset.y - label.size.y/2);
this.ctx.strokeRoundedRect(-label.size.x / 2, -label.size.y / 2,
label.size.x, label.size.y + ((lines.length - 1) * label.fontSize), label.borderRadius); this.ctx.globalAlpha = previousAlpha;
this.ctx.fillStyle = label.calculateTextColor();
this.ctx.globalAlpha = label.textColor.a;
if (lines.length === 1) {
this.ctx.fillText(label.text, offset.x - label.size.x / 2, (offset.y - label.size.y / 2));
} else {
for (let i = 0; i < lines.length; i++) {
let additionalY = i * (label.size.y / 2 + (label.fontSize === 40 ? 20 : 10));
label.text = lines[i];
offset = label.calculateTextOffset(this.ctx);
this.ctx.fillText(lines[i], (offset.x - label.size.x / 2), (offset.y - label.size.y / 2 + additionalY));
}
}
this.ctx.globalAlpha = previousAlpha;
label.text = tempText;
} }
/** /**
@ -123,24 +75,24 @@ export default class UIElementRenderer {
* @param slider The slider to render * @param slider The slider to render
*/ */
renderSlider(slider: Slider): void { renderSlider(slider: Slider): void {
// Grab the global alpha so we can adjust it for this render // Grab the global alpha so we can adjust it for this render
let previousAlpha = this.ctx.globalAlpha; let previousAlpha = this.ctx.globalAlpha;
this.ctx.globalAlpha = slider.getLayer().getAlpha(); this.ctx.globalAlpha = slider.getLayer().getAlpha();
// Calcualate the slider size // Calcualate the slider size
let sliderSize = new Vec2(slider.size.x, 2); let sliderSize = new Vec2(slider.size.x, 2);
// Draw the slider // Draw the slider
this.ctx.fillStyle = slider.sliderColor.toString(); this.ctx.fillStyle = slider.sliderColor.toString();
this.ctx.fillRoundedRect(-sliderSize.x / 2, -sliderSize.y / 2, this.ctx.fillRoundedRect(-sliderSize.x/2, -sliderSize.y/2,
sliderSize.x, sliderSize.y, slider.borderRadius); sliderSize.x, sliderSize.y, slider.borderRadius);
// Calculate the nib size and position // Calculate the nib size and position
let x = MathUtils.lerp(-slider.size.x / 2, slider.size.x / 2, slider.getValue()); let x = MathUtils.lerp(-slider.size.x/2, slider.size.x/2, slider.getValue());
// Draw the nib // Draw the nib
this.ctx.fillStyle = slider.nibColor.toString(); this.ctx.fillStyle = slider.nibColor.toString();
this.ctx.fillRoundedRect(x - slider.nibSize.x / 2, -slider.nibSize.y / 2, this.ctx.fillRoundedRect(x-slider.nibSize.x/2, -slider.nibSize.y/2,
slider.nibSize.x, slider.nibSize.y, slider.borderRadius); slider.nibSize.x, slider.nibSize.y, slider.borderRadius);
// Reset the alpha // Reset the alpha
@ -153,19 +105,19 @@ export default class UIElementRenderer {
*/ */
renderTextInput(textInput: TextInput): void { renderTextInput(textInput: TextInput): void {
// Show a cursor sometimes // Show a cursor sometimes
if (textInput.focused && textInput.cursorCounter % 60 > 30) { if(textInput.focused && textInput.cursorCounter % 60 > 30){
textInput.text += "|"; textInput.text += "|";
} }
this.renderLabel(textInput); this.renderLabel(textInput);
if (textInput.focused) { if(textInput.focused){
if (textInput.cursorCounter % 60 > 30) { if(textInput.cursorCounter % 60 > 30){
textInput.text = textInput.text.substring(0, textInput.text.length - 1); textInput.text = textInput.text.substring(0, textInput.text.length - 1);
} }
textInput.cursorCounter += 1; textInput.cursorCounter += 1;
if (textInput.cursorCounter >= 60) { if(textInput.cursorCounter >= 60){
textInput.cursorCounter = 0; textInput.cursorCounter = 0;
} }
} }

View File

@ -16,7 +16,7 @@ import WebGLProgramType from "../DataTypes/Rendering/WebGLProgramType";
export default class ResourceManager { export default class ResourceManager {
// Instance for the singleton class // Instance for the singleton class
private static instance: ResourceManager; private static instance: ResourceManager;
// Booleans to keep track of whether or not the ResourceManager is currently loading something // Booleans to keep track of whether or not the ResourceManager is currently loading something
/** Whether or not any resources are loading */ /** Whether or not any resources are loading */
private loading: boolean; private loading: boolean;
@ -81,15 +81,11 @@ 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 loadonly_tilemapObjectToLoad: number;
private loadonly_tilemapObjectLoaded: number;
private loadonly_tilemapObjectLoadingQueue: Queue<KeyMapPair>;
private gl_ShaderPrograms: Map<WebGLProgramType>; private gl_ShaderPrograms: Map<WebGLProgramType>;
private gl_Textures: Map<number>; private gl_Textures: Map<number>;
private gl_NextTextureID: number; private gl_NextTextureID: number;
private gl_Buffers: Map<WebGLBuffer>; private gl_Buffers: Map<WebGLBuffer>;
private gl: WebGLRenderingContext; private gl: WebGLRenderingContext;
@ -100,7 +96,7 @@ export default class ResourceManager {
/** A list of resources to keep until further notice */ /** A list of resources to keep until further notice */
private resourcesToKeep: Array<ResourceReference>; private resourcesToKeep: Array<ResourceReference>;
private constructor() { private constructor(){
this.loading = false; this.loading = false;
this.justLoaded = false; this.justLoaded = false;
@ -141,10 +137,6 @@ export default class ResourceManager {
this.resourcesToUnload = new Array(); this.resourcesToUnload = new Array();
this.resourcesToKeep = new Array(); this.resourcesToKeep = new Array();
this.loadonly_tilemapObjectToLoad = 0;
this.loadonly_tilemapObjectToLoad = 0;
this.loadonly_tilemapObjectLoadingQueue = new Queue();
}; };
/* ######################################## SINGLETON ########################################*/ /* ######################################## SINGLETON ########################################*/
@ -153,7 +145,7 @@ export default class ResourceManager {
* @returns The resource manager * @returns The resource manager
*/ */
static getInstance(): ResourceManager { static getInstance(): ResourceManager {
if (!this.instance) { if(!this.instance){
this.instance = new ResourceManager(); this.instance = new ResourceManager();
} }
@ -169,7 +161,7 @@ export default class ResourceManager {
public useWebGL(flag: boolean, gl: WebGLRenderingContext): void { public useWebGL(flag: boolean, gl: WebGLRenderingContext): void {
this.gl_WebGLActive = flag; this.gl_WebGLActive = flag;
if (this.gl_WebGLActive) { if(this.gl_WebGLActive){
this.gl = gl; this.gl = gl;
} }
} }
@ -180,7 +172,7 @@ export default class ResourceManager {
* @param path The path to the image to load * @param path The path to the image to load
*/ */
public image(key: string, path: string): void { public image(key: string, path: string): void {
this.loadonly_imageLoadingQueue.enqueue({ key: key, path: path }); this.loadonly_imageLoadingQueue.enqueue({key: key, path: path});
} }
/** /**
@ -198,9 +190,9 @@ export default class ResourceManager {
*/ */
public getImage(key: string): HTMLImageElement { public getImage(key: string): HTMLImageElement {
let image = this.images.get(key); let image = this.images.get(key);
// if (image === undefined) { if(image === undefined){
// throw `There is no image associated with key "${key}"` throw `There is no image associated with key "${key}"`
// } }
return image; return image;
} }
@ -210,7 +202,7 @@ export default class ResourceManager {
* @param path The path to the spritesheet to load * @param path The path to the spritesheet to load
*/ */
public spritesheet(key: string, path: string): void { public spritesheet(key: string, path: string): void {
this.loadonly_spritesheetLoadingQueue.enqueue({ key: key, path: path }); this.loadonly_spritesheetLoadingQueue.enqueue({key: key, path: path});
} }
/** /**
@ -236,14 +228,14 @@ export default class ResourceManager {
* @param path The path to the audio file to load * @param path The path to the audio file to load
*/ */
public audio(key: string, path: string): void { public audio(key: string, path: string): void {
this.loadonly_audioLoadingQueue.enqueue({ key: key, path: path }); this.loadonly_audioLoadingQueue.enqueue({key: key, path: path});
} }
/** /**
* Tells the resource manager to keep this resource * Tells the resource manager to keep this resource
* @param key The key of the resource * @param key The key of the resource
*/ */
public keepAudio(key: string): void { public keepAudio(key: string): void {
this.keepResource(key, ResourceType.AUDIO); this.keepResource(key, ResourceType.AUDIO);
} }
@ -262,14 +254,14 @@ export default class ResourceManager {
* @param path The path to the tilemap to load * @param path The path to the tilemap to load
*/ */
public tilemap(key: string, path: string): void { public tilemap(key: string, path: string): void {
this.loadonly_tilemapLoadingQueue.enqueue({ key: key, path: path }); this.loadonly_tilemapLoadingQueue.enqueue({key: key, path: path});
} }
/** /**
* Tells the resource manager to keep this resource * Tells the resource manager to keep this resource
* @param key The key of the resource * @param key The key of the resource
*/ */
public keepTilemap(key: string): void { public keepTilemap(key: string): void {
this.keepResource(key, ResourceType.TILEMAP); this.keepResource(key, ResourceType.TILEMAP);
} }
@ -287,15 +279,15 @@ export default class ResourceManager {
* @param key The key to associate with the loaded object * @param key The key to associate with the loaded object
* @param path The path to the json file to load * @param path The path to the json file to load
*/ */
public object(key: string, path: string) { public object(key: string, path: string){
this.loadonly_jsonLoadingQueue.enqueue({ key: key, path: path }); this.loadonly_jsonLoadingQueue.enqueue({key: key, path: path});
} }
/** /**
* Tells the resource manager to keep this resource * Tells the resource manager to keep this resource
* @param key The key of the resource * @param key The key of the resource
*/ */
public keepObject(key: string): void { public keepObject(key: string): void {
this.keepResource(key, ResourceType.JSON); this.keepResource(key, ResourceType.JSON);
} }
@ -304,7 +296,7 @@ export default class ResourceManager {
* @param key The key of the loaded object * @param key The key of the loaded object
* @returns The object data associated with the key * @returns The object data associated with the key
*/ */
public getObject(key: string) { public getObject(key: string){
return this.jsonObjects.get(key); return this.jsonObjects.get(key);
} }
@ -319,30 +311,26 @@ export default class ResourceManager {
this.loading = true; this.loading = true;
// Load everything in the queues. Tilemaps have to come before images because they will add new images to the queue // Load everything in the queues. Tilemaps have to come before images because they will add new images to the queue
this.loadTilemapsFromQueue(() => {
this.loadTilemapObjectFromQueue(() => { console.log("Loaded Tilemaps");
console.log("Loaded TilemapObjects"); this.loadSpritesheetsFromQueue(() => {
this.loadTilemapsFromQueue(() => { console.log("Loaded Spritesheets");
console.log("Loaded Tilemaps"); this.loadImagesFromQueue(() => {
this.loadSpritesheetsFromQueue(() => { console.log("Loaded Images");
console.log("Loaded Spritesheets"); this.loadAudioFromQueue(() => {
this.loadImagesFromQueue(() => { console.log("Loaded Audio");
console.log("Loaded Images"); this.loadObjectsFromQueue(() => {
this.loadAudioFromQueue(() => { console.log("Loaded Objects");
console.log("Loaded Audio");
this.loadObjectsFromQueue(() => { if(this.gl_WebGLActive){
console.log("Loaded Objects"); this.gl_LoadShadersFromQueue(() => {
console.log("Loaded Shaders");
if (this.gl_WebGLActive) {
this.gl_LoadShadersFromQueue(() => {
console.log("Loaded Shaders");
this.finishLoading(callback);
});
} else {
this.finishLoading(callback); this.finishLoading(callback);
} });
}) } else {
}); this.finishLoading(callback);
}
})
}); });
}); });
}); });
@ -357,12 +345,12 @@ export default class ResourceManager {
} }
/* ######################################## UNLOAD FUNCTION ########################################*/ /* ######################################## UNLOAD FUNCTION ########################################*/
private keepResource(key: string, type: ResourceType): void { private keepResource(key: string, type: ResourceType): void {
console.log("Keep resource..."); console.log("Keep resource...");
for (let i = 0; i < this.resourcesToUnload.length; i++) { for(let i = 0; i < this.resourcesToUnload.length; i++){
let resource = this.resourcesToUnload[i]; let resource = this.resourcesToUnload[i];
if (resource.key === key && resource.resourceType === type) { if(resource.key === key && resource.resourceType === type){
console.log("Found resource " + key + " of type " + type + ". Keeping."); console.log("Found resource " + key + " of type " + type + ". Keeping.");
let resourceToMove = this.resourcesToUnload.splice(i, 1); let resourceToMove = this.resourcesToUnload.splice(i, 1);
this.resourcesToKeep.push(...resourceToMove); this.resourcesToKeep.push(...resourceToMove);
@ -370,7 +358,7 @@ export default class ResourceManager {
} }
} }
} }
/** /**
* Deletes references to all resources in the resource manager * Deletes references to all resources in the resource manager
*/ */
@ -378,7 +366,7 @@ export default class ResourceManager {
this.loading = false; this.loading = false;
this.justLoaded = false; this.justLoaded = false;
for (let resource of this.resourcesToUnload) { for(let resource of this.resourcesToUnload){
// Unload the resource // Unload the resource
this.unloadResource(resource); this.unloadResource(resource);
} }
@ -386,10 +374,10 @@ export default class ResourceManager {
private unloadResource(resource: ResourceReference): void { private unloadResource(resource: ResourceReference): void {
// Delete the resource itself // Delete the resource itself
switch (resource.resourceType) { switch(resource.resourceType){
case ResourceType.IMAGE: case ResourceType.IMAGE:
this.images.delete(resource.key); this.images.delete(resource.key);
if (this.gl_WebGLActive) { if(this.gl_WebGLActive){
this.gl_Textures.delete(resource.key); this.gl_Textures.delete(resource.key);
} }
break; break;
@ -412,7 +400,7 @@ export default class ResourceManager {
} }
// Delete any dependencies // Delete any dependencies
for (let dependency of resource.dependencies) { for(let dependency of resource.dependencies){
this.unloadResource(dependency); this.unloadResource(dependency);
} }
} }
@ -427,12 +415,12 @@ export default class ResourceManager {
this.loadonly_tilemapsLoaded = 0; this.loadonly_tilemapsLoaded = 0;
// If no items to load, we're finished // If no items to load, we're finished
if (this.loadonly_tilemapsToLoad === 0) { if(this.loadonly_tilemapsToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
while (this.loadonly_tilemapLoadingQueue.hasItems()) { while(this.loadonly_tilemapLoadingQueue.hasItems()){
let tilemap = this.loadonly_tilemapLoadingQueue.dequeue(); let tilemap = this.loadonly_tilemapLoadingQueue.dequeue();
this.loadTilemap(tilemap.key, tilemap.path, onFinishLoading); this.loadTilemap(tilemap.key, tilemap.path, onFinishLoading);
} }
@ -447,25 +435,25 @@ export default class ResourceManager {
private loadTilemap(key: string, pathToTilemapJSON: string, callbackIfLast: Function): void { private loadTilemap(key: string, pathToTilemapJSON: string, callbackIfLast: Function): void {
this.loadTextFile(pathToTilemapJSON, (fileText: string) => { this.loadTextFile(pathToTilemapJSON, (fileText: string) => {
let tilemapObject = <TiledTilemapData>JSON.parse(fileText); let tilemapObject = <TiledTilemapData>JSON.parse(fileText);
// 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); 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, isDependency: true }); this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
// Add this image as a dependency to the tilemap // Add this image as a dependency to the tilemap
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE)); 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, isDependency: true }); this.loadonly_imageLoadingQueue.enqueue({key: key, path: path, isDependency: true});
// Add this image as a dependency to the tilemap // Add this image as a dependency to the tilemap
resource.addDependency(new ResourceReference(key, ResourceType.IMAGE)); resource.addDependency(new ResourceReference(key, ResourceType.IMAGE));
@ -488,7 +476,7 @@ export default class ResourceManager {
private finishLoadingTilemap(callback: Function): void { private finishLoadingTilemap(callback: Function): void {
this.loadonly_tilemapsLoaded += 1; this.loadonly_tilemapsLoaded += 1;
if (this.loadonly_tilemapsLoaded === this.loadonly_tilemapsToLoad) { if(this.loadonly_tilemapsLoaded === this.loadonly_tilemapsToLoad){
// We're done loading tilemaps // We're done loading tilemaps
callback(); callback();
} }
@ -503,12 +491,12 @@ export default class ResourceManager {
this.loadonly_spritesheetsLoaded = 0; this.loadonly_spritesheetsLoaded = 0;
// If no items to load, we're finished // If no items to load, we're finished
if (this.loadonly_spritesheetsToLoad === 0) { if(this.loadonly_spritesheetsToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
while (this.loadonly_spritesheetLoadingQueue.hasItems()) { while(this.loadonly_spritesheetLoadingQueue.hasItems()){
let spritesheet = this.loadonly_spritesheetLoadingQueue.dequeue(); let spritesheet = this.loadonly_spritesheetLoadingQueue.dequeue();
this.loadSpritesheet(spritesheet.key, spritesheet.path, onFinishLoading); this.loadSpritesheet(spritesheet.key, spritesheet.path, onFinishLoading);
} }
@ -523,7 +511,7 @@ export default class ResourceManager {
private loadSpritesheet(key: string, pathToSpritesheetJSON: string, callbackIfLast: Function): void { private loadSpritesheet(key: string, pathToSpritesheetJSON: string, callbackIfLast: Function): void {
this.loadTextFile(pathToSpritesheetJSON, (fileText: string) => { this.loadTextFile(pathToSpritesheetJSON, (fileText: string) => {
let spritesheet = <Spritesheet>JSON.parse(fileText); let spritesheet = <Spritesheet>JSON.parse(fileText);
// 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);
@ -531,7 +519,7 @@ export default class ResourceManager {
// 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, isDependency: true }); this.loadonly_imageLoadingQueue.enqueue({key: spritesheet.name, path: path, isDependency: true});
resource.addDependency(new ResourceReference(spritesheet.name, ResourceType.IMAGE)); resource.addDependency(new ResourceReference(spritesheet.name, ResourceType.IMAGE));
this.resourcesToUnload.push(resource); this.resourcesToUnload.push(resource);
@ -548,7 +536,7 @@ export default class ResourceManager {
private finishLoadingSpritesheet(callback: Function): void { private finishLoadingSpritesheet(callback: Function): void {
this.loadonly_spritesheetsLoaded += 1; this.loadonly_spritesheetsLoaded += 1;
if (this.loadonly_spritesheetsLoaded === this.loadonly_spritesheetsToLoad) { if(this.loadonly_spritesheetsLoaded === this.loadonly_spritesheetsToLoad){
// We're done loading spritesheets // We're done loading spritesheets
callback(); callback();
} }
@ -563,12 +551,12 @@ export default class ResourceManager {
this.loadonly_imagesLoaded = 0; this.loadonly_imagesLoaded = 0;
// If no items to load, we're finished // If no items to load, we're finished
if (this.loadonly_imagesToLoad === 0) { if(this.loadonly_imagesToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
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, image.isDependency, onFinishLoading); this.loadImage(image.key, image.path, image.isDependency, onFinishLoading);
} }
@ -588,12 +576,12 @@ export default class ResourceManager {
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 not a dependency, push it to the unload list. Otherwise it's managed by something else
if (!isDependency) { if(!isDependency){
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.IMAGE)); 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);
} }
@ -611,7 +599,7 @@ export default class ResourceManager {
private finishLoadingImage(callback: Function): void { private finishLoadingImage(callback: Function): void {
this.loadonly_imagesLoaded += 1; this.loadonly_imagesLoaded += 1;
if (this.loadonly_imagesLoaded === this.loadonly_imagesToLoad) { if(this.loadonly_imagesLoaded === this.loadonly_imagesToLoad ){
// We're done loading images // We're done loading images
callback(); callback();
} }
@ -621,17 +609,17 @@ export default class ResourceManager {
* Loads all audio currently in the tilemap loading queue * Loads all audio currently in the tilemap loading queue
* @param onFinishLoading The function to call when tilemaps are done loading * @param onFinishLoading The function to call when tilemaps are done loading
*/ */
private loadAudioFromQueue(onFinishLoading: Function) { private loadAudioFromQueue(onFinishLoading: Function){
this.loadonly_audioToLoad = this.loadonly_audioLoadingQueue.getSize(); this.loadonly_audioToLoad = this.loadonly_audioLoadingQueue.getSize();
this.loadonly_audioLoaded = 0; this.loadonly_audioLoaded = 0;
// If no items to load, we're finished // If no items to load, we're finished
if (this.loadonly_audioToLoad === 0) { if(this.loadonly_audioToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
while (this.loadonly_audioLoadingQueue.hasItems()) { while(this.loadonly_audioLoadingQueue.hasItems()){
let audio = this.loadonly_audioLoadingQueue.dequeue(); let audio = this.loadonly_audioLoadingQueue.dequeue();
this.loadAudio(audio.key, audio.path, onFinishLoading); this.loadAudio(audio.key, audio.path, onFinishLoading);
} }
@ -658,7 +646,7 @@ export default class ResourceManager {
// Finish loading sound // Finish loading sound
this.finishLoadingAudio(callbackIfLast); this.finishLoadingAudio(callbackIfLast);
}, (error) => { }, (error) =>{
throw "Error loading sound"; throw "Error loading sound";
}); });
} }
@ -672,7 +660,7 @@ export default class ResourceManager {
private finishLoadingAudio(callback: Function): void { private finishLoadingAudio(callback: Function): void {
this.loadonly_audioLoaded += 1; this.loadonly_audioLoaded += 1;
if (this.loadonly_audioLoaded === this.loadonly_audioToLoad) { if(this.loadonly_audioLoaded === this.loadonly_audioToLoad){
// We're done loading audio // We're done loading audio
callback(); callback();
} }
@ -687,12 +675,12 @@ export default class ResourceManager {
this.loadonly_jsonLoaded = 0; this.loadonly_jsonLoaded = 0;
// If no items to load, we're finished // If no items to load, we're finished
if (this.loadonly_jsonToLoad === 0) { if(this.loadonly_jsonToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
while (this.loadonly_jsonLoadingQueue.hasItems()) { while(this.loadonly_jsonLoadingQueue.hasItems()){
let obj = this.loadonly_jsonLoadingQueue.dequeue(); let obj = this.loadonly_jsonLoadingQueue.dequeue();
this.loadObject(obj.key, obj.path, onFinishLoading); this.loadObject(obj.key, obj.path, onFinishLoading);
} }
@ -722,7 +710,7 @@ export default class ResourceManager {
private finishLoadingObject(callback: Function): void { private finishLoadingObject(callback: Function): void {
this.loadonly_jsonLoaded += 1; this.loadonly_jsonLoaded += 1;
if (this.loadonly_jsonLoaded === this.loadonly_jsonToLoad) { if(this.loadonly_jsonLoaded === this.loadonly_jsonToLoad){
// We're done loading objects // We're done loading objects
callback(); callback();
} }
@ -774,7 +762,7 @@ export default class ResourceManager {
private getTextureID(id: number): number { private getTextureID(id: number): number {
// Start with 9 cases - this can be expanded if needed, but for the best performance, // Start with 9 cases - this can be expanded if needed, but for the best performance,
// Textures should be stitched into an atlas // Textures should be stitched into an atlas
switch (id) { switch(id){
case 0: return this.gl.TEXTURE0; case 0: return this.gl.TEXTURE0;
case 1: return this.gl.TEXTURE1; case 1: return this.gl.TEXTURE1;
case 2: return this.gl.TEXTURE2; case 2: return this.gl.TEXTURE2;
@ -789,7 +777,7 @@ export default class ResourceManager {
} }
public createBuffer(key: string): void { public createBuffer(key: string): void {
if (this.gl_WebGLActive) { if(this.gl_WebGLActive){
let buffer = this.gl.createBuffer(); let buffer = this.gl.createBuffer();
this.gl_Buffers.add(key, buffer); this.gl_Buffers.add(key, buffer);
@ -806,14 +794,14 @@ export default class ResourceManager {
let splitPath = vShaderFilepath.split("."); let splitPath = vShaderFilepath.split(".");
let end = splitPath[splitPath.length - 1]; let end = splitPath[splitPath.length - 1];
if (end !== "vshader") { if(end !== "vshader"){
throw `${vShaderFilepath} is not a valid vertex shader - must end in ".vshader`; throw `${vShaderFilepath} is not a valid vertex shader - must end in ".vshader`;
} }
splitPath = fShaderFilepath.split("."); splitPath = fShaderFilepath.split(".");
end = splitPath[splitPath.length - 1]; end = splitPath[splitPath.length - 1];
if (end !== "fshader") { if(end !== "fshader"){
throw `${fShaderFilepath} is not a valid vertex shader - must end in ".fshader`; throw `${fShaderFilepath} is not a valid vertex shader - must end in ".fshader`;
} }
@ -829,7 +817,7 @@ export default class ResourceManager {
* Tells the resource manager to keep this resource * Tells the resource manager to keep this resource
* @param key The key of the resource * @param key The key of the resource
*/ */
public keepShader(key: string): void { public keepShader(key: string): void {
this.keepResource(key, ResourceType.IMAGE); this.keepResource(key, ResourceType.IMAGE);
} }
@ -838,12 +826,12 @@ export default class ResourceManager {
this.loadonly_gl_ShaderProgramsLoaded = 0; this.loadonly_gl_ShaderProgramsLoaded = 0;
// If webGL isn'active or there are no items to load, we're finished // If webGL isn'active or there are no items to load, we're finished
if (!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0) { if(!this.gl_WebGLActive || this.loadonly_gl_ShaderProgramsToLoad === 0){
onFinishLoading(); onFinishLoading();
return; return;
} }
while (this.loadonly_gl_ShaderLoadingQueue.hasItems()) { while(this.loadonly_gl_ShaderLoadingQueue.hasItems()){
let shader = this.loadonly_gl_ShaderLoadingQueue.dequeue(); let shader = this.loadonly_gl_ShaderLoadingQueue.dequeue();
this.gl_LoadShader(shader.key, shader.vpath, shader.fpath, onFinishLoading); this.gl_LoadShader(shader.key, shader.vpath, shader.fpath, onFinishLoading);
} }
@ -879,85 +867,85 @@ export default class ResourceManager {
private gl_FinishLoadingShader(callback: Function): void { private gl_FinishLoadingShader(callback: Function): void {
this.loadonly_gl_ShaderProgramsLoaded += 1; this.loadonly_gl_ShaderProgramsLoaded += 1;
if (this.loadonly_gl_ShaderProgramsLoaded === this.loadonly_gl_ShaderProgramsToLoad) { if(this.loadonly_gl_ShaderProgramsLoaded === this.loadonly_gl_ShaderProgramsToLoad){
// We're done loading shaders // We're done loading shaders
callback(); callback();
} }
} }
private createShaderProgram(vShaderSource: string, fShaderSource: string) { private createShaderProgram(vShaderSource: string, fShaderSource: string){
const vertexShader = this.loadVertexShader(vShaderSource); const vertexShader = this.loadVertexShader(vShaderSource);
const fragmentShader = this.loadFragmentShader(fShaderSource); const fragmentShader = this.loadFragmentShader(fShaderSource);
if (vertexShader === null || fragmentShader === null) { if(vertexShader === null || fragmentShader === null){
// We had a problem intializing - error // We had a problem intializing - error
return null; return null;
} }
// Create a shader program // Create a shader program
const program = this.gl.createProgram(); const program = this.gl.createProgram();
if (!program) { if(!program) {
// Error creating // Error creating
console.warn("Failed to create program"); console.warn("Failed to create program");
return null; return null;
} }
// Attach our vertex and fragment shader // Attach our vertex and fragment shader
this.gl.attachShader(program, vertexShader); this.gl.attachShader(program, vertexShader);
this.gl.attachShader(program, fragmentShader); this.gl.attachShader(program, fragmentShader);
// Link // Link
this.gl.linkProgram(program); this.gl.linkProgram(program);
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.warn("Failed to link program: " + error); console.warn("Failed to link program: " + error);
// Clean up // Clean up
this.gl.deleteProgram(program); this.gl.deleteProgram(program);
this.gl.deleteShader(vertexShader); this.gl.deleteShader(vertexShader);
this.gl.deleteShader(fragmentShader); this.gl.deleteShader(fragmentShader);
return null; return null;
} }
// We successfully create a program // We successfully create a program
return [program, vertexShader, fragmentShader]; return [program, vertexShader, fragmentShader];
} }
private loadVertexShader(shaderSource: string): WebGLShader { private loadVertexShader(shaderSource: string): WebGLShader{
// Create a new vertex shader // Create a new vertex shader
return this.loadShader(this.gl.VERTEX_SHADER, shaderSource); return this.loadShader(this.gl.VERTEX_SHADER, shaderSource);
} }
private loadFragmentShader(shaderSource: string): WebGLShader { private loadFragmentShader(shaderSource: string): WebGLShader{
// Create a new fragment shader // Create a new fragment shader
return this.loadShader(this.gl.FRAGMENT_SHADER, shaderSource); return this.loadShader(this.gl.FRAGMENT_SHADER, shaderSource);
} }
private loadShader(type: number, shaderSource: string): WebGLShader { private loadShader(type: number, shaderSource: string): WebGLShader{
const shader = this.gl.createShader(type); const shader = this.gl.createShader(type);
// If we couldn't create the shader, error // If we couldn't create the shader, error
if (shader === null) { if(shader === null){
console.warn("Unable to create shader"); console.warn("Unable to create shader");
return null; return null;
} }
// Add the source to the shader and compile // Add the source to the shader and compile
this.gl.shaderSource(shader, shaderSource); this.gl.shaderSource(shader, shaderSource);
this.gl.compileShader(shader); this.gl.compileShader(shader);
// Make sure there were no errors during this process // Make sure there were no errors during this process
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.warn("Failed to compile shader: " + error); console.warn("Failed to compile shader: " + error);
// Clean up // Clean up
this.gl.deleteShader(shader); this.gl.deleteShader(shader);
return null; return null;
} }
// Sucess, so return the shader // Sucess, so return the shader
return shader; return shader;
} }
@ -979,125 +967,21 @@ export default class ResourceManager {
/* ########## LOADING BAR INFO ########## */ /* ########## LOADING BAR INFO ########## */
private getLoadPercent(): number { private getLoadPercent(): number {
return (this.loadonly_tilemapsLoaded / this.loadonly_tilemapsToLoad return (this.loadonly_tilemapsLoaded/this.loadonly_tilemapsToLoad
+ this.loadonly_spritesheetsLoaded / this.loadonly_spritesheetsToLoad + this.loadonly_spritesheetsLoaded/this.loadonly_spritesheetsToLoad
+ this.loadonly_imagesLoaded / this.loadonly_imagesToLoad + this.loadonly_imagesLoaded/this.loadonly_imagesToLoad
+ this.loadonly_audioLoaded / this.loadonly_audioToLoad) + this.loadonly_audioLoaded/this.loadonly_audioToLoad)
/ this.loadonly_typesToLoad; / this.loadonly_typesToLoad;
} }
// Customized funtions below
// These funtions are NOT well tested!!!
// Only used for shattered sword specific purpose!!!
// Use them carefully!!!
public tilemapFromObject(key: string, tilemap: TiledTilemapData): void {
this.loadonly_tilemapObjectLoadingQueue.enqueue({ key: key, map: tilemap });
}
private loadTilemapObjectFromQueue(onFinishLoading: Function) {
this.loadonly_tilemapObjectToLoad = this.loadonly_tilemapObjectLoadingQueue.getSize();
this.loadonly_tilemapObjectLoaded = 0;
// If no items to load, we're finished
if (this.loadonly_tilemapObjectToLoad === 0) {
onFinishLoading();
return;
}
while (this.loadonly_tilemapObjectLoadingQueue.hasItems()) {
let map = this.loadonly_tilemapObjectLoadingQueue.dequeue();
this.loadTilemapFromObject(map.key, map.map, onFinishLoading);
}
}
private loadTilemapFromObject(key: string, tiledMap: TiledTilemapData, callbackIfLast: Function): void {
// We can parse the object later - it's much faster than loading
this.tilemaps.add(key, tiledMap);
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 tiledMap.tilesets) {
if (tileset.image) {
let key = tileset.image;
let path = key;
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);
this.finishLoadingTilemapObject(callbackIfLast);
}
private finishLoadingTilemapObject(callback: Function): void {
this.loadonly_tilemapObjectLoaded += 1;
if (this.loadonly_tilemapObjectLoaded === this.loadonly_tilemapObjectToLoad) {
// We're done loading tilemaps
callback();
}
}
public singleImage(key: string, path: string, callbackIfLast: Function): void {
var image = new Image();
image.onload = () => {
// Add to loaded images
this.images.add(key, image);
this.resourcesToUnload.push(new ResourceReference(key, ResourceType.IMAGE));
// If WebGL is active, create a texture
if (this.gl_WebGLActive) {
this.createWebGLTexture(key, image);
}
// Finish image load
this.finishLoadingSingleObject(callbackIfLast);
}
image.src = path;
}
public singleAudio(key: string, path: string, callbackIfLast: Function): void {
let audioCtx = AudioManager.getInstance().getAudioContext();
let request = new XMLHttpRequest();
request.open('GET', path, true);
request.responseType = 'arraybuffer';
request.onload = () => {
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.finishLoadingSingleObject(callbackIfLast);
}, (error) => {
throw "Error loading sound";
});
}
request.send();
}
private finishLoadingSingleObject(callback: Function): void {
callback();
}
update(deltaT: number): void { update(deltaT: number): void {
if (this.loading) { if(this.loading){
if (this.onLoadProgress) { if(this.onLoadProgress){
this.onLoadProgress(this.getLoadPercent()); this.onLoadProgress(this.getLoadPercent());
} }
} else if (this.justLoaded) { } else if(this.justLoaded){
this.justLoaded = false; this.justLoaded = false;
if (this.onLoadComplete) { if(this.onLoadComplete){
this.onLoadComplete(); this.onLoadComplete();
} }
} }
@ -1114,10 +998,10 @@ class ResourceReference {
resourceType: ResourceType; resourceType: ResourceType;
dependencies: Array<ResourceReference>; dependencies: Array<ResourceReference>;
constructor(key: string, resourceType: ResourceType) { constructor(key: string, resourceType: ResourceType){
this.key = key; this.key = key;
this.resourceType = resourceType; this.resourceType = resourceType;
this.dependencies = new Array(); this. dependencies = new Array();
} }
addDependency(resource: ResourceReference): void { addDependency(resource: ResourceReference): void {
@ -1144,11 +1028,6 @@ class KeyPathPair {
isDependency?: boolean = false; isDependency?: boolean = false;
} }
class KeyMapPair {
key: string;
map: TiledTilemapData;
}
class KeyPath_Shader { class KeyPath_Shader {
key: string; key: string;
vpath: string; vpath: string;