restructured project, added default scene, fixed viewport bug
This commit is contained in:
		
							parent
							
								
									1512fa5c8f
								
							
						
					
					
						commit
						681d63f202
					
				| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "name": "gameengine",
 | 
					  "name": "wolfie2d",
 | 
				
			||||||
  "version": "1.0.0",
 | 
					  "version": "1.0.0",
 | 
				
			||||||
  "description": "A game engine written in TypeScript",
 | 
					  "description": "A game engine written in TypeScript",
 | 
				
			||||||
  "main": "./dist/main.js",
 | 
					  "main": "./dist/main.js",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,60 +0,0 @@
 | 
				
			||||||
import Vec2 from "./DataTypes/Vec2";
 | 
					 | 
				
			||||||
import Scene from "./Scene/Scene";
 | 
					 | 
				
			||||||
import SceneGraphQuadTree from "./SceneGraph/SceneGraphQuadTree";
 | 
					 | 
				
			||||||
import Color from "./Utils/Color";
 | 
					 | 
				
			||||||
import Boid from "./_DemoClasses/Boids/Boid";
 | 
					 | 
				
			||||||
import FlockBehavior from "./_DemoClasses/Boids/FlockBehavior";
 | 
					 | 
				
			||||||
import Player from "./_DemoClasses/Player/Player";
 | 
					 | 
				
			||||||
import PlayerController from "./_DemoClasses/Player/PlayerController";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * This demo emphasizes an ai system for the game engine with component architecture
 | 
					 | 
				
			||||||
 * Boids move around with components
 | 
					 | 
				
			||||||
 * Boids have randomized affects (maybe?)
 | 
					 | 
				
			||||||
 * Boids respond to player movement
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export default class BoidDemo extends Scene {
 | 
					 | 
				
			||||||
    boids: Array<Boid>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    startScene(){
 | 
					 | 
				
			||||||
        // Set the world size
 | 
					 | 
				
			||||||
        // this.worldSize = new Vec2(800, 600);
 | 
					 | 
				
			||||||
        // this.sceneGraph = new SceneGraphQuadTree(this.viewport, this);
 | 
					 | 
				
			||||||
        // this.viewport.setBounds(0, 0, 800, 600)
 | 
					 | 
				
			||||||
        // this.viewport.setCenter(400, 300);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let layer = this.addLayer();
 | 
					 | 
				
			||||||
        // this.boids = new Array();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // // Add the player
 | 
					 | 
				
			||||||
        // let player = this.add.graphic(Player, layer, new Vec2(0, 0));
 | 
					 | 
				
			||||||
        // player.addPhysics();
 | 
					 | 
				
			||||||
        // let ai = new PlayerController(player, "topdown");
 | 
					 | 
				
			||||||
        // player.update = (deltaT: number) => {ai.update(deltaT)}
 | 
					 | 
				
			||||||
        // this.viewport.follow(player);
 | 
					 | 
				
			||||||
        // this.viewport.enableZoom();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // // Create a bunch of boids
 | 
					 | 
				
			||||||
        // for(let i = 0; i < 150; i++){
 | 
					 | 
				
			||||||
        //     let boid = this.add.graphic(Boid, layer, new Vec2(this.worldSize.x*Math.random(), this.worldSize.y*Math.random()));
 | 
					 | 
				
			||||||
        //     boid.fb = new FlockBehavior(this, boid, this.boids, 75, 50);
 | 
					 | 
				
			||||||
        //     boid.size.set(5, 5);
 | 
					 | 
				
			||||||
        //     this.boids.push(boid);
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    updateScene(deltaT: number): void {
 | 
					 | 
				
			||||||
        for(let boid of this.boids){
 | 
					 | 
				
			||||||
            boid.setColor(Color.RED);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.updateFlock();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    updateFlock(): void {
 | 
					 | 
				
			||||||
        for(let boid of this.boids){
 | 
					 | 
				
			||||||
            boid.fb.update();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,52 +0,0 @@
 | 
				
			||||||
import Vec2 from "./Vec2";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// @ignorePage
 | 
					 | 
				
			||||||
export default class Vec4 {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public vec: Float32Array;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor(x : number = 0, y : number = 0, z : number = 0, w : number = 0) {
 | 
					 | 
				
			||||||
        this.vec = new Float32Array(4);
 | 
					 | 
				
			||||||
        this.vec[0] = x;
 | 
					 | 
				
			||||||
        this.vec[1] = y;
 | 
					 | 
				
			||||||
        this.vec[2] = z;
 | 
					 | 
				
			||||||
        this.vec[3] = w;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Expose x and y with getters and setters
 | 
					 | 
				
			||||||
	get x() {
 | 
					 | 
				
			||||||
		return this.vec[0];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set x(x: number) {
 | 
					 | 
				
			||||||
		this.vec[0] = x;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	get y() {
 | 
					 | 
				
			||||||
		return this.vec[1];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set y(y: number) {
 | 
					 | 
				
			||||||
		this.vec[1] = y;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	get z() {
 | 
					 | 
				
			||||||
		return this.vec[2];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set z(x: number) {
 | 
					 | 
				
			||||||
		this.vec[2] = x;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	get w() {
 | 
					 | 
				
			||||||
		return this.vec[3];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set w(y: number) {
 | 
					 | 
				
			||||||
		this.vec[3] = y;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    split() : [Vec2, Vec2] {
 | 
					 | 
				
			||||||
        return [new Vec2(this.x, this.y), new Vec2(this.z, this.w)];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,239 +0,0 @@
 | 
				
			||||||
import Receiver from "../Events/Receiver";
 | 
					 | 
				
			||||||
import Map from "../DataTypes/Map";
 | 
					 | 
				
			||||||
import Vec2 from "../DataTypes/Vec2";
 | 
					 | 
				
			||||||
import EventQueue from "../Events/EventQueue";
 | 
					 | 
				
			||||||
import Viewport from "../SceneGraph/Viewport";
 | 
					 | 
				
			||||||
import GameEvent from "../Events/GameEvent";
 | 
					 | 
				
			||||||
import { GameEventType } from "../Events/GameEventType";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Receives input events from the @reference[EventQueue] and allows for easy access of information about input by other systems
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export default class InputReceiver{
 | 
					 | 
				
			||||||
	private static instance: InputReceiver = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private mousePressed: boolean;
 | 
					 | 
				
			||||||
	private mouseJustPressed: boolean;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private keyJustPressed: Map<boolean>;
 | 
					 | 
				
			||||||
	private keyPressed: Map<boolean>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private mousePosition: Vec2;
 | 
					 | 
				
			||||||
	private mousePressPosition: Vec2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private scrollDirection: number;
 | 
					 | 
				
			||||||
	private justScrolled: boolean;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private eventQueue: EventQueue;
 | 
					 | 
				
			||||||
	private receiver: Receiver;
 | 
					 | 
				
			||||||
	private viewport: Viewport;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private constructor(){
 | 
					 | 
				
			||||||
		this.mousePressed = false;
 | 
					 | 
				
			||||||
		this.mouseJustPressed = false;
 | 
					 | 
				
			||||||
		this.receiver = new Receiver();
 | 
					 | 
				
			||||||
		this.keyJustPressed = new Map<boolean>();
 | 
					 | 
				
			||||||
		this.keyPressed = new Map<boolean>();
 | 
					 | 
				
			||||||
		this.mousePosition = new Vec2(0, 0);
 | 
					 | 
				
			||||||
		this.mousePressPosition = new Vec2(0, 0);
 | 
					 | 
				
			||||||
		this.scrollDirection = 0;
 | 
					 | 
				
			||||||
		this.justScrolled = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.eventQueue = EventQueue.getInstance();
 | 
					 | 
				
			||||||
		// Subscribe to all input events
 | 
					 | 
				
			||||||
		this.eventQueue.subscribe(this.receiver, [GameEventType.MOUSE_DOWN, GameEventType.MOUSE_UP, GameEventType.MOUSE_MOVE,
 | 
					 | 
				
			||||||
			 GameEventType.KEY_DOWN, GameEventType.KEY_UP, GameEventType.CANVAS_BLUR, GameEventType.WHEEL_UP, GameEventType.WHEEL_DOWN]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the statc instance of the Singleton InputReceiver
 | 
					 | 
				
			||||||
	 * @returns The InputReceiver instance
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	static getInstance(): InputReceiver{
 | 
					 | 
				
			||||||
		if(this.instance === null){
 | 
					 | 
				
			||||||
			this.instance = new InputReceiver();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return this.instance;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	update(deltaT: number): void {
 | 
					 | 
				
			||||||
		// Reset the justPressed values to false
 | 
					 | 
				
			||||||
		this.mouseJustPressed = false;
 | 
					 | 
				
			||||||
		this.keyJustPressed.forEach((key: string) => this.keyJustPressed.set(key, false));
 | 
					 | 
				
			||||||
		this.justScrolled = false;
 | 
					 | 
				
			||||||
		this.scrollDirection = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		while(this.receiver.hasNextEvent()){			
 | 
					 | 
				
			||||||
			let event = this.receiver.getNextEvent();
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			// Handle each event type
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.MOUSE_DOWN){
 | 
					 | 
				
			||||||
				this.mouseJustPressed = true;
 | 
					 | 
				
			||||||
				this.mousePressed = true;
 | 
					 | 
				
			||||||
				this.mousePressPosition = event.data.get("position");	
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.MOUSE_UP){
 | 
					 | 
				
			||||||
				this.mousePressed = false;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.MOUSE_MOVE){
 | 
					 | 
				
			||||||
				this.mousePosition = event.data.get("position");
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.KEY_DOWN){
 | 
					 | 
				
			||||||
				let key = event.data.get("key");
 | 
					 | 
				
			||||||
				// Handle space bar
 | 
					 | 
				
			||||||
				if(key === " "){
 | 
					 | 
				
			||||||
					key = "space";
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if(!this.keyPressed.get(key)){
 | 
					 | 
				
			||||||
					this.keyJustPressed.set(key, true);
 | 
					 | 
				
			||||||
					this.keyPressed.set(key, true);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.KEY_UP){
 | 
					 | 
				
			||||||
				let key = event.data.get("key");
 | 
					 | 
				
			||||||
				// Handle space bar
 | 
					 | 
				
			||||||
				if(key === " "){
 | 
					 | 
				
			||||||
					key = "space";
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				this.keyPressed.set(key, false);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.CANVAS_BLUR){
 | 
					 | 
				
			||||||
				this.clearKeyPresses()
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(event.type === GameEventType.WHEEL_UP){
 | 
					 | 
				
			||||||
				this.scrollDirection = -1;
 | 
					 | 
				
			||||||
				this.justScrolled = true;
 | 
					 | 
				
			||||||
			} else if(event.type === GameEventType.WHEEL_DOWN){
 | 
					 | 
				
			||||||
				this.scrollDirection = 1;
 | 
					 | 
				
			||||||
				this.justScrolled = true;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private clearKeyPresses(): void {
 | 
					 | 
				
			||||||
		this.keyJustPressed.forEach((key: string) => this.keyJustPressed.set(key, false));
 | 
					 | 
				
			||||||
		this.keyPressed.forEach((key: string) => this.keyPressed.set(key, false));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns whether or not a key was newly pressed this frame.
 | 
					 | 
				
			||||||
	 * If the key is still pressed from last frame and wasn't re-pressed, this will return false.
 | 
					 | 
				
			||||||
	 * @param key The key
 | 
					 | 
				
			||||||
	 * @returns True if the key was just pressed, false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	isJustPressed(key: string): boolean {
 | 
					 | 
				
			||||||
		if(this.keyJustPressed.has(key)){
 | 
					 | 
				
			||||||
			return this.keyJustPressed.get(key)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns an array of all of the keys that are newly pressed this frame.
 | 
					 | 
				
			||||||
	 * If a key is still pressed from last frame and wasn't re-pressed, it will not be in this list.
 | 
					 | 
				
			||||||
	 * @returns An array of all of the newly pressed keys.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getKeysJustPressed(): Array<string> {
 | 
					 | 
				
			||||||
		let keys = Array<string>();
 | 
					 | 
				
			||||||
		this.keyJustPressed.forEach(key => {
 | 
					 | 
				
			||||||
			if(this.keyJustPressed.get(key)){
 | 
					 | 
				
			||||||
				keys.push(key);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
		return keys;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns whether or not a key is being pressed.
 | 
					 | 
				
			||||||
	 * @param key The key
 | 
					 | 
				
			||||||
	 * @returns True if the key is currently pressed, false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	isPressed(key: string): boolean {
 | 
					 | 
				
			||||||
		if(this.keyPressed.has(key)){
 | 
					 | 
				
			||||||
			return this.keyPressed.get(key)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns whether or not the mouse was newly pressed this frame
 | 
					 | 
				
			||||||
	 * @returns True if the mouse was just pressed, false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	isMouseJustPressed(): boolean {
 | 
					 | 
				
			||||||
		return this.mouseJustPressed;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns whether or not the mouse is currently pressed
 | 
					 | 
				
			||||||
	 * @returns True if the mouse is currently pressed, false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	isMousePressed(): boolean {
 | 
					 | 
				
			||||||
		return this.mousePressed;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Returns whether the user scrolled or not
 | 
					 | 
				
			||||||
	 * @returns True if the user just scrolled this frame, false otherwise
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	didJustScroll(): boolean {
 | 
					 | 
				
			||||||
		return this.justScrolled;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the direction of the scroll
 | 
					 | 
				
			||||||
	 * @returns -1 if the user scrolled up, 1 if they scrolled down
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getScrollDirection(): number {
 | 
					 | 
				
			||||||
		return this.scrollDirection;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the position of the player's mouse
 | 
					 | 
				
			||||||
	 * @returns The mouse position stored as a Vec2
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getMousePosition(): Vec2 {
 | 
					 | 
				
			||||||
		return this.mousePosition;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the position of the player's mouse in the game world,
 | 
					 | 
				
			||||||
	 * taking into consideration the scrolling of the viewport
 | 
					 | 
				
			||||||
	 * @returns The mouse position stored as a Vec2
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getGlobalMousePosition(): Vec2 {
 | 
					 | 
				
			||||||
		return this.mousePosition.clone().add(this.viewport.getOrigin());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the position of the last mouse press
 | 
					 | 
				
			||||||
	 * @returns The mouse position stored as a Vec2
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getMousePressPosition(): Vec2 {
 | 
					 | 
				
			||||||
		return this.mousePressPosition;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gets the position of the last mouse press in the game world,
 | 
					 | 
				
			||||||
	 * taking into consideration the scrolling of the viewport
 | 
					 | 
				
			||||||
	 * @returns The mouse position stored as a Vec2
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	getGlobalMousePressPosition(): Vec2 {
 | 
					 | 
				
			||||||
		return this.mousePressPosition.clone().add(this.viewport.getOrigin());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Gives the input receiver a reference to the viewport
 | 
					 | 
				
			||||||
	 * @param viewport The viewport
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	setViewport(viewport: Viewport): void {
 | 
					 | 
				
			||||||
		this.viewport = viewport;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										136
									
								
								src/MainScene.ts
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/MainScene.ts
									
									
									
									
									
								
							| 
						 | 
					@ -1,136 +0,0 @@
 | 
				
			||||||
import Scene from "./Scene/Scene";
 | 
					 | 
				
			||||||
import Rect from "./Nodes/Graphics/Rect";
 | 
					 | 
				
			||||||
import Color from "./Utils/Color";
 | 
					 | 
				
			||||||
import Vec2 from "./DataTypes/Vec2";
 | 
					 | 
				
			||||||
import UIElement from "./Nodes/UIElement";
 | 
					 | 
				
			||||||
import Button from "./Nodes/UIElements/Button";
 | 
					 | 
				
			||||||
import Layer from "./Scene/Layer";
 | 
					 | 
				
			||||||
import SecondScene from "./SecondScene";
 | 
					 | 
				
			||||||
import { GameEventType } from "./Events/GameEventType";
 | 
					 | 
				
			||||||
import SceneGraphQuadTree from "./SceneGraph/SceneGraphQuadTree";
 | 
					 | 
				
			||||||
import PlayerController from "./_DemoClasses/Player/PlayerStates/Platformer/PlayerController";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class MainScene extends Scene {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    loadScene(){
 | 
					 | 
				
			||||||
        this.load.tilemap("platformer", "assets/tilemaps/Platformer.json");
 | 
					 | 
				
			||||||
        this.load.tilemap("background", "assets/tilemaps/Background.json");
 | 
					 | 
				
			||||||
        this.load.image("player", "assets/sprites/player.png");
 | 
					 | 
				
			||||||
        this.load.audio("player_jump", "assets/sounds/jump-3.wav");
 | 
					 | 
				
			||||||
        //this.load.audio("level_music", "assets/sounds/level.wav");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let loadingScreen = this.addLayer();
 | 
					 | 
				
			||||||
        let box = this.add.graphic(Rect, loadingScreen, new Vec2(200, 300), new Vec2(400, 60));
 | 
					 | 
				
			||||||
        box.setColor(new Color(0, 0, 0));
 | 
					 | 
				
			||||||
        let bar = this.add.graphic(Rect, loadingScreen, new Vec2(205, 305), new Vec2(0, 50));
 | 
					 | 
				
			||||||
        bar.setColor(new Color(0, 200, 200));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.load.onLoadProgress = (percentProgress: number) => {
 | 
					 | 
				
			||||||
            bar.size.x = 295 * percentProgress;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.load.onLoadComplete = () => {
 | 
					 | 
				
			||||||
            loadingScreen.disable();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    startScene(){
 | 
					 | 
				
			||||||
        // Set world size
 | 
					 | 
				
			||||||
        this.worldSize = new Vec2(2560, 1280)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Use a quadtree
 | 
					 | 
				
			||||||
        this.sceneGraph = new SceneGraphQuadTree(this.viewport, this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Add the background tilemap
 | 
					 | 
				
			||||||
        let backgroundTilemapLayer = this.add.tilemap("background", new Vec2(4, 4))[0];
 | 
					 | 
				
			||||||
        // ...and make it have parallax
 | 
					 | 
				
			||||||
        backgroundTilemapLayer.setParallax(0.5, 0.8);
 | 
					 | 
				
			||||||
        backgroundTilemapLayer.setAlpha(0.5);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Add the music and start playing it on a loop
 | 
					 | 
				
			||||||
        //this.emitter.fireEvent(GameEventType.PLAY_SOUND, {key: "level_music", loop: true, holdReference: true});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Add the tilemap
 | 
					 | 
				
			||||||
        this.add.tilemap("platformer", new Vec2(4, 4));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Create the main game layer
 | 
					 | 
				
			||||||
        let mainLayer = this.addLayer();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Add a player
 | 
					 | 
				
			||||||
        let playerSprite = this.add.sprite("player", mainLayer)
 | 
					 | 
				
			||||||
        playerSprite.position.set(0, 0);
 | 
					 | 
				
			||||||
        playerSprite.size.set(64, 64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.viewport.follow(playerSprite);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Initialize UI
 | 
					 | 
				
			||||||
        let uiLayer = this.addLayer();
 | 
					 | 
				
			||||||
        uiLayer.setParallax(0, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let recordButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        recordButton.size.set(100, 50);
 | 
					 | 
				
			||||||
        recordButton.setText("Record");
 | 
					 | 
				
			||||||
        recordButton.position.set(400, 30);
 | 
					 | 
				
			||||||
        recordButton.onClickEventId = GameEventType.START_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let stopButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        stopButton.size.set(100, 50);
 | 
					 | 
				
			||||||
        stopButton.setText("Stop");
 | 
					 | 
				
			||||||
        stopButton.position.set(550, 30);
 | 
					 | 
				
			||||||
        stopButton.onClickEventId = GameEventType.STOP_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let playButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        playButton.size.set(100, 50);
 | 
					 | 
				
			||||||
        playButton.setText("Play");
 | 
					 | 
				
			||||||
        playButton.position.set(700, 30);
 | 
					 | 
				
			||||||
        playButton.onClickEventId = GameEventType.PLAY_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let cycleFramerateButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        cycleFramerateButton.size.set(150, 50);
 | 
					 | 
				
			||||||
        cycleFramerateButton.setText("Cycle FPS");
 | 
					 | 
				
			||||||
        cycleFramerateButton.position.set(5, 400);
 | 
					 | 
				
			||||||
        let i = 0;
 | 
					 | 
				
			||||||
        let fps = [15, 30, 60];
 | 
					 | 
				
			||||||
        cycleFramerateButton.onClick = () => {
 | 
					 | 
				
			||||||
            this.game.setMaxUpdateFPS(fps[i]);
 | 
					 | 
				
			||||||
            i = (i + 1) % 3;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Pause Menu
 | 
					 | 
				
			||||||
        let pauseLayer = this.addLayer();
 | 
					 | 
				
			||||||
        pauseLayer.setParallax(0, 0);
 | 
					 | 
				
			||||||
        pauseLayer.disable();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let pauseButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        pauseButton.size.set(100, 50);
 | 
					 | 
				
			||||||
        pauseButton.setText("Pause");
 | 
					 | 
				
			||||||
        pauseButton.position.set(700, 400);
 | 
					 | 
				
			||||||
        pauseButton.onClick = () => {
 | 
					 | 
				
			||||||
            this.sceneGraph.getLayers().forEach((layer: Layer) => layer.setPaused(true));
 | 
					 | 
				
			||||||
            pauseLayer.enable();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let modalBackground = this.add.uiElement(UIElement, pauseLayer);
 | 
					 | 
				
			||||||
        modalBackground.size.set(400, 200);
 | 
					 | 
				
			||||||
        modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4));
 | 
					 | 
				
			||||||
        modalBackground.position.set(200, 100);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let resumeButton = this.add.uiElement(Button, pauseLayer);
 | 
					 | 
				
			||||||
        resumeButton.size.set(100, 50);
 | 
					 | 
				
			||||||
        resumeButton.setText("Resume");
 | 
					 | 
				
			||||||
        resumeButton.position.set(360, 150);
 | 
					 | 
				
			||||||
        resumeButton.onClick = () => {
 | 
					 | 
				
			||||||
            this.sceneGraph.getLayers().forEach((layer: Layer) => layer.setPaused(false));
 | 
					 | 
				
			||||||
            pauseLayer.disable();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let switchButton = this.add.uiElement(Button, pauseLayer);
 | 
					 | 
				
			||||||
        switchButton.size.set(140, 50);
 | 
					 | 
				
			||||||
        switchButton.setText("Change Scene");
 | 
					 | 
				
			||||||
        switchButton.position.set(340, 190);
 | 
					 | 
				
			||||||
        switchButton.onClick = () => {
 | 
					 | 
				
			||||||
            this.emitter.fireEvent(GameEventType.STOP_SOUND, {key: "level_music"});
 | 
					 | 
				
			||||||
            this.sceneManager.changeScene(SecondScene);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,353 +0,0 @@
 | 
				
			||||||
import Physical from "../DataTypes/Interfaces/Physical";
 | 
					 | 
				
			||||||
import Vec2 from "../DataTypes/Vec2";
 | 
					 | 
				
			||||||
import GameNode from "../Nodes/GameNode";
 | 
					 | 
				
			||||||
import Tilemap from "../Nodes/Tilemap";
 | 
					 | 
				
			||||||
import PhysicsManager from "./PhysicsManager";
 | 
					 | 
				
			||||||
import BroadPhase from "./BroadPhaseAlgorithms/BroadPhase";
 | 
					 | 
				
			||||||
import SweepAndPrune from "./BroadPhaseAlgorithms/SweepAndPrune";
 | 
					 | 
				
			||||||
import Shape from "../DataTypes/Shapes/Shape";
 | 
					 | 
				
			||||||
import MathUtils from "../Utils/MathUtils";
 | 
					 | 
				
			||||||
import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
 | 
					 | 
				
			||||||
import AABB from "../DataTypes/Shapes/AABB";
 | 
					 | 
				
			||||||
import Debug from "../Debug/Debug";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// @ignorePage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class BasicPhysicsManager extends PhysicsManager {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** The array of static nodes */
 | 
					 | 
				
			||||||
	protected staticNodes: Array<Physical>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** The array of dynamic nodes */
 | 
					 | 
				
			||||||
	protected dynamicNodes: Array<Physical>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** The array of tilemaps */
 | 
					 | 
				
			||||||
	protected tilemaps: Array<Tilemap>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** The broad phase collision detection algorithm used by this physics system */
 | 
					 | 
				
			||||||
	protected broadPhase: BroadPhase;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** A 2D array that contains information about which layers interact with each other */
 | 
					 | 
				
			||||||
	protected layerMask: number[][];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	constructor(physicsOptions: Record<string, any>){
 | 
					 | 
				
			||||||
		super();
 | 
					 | 
				
			||||||
		this.staticNodes = new Array();
 | 
					 | 
				
			||||||
		this.dynamicNodes = new Array();
 | 
					 | 
				
			||||||
		this.tilemaps = new Array();
 | 
					 | 
				
			||||||
		this.broadPhase = new SweepAndPrune();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let i = 0;
 | 
					 | 
				
			||||||
		if(physicsOptions.physicsLayerNames !== null){
 | 
					 | 
				
			||||||
			for(let layer of physicsOptions.physicsLayerNames){
 | 
					 | 
				
			||||||
				if(i >= physicsOptions.numPhysicsLayers){
 | 
					 | 
				
			||||||
					// If we have too many string layers, don't add extras
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				this.layerNames[i] = layer;
 | 
					 | 
				
			||||||
				this.layerMap.add(layer, i);
 | 
					 | 
				
			||||||
				i += 1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for(i; i < physicsOptions.numPhysicsLayers; i++){
 | 
					 | 
				
			||||||
			this.layerNames[i] = "" + i;
 | 
					 | 
				
			||||||
			this.layerMap.add("" + i, i);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.layerMask = physicsOptions.physicsLayerCollisions;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Add a new physics object to be updated with the physics system
 | 
					 | 
				
			||||||
	 * @param node The node to be added to the physics system
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	registerObject(node: GameNode): void {
 | 
					 | 
				
			||||||
		if(node.isStatic){
 | 
					 | 
				
			||||||
			// Static and not collidable
 | 
					 | 
				
			||||||
			this.staticNodes.push(node);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			// Dynamic and not collidable
 | 
					 | 
				
			||||||
			this.dynamicNodes.push(node);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		this.broadPhase.addNode(node);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Add a new tilemap to be updated with the physics system
 | 
					 | 
				
			||||||
	 * @param tilemap The tilemap to be added to the physics system
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	registerTilemap(tilemap: Tilemap): void {
 | 
					 | 
				
			||||||
		this.tilemaps.push(tilemap);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Resolves a collision between two nodes, adjusting their velocities accordingly.
 | 
					 | 
				
			||||||
	 * @param node1 
 | 
					 | 
				
			||||||
	 * @param node2 
 | 
					 | 
				
			||||||
	 * @param firstContact 
 | 
					 | 
				
			||||||
	 * @param lastContact 
 | 
					 | 
				
			||||||
	 * @param collidingX 
 | 
					 | 
				
			||||||
	 * @param collidingY 
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	resolveCollision(node1: Physical, node2: Physical, firstContact: Vec2, lastContact: Vec2, collidingX: boolean, collidingY: boolean): void {
 | 
					 | 
				
			||||||
		// Handle collision
 | 
					 | 
				
			||||||
		if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
 | 
					 | 
				
			||||||
			if(node1.isPlayer){
 | 
					 | 
				
			||||||
				node1.isColliding = true;
 | 
					 | 
				
			||||||
			} else if(node2.isPlayer){
 | 
					 | 
				
			||||||
				node2.isColliding = true;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// We are colliding. Check for any triggers
 | 
					 | 
				
			||||||
			let group1 = node1.group;
 | 
					 | 
				
			||||||
			let group2 = node2.group;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// TODO - This is problematic if a collision happens, but it is later learned that another collision happens before it
 | 
					 | 
				
			||||||
			if(node1.triggers.has(group2)){
 | 
					 | 
				
			||||||
				// Node1 should send an event
 | 
					 | 
				
			||||||
				let eventType = node1.triggers.get(group2);
 | 
					 | 
				
			||||||
				this.emitter.fireEvent(eventType, {node: node1, other: node2, collision: {firstContact: firstContact}});
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(node2.triggers.has(group1)){
 | 
					 | 
				
			||||||
				// Node2 should send an event
 | 
					 | 
				
			||||||
				let eventType = node2.triggers.get(group1);
 | 
					 | 
				
			||||||
				this.emitter.fireEvent(eventType, {node: node2, other: node1, collision: {firstContact: firstContact}});
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(collidingX && collidingY){
 | 
					 | 
				
			||||||
				// If we're already intersecting, resolve the current collision
 | 
					 | 
				
			||||||
			} else if(node1.isCollidable && node2.isCollidable) {
 | 
					 | 
				
			||||||
				// We aren't already colliding, and both nodes can collide, so this is a new collision.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Get the amount to scale x and y based on their initial collision times
 | 
					 | 
				
			||||||
				let xScale = MathUtils.clamp(firstContact.x, 0, 1);
 | 
					 | 
				
			||||||
				let yScale = MathUtils.clamp(firstContact.y, 0, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				MathUtils.floorToPlace(xScale, 4);
 | 
					 | 
				
			||||||
				MathUtils.floorToPlace(yScale, 4);
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
				// Handle special case of stickiness on perfect corner to corner collisions
 | 
					 | 
				
			||||||
				if(xScale === yScale){
 | 
					 | 
				
			||||||
					xScale = 1;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Handle being stopped moving in the y-direction
 | 
					 | 
				
			||||||
				if(yScale !== 1){
 | 
					 | 
				
			||||||
					// Figure out which node is on top
 | 
					 | 
				
			||||||
					let node1onTop = node1.collisionShape.center.y < node2.collisionShape.center.y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					// If either is moving, set their onFloor and onCeiling appropriately
 | 
					 | 
				
			||||||
					if(!node1.isStatic && node1.moving){
 | 
					 | 
				
			||||||
						node1.onGround = node1onTop;
 | 
					 | 
				
			||||||
						node1.onCeiling = !node1onTop;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
					if(!node2.isStatic && node2.moving){
 | 
					 | 
				
			||||||
						node2.onGround = !node1onTop;
 | 
					 | 
				
			||||||
						node2.onCeiling = node1onTop;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Handle being stopped moving in the x-direction
 | 
					 | 
				
			||||||
				if(xScale !== 1){
 | 
					 | 
				
			||||||
					// If either node is non-static and moving, set its onWall to true
 | 
					 | 
				
			||||||
					if(!node1.isStatic && node1.moving){
 | 
					 | 
				
			||||||
						node1.onWall = true;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
					if(!node2.isStatic && node2.moving){
 | 
					 | 
				
			||||||
						node2.onWall = true;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// Scale velocity for either node if it is moving
 | 
					 | 
				
			||||||
				node1._velocity.scale(xScale, yScale);
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
				node2._velocity.scale(xScale, yScale);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	collideWithTilemap(node: Physical, tilemap: Tilemap, velocity: Vec2): void {
 | 
					 | 
				
			||||||
		if(tilemap instanceof OrthogonalTilemap){
 | 
					 | 
				
			||||||
            this.collideWithOrthogonalTilemap(node, tilemap, velocity);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	collideWithOrthogonalTilemap(node: Physical, tilemap: OrthogonalTilemap, velocity: Vec2): void {
 | 
					 | 
				
			||||||
        // Get the starting position, ending position, and size of the node
 | 
					 | 
				
			||||||
        let startPos = node.collisionShape.center;
 | 
					 | 
				
			||||||
        let endPos = startPos.clone().add(velocity);
 | 
					 | 
				
			||||||
        let size = node.collisionShape.halfSize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Get the min and max x and y coordinates of the moving node
 | 
					 | 
				
			||||||
        let min = new Vec2(Math.min(startPos.x - size.x, endPos.x - size.x), Math.min(startPos.y - size.y, endPos.y - size.y));
 | 
					 | 
				
			||||||
        let max = new Vec2(Math.max(startPos.x + size.x, endPos.x + size.x), Math.max(startPos.y + size.y, endPos.y + size.y));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Convert the min/max x/y to the min and max row/col in the tilemap array
 | 
					 | 
				
			||||||
        let minIndex = tilemap.getColRowAt(min);
 | 
					 | 
				
			||||||
        let maxIndex = tilemap.getColRowAt(max);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Create an empty set of tilemap collisions (We'll handle all of them at the end)
 | 
					 | 
				
			||||||
        let tilemapCollisions = new Array<TileCollisionData>();
 | 
					 | 
				
			||||||
        let tileSize = tilemap.getTileSize();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Loop over all possible tiles (which isn't many in the scope of the velocity per frame)
 | 
					 | 
				
			||||||
        for(let col = minIndex.x; col <= maxIndex.x; col++){
 | 
					 | 
				
			||||||
            for(let row = minIndex.y; row <= maxIndex.y; row++){
 | 
					 | 
				
			||||||
                if(tilemap.isTileCollidable(col, row)){
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Get the position of this tile
 | 
					 | 
				
			||||||
                    let tilePos = new Vec2(col * tileSize.x + tileSize.x/2, row * tileSize.y + tileSize.y/2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Create a new collider for this tile
 | 
					 | 
				
			||||||
                    let collider = new AABB(tilePos, tileSize.scaled(1/2));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Calculate collision area between the node and the tile
 | 
					 | 
				
			||||||
                    let dx = Math.min(startPos.x, tilePos.x) - Math.max(startPos.x + size.x, tilePos.x + size.x);
 | 
					 | 
				
			||||||
                    let dy = Math.min(startPos.y, tilePos.y) - Math.max(startPos.y + size.y, tilePos.y + size.y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // If we overlap, how much do we overlap by?
 | 
					 | 
				
			||||||
                    let overlap = 0;
 | 
					 | 
				
			||||||
                    if(dx * dy > 0){
 | 
					 | 
				
			||||||
                        overlap = dx * dy;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    tilemapCollisions.push(new TileCollisionData(collider, overlap));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Now that we have all collisions, sort by collision area highest to lowest
 | 
					 | 
				
			||||||
		tilemapCollisions = tilemapCollisions.sort((a, b) => a.overlapArea - b.overlapArea);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Resolve the collisions in order of collision area (i.e. "closest" tiles are collided with first, so we can slide along a surface of tiles)
 | 
					 | 
				
			||||||
        tilemapCollisions.forEach(collision => {
 | 
					 | 
				
			||||||
            let [firstContact, _, collidingX, collidingY] = Shape.getTimeOfCollision(node.collisionShape, velocity, collision.collider, Vec2.ZERO);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Handle collision
 | 
					 | 
				
			||||||
            if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
 | 
					 | 
				
			||||||
				// We are definitely colliding, so add to this node's tilemap collision list
 | 
					 | 
				
			||||||
				node.collidedWithTilemap = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if(collidingX && collidingY){
 | 
					 | 
				
			||||||
                    // If we're already intersecting, freak out I guess? Probably should handle this in some way for if nodes get spawned inside of tiles
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    // Get the amount to scale x and y based on their initial collision times
 | 
					 | 
				
			||||||
                    let xScale = MathUtils.clamp(firstContact.x, 0, 1);
 | 
					 | 
				
			||||||
                    let yScale = MathUtils.clamp(firstContact.y, 0, 1);
 | 
					 | 
				
			||||||
                    
 | 
					 | 
				
			||||||
                    // Handle special case of stickiness on perfect corner to corner collisions
 | 
					 | 
				
			||||||
                    if(xScale === yScale){
 | 
					 | 
				
			||||||
                        xScale = 1;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if(yScale !== 1){
 | 
					 | 
				
			||||||
                        // If the tile is below us
 | 
					 | 
				
			||||||
                        if(collision.collider.y > node.collisionShape.center.y){
 | 
					 | 
				
			||||||
                            node.onGround = true;
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            node.onCeiling = true;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if(xScale !== 1){
 | 
					 | 
				
			||||||
                        node.onWall = true;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Scale the velocity of the node
 | 
					 | 
				
			||||||
                    velocity.scale(xScale, yScale);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	update(deltaT: number): void {
 | 
					 | 
				
			||||||
		/*---------- INITIALIZATION PHASE ----------*/
 | 
					 | 
				
			||||||
		for(let node of this.dynamicNodes){
 | 
					 | 
				
			||||||
			// Clear frame dependent boolean values for each node
 | 
					 | 
				
			||||||
			node.onGround = false;
 | 
					 | 
				
			||||||
			node.onCeiling = false;
 | 
					 | 
				
			||||||
			node.onWall = false;
 | 
					 | 
				
			||||||
			node.collidedWithTilemap = false;
 | 
					 | 
				
			||||||
			node.isColliding = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(node.isPlayer){
 | 
					 | 
				
			||||||
				Debug.log("pvel", "Player Velocity:", node._velocity.toString());
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Update the swept shapes of each node
 | 
					 | 
				
			||||||
			if(node.moving){
 | 
					 | 
				
			||||||
				// Round Velocity
 | 
					 | 
				
			||||||
				node._velocity.x = Math.round(node._velocity.x*1000)/1000;
 | 
					 | 
				
			||||||
				node._velocity.y = Math.round(node._velocity.y*1000)/1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				// If moving, reflect that in the swept shape
 | 
					 | 
				
			||||||
				node.sweptRect.sweep(node._velocity, node.collisionShape.center, node.collisionShape.halfSize);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				node.sweptRect.sweep(Vec2.ZERO_STATIC, node.collisionShape.center, node.collisionShape.halfSize);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*---------- BROAD PHASE ----------*/
 | 
					 | 
				
			||||||
		// Get a potentially colliding set
 | 
					 | 
				
			||||||
		let potentialCollidingPairs = this.broadPhase.runAlgorithm();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// TODO - Should I be getting all collisions first, sorting by the time they happen, the resolving them?
 | 
					 | 
				
			||||||
		/*---------- NARROW PHASE ----------*/
 | 
					 | 
				
			||||||
		for(let pair of potentialCollidingPairs){
 | 
					 | 
				
			||||||
			let node1 = pair[0];
 | 
					 | 
				
			||||||
			let node2 = pair[1];
 | 
					 | 
				
			||||||
			
 | 
					 | 
				
			||||||
			// Make sure both nodes are active
 | 
					 | 
				
			||||||
			if(!node1.active || !node2.active){
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Make sure both nodes can collide with each other based on their physics layer
 | 
					 | 
				
			||||||
			if(!(node1.physicsLayer === -1 || node2.physicsLayer === -1 || this.layerMask[node1.physicsLayer][node2.physicsLayer] === 1)){
 | 
					 | 
				
			||||||
				// Nodes do not collide. Continue onto the next pair
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Get Collision (which may or may not happen)
 | 
					 | 
				
			||||||
			let [firstContact, lastContact, collidingX, collidingY] = Shape.getTimeOfCollision(node1.collisionShape, node1._velocity, node2.collisionShape, node2._velocity);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			this.resolveCollision(node1, node2, firstContact, lastContact, collidingX, collidingY);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*---------- TILEMAP PHASE ----------*/
 | 
					 | 
				
			||||||
		for(let node of this.dynamicNodes){
 | 
					 | 
				
			||||||
			if(node.moving && node.isCollidable){
 | 
					 | 
				
			||||||
				// If a node is moving and can collide, check it against every tilemap
 | 
					 | 
				
			||||||
				for(let tilemap of this.tilemaps){
 | 
					 | 
				
			||||||
					// Check if there could even be a collision
 | 
					 | 
				
			||||||
					if(node.sweptRect.overlaps(tilemap.boundary)){
 | 
					 | 
				
			||||||
						this.collideWithTilemap(node, tilemap, node._velocity);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*---------- ENDING PHASE ----------*/
 | 
					 | 
				
			||||||
		for(let node of this.dynamicNodes){
 | 
					 | 
				
			||||||
			if(node.moving){
 | 
					 | 
				
			||||||
				node.finishMove();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Collision data objects for tilemaps
 | 
					 | 
				
			||||||
class TileCollisionData {
 | 
					 | 
				
			||||||
    collider: AABB;
 | 
					 | 
				
			||||||
    overlapArea: number;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    constructor(collider: AABB, overlapArea: number){
 | 
					 | 
				
			||||||
        this.collider = collider;
 | 
					 | 
				
			||||||
        this.overlapArea = overlapArea;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
import Physical from "../../DataTypes/Interfaces/Physical";
 | 
					 | 
				
			||||||
import GameNode from "../../Nodes/GameNode";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// @ignorePage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default abstract class BroadPhase {
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Runs the algorithm and returns an array of possible collision pairs.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	abstract runAlgorithm(): Array<Physical[]>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	abstract addNode(node: GameNode): void;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,70 +0,0 @@
 | 
				
			||||||
import Physical from "../../DataTypes/Interfaces/Physical";
 | 
					 | 
				
			||||||
import SortingUtils from "../../Utils/SortingUtils";
 | 
					 | 
				
			||||||
import BroadPhase from "./BroadPhase";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// @ignorePage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class SweepAndPrune extends BroadPhase {
 | 
					 | 
				
			||||||
	protected xList: Array<Physical>;
 | 
					 | 
				
			||||||
	protected yList: Array<Physical>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	constructor(){
 | 
					 | 
				
			||||||
		super();
 | 
					 | 
				
			||||||
		this.xList = new Array();
 | 
					 | 
				
			||||||
		this.yList = new Array();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	addNode(node: Physical): void {
 | 
					 | 
				
			||||||
		this.xList.push(node);
 | 
					 | 
				
			||||||
		this.yList.push(node);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO - Can optimize further by doing a callback whenever a swap occurs
 | 
					 | 
				
			||||||
	// TODO - And by using better pair management
 | 
					 | 
				
			||||||
	runAlgorithm(): Array<Physical[]> {
 | 
					 | 
				
			||||||
		// Sort the xList
 | 
					 | 
				
			||||||
		SortingUtils.insertionSort(this.xList, (a, b) => (a.sweptRect.left - b.sweptRect.left) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let xCollisions = [];
 | 
					 | 
				
			||||||
		for(let i = 0; i < this.xList.length; i++){
 | 
					 | 
				
			||||||
			let node = this.xList[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			let index = 1;
 | 
					 | 
				
			||||||
			while(i + index < this.xList.length && node.sweptRect.right >= this.xList[i + index].sweptRect.left){
 | 
					 | 
				
			||||||
				// Colliding pair in x-axis
 | 
					 | 
				
			||||||
				xCollisions.push([node, this.xList[i + index]]);
 | 
					 | 
				
			||||||
				index++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Sort the y-list
 | 
					 | 
				
			||||||
		SortingUtils.insertionSort(this.yList, (a, b) => (a.sweptRect.top - b.sweptRect.top) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		let yCollisions = [];
 | 
					 | 
				
			||||||
		for(let i = 0; i < this.yList.length; i++){
 | 
					 | 
				
			||||||
			let node = this.yList[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			let index = 1;
 | 
					 | 
				
			||||||
			while(i + index < this.yList.length && node.sweptRect.bottom >= this.yList[i + index].sweptRect.top){
 | 
					 | 
				
			||||||
				// Colliding pair in y-axis
 | 
					 | 
				
			||||||
				yCollisions.push([node, this.yList[i + index]]);
 | 
					 | 
				
			||||||
				index++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Check the pairs
 | 
					 | 
				
			||||||
		let collisions = []
 | 
					 | 
				
			||||||
		for(let xPair of xCollisions){
 | 
					 | 
				
			||||||
			for(let yPair of yCollisions){
 | 
					 | 
				
			||||||
				if((xPair[0] === yPair[0] && xPair[1] === yPair[1])
 | 
					 | 
				
			||||||
				||(xPair[0] === yPair[1] && xPair[1] === yPair[0])){
 | 
					 | 
				
			||||||
					// Colliding in both axes, add to set
 | 
					 | 
				
			||||||
					collisions.push(xPair);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		return collisions;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,13 +0,0 @@
 | 
				
			||||||
import Physical from "../DataTypes/Interfaces/Physical";
 | 
					 | 
				
			||||||
import Vec2 from "../DataTypes/Vec2";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// @ignorePage
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class Collision {
 | 
					 | 
				
			||||||
	firstContact: Vec2;
 | 
					 | 
				
			||||||
	lastContact: Vec2;
 | 
					 | 
				
			||||||
	collidingX: boolean;
 | 
					 | 
				
			||||||
	collidingY: boolean;
 | 
					 | 
				
			||||||
	node1: Physical;
 | 
					 | 
				
			||||||
	node2: Physical;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
import Scene from "./Scene/Scene";
 | 
					 | 
				
			||||||
import Point from "./Nodes/Graphics/Point";
 | 
					 | 
				
			||||||
import Rect from "./Nodes/Graphics/Rect";
 | 
					 | 
				
			||||||
import Layer from "./Scene/Layer";
 | 
					 | 
				
			||||||
import SceneGraphQuadTree from "./SceneGraph/SceneGraphQuadTree"
 | 
					 | 
				
			||||||
import Vec2 from "./DataTypes/Vec2";
 | 
					 | 
				
			||||||
import InputReceiver from "./Input/InputReceiver";
 | 
					 | 
				
			||||||
import Color from "./Utils/Color";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class QuadTreeScene extends Scene {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mainLayer: Layer;
 | 
					 | 
				
			||||||
    view: Rect;
 | 
					 | 
				
			||||||
    points: Array<Point>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    loadScene(){}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    startScene(){
 | 
					 | 
				
			||||||
        // Make the scene graph a quadtree scenegraph
 | 
					 | 
				
			||||||
        this.sceneGraph = new SceneGraphQuadTree(this.viewport, this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Make a main layer
 | 
					 | 
				
			||||||
        this.mainLayer = this.sceneGraph.addLayer();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Generate a bunch of random points
 | 
					 | 
				
			||||||
        this.points = [];
 | 
					 | 
				
			||||||
        for(let i = 0; i < 1000; i++){
 | 
					 | 
				
			||||||
            let pos = new Vec2(500/3*(Math.random() + Math.random() + Math.random()), 500/3*(Math.random() + Math.random() + Math.random()));
 | 
					 | 
				
			||||||
            let point = this.add.graphic(Point, this.mainLayer, pos);
 | 
					 | 
				
			||||||
            point.setColor(Color.RED);
 | 
					 | 
				
			||||||
            this.points.push(point);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.view = this.add.graphic(Rect, this.mainLayer, Vec2.ZERO, new Vec2(150, 100));
 | 
					 | 
				
			||||||
        this.view.setColor(Color.TRANSPARENT);
 | 
					 | 
				
			||||||
        this.view.setBorderColor(Color.ORANGE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    updateScene(deltaT: number): void {
 | 
					 | 
				
			||||||
        this.view.position.copy(InputReceiver.getInstance().getGlobalMousePosition());
 | 
					 | 
				
			||||||
        for(let point of this.points){
 | 
					 | 
				
			||||||
            point.setColor(Color.RED);
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            point.position.add(Vec2.UP.rotateCCW(Math.random()*2*Math.PI).add(point.position.vecTo(this.view.position).normalize().scale(0.1)));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let results = this.sceneGraph.getNodesInRegion(this.view.boundary);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(let result of results){
 | 
					 | 
				
			||||||
            if(result instanceof Point){
 | 
					 | 
				
			||||||
                result.setColor(Color.GREEN);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        results = this.sceneGraph.getNodesAt(this.view.position);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(let result of results){
 | 
					 | 
				
			||||||
            if(result instanceof Point){
 | 
					 | 
				
			||||||
                result.setColor(Color.YELLOW);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,105 +0,0 @@
 | 
				
			||||||
import Scene from "./Scene/Scene";
 | 
					 | 
				
			||||||
import Rect from "./Nodes/Graphics/Rect";
 | 
					 | 
				
			||||||
import Color from "./Utils/Color";
 | 
					 | 
				
			||||||
import Vec2 from "./DataTypes/Vec2";
 | 
					 | 
				
			||||||
import UIElement from "./Nodes/UIElement";
 | 
					 | 
				
			||||||
import Button from "./Nodes/UIElements/Button";
 | 
					 | 
				
			||||||
import Layer from "./Scene/Layer";
 | 
					 | 
				
			||||||
import { GameEventType } from "./Events/GameEventType";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class SecondScene extends Scene {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    loadScene(){
 | 
					 | 
				
			||||||
        this.load.tilemap("level2", "assets/tilemaps/TopDown2.json");
 | 
					 | 
				
			||||||
        this.load.image("player", "assets/sprites/player.png");
 | 
					 | 
				
			||||||
        this.load.audio("music", "assets/sounds/level.wav")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let loadingScreen = this.addLayer();
 | 
					 | 
				
			||||||
        let box = this.add.graphic(Rect, loadingScreen, new Vec2(200, 300), new Vec2(400, 60));
 | 
					 | 
				
			||||||
        box.setColor(new Color(0, 0, 0));
 | 
					 | 
				
			||||||
        let bar = this.add.graphic(Rect, loadingScreen, new Vec2(205, 305), new Vec2(0, 50));
 | 
					 | 
				
			||||||
        bar.setColor(new Color(255, 100, 0));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.load.onLoadProgress = (percentProgress: number) => {
 | 
					 | 
				
			||||||
            //bar.setSize(295 * percentProgress, bar.getSize().y);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.load.onLoadComplete = () => {
 | 
					 | 
				
			||||||
            loadingScreen.disable();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    startScene(){
 | 
					 | 
				
			||||||
        // // Add the tilemap
 | 
					 | 
				
			||||||
        // let mainLayer = this.add.tilemap("level2")[1];
 | 
					 | 
				
			||||||
        // mainLayer.setYSort(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // // Add a player
 | 
					 | 
				
			||||||
        // let player = this.add.physics(Player, mainLayer, "topdown");
 | 
					 | 
				
			||||||
        // let playerSprite = this.add.sprite("player", mainLayer);
 | 
					 | 
				
			||||||
        // player.setSprite(playerSprite);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // this.viewport.follow(player);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // // Initialize UI
 | 
					 | 
				
			||||||
        // let uiLayer = this.addLayer();
 | 
					 | 
				
			||||||
        // uiLayer.setParallax(0, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let recordButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        // recordButton.setSize(100, 50);
 | 
					 | 
				
			||||||
        // recordButton.setText("Record");
 | 
					 | 
				
			||||||
        // recordButton.setPosition(400, 30);
 | 
					 | 
				
			||||||
        // recordButton.onClickEventId = GameEventType.START_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let stopButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        // stopButton.setSize(100, 50);
 | 
					 | 
				
			||||||
        // stopButton.setText("Stop");
 | 
					 | 
				
			||||||
        // stopButton.setPosition(550, 30);
 | 
					 | 
				
			||||||
        // stopButton.onClickEventId = GameEventType.STOP_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let playButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        // playButton.setSize(100, 50);
 | 
					 | 
				
			||||||
        // playButton.setText("Play");
 | 
					 | 
				
			||||||
        // playButton.setPosition(700, 30);
 | 
					 | 
				
			||||||
        // playButton.onClickEventId = GameEventType.PLAY_RECORDING;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let cycleFramerateButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        // cycleFramerateButton.setSize(150, 50);
 | 
					 | 
				
			||||||
        // cycleFramerateButton.setText("Cycle FPS");
 | 
					 | 
				
			||||||
        // cycleFramerateButton.setPosition(5, 400);
 | 
					 | 
				
			||||||
        // let i = 0;
 | 
					 | 
				
			||||||
        // let fps = [15, 30, 60];
 | 
					 | 
				
			||||||
        // cycleFramerateButton.onClick = () => {
 | 
					 | 
				
			||||||
        //     this.game.setMaxUpdateFPS(fps[i]);
 | 
					 | 
				
			||||||
        //     i = (i + 1) % 3;
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // // Pause Menu
 | 
					 | 
				
			||||||
        // let pauseLayer = this.addLayer();
 | 
					 | 
				
			||||||
        // pauseLayer.setParallax(0, 0);
 | 
					 | 
				
			||||||
        // pauseLayer.disable();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let pauseButton = this.add.uiElement(Button, uiLayer);
 | 
					 | 
				
			||||||
        // pauseButton.setSize(100, 50);
 | 
					 | 
				
			||||||
        // pauseButton.setText("Pause");
 | 
					 | 
				
			||||||
        // pauseButton.setPosition(700, 400);
 | 
					 | 
				
			||||||
        // pauseButton.onClick = () => {
 | 
					 | 
				
			||||||
        //     this.sceneGraph.getLayers().forEach((layer: Layer) => layer.setPaused(true));
 | 
					 | 
				
			||||||
        //     pauseLayer.enable();
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let modalBackground = this.add.uiElement(UIElement, pauseLayer);
 | 
					 | 
				
			||||||
        // modalBackground.setSize(400, 200);
 | 
					 | 
				
			||||||
        // modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4));
 | 
					 | 
				
			||||||
        // modalBackground.setPosition(200, 100);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // let resumeButton = this.add.uiElement(Button, pauseLayer);
 | 
					 | 
				
			||||||
        // resumeButton.setSize(100, 50);
 | 
					 | 
				
			||||||
        // resumeButton.setText("Resume");
 | 
					 | 
				
			||||||
        // resumeButton.setPosition(400, 200);
 | 
					 | 
				
			||||||
        // resumeButton.onClick = () => {
 | 
					 | 
				
			||||||
        //     this.sceneGraph.getLayers().forEach((layer: Layer) => layer.setPaused(false));
 | 
					 | 
				
			||||||
        //     pauseLayer.disable();
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					// @ignorePage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A placeholder function for No Operation. Does nothing
 | 
					 * A placeholder function for No Operation. Does nothing
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
							
								
								
									
										291
									
								
								src/Wolfie2D/Input/Input.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								src/Wolfie2D/Input/Input.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,291 @@
 | 
				
			||||||
 | 
					import Receiver from "../Events/Receiver";
 | 
				
			||||||
 | 
					import Map from "../DataTypes/Map";
 | 
				
			||||||
 | 
					import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
 | 
					import EventQueue from "../Events/EventQueue";
 | 
				
			||||||
 | 
					import Viewport from "../SceneGraph/Viewport";
 | 
				
			||||||
 | 
					import GameEvent from "../Events/GameEvent";
 | 
				
			||||||
 | 
					import { GameEventType } from "../Events/GameEventType";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Receives input events from the @reference[EventQueue] and allows for easy access of information about input by other systems
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class Input {
 | 
				
			||||||
 | 
						private static mousePressed: boolean;
 | 
				
			||||||
 | 
						private static mouseJustPressed: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static keyJustPressed: Map<boolean>;
 | 
				
			||||||
 | 
						private static keyPressed: Map<boolean>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static mousePosition: Vec2;
 | 
				
			||||||
 | 
						private static mousePressPosition: Vec2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static scrollDirection: number;
 | 
				
			||||||
 | 
						private static justScrolled: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static eventQueue: EventQueue;
 | 
				
			||||||
 | 
						private static receiver: Receiver;
 | 
				
			||||||
 | 
						private static viewport: Viewport;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static keyMap: Map<Array<string>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Initializes the Input object
 | 
				
			||||||
 | 
						 * @param viewport A reference to the viewport of the game
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static initialize(viewport: Viewport, keyMap: Array<Record<string, any>>){
 | 
				
			||||||
 | 
							Input.viewport = viewport;
 | 
				
			||||||
 | 
							Input.mousePressed = false;
 | 
				
			||||||
 | 
							Input.mouseJustPressed = false;
 | 
				
			||||||
 | 
							Input.receiver = new Receiver();
 | 
				
			||||||
 | 
							Input.keyJustPressed = new Map<boolean>();
 | 
				
			||||||
 | 
							Input.keyPressed = new Map<boolean>();
 | 
				
			||||||
 | 
							Input.mousePosition = new Vec2(0, 0);
 | 
				
			||||||
 | 
							Input.mousePressPosition = new Vec2(0, 0);
 | 
				
			||||||
 | 
							Input.scrollDirection = 0;
 | 
				
			||||||
 | 
							Input.justScrolled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize the keymap
 | 
				
			||||||
 | 
							Input.keyMap = new Map();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Add all keys to the keymap
 | 
				
			||||||
 | 
							for(let entry in keyMap){
 | 
				
			||||||
 | 
								let name = keyMap[entry].name;
 | 
				
			||||||
 | 
								let keys = keyMap[entry].keys;
 | 
				
			||||||
 | 
								Input.keyMap.add(name, keys);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Input.eventQueue = EventQueue.getInstance();
 | 
				
			||||||
 | 
							// Subscribe to all input events
 | 
				
			||||||
 | 
							Input.eventQueue.subscribe(Input.receiver, [GameEventType.MOUSE_DOWN, GameEventType.MOUSE_UP, GameEventType.MOUSE_MOVE,
 | 
				
			||||||
 | 
								 GameEventType.KEY_DOWN, GameEventType.KEY_UP, GameEventType.CANVAS_BLUR, GameEventType.WHEEL_UP, GameEventType.WHEEL_DOWN]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static update(deltaT: number): void {
 | 
				
			||||||
 | 
							// Reset the justPressed values to false
 | 
				
			||||||
 | 
							Input.mouseJustPressed = false;
 | 
				
			||||||
 | 
							Input.keyJustPressed.forEach((key: string) => Input.keyJustPressed.set(key, false));
 | 
				
			||||||
 | 
							Input.justScrolled = false;
 | 
				
			||||||
 | 
							Input.scrollDirection = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while(Input.receiver.hasNextEvent()){			
 | 
				
			||||||
 | 
								let event = Input.receiver.getNextEvent();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Handle each event type
 | 
				
			||||||
 | 
								if(event.type === GameEventType.MOUSE_DOWN){
 | 
				
			||||||
 | 
									Input.mouseJustPressed = true;
 | 
				
			||||||
 | 
									Input.mousePressed = true;
 | 
				
			||||||
 | 
									Input.mousePressPosition = event.data.get("position");	
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.MOUSE_UP){
 | 
				
			||||||
 | 
									Input.mousePressed = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.MOUSE_MOVE){
 | 
				
			||||||
 | 
									Input.mousePosition = event.data.get("position");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.KEY_DOWN){
 | 
				
			||||||
 | 
									let key = event.data.get("key");
 | 
				
			||||||
 | 
									// Handle space bar
 | 
				
			||||||
 | 
									if(key === " "){
 | 
				
			||||||
 | 
										key = "space";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if(!Input.keyPressed.get(key)){
 | 
				
			||||||
 | 
										Input.keyJustPressed.set(key, true);
 | 
				
			||||||
 | 
										Input.keyPressed.set(key, true);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.KEY_UP){
 | 
				
			||||||
 | 
									let key = event.data.get("key");
 | 
				
			||||||
 | 
									// Handle space bar
 | 
				
			||||||
 | 
									if(key === " "){
 | 
				
			||||||
 | 
										key = "space";
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									Input.keyPressed.set(key, false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.CANVAS_BLUR){
 | 
				
			||||||
 | 
									Input.clearKeyPresses()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(event.type === GameEventType.WHEEL_UP){
 | 
				
			||||||
 | 
									Input.scrollDirection = -1;
 | 
				
			||||||
 | 
									Input.justScrolled = true;
 | 
				
			||||||
 | 
								} else if(event.type === GameEventType.WHEEL_DOWN){
 | 
				
			||||||
 | 
									Input.scrollDirection = 1;
 | 
				
			||||||
 | 
									Input.justScrolled = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static clearKeyPresses(): void {
 | 
				
			||||||
 | 
							Input.keyJustPressed.forEach((key: string) => Input.keyJustPressed.set(key, false));
 | 
				
			||||||
 | 
							Input.keyPressed.forEach((key: string) => Input.keyPressed.set(key, false));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not a key was newly pressed Input frame.
 | 
				
			||||||
 | 
						 * If the key is still pressed from last frame and wasn't re-pressed, Input will return false.
 | 
				
			||||||
 | 
						 * @param key The key
 | 
				
			||||||
 | 
						 * @returns True if the key was just pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isKeyJustPressed(key: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keyJustPressed.has(key)){
 | 
				
			||||||
 | 
								return Input.keyJustPressed.get(key)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns an array of all of the keys that are newly pressed Input frame.
 | 
				
			||||||
 | 
						 * If a key is still pressed from last frame and wasn't re-pressed, it will not be in Input list.
 | 
				
			||||||
 | 
						 * @returns An array of all of the newly pressed keys.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getKeysJustPressed(): Array<string> {
 | 
				
			||||||
 | 
							let keys = Array<string>();
 | 
				
			||||||
 | 
							Input.keyJustPressed.forEach(key => {
 | 
				
			||||||
 | 
								if(Input.keyJustPressed.get(key)){
 | 
				
			||||||
 | 
									keys.push(key);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							return keys;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not a key is being pressed.
 | 
				
			||||||
 | 
						 * @param key The key
 | 
				
			||||||
 | 
						 * @returns True if the key is currently pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isKeyPressed(key: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keyPressed.has(key)){
 | 
				
			||||||
 | 
								return Input.keyPressed.get(key)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Changes the binding of an input name to keys
 | 
				
			||||||
 | 
						 * @param inputName The name of the input
 | 
				
			||||||
 | 
						 * @param keys The corresponding keys
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static changeKeyBinding(inputName: string, keys: Array<string>): void {
 | 
				
			||||||
 | 
							Input.keyMap.set(inputName, keys);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Clears all key bindings
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static clearAllKeyBindings(): void {
 | 
				
			||||||
 | 
							Input.keyMap.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not an input was just pressed this frame
 | 
				
			||||||
 | 
						 * @param inputName The name of the input
 | 
				
			||||||
 | 
						 * @returns True if the input was just pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isJustPressed(inputName: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keyMap.has(inputName)){
 | 
				
			||||||
 | 
								const keys = Input.keyMap.get(inputName);
 | 
				
			||||||
 | 
								let justPressed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for(let key of keys){
 | 
				
			||||||
 | 
									justPressed = justPressed || Input.isKeyJustPressed(key);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return justPressed;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}	
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not an input is currently pressed
 | 
				
			||||||
 | 
						 * @param inputName The name of the input
 | 
				
			||||||
 | 
						 * @returns True if the input is pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isPressed(inputName: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keyMap.has(inputName)){
 | 
				
			||||||
 | 
								const keys = Input.keyMap.get(inputName);
 | 
				
			||||||
 | 
								let pressed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for(let key of keys){
 | 
				
			||||||
 | 
									pressed = pressed || Input.isKeyPressed(key);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return pressed;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not the mouse was newly pressed Input frame
 | 
				
			||||||
 | 
						 * @returns True if the mouse was just pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isMouseJustPressed(): boolean {
 | 
				
			||||||
 | 
							return Input.mouseJustPressed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether or not the mouse is currently pressed
 | 
				
			||||||
 | 
						 * @returns True if the mouse is currently pressed, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static isMousePressed(): boolean {
 | 
				
			||||||
 | 
							return Input.mousePressed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Returns whether the user scrolled or not
 | 
				
			||||||
 | 
						 * @returns True if the user just scrolled Input frame, false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static didJustScroll(): boolean {
 | 
				
			||||||
 | 
							return Input.justScrolled;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets the direction of the scroll
 | 
				
			||||||
 | 
						 * @returns -1 if the user scrolled up, 1 if they scrolled down
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getScrollDirection(): number {
 | 
				
			||||||
 | 
							return Input.scrollDirection;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets the position of the player's mouse
 | 
				
			||||||
 | 
						 * @returns The mouse position stored as a Vec2
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getMousePosition(): Vec2 {
 | 
				
			||||||
 | 
							return Input.mousePosition;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets the position of the player's mouse in the game world,
 | 
				
			||||||
 | 
						 * taking into consideration the scrolling of the viewport
 | 
				
			||||||
 | 
						 * @returns The mouse position stored as a Vec2
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getGlobalMousePosition(): Vec2 {
 | 
				
			||||||
 | 
							return Input.mousePosition.clone().add(Input.viewport.getOrigin());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets the position of the last mouse press
 | 
				
			||||||
 | 
						 * @returns The mouse position stored as a Vec2
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getMousePressPosition(): Vec2 {
 | 
				
			||||||
 | 
							return Input.mousePressPosition;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets the position of the last mouse press in the game world,
 | 
				
			||||||
 | 
						 * taking into consideration the scrolling of the viewport
 | 
				
			||||||
 | 
						 * @returns The mouse position stored as a Vec2
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static getGlobalMousePressPosition(): Vec2 {
 | 
				
			||||||
 | 
							return Input.mousePressPosition.clone().add(Input.viewport.getOrigin());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/Wolfie2D/Loop/EnvironmentInitializer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/Wolfie2D/Loop/EnvironmentInitializer.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					import {} from "../../index";  // This import allows us to modify the CanvasRenderingContext2D to add extra functionality
 | 
				
			||||||
 | 
					// @ignorePage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sets up the environment of the game engine
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class EnvironmentInitializer {
 | 
				
			||||||
 | 
					    static setup(){
 | 
				
			||||||
 | 
					        CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void {
 | 
				
			||||||
 | 
					            // Clamp the radius between 0 and the min of the width or height
 | 
				
			||||||
 | 
					            if(r < 0) r = 0;
 | 
				
			||||||
 | 
					            if(r > Math.min(w, h)) r = Math.min(w, h);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            // Draw the rounded rect
 | 
				
			||||||
 | 
					            this.beginPath();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            // Top
 | 
				
			||||||
 | 
					            this.moveTo(x + r, y);
 | 
				
			||||||
 | 
					            this.lineTo(x + w - r, y);
 | 
				
			||||||
 | 
					            this.arcTo(x + w, y, x + w, y + r, r);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            // Right
 | 
				
			||||||
 | 
					            this.lineTo(x + w, y + h - r);
 | 
				
			||||||
 | 
					            this.arcTo(x + w, y + h, x + w - r, y + h, r);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            // Bottom
 | 
				
			||||||
 | 
					            this.lineTo(x + r, y + h);
 | 
				
			||||||
 | 
					            this.arcTo(x, y + h, x, y + h - r, r);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            // Left
 | 
				
			||||||
 | 
					            this.lineTo(x, y + r);
 | 
				
			||||||
 | 
					            this.arcTo(x, y, x + r, y, r)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            this.closePath();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        CanvasRenderingContext2D.prototype.strokeRoundedRect = function(x, y, w, h, r){
 | 
				
			||||||
 | 
					            this.roundedRect(x, y, w, h, r);
 | 
				
			||||||
 | 
					            this.stroke();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        CanvasRenderingContext2D.prototype.fillRoundedRect = function(x, y, w, h, r){
 | 
				
			||||||
 | 
					            this.roundedRect(x, y, w, h, r);
 | 
				
			||||||
 | 
					            this.fill();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import EventQueue from "../Events/EventQueue";
 | 
					import EventQueue from "../Events/EventQueue";
 | 
				
			||||||
import InputReceiver from "../Input/InputReceiver";
 | 
					import Input from "../Input/Input";
 | 
				
			||||||
import InputHandler from "../Input/InputHandler";
 | 
					import InputHandler from "../Input/InputHandler";
 | 
				
			||||||
import Recorder from "../Playback/Recorder";
 | 
					import Recorder from "../Playback/Recorder";
 | 
				
			||||||
import Debug from "../Debug/Debug";
 | 
					import Debug from "../Debug/Debug";
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ import Color from "../Utils/Color";
 | 
				
			||||||
import GameOptions from "./GameOptions";
 | 
					import GameOptions from "./GameOptions";
 | 
				
			||||||
import GameLoop from "./GameLoop";
 | 
					import GameLoop from "./GameLoop";
 | 
				
			||||||
import FixedUpdateGameLoop from "./FixedUpdateGameLoop";
 | 
					import FixedUpdateGameLoop from "./FixedUpdateGameLoop";
 | 
				
			||||||
 | 
					import EnvironmentInitializer from "./EnvironmentInitializer";
 | 
				
			||||||
 | 
					import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The main loop of the game engine.
 | 
					 * The main loop of the game engine.
 | 
				
			||||||
| 
						 | 
					@ -22,6 +24,8 @@ import FixedUpdateGameLoop from "./FixedUpdateGameLoop";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default class Game {
 | 
					export default class Game {
 | 
				
			||||||
    gameOptions: GameOptions;
 | 
					    gameOptions: GameOptions;
 | 
				
			||||||
 | 
					    private showDebug: boolean;
 | 
				
			||||||
 | 
					    private showStats: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // The game loop
 | 
					    // The game loop
 | 
				
			||||||
    private loop: GameLoop;
 | 
					    private loop: GameLoop;
 | 
				
			||||||
| 
						 | 
					@ -38,7 +42,6 @@ export default class Game {
 | 
				
			||||||
    // All of the necessary subsystems that need to run here
 | 
					    // All of the necessary subsystems that need to run here
 | 
				
			||||||
	private eventQueue: EventQueue;
 | 
						private eventQueue: EventQueue;
 | 
				
			||||||
	private inputHandler: InputHandler;
 | 
						private inputHandler: InputHandler;
 | 
				
			||||||
	private inputReceiver: InputReceiver;
 | 
					 | 
				
			||||||
	private recorder: Recorder;
 | 
						private recorder: Recorder;
 | 
				
			||||||
    private resourceManager: ResourceManager;
 | 
					    private resourceManager: ResourceManager;
 | 
				
			||||||
    private sceneManager: SceneManager;
 | 
					    private sceneManager: SceneManager;
 | 
				
			||||||
| 
						 | 
					@ -50,9 +53,15 @@ export default class Game {
 | 
				
			||||||
     * @param options The options for Game initialization
 | 
					     * @param options The options for Game initialization
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    constructor(options?: Record<string, any>){
 | 
					    constructor(options?: Record<string, any>){
 | 
				
			||||||
 | 
					        // Before anything else, build the environment
 | 
				
			||||||
 | 
					        EnvironmentInitializer.setup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Typecast the config object to a GameConfig object
 | 
					        // Typecast the config object to a GameConfig object
 | 
				
			||||||
        this.gameOptions = GameOptions.parse(options);
 | 
					        this.gameOptions = GameOptions.parse(options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.showDebug = this.gameOptions.showDebug;
 | 
				
			||||||
 | 
					        this.showStats = this.gameOptions.showStats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Create an instance of a game loop
 | 
					        // Create an instance of a game loop
 | 
				
			||||||
        this.loop = new FixedUpdateGameLoop();
 | 
					        this.loop = new FixedUpdateGameLoop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,22 +83,23 @@ export default class Game {
 | 
				
			||||||
        Debug.initializeDebugCanvas(this.DEBUG_CANVAS, this.WIDTH, this.HEIGHT);
 | 
					        Debug.initializeDebugCanvas(this.DEBUG_CANVAS, this.WIDTH, this.HEIGHT);
 | 
				
			||||||
        Stats.initStats();
 | 
					        Stats.initStats();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.gameOptions.showStats) {
 | 
				
			||||||
 | 
					            // Find the stats output and make it no longer hidden
 | 
				
			||||||
 | 
					            document.getElementById("stats").hidden = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Size the viewport to the game canvas
 | 
					        // Size the viewport to the game canvas
 | 
				
			||||||
        this.viewport = new Viewport();
 | 
					        const viewportSize = new Vec2(this.WIDTH, this.HEIGHT);
 | 
				
			||||||
        this.viewport.setCanvasSize(this.WIDTH, this.HEIGHT);
 | 
					        this.viewport = new Viewport(viewportSize.scaled(0.5), viewportSize);
 | 
				
			||||||
        this.viewport.setSize(this.WIDTH, this.HEIGHT);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Initialize all necessary game subsystems
 | 
					        // Initialize all necessary game subsystems
 | 
				
			||||||
        this.eventQueue = EventQueue.getInstance();
 | 
					        this.eventQueue = EventQueue.getInstance();
 | 
				
			||||||
        this.inputHandler = new InputHandler(this.GAME_CANVAS);
 | 
					        this.inputHandler = new InputHandler(this.GAME_CANVAS);
 | 
				
			||||||
        this.inputReceiver = InputReceiver.getInstance();
 | 
					        Input.initialize(this.viewport, this.gameOptions.inputs);
 | 
				
			||||||
        this.inputReceiver.setViewport(this.viewport);
 | 
					 | 
				
			||||||
        this.recorder = new Recorder();
 | 
					        this.recorder = new Recorder();
 | 
				
			||||||
        this.resourceManager = ResourceManager.getInstance();
 | 
					        this.resourceManager = ResourceManager.getInstance();
 | 
				
			||||||
        this.sceneManager = new SceneManager(this.viewport, this.renderingManager);
 | 
					        this.sceneManager = new SceneManager(this.viewport, this.renderingManager);
 | 
				
			||||||
        this.audioManager = AudioManager.getInstance();
 | 
					        this.audioManager = AudioManager.getInstance();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -134,7 +144,7 @@ export default class Game {
 | 
				
			||||||
        this.eventQueue.update(deltaT);
 | 
					        this.eventQueue.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update the input data structures so game objects can see the input
 | 
					        // Update the input data structures so game objects can see the input
 | 
				
			||||||
        this.inputReceiver.update(deltaT);
 | 
					        Input.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update the recording of the game
 | 
					        // Update the recording of the game
 | 
				
			||||||
        this.recorder.update(deltaT);
 | 
					        this.recorder.update(deltaT);
 | 
				
			||||||
| 
						 | 
					@ -163,7 +173,12 @@ export default class Game {
 | 
				
			||||||
        this.sceneManager.render();
 | 
					        this.sceneManager.render();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Debug render
 | 
					        // Debug render
 | 
				
			||||||
 | 
					        if(this.showDebug){
 | 
				
			||||||
            Debug.render();
 | 
					            Debug.render();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.showStats){
 | 
				
			||||||
            Stats.render();
 | 
					            Stats.render();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,15 @@ export default class GameOptions {
 | 
				
			||||||
    /** The color to clear the canvas to each frame */
 | 
					    /** The color to clear the canvas to each frame */
 | 
				
			||||||
    clearColor: {r: number, g: number, b: number}
 | 
					    clearColor: {r: number, g: number, b: number}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* A list of input bindings */
 | 
				
			||||||
 | 
					    inputs: Array<{name: string, keys: Array<string>}>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Whether or not the debug rendering should occur */
 | 
				
			||||||
 | 
					    showDebug: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Whether or not the stats rendering should occur */
 | 
				
			||||||
 | 
					    showStats: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Parses the data in the raw options object
 | 
					     * Parses the data in the raw options object
 | 
				
			||||||
     * @param options The game options as a Record
 | 
					     * @param options The game options as a Record
 | 
				
			||||||
| 
						 | 
					@ -18,6 +27,9 @@ export default class GameOptions {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600};
 | 
					        gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600};
 | 
				
			||||||
        gOpt.clearColor = options.clearColor ? options.clearColor : {r: 255, g: 255, b: 255};
 | 
					        gOpt.clearColor = options.clearColor ? options.clearColor : {r: 255, g: 255, b: 255};
 | 
				
			||||||
 | 
					        gOpt.inputs = options.inputs ? options.inputs : [];
 | 
				
			||||||
 | 
					        gOpt.showDebug = !!options.showDebug;
 | 
				
			||||||
 | 
					        gOpt.showStats = !!options.showStats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return gOpt;
 | 
					        return gOpt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
import InputReceiver from "../Input/InputReceiver";
 | 
					 | 
				
			||||||
import Vec2 from "../DataTypes/Vec2";
 | 
					import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
import Receiver from "../Events/Receiver";
 | 
					import Receiver from "../Events/Receiver";
 | 
				
			||||||
import Emitter from "../Events/Emitter";
 | 
					import Emitter from "../Events/Emitter";
 | 
				
			||||||
| 
						 | 
					@ -60,8 +59,6 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
	pathfinding: boolean = false;
 | 
						pathfinding: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*---------- GENERAL ----------*/
 | 
						/*---------- GENERAL ----------*/
 | 
				
			||||||
	/** An reference to the user input handler. This allows subclasses to easily access information about user input. */
 | 
					 | 
				
			||||||
	protected input: InputReceiver;
 | 
					 | 
				
			||||||
	/** An event receiver. */
 | 
						/** An event receiver. */
 | 
				
			||||||
	protected receiver: Receiver;
 | 
						protected receiver: Receiver;
 | 
				
			||||||
	/** An event emitter. */
 | 
						/** An event emitter. */
 | 
				
			||||||
| 
						 | 
					@ -79,7 +76,6 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Constructor docs are ignored, as the user should NOT create new GameNodes with a raw constructor
 | 
						// Constructor docs are ignored, as the user should NOT create new GameNodes with a raw constructor
 | 
				
			||||||
	constructor(){
 | 
						constructor(){
 | 
				
			||||||
		this.input = InputReceiver.getInstance();
 | 
					 | 
				
			||||||
		this._position = new Vec2(0, 0);
 | 
							this._position = new Vec2(0, 0);
 | 
				
			||||||
		this._position.setOnChange(() => this.positionChanged());
 | 
							this._position.setOnChange(() => this.positionChanged());
 | 
				
			||||||
		this.receiver = new Receiver();
 | 
							this.receiver = new Receiver();
 | 
				
			||||||
| 
						 | 
					@ -136,6 +132,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
     * @param velocity The velocity with which the object will move.
 | 
					     * @param velocity The velocity with which the object will move.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
	finishMove(): void {
 | 
						finishMove(): void {
 | 
				
			||||||
 | 
							console.log("finish");
 | 
				
			||||||
		this.moving = false;
 | 
							this.moving = false;
 | 
				
			||||||
		this.position.add(this._velocity);
 | 
							this.position.add(this._velocity);
 | 
				
			||||||
		if(this.pathfinding){
 | 
							if(this.pathfinding){
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import CanvasNode from "./CanvasNode";
 | 
					import CanvasNode from "./CanvasNode";
 | 
				
			||||||
import Color from "../Utils/Color";
 | 
					import Color from "../Utils/Color";
 | 
				
			||||||
import Vec2 from "../DataTypes/Vec2";
 | 
					import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Input from "../Input/Input";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The representation of a UIElement - the parent class of things like buttons
 | 
					 * The representation of a UIElement - the parent class of things like buttons
 | 
				
			||||||
| 
						 | 
					@ -79,8 +80,8 @@ export default abstract class UIElement extends CanvasNode {
 | 
				
			||||||
		super.update(deltaT);
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// See of this object was just clicked
 | 
							// See of this object was just clicked
 | 
				
			||||||
		if(this.input.isMouseJustPressed()){
 | 
							if(Input.isMouseJustPressed()){
 | 
				
			||||||
			let clickPos = this.input.getMousePressPosition();
 | 
								let clickPos = Input.getMousePressPosition();
 | 
				
			||||||
			if(this.contains(clickPos.x, clickPos.y)){
 | 
								if(this.contains(clickPos.x, clickPos.y)){
 | 
				
			||||||
				this.isClicked = true;
 | 
									this.isClicked = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,14 +97,14 @@ export default abstract class UIElement extends CanvasNode {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If the mouse wasn't just pressed, then we definitely weren't clicked
 | 
							// If the mouse wasn't just pressed, then we definitely weren't clicked
 | 
				
			||||||
		if(!this.input.isMousePressed()){
 | 
							if(!Input.isMousePressed()){
 | 
				
			||||||
			if(this.isClicked){
 | 
								if(this.isClicked){
 | 
				
			||||||
				this.isClicked = false;
 | 
									this.isClicked = false;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Check if the mouse is hovering over this element
 | 
							// Check if the mouse is hovering over this element
 | 
				
			||||||
		let mousePos = this.input.getMousePosition();
 | 
							let mousePos = Input.getMousePosition();
 | 
				
			||||||
		if(mousePos && this.contains(mousePos.x, mousePos.y)){
 | 
							if(mousePos && this.contains(mousePos.x, mousePos.y)){
 | 
				
			||||||
			this.isEntered = true;
 | 
								this.isEntered = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
import Vec2 from "../../DataTypes/Vec2";
 | 
					import Vec2 from "../../DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Input from "../../Input/Input";
 | 
				
			||||||
import Color from "../../Utils/Color";
 | 
					import Color from "../../Utils/Color";
 | 
				
			||||||
import MathUtils from "../../Utils/MathUtils";
 | 
					import MathUtils from "../../Utils/MathUtils";
 | 
				
			||||||
import UIElement from "../UIElement";
 | 
					import UIElement from "../UIElement";
 | 
				
			||||||
| 
						 | 
					@ -52,7 +53,7 @@ export default class Slider extends UIElement {
 | 
				
			||||||
        super.update(deltaT);
 | 
					        super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(this.isClicked){
 | 
					        if(this.isClicked){
 | 
				
			||||||
            let val = MathUtils.invLerp(this.position.x - this.size.x/2, this.position.x + this.size.x/2, this.input.getMousePosition().x);
 | 
					            let val = MathUtils.invLerp(this.position.x - this.size.x/2, this.position.x + this.size.x/2, Input.getMousePosition().x);
 | 
				
			||||||
            this.value = MathUtils.clamp01(val);
 | 
					            this.value = MathUtils.clamp01(val);
 | 
				
			||||||
            this.valueChanged();
 | 
					            this.valueChanged();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import Vec2 from "../../DataTypes/Vec2";
 | 
					import Vec2 from "../../DataTypes/Vec2";
 | 
				
			||||||
import Color from "../../Utils/Color";
 | 
					import Color from "../../Utils/Color";
 | 
				
			||||||
import Label from "./Label";
 | 
					import Label from "./Label";
 | 
				
			||||||
 | 
					import Input from "../../Input/Input";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** A text input UIElement */
 | 
					/** A text input UIElement */
 | 
				
			||||||
export default class TextInput extends Label {
 | 
					export default class TextInput extends Label {
 | 
				
			||||||
| 
						 | 
					@ -26,8 +27,8 @@ export default class TextInput extends Label {
 | 
				
			||||||
    update(deltaT: number): void {
 | 
					    update(deltaT: number): void {
 | 
				
			||||||
        super.update(deltaT);
 | 
					        super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(this.input.isMouseJustPressed()){
 | 
					        if(Input.isMouseJustPressed()){
 | 
				
			||||||
			let clickPos = this.input.getMousePressPosition();
 | 
								let clickPos = Input.getMousePressPosition();
 | 
				
			||||||
			if(this.contains(clickPos.x, clickPos.y)){
 | 
								if(this.contains(clickPos.x, clickPos.y)){
 | 
				
			||||||
                this.focused = true;
 | 
					                this.focused = true;
 | 
				
			||||||
                this.cursorCounter = 30;
 | 
					                this.cursorCounter = 30;
 | 
				
			||||||
| 
						 | 
					@ -37,15 +38,15 @@ export default class TextInput extends Label {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(this.focused){
 | 
					        if(this.focused){
 | 
				
			||||||
            let keys = this.input.getKeysJustPressed();
 | 
					            let keys = Input.getKeysJustPressed();
 | 
				
			||||||
            let nums = "1234567890";
 | 
					            let nums = "1234567890";
 | 
				
			||||||
            let specialChars = "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?";
 | 
					            let specialChars = "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?";
 | 
				
			||||||
            let letters = "qwertyuiopasdfghjklzxcvbnm";
 | 
					            let letters = "qwertyuiopasdfghjklzxcvbnm";
 | 
				
			||||||
            let mask = nums + specialChars + letters;
 | 
					            let mask = nums + specialChars + letters;
 | 
				
			||||||
            keys = keys.filter(key => mask.includes(key));
 | 
					            keys = keys.filter(key => mask.includes(key));
 | 
				
			||||||
            let shiftPressed = this.input.isPressed("shift");
 | 
					            let shiftPressed = Input.isKeyPressed("shift");
 | 
				
			||||||
            let backspacePressed = this.input.isJustPressed("backspace");
 | 
					            let backspacePressed = Input.isKeyJustPressed("backspace");
 | 
				
			||||||
            let spacePressed = this.input.isJustPressed("space");
 | 
					            let spacePressed = Input.isKeyJustPressed("space");
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            if(backspacePressed){
 | 
					            if(backspacePressed){
 | 
				
			||||||
                this.text = this.text.substring(0, this.text.length - 1);
 | 
					                this.text = this.text.substring(0, this.text.length - 1);
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ import AreaCollision from "../DataTypes/Physics/AreaCollision";
 | 
				
			||||||
 * 	Cons:
 | 
					 * 	Cons:
 | 
				
			||||||
 * 		- Nodes that are processed early have movement priority over other nodes. This can lead to some undesirable interactions.
 | 
					 * 		- Nodes that are processed early have movement priority over other nodes. This can lead to some undesirable interactions.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default class TestPhysicsManager extends PhysicsManager {
 | 
					export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** The array of static nodes */
 | 
						/** The array of static nodes */
 | 
				
			||||||
	protected staticNodes: Array<Physical>;
 | 
						protected staticNodes: Array<Physical>;
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,7 @@ export default class TestPhysicsManager extends PhysicsManager {
 | 
				
			||||||
	/** The array of tilemaps */
 | 
						/** The array of tilemaps */
 | 
				
			||||||
	protected tilemaps: Array<Tilemap>;
 | 
						protected tilemaps: Array<Tilemap>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constructor(){
 | 
						constructor(options: Record<string, any>){
 | 
				
			||||||
		super();
 | 
							super();
 | 
				
			||||||
		this.staticNodes = new Array();
 | 
							this.staticNodes = new Array();
 | 
				
			||||||
		this.dynamicNodes = new Array();
 | 
							this.dynamicNodes = new Array();
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user