cleaned up typescript inconsistencies in code
This commit is contained in:
parent
2dd60b5197
commit
bd49258d30
|
@ -1,7 +1,7 @@
|
||||||
import CanvasNode from "./CanvasNode";
|
import CanvasNode from "./Nodes/CanvasNode";
|
||||||
import Color from "../Utils/Color";
|
import Color from "./Utils/Color";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "./DataTypes/Vec2";
|
||||||
import RandUtils from "../Utils/RandUtils";
|
import RandUtils from "./Utils/RandUtils";
|
||||||
|
|
||||||
export default class ColoredCircle extends CanvasNode{
|
export default class ColoredCircle extends CanvasNode{
|
||||||
private color: Color;
|
private color: Color;
|
|
@ -1,3 +1,3 @@
|
||||||
export default interface Collection{
|
export default interface Collection {
|
||||||
forEach(func: Function): void;
|
forEach(func: Function): void;
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import Collection from "./Collection";
|
import Collection from "./Collection";
|
||||||
|
|
||||||
export default class Queue<T> implements Collection{
|
export default class Queue<T> implements Collection{
|
||||||
readonly MAX_ELEMENTS: number;
|
private readonly MAX_ELEMENTS: number;
|
||||||
private q: Array<T>;
|
private q: Array<T>;
|
||||||
private head: number;
|
private head: number;
|
||||||
private tail: number;
|
private tail: number;
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default class Stack<T> implements Collection{
|
||||||
/**
|
/**
|
||||||
* Removes an item from the top of the stack
|
* Removes an item from the top of the stack
|
||||||
*/
|
*/
|
||||||
pop(): T{
|
pop(): T {
|
||||||
if(this.head === -1){
|
if(this.head === -1){
|
||||||
throw "Stack empty - cannot remove element";
|
throw "Stack empty - cannot remove element";
|
||||||
}
|
}
|
||||||
|
@ -34,13 +34,6 @@ export default class Stack<T> implements Collection{
|
||||||
return this.stack[this.head + 1];
|
return this.stack[this.head + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all elements from the stack
|
|
||||||
*/
|
|
||||||
clear(): void{
|
|
||||||
this.head = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the element currently at the top of the stack
|
* Returns the element currently at the top of the stack
|
||||||
*/
|
*/
|
||||||
|
@ -51,6 +44,13 @@ export default class Stack<T> implements Collection{
|
||||||
return this.stack[this.head];
|
return this.stack[this.head];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements from the stack
|
||||||
|
*/
|
||||||
|
clear(): void{
|
||||||
|
this.head = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of items currently in the stack
|
* Returns the number of items currently in the stack
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,8 +4,8 @@ export class TiledTilemapData {
|
||||||
tileheight: number;
|
tileheight: number;
|
||||||
tilewidth: number;
|
tilewidth: number;
|
||||||
orientation: string;
|
orientation: string;
|
||||||
layers: TiledLayerData[];
|
layers: Array<TiledLayerData>;
|
||||||
tilesets: TiledTilesetData[];
|
tilesets: Array<TiledTilesetData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TiledLayerProperty {
|
export class TiledLayerProperty {
|
||||||
|
|
|
@ -15,11 +15,12 @@ export default class Tileset {
|
||||||
protected numRows: number;
|
protected numRows: number;
|
||||||
protected numCols: number;
|
protected numCols: number;
|
||||||
|
|
||||||
|
// TODO: Change this to be more general and work with other tileset formats
|
||||||
constructor(tilesetData: TiledTilesetData){
|
constructor(tilesetData: TiledTilesetData){
|
||||||
this.initFromTiledData(tilesetData);
|
this.initFromTiledData(tilesetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
initFromTiledData(tiledData: TiledTilesetData){
|
initFromTiledData(tiledData: TiledTilesetData): void {
|
||||||
this.numRows = tiledData.tilecount/tiledData.columns;
|
this.numRows = tiledData.tilecount/tiledData.columns;
|
||||||
this.numCols = tiledData.columns;
|
this.numCols = tiledData.columns;
|
||||||
this.startIndex = tiledData.firstgid;
|
this.startIndex = tiledData.firstgid;
|
||||||
|
@ -57,6 +58,7 @@ export default class Tileset {
|
||||||
return this.numCols;
|
return this.numCols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This should probably be a thing that is tracked in the resource loader, not here
|
||||||
isReady(): boolean {
|
isReady(): boolean {
|
||||||
return this.image !== null;
|
return this.image !== null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default class Vec2 {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate(angle: number): Vec2 {
|
rotateCCW(angle: number): Vec2 {
|
||||||
let cs = Math.cos(angle);
|
let cs = Math.cos(angle);
|
||||||
let sn = Math.sin(angle);
|
let sn = Math.sin(angle);
|
||||||
let tempX = this.x*cs - this.y*sn;
|
let tempX = this.x*cs - this.y*sn;
|
||||||
|
@ -74,11 +74,11 @@ export default class Vec2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return "(" + this.x + ", " + this.y + ")";
|
return this.toFixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
toFixed(): string {
|
toFixed(numDecimalPoints: number = 1): string {
|
||||||
return "(" + this.x.toFixed(1) + ", " + this.y.toFixed(1) + ")";
|
return "(" + this.x.toFixed(numDecimalPoints) + ", " + this.y.toFixed(numDecimalPoints) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): Vec2 {
|
clone(): Vec2 {
|
||||||
|
|
|
@ -7,14 +7,14 @@ export default class Vec4{
|
||||||
public z : number;
|
public z : number;
|
||||||
public w : number;
|
public w : number;
|
||||||
|
|
||||||
constructor(x : number = 0, y : number = 0, z : number = 0, w : number = 0){
|
constructor(x : number = 0, y : number = 0, z : number = 0, w : number = 0) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
this.w = w;
|
this.w = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
split() : [Vec2, Vec2]{
|
split() : [Vec2, Vec2] {
|
||||||
return [new Vec2(this.x, this.y), new Vec2(this.z, this.w)];
|
return [new Vec2(this.x, this.y), new Vec2(this.z, this.w)];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,30 +1,16 @@
|
||||||
import Map from "../DataTypes/Map";
|
import Map from "../DataTypes/Map";
|
||||||
|
|
||||||
export default class Debug {
|
export default class Debug {
|
||||||
private static instance: Debug = null;
|
|
||||||
|
|
||||||
logIds: number;
|
private static logMessages: Map<string> = new Map();
|
||||||
logMessages: Map<string>;
|
|
||||||
|
|
||||||
|
|
||||||
constructor(){
|
static log(id: string, message: string): void {
|
||||||
this.logIds = 0;
|
|
||||||
this.logMessages = new Map();
|
|
||||||
};
|
|
||||||
|
|
||||||
static getInstance(): Debug {
|
|
||||||
if(this.instance === null){
|
|
||||||
this.instance = new Debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(id: string, message: string): void {
|
|
||||||
this.logMessages.add(id, message);
|
this.logMessages.add(id, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(ctx: CanvasRenderingContext2D): void {
|
// TODO: Create a method that can delete messages from the log
|
||||||
|
|
||||||
|
static render(ctx: CanvasRenderingContext2D): void {
|
||||||
let y = 20;
|
let y = 20;
|
||||||
ctx.font = "20px Arial";
|
ctx.font = "20px Arial";
|
||||||
ctx.fillStyle = "#000000";
|
ctx.fillStyle = "#000000";
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import Scene from "../Scene";
|
import Scene from "../Scene";
|
||||||
import Viewport from "../../SceneGraph/Viewport";
|
import Viewport from "../../SceneGraph/Viewport";
|
||||||
import CanvasItem from "../../Nodes/CanvasNode"
|
import CanvasItem from "../../Nodes/CanvasNode"
|
||||||
import PlayerSprite from "../../Nodes/PlayerSprite";
|
|
||||||
|
|
||||||
export default class CanvasNodeFactory {
|
export default class CanvasNodeFactory {
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
private viewport: Viewport;
|
|
||||||
|
|
||||||
constructor(scene: Scene, viewport: Viewport){
|
constructor(scene: Scene){
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
|
||||||
export default class TilemapFactory {
|
export default class TilemapFactory {
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
private viewport: Viewport;
|
// TODO: get the resource manager OUT of here, it does not belong
|
||||||
private resourceManager: ResourceManager;
|
private resourceManager: ResourceManager;
|
||||||
|
|
||||||
constructor(scene: Scene, viewport: Viewport){
|
constructor(scene: Scene){
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.resourceManager = ResourceManager.getInstance();
|
this.resourceManager = ResourceManager.getInstance();
|
||||||
}
|
}
|
||||||
|
@ -30,18 +30,6 @@ export default class TilemapFactory {
|
||||||
if(tilemap.isCollidable()){
|
if(tilemap.isCollidable()){
|
||||||
// Register in physics as a tilemap
|
// Register in physics as a tilemap
|
||||||
this.scene.physics.addTilemap(tilemap);
|
this.scene.physics.addTilemap(tilemap);
|
||||||
|
|
||||||
// Create colliders
|
|
||||||
// let worldSize = tilemap.getWorldSize();
|
|
||||||
// let tileSize = tilemap.getTileSize();
|
|
||||||
|
|
||||||
// tilemap.forEachTile((tileIndex: number, i: number) => {
|
|
||||||
// if(tileIndex !== 0){
|
|
||||||
// let x = (i % worldSize.x) * tileSize.x * 4;
|
|
||||||
// let y = Math.floor(i / worldSize.x) * tileSize.y * 4;
|
|
||||||
// this.scene.physics.add(StaticBody, new Vec2(x, y), new Vec2(tileSize.x * 4, tileSize.y * 4));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load images for the tilesets
|
// Load images for the tilesets
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class Scene {
|
||||||
private gameState: GameState;
|
private gameState: GameState;
|
||||||
private viewport: Viewport
|
private viewport: Viewport
|
||||||
private parallax: Vec2;
|
private parallax: Vec2;
|
||||||
sceneGraph: SceneGraph;
|
private sceneGraph: SceneGraph;
|
||||||
private physicsManager: PhysicsManager;
|
private physicsManager: PhysicsManager;
|
||||||
private tilemaps: Array<Tilemap>;
|
private tilemaps: Array<Tilemap>;
|
||||||
private paused: boolean;
|
private paused: boolean;
|
||||||
|
@ -38,25 +38,25 @@ export default class Scene {
|
||||||
this.physicsManager = new PhysicsManager();
|
this.physicsManager = new PhysicsManager();
|
||||||
|
|
||||||
// Factories
|
// Factories
|
||||||
this.canvasNode = new CanvasNodeFactory(this, this.viewport);
|
this.canvasNode = new CanvasNodeFactory(this);
|
||||||
this.tilemap = new TilemapFactory(this, this.viewport);
|
this.tilemap = new TilemapFactory(this);
|
||||||
this.physics = new PhysicsNodeFactory(this, this.physicsManager);
|
this.physics = new PhysicsNodeFactory(this, this.physicsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPaused(pauseValue: boolean): void {
|
setPaused(pauseValue: boolean): void {
|
||||||
this.paused = pauseValue;
|
this.paused = pauseValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isPaused(): boolean {
|
||||||
|
return this.paused;
|
||||||
|
}
|
||||||
|
|
||||||
setAlpha(alpha: number): void {
|
setAlpha(alpha: number): void {
|
||||||
this.alpha = MathUtils.clamp(alpha, 0, 1);
|
this.alpha = MathUtils.clamp(alpha, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
isPaused(): boolean {
|
setHidden(hidden: boolean): void {
|
||||||
return this.paused;
|
this.hidden = hidden;
|
||||||
}
|
|
||||||
|
|
||||||
setHidden(hiddenValue: boolean): void {
|
|
||||||
this.hidden = hiddenValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isHidden(): boolean {
|
isHidden(): boolean {
|
||||||
|
@ -85,8 +85,8 @@ export default class Scene {
|
||||||
return this.parallax;
|
return this.parallax;
|
||||||
}
|
}
|
||||||
|
|
||||||
add(children: CanvasNode): void {
|
add(child: CanvasNode): void {
|
||||||
this.sceneGraph.addNode(children);
|
this.sceneGraph.addNode(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTilemap(tilemap: Tilemap): void {
|
addTilemap(tilemap: Tilemap): void {
|
||||||
|
|
|
@ -38,7 +38,6 @@ export default class GameLoop{
|
||||||
private inputReceiver: InputReceiver;
|
private inputReceiver: InputReceiver;
|
||||||
private recorder: Recorder;
|
private recorder: Recorder;
|
||||||
private gameState: GameState;
|
private gameState: GameState;
|
||||||
private debug: Debug;
|
|
||||||
private resourceManager: ResourceManager;
|
private resourceManager: ResourceManager;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
|
@ -68,7 +67,6 @@ export default class GameLoop{
|
||||||
this.inputReceiver.setViewport(this.viewport);
|
this.inputReceiver.setViewport(this.viewport);
|
||||||
this.recorder = new Recorder();
|
this.recorder = new Recorder();
|
||||||
this.gameState = new GameState(this.viewport);
|
this.gameState = new GameState(this.viewport);
|
||||||
this.debug = Debug.getInstance();
|
|
||||||
this.resourceManager = ResourceManager.getInstance();
|
this.resourceManager = ResourceManager.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +97,7 @@ export default class GameLoop{
|
||||||
this.runningFrameSum = 0;
|
this.runningFrameSum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.debug.log("fps", "FPS: " + this.fps.toFixed(1));
|
Debug.log("fps", "FPS: " + this.fps.toFixed(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
start(): void {
|
start(): void {
|
||||||
|
@ -157,6 +155,6 @@ export default class GameLoop{
|
||||||
render(): void {
|
render(): void {
|
||||||
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
||||||
this.gameState.render(this.ctx);
|
this.gameState.render(this.ctx);
|
||||||
this.debug.render(this.ctx);
|
Debug.render(this.ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,11 +39,11 @@ export default abstract class GameNode{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(eventType: string){
|
subscribe(eventType: string): void {
|
||||||
this.eventQueue.subscribe(this.receiver, eventType);
|
this.eventQueue.subscribe(this.receiver, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(eventType: string, data: Map<any> | Record<string, any> = null){
|
emit(eventType: string, data: Map<any> | Record<string, any> = null): void {
|
||||||
let event = new GameEvent(eventType, data);
|
let event = new GameEvent(eventType, data);
|
||||||
this.eventQueue.addEvent(event);
|
this.eventQueue.addEvent(event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { TiledTilemapData, TiledLayerData } from "../DataTypes/Tilesets/TiledDat
|
||||||
*/
|
*/
|
||||||
export default abstract class Tilemap extends GameNode {
|
export default abstract class Tilemap extends GameNode {
|
||||||
protected data: number[];
|
protected data: number[];
|
||||||
protected collisionData: number [];
|
protected collisionData: number[];
|
||||||
protected tilesets: Tileset[];
|
protected tilesets: Tileset[];
|
||||||
protected worldSize: Vec2;
|
protected worldSize: Vec2;
|
||||||
protected tileSize: Vec2;
|
protected tileSize: Vec2;
|
||||||
|
@ -16,7 +16,8 @@ export default abstract class Tilemap extends GameNode {
|
||||||
protected collidable: boolean;
|
protected collidable: boolean;
|
||||||
protected scale: Vec2;
|
protected scale: Vec2;
|
||||||
|
|
||||||
constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData){
|
// TODO: Make this no longer be specific to Tiled
|
||||||
|
constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData) {
|
||||||
super();
|
super();
|
||||||
this.tilesets = new Array<Tileset>();
|
this.tilesets = new Array<Tileset>();
|
||||||
this.worldSize = new Vec2(0, 0);
|
this.worldSize = new Vec2(0, 0);
|
||||||
|
@ -71,7 +72,8 @@ export default abstract class Tilemap extends GameNode {
|
||||||
/**
|
/**
|
||||||
* Sets up the tileset using the data loaded from file
|
* Sets up the tileset using the data loaded from file
|
||||||
*/
|
*/
|
||||||
abstract parseTilemapData(tilemapData: TiledTilemapData, layerData: TiledLayerData): void;
|
// TODO: This shouldn't use tiled data specifically - it should be more general
|
||||||
|
protected abstract parseTilemapData(tilemapData: TiledTilemapData, layerData: TiledLayerData): void;
|
||||||
|
|
||||||
abstract render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2): void;
|
abstract render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2): void;
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ import Tileset from "../../DataTypes/Tilesets/Tileset";
|
||||||
|
|
||||||
export default class OrthogonalTilemap extends Tilemap {
|
export default class OrthogonalTilemap extends Tilemap {
|
||||||
|
|
||||||
parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void {
|
protected parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void {
|
||||||
this.worldSize.set(tilemapData.width, tilemapData.height);
|
this.worldSize.set(tilemapData.width, tilemapData.height);
|
||||||
this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight);
|
this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight);
|
||||||
this.data = layer.data;
|
this.data = layer.data;
|
||||||
|
|
|
@ -4,16 +4,16 @@ import Vec2 from "../DataTypes/Vec2";
|
||||||
|
|
||||||
export default class UIElement extends CanvasNode{
|
export default class UIElement extends CanvasNode{
|
||||||
// Style attributes
|
// Style attributes
|
||||||
textColor: Color;
|
protected textColor: Color;
|
||||||
backgroundColor: Color;
|
protected backgroundColor: Color;
|
||||||
borderColor: Color;
|
protected borderColor: Color;
|
||||||
text: string;
|
protected text: string;
|
||||||
font: string;
|
protected font: string;
|
||||||
fontSize: number;
|
protected fontSize: number;
|
||||||
hAlign: string;
|
protected hAlign: string;
|
||||||
vAlign: string;
|
protected vAlign: string;
|
||||||
borderRadius: number;
|
protected borderRadius: number;
|
||||||
borderWidth: number;
|
protected borderWidth: number;
|
||||||
|
|
||||||
// EventAttributes
|
// EventAttributes
|
||||||
onClick: Function;
|
onClick: Function;
|
||||||
|
|
|
@ -8,6 +8,7 @@ export default abstract class Collider extends GameNode {
|
||||||
return this.size;
|
return this.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make this accept vector arguments and number arguments
|
||||||
setSize(size: Vec2): void {
|
setSize(size: Vec2): void {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@ import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
|
||||||
|
|
||||||
export default class PhysicsManager {
|
export default class PhysicsManager {
|
||||||
|
|
||||||
physicsNodes: Array<PhysicsNode>;
|
private physicsNodes: Array<PhysicsNode>;
|
||||||
tilemaps: Array<Tilemap>;
|
private tilemaps: Array<Tilemap>;
|
||||||
movements: Array<MovementData>;
|
private movements: Array<MovementData>;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
this.physicsNodes = new Array();
|
this.physicsNodes = new Array();
|
||||||
this.tilemaps = new Array();
|
this.tilemaps = new Array();
|
||||||
|
@ -26,63 +26,17 @@ export default class PhysicsManager {
|
||||||
this.tilemaps.push(tilemap);
|
this.tilemaps.push(tilemap);
|
||||||
}
|
}
|
||||||
|
|
||||||
addMovement(node: PhysicsNode, velocity: Vec2){
|
addMovement(node: PhysicsNode, velocity: Vec2): void {
|
||||||
this.movements.push(new MovementData(node, velocity));
|
this.movements.push(new MovementData(node, velocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
private collideWithTilemap(node: PhysicsNode, tilemap: Tilemap, velocity: Vec2): void {
|
||||||
for(let node of this.physicsNodes){
|
|
||||||
node.update(deltaT);
|
|
||||||
}
|
|
||||||
|
|
||||||
let staticSet = new Array<PhysicsNode>();
|
|
||||||
let dynamicSet = new Array<PhysicsNode>();
|
|
||||||
|
|
||||||
// TODO: REALLY bad, the physics system has to be improved, but that isn't the focus for now
|
|
||||||
for(let node of this.physicsNodes){
|
|
||||||
if(node.isMoving){
|
|
||||||
dynamicSet.push(node);
|
|
||||||
node.isMoving = false;
|
|
||||||
} else {
|
|
||||||
staticSet.push(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, we will only have the moving player, don't bother checking for collisions with other moving things
|
|
||||||
for(let movingNode of dynamicSet){
|
|
||||||
movingNode.setIsGrounded(false);
|
|
||||||
// Get velocity of node
|
|
||||||
let velocity = null;
|
|
||||||
for(let data of this.movements){
|
|
||||||
if(data.node === movingNode){
|
|
||||||
velocity = new Vec2(data.velocity.x, data.velocity.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO handle collisions between dynamic nodes
|
|
||||||
// We probably want to sort them by their left edges
|
|
||||||
|
|
||||||
// TODO: handle collisions between dynamic nodes and static nodes
|
|
||||||
|
|
||||||
// Handle Collisions with the tilemaps
|
|
||||||
for(let tilemap of this.tilemaps){
|
|
||||||
this.collideWithTilemap(movingNode, tilemap, velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
movingNode.finishMove(velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset movements
|
|
||||||
this.movements = new Array();
|
|
||||||
}
|
|
||||||
|
|
||||||
collideWithTilemap(node: PhysicsNode, tilemap: Tilemap, velocity: Vec2){
|
|
||||||
if(tilemap instanceof OrthogonalTilemap){
|
if(tilemap instanceof OrthogonalTilemap){
|
||||||
this.collideWithOrthogonalTilemap(node, tilemap, velocity);
|
this.collideWithOrthogonalTilemap(node, tilemap, velocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collideWithOrthogonalTilemap(node: PhysicsNode, tilemap: OrthogonalTilemap, velocity: Vec2){
|
private collideWithOrthogonalTilemap(node: PhysicsNode, tilemap: OrthogonalTilemap, velocity: Vec2): void {
|
||||||
let startPos = node.getPosition();
|
let startPos = node.getPosition();
|
||||||
let endPos = startPos.clone().add(velocity);
|
let endPos = startPos.clone().add(velocity);
|
||||||
let size = node.getCollider().getSize();
|
let size = node.getCollider().getSize();
|
||||||
|
@ -95,12 +49,12 @@ export default class PhysicsManager {
|
||||||
let tilemapCollisions = new Array<TileCollisionData>();
|
let tilemapCollisions = new Array<TileCollisionData>();
|
||||||
let tileSize = tilemap.getTileSize();
|
let tileSize = tilemap.getTileSize();
|
||||||
|
|
||||||
Debug.getInstance().log("tilemapCollision", "");
|
Debug.log("tilemapCollision", "");
|
||||||
// Loop over all possible tiles
|
// Loop over all possible tiles
|
||||||
for(let col = minIndex.x; col <= maxIndex.x; col++){
|
for(let col = minIndex.x; col <= maxIndex.x; col++){
|
||||||
for(let row = minIndex.y; row <= maxIndex.y; row++){
|
for(let row = minIndex.y; row <= maxIndex.y; row++){
|
||||||
if(tilemap.isTileCollidable(col, row)){
|
if(tilemap.isTileCollidable(col, row)){
|
||||||
Debug.getInstance().log("tilemapCollision", "Colliding with Tile");
|
Debug.log("tilemapCollision", "Colliding with Tile");
|
||||||
|
|
||||||
// Tile position
|
// Tile position
|
||||||
let tilePos = new Vec2(col * tileSize.x, row * tileSize.y);
|
let tilePos = new Vec2(col * tileSize.x, row * tileSize.y);
|
||||||
|
@ -124,7 +78,7 @@ export default class PhysicsManager {
|
||||||
|
|
||||||
// Resolve the collisions
|
// Resolve the collisions
|
||||||
tilemapCollisions.forEach(collision => {
|
tilemapCollisions.forEach(collision => {
|
||||||
let [firstContact, _, collidingX, collidingY] = this.getTimeOfCollision(startPos, size, velocity, collision.position, tileSize, new Vec2(0, 0));
|
let [firstContact, _, collidingX, collidingY] = this.getTimeOfAABBCollision(startPos, size, velocity, collision.position, tileSize, new Vec2(0, 0));
|
||||||
|
|
||||||
// Handle collision
|
// Handle collision
|
||||||
if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
|
if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
|
||||||
|
@ -142,7 +96,7 @@ export default class PhysicsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(yScale !== 1){
|
if(yScale !== 1){
|
||||||
node.setIsGrounded(true);
|
node.setGrounded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
velocity.scale(xScale, yScale);
|
velocity.scale(xScale, yScale);
|
||||||
|
@ -151,7 +105,7 @@ export default class PhysicsManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2, id: String){
|
private handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2, id: String){
|
||||||
let sizeA = movingNode.getCollider().getSize();
|
let sizeA = movingNode.getCollider().getSize();
|
||||||
let posA = movingNode.getPosition();
|
let posA = movingNode.getPosition();
|
||||||
let velA = velocity;
|
let velA = velocity;
|
||||||
|
@ -159,7 +113,7 @@ export default class PhysicsManager {
|
||||||
let posB = staticNode.getPosition();
|
let posB = staticNode.getPosition();
|
||||||
let velB = new Vec2(0, 0);
|
let velB = new Vec2(0, 0);
|
||||||
|
|
||||||
let [firstContact, _, collidingX, collidingY] = this.getTimeOfCollision(posA, sizeA, velA, posB, sizeB, velB);
|
let [firstContact, _, collidingX, collidingY] = this.getTimeOfAABBCollision(posA, sizeA, velA, posB, sizeB, velB);
|
||||||
|
|
||||||
if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
|
if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
|
||||||
if(collidingX && collidingY){
|
if(collidingX && collidingY){
|
||||||
|
@ -170,7 +124,7 @@ export default class PhysicsManager {
|
||||||
let xScale = MathUtils.clamp(firstContact.x, 0, 1);
|
let xScale = MathUtils.clamp(firstContact.x, 0, 1);
|
||||||
let yScale = MathUtils.clamp(firstContact.y, 0, 1);
|
let yScale = MathUtils.clamp(firstContact.y, 0, 1);
|
||||||
if(yScale !== 1){
|
if(yScale !== 1){
|
||||||
movingNode.setIsGrounded(true);
|
movingNode.setGrounded(true);
|
||||||
}
|
}
|
||||||
velocity.scale(xScale, yScale);
|
velocity.scale(xScale, yScale);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +136,7 @@ export default class PhysicsManager {
|
||||||
* of the start and end of the collision and booleans for whether or not the objects are currently overlapping
|
* of the start and end of the collision and booleans for whether or not the objects are currently overlapping
|
||||||
* (before they move).
|
* (before they move).
|
||||||
*/
|
*/
|
||||||
getTimeOfCollision(posA: Vec2, sizeA: Vec2, velA: Vec2, posB: Vec2, sizeB: Vec2, velB: Vec2): [Vec2, Vec2, boolean, boolean] {
|
private getTimeOfAABBCollision(posA: Vec2, sizeA: Vec2, velA: Vec2, posB: Vec2, sizeB: Vec2, velB: Vec2): [Vec2, Vec2, boolean, boolean] {
|
||||||
let firstContact = new Vec2(0, 0);
|
let firstContact = new Vec2(0, 0);
|
||||||
let lastContact = new Vec2(0, 0);
|
let lastContact = new Vec2(0, 0);
|
||||||
|
|
||||||
|
@ -258,10 +212,57 @@ export default class PhysicsManager {
|
||||||
|
|
||||||
return [firstContact, lastContact, collidingX, collidingY];
|
return [firstContact, lastContact, collidingX, collidingY];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
for(let node of this.physicsNodes){
|
||||||
|
node.update(deltaT);
|
||||||
|
}
|
||||||
|
|
||||||
|
let staticSet = new Array<PhysicsNode>();
|
||||||
|
let dynamicSet = new Array<PhysicsNode>();
|
||||||
|
|
||||||
|
// TODO: REALLY bad, the physics system has to be improved, but that isn't the focus for now
|
||||||
|
for(let node of this.physicsNodes){
|
||||||
|
if(node.isMoving()){
|
||||||
|
dynamicSet.push(node);
|
||||||
|
node.setMoving(false);
|
||||||
|
} else {
|
||||||
|
staticSet.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, we will only have the moving player, don't bother checking for collisions with other moving things
|
||||||
|
for(let movingNode of dynamicSet){
|
||||||
|
movingNode.setGrounded(false);
|
||||||
|
// Get velocity of node
|
||||||
|
let velocity = null;
|
||||||
|
for(let data of this.movements){
|
||||||
|
if(data.node === movingNode){
|
||||||
|
velocity = new Vec2(data.velocity.x, data.velocity.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle collisions between dynamic nodes
|
||||||
|
// We probably want to sort them by their left edges
|
||||||
|
|
||||||
|
// TODO: handle collisions between dynamic nodes and static nodes
|
||||||
|
|
||||||
|
// Handle Collisions with the tilemaps
|
||||||
|
for(let tilemap of this.tilemaps){
|
||||||
|
this.collideWithTilemap(movingNode, tilemap, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
movingNode.finishMove(velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset movements
|
||||||
|
this.movements = new Array();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper classes for internal data
|
// Helper classes for internal data
|
||||||
class MovementData{
|
// TODO: Move these to data
|
||||||
|
class MovementData {
|
||||||
node: PhysicsNode;
|
node: PhysicsNode;
|
||||||
velocity: Vec2;
|
velocity: Vec2;
|
||||||
constructor(node: PhysicsNode, velocity: Vec2){
|
constructor(node: PhysicsNode, velocity: Vec2){
|
||||||
|
|
|
@ -8,17 +8,18 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
protected collider: Collider = null;
|
protected collider: Collider = null;
|
||||||
protected children: Array<GameNode>;
|
protected children: Array<GameNode>;
|
||||||
private manager: PhysicsManager;
|
private manager: PhysicsManager;
|
||||||
isMoving: boolean;
|
protected moving: boolean;
|
||||||
protected isGrounded: boolean;
|
protected grounded: boolean;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
this.children = new Array();
|
this.children = new Array();
|
||||||
this.isMoving = false;
|
this.grounded = false;
|
||||||
|
this.moving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsGrounded(isGrounded: boolean): void {
|
setGrounded(grounded: boolean): void {
|
||||||
this.isGrounded = isGrounded;
|
this.grounded = grounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
addManager(manager: PhysicsManager): void {
|
addManager(manager: PhysicsManager): void {
|
||||||
|
@ -33,8 +34,16 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
return this.collider;
|
return this.collider;
|
||||||
}
|
}
|
||||||
|
|
||||||
move(velocity: Vec2): void {
|
setMoving(moving: boolean): void {
|
||||||
this.isMoving = true;
|
this.moving = moving;
|
||||||
|
}
|
||||||
|
|
||||||
|
isMoving(): boolean {
|
||||||
|
return this.moving;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected move(velocity: Vec2): void {
|
||||||
|
this.moving = true;
|
||||||
this.manager.addMovement(this, velocity);
|
this.manager.addMovement(this, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import PhysicsNode from "./Physics/PhysicsNode";
|
||||||
import Vec2 from "./DataTypes/Vec2";
|
import Vec2 from "./DataTypes/Vec2";
|
||||||
import Debug from "./Debug/Debug";
|
import Debug from "./Debug/Debug";
|
||||||
import AABB from "./Physics/Colliders/AABB";
|
import AABB from "./Physics/Colliders/AABB";
|
||||||
import PlayerSprite from "./Nodes/PlayerSprite";
|
import PlayerSprite from "./PlayerSprite";
|
||||||
|
|
||||||
export default class Player extends PhysicsNode {
|
export default class Player extends PhysicsNode {
|
||||||
velocity: Vec2;
|
velocity: Vec2;
|
||||||
|
@ -24,7 +24,6 @@ export default class Player extends PhysicsNode {
|
||||||
if(this.type === "topdown"){
|
if(this.type === "topdown"){
|
||||||
this.position = new Vec2(100, 100);
|
this.position = new Vec2(100, 100);
|
||||||
}
|
}
|
||||||
this.debug = Debug.getInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create(): void {
|
create(): void {
|
||||||
|
@ -45,7 +44,7 @@ export default class Player extends PhysicsNode {
|
||||||
|
|
||||||
this.move(new Vec2(this.velocity.x * deltaT, this.velocity.y * deltaT));
|
this.move(new Vec2(this.velocity.x * deltaT, this.velocity.y * deltaT));
|
||||||
|
|
||||||
this.debug.log("player", "Player Pos: " + this.position.toFixed() + ", Player Vel: " + this.velocity.toFixed());
|
Debug.log("player", "Player Pos: " + this.position + ", Player Vel: " + this.velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
topdown_computeDirection(): Vec2 {
|
topdown_computeDirection(): Vec2 {
|
||||||
|
@ -70,7 +69,7 @@ export default class Player extends PhysicsNode {
|
||||||
dir.x += this.input.isPressed('a') ? -1 : 0;
|
dir.x += this.input.isPressed('a') ? -1 : 0;
|
||||||
dir.x += this.input.isPressed('d') ? 1 : 0;
|
dir.x += this.input.isPressed('d') ? 1 : 0;
|
||||||
|
|
||||||
if(this.isGrounded){
|
if(this.grounded){
|
||||||
dir.y += this.input.isJustPressed('w') ? -1 : 0;
|
dir.y += this.input.isJustPressed('w') ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +79,7 @@ export default class Player extends PhysicsNode {
|
||||||
platformer_computeVelocity(dir: Vec2, deltaT: number): Vec2 {
|
platformer_computeVelocity(dir: Vec2, deltaT: number): Vec2 {
|
||||||
let vel = new Vec2(0, this.velocity.y);
|
let vel = new Vec2(0, this.velocity.y);
|
||||||
|
|
||||||
if(this.isGrounded){
|
if(this.grounded){
|
||||||
vel.y = dir.y*1800;
|
vel.y = dir.y*1800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import CanvasNode from "./CanvasNode";
|
import CanvasNode from "./Nodes/CanvasNode";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "./DataTypes/Vec2";
|
||||||
import Debug from "../Debug/Debug";
|
import Debug from "./Debug/Debug";
|
||||||
|
|
||||||
export default class Player extends CanvasNode{
|
export default class Player extends CanvasNode{
|
||||||
debug: Debug;
|
debug: Debug;
|
|
@ -2,14 +2,17 @@ import Viewport from "./Viewport";
|
||||||
import CanvasNode from "../Nodes/CanvasNode";
|
import CanvasNode from "../Nodes/CanvasNode";
|
||||||
import Map from "../DataTypes/Map";
|
import Map from "../DataTypes/Map";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
import Scene from "../GameState/Scene";
|
||||||
|
|
||||||
export default abstract class SceneGraph{
|
export default abstract class SceneGraph{
|
||||||
protected viewport: Viewport;
|
protected viewport: Viewport;
|
||||||
protected nodeMap: Map<CanvasNode>;
|
protected nodeMap: Map<CanvasNode>;
|
||||||
protected idCounter: number;
|
protected idCounter: number;
|
||||||
|
protected scene: Scene;
|
||||||
|
|
||||||
constructor(viewport: Viewport){
|
constructor(viewport: Viewport, scene: Scene){
|
||||||
this.viewport = viewport;
|
this.viewport = viewport;
|
||||||
|
this.scene = scene;
|
||||||
this.nodeMap = new Map<CanvasNode>();
|
this.nodeMap = new Map<CanvasNode>();
|
||||||
this.idCounter = 0;
|
this.idCounter = 0;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +42,7 @@ export default abstract class SceneGraph{
|
||||||
return this.nodeMap.get(id);
|
return this.nodeMap.get(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
getNodeAt(vecOrX: Vec2 | number, y: number = null): CanvasNode{
|
getNodeAt(vecOrX: Vec2 | number, y: number = null): CanvasNode {
|
||||||
if(vecOrX instanceof Vec2){
|
if(vecOrX instanceof Vec2){
|
||||||
return this.getNodeAtCoords(vecOrX.x, vecOrX.y);
|
return this.getNodeAtCoords(vecOrX.x, vecOrX.y);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,11 +6,9 @@ import Scene from "../GameState/Scene";
|
||||||
export default class SceneGraphArray extends SceneGraph{
|
export default class SceneGraphArray extends SceneGraph{
|
||||||
private nodeList: Array<CanvasNode>;
|
private nodeList: Array<CanvasNode>;
|
||||||
private turnOffViewportCulling_demoTool: boolean;
|
private turnOffViewportCulling_demoTool: boolean;
|
||||||
private scene: Scene;
|
|
||||||
|
|
||||||
constructor(viewport: Viewport, scene: Scene){
|
constructor(viewport: Viewport, scene: Scene){
|
||||||
super(viewport);
|
super(viewport, scene);
|
||||||
this.scene = scene;
|
|
||||||
|
|
||||||
this.nodeList = new Array<CanvasNode>();
|
this.nodeList = new Array<CanvasNode>();
|
||||||
this.turnOffViewportCulling_demoTool = false;
|
this.turnOffViewportCulling_demoTool = false;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import MathUtils from "./MathUtils";
|
import MathUtils from "./MathUtils";
|
||||||
|
|
||||||
|
// TODO: This should be moved to the datatypes folder
|
||||||
export default class Color{
|
export default class Color{
|
||||||
public r: number;
|
public r: number;
|
||||||
public g: number;
|
public g: number;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
export default class MathUtils{
|
export default class MathUtils{
|
||||||
static clamp(x: number, min: number, max: number): number{
|
static clamp(x: number, min: number, max: number): number {
|
||||||
if(x < min) return min;
|
if(x < min) return min;
|
||||||
if(x > max) return max;
|
if(x > max) return max;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static toHex(num: number, minLength: number = null): string{
|
static toHex(num: number, minLength: number = null): string {
|
||||||
let factor = 1;
|
let factor = 1;
|
||||||
while(factor*16 < num){
|
while(factor*16 < num){
|
||||||
factor *= 16;
|
factor *= 16;
|
||||||
|
@ -27,7 +27,7 @@ export default class MathUtils{
|
||||||
return hexStr;
|
return hexStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static toHexDigit(num: number): string{
|
static toHexDigit(num: number): string {
|
||||||
if(num < 10){
|
if(num < 10){
|
||||||
return "" + num;
|
return "" + num;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,15 +2,15 @@ import MathUtils from "./MathUtils";
|
||||||
import Color from "./Color";
|
import Color from "./Color";
|
||||||
|
|
||||||
export default class RandUtils{
|
export default class RandUtils{
|
||||||
static randInt(min: number, max: number): number{
|
static randInt(min: number, max: number): number {
|
||||||
return Math.floor(Math.random()*(max - min) + min);
|
return Math.floor(Math.random()*(max - min) + min);
|
||||||
}
|
}
|
||||||
|
|
||||||
static randHex(min: number, max: number): string{
|
static randHex(min: number, max: number): string {
|
||||||
return MathUtils.toHex(RandUtils.randInt(min, max));
|
return MathUtils.toHex(RandUtils.randInt(min, max));
|
||||||
}
|
}
|
||||||
|
|
||||||
static randColor(): Color{
|
static randColor(): Color {
|
||||||
let r = RandUtils.randInt(0, 256);
|
let r = RandUtils.randInt(0, 256);
|
||||||
let g = RandUtils.randInt(0, 256);
|
let g = RandUtils.randInt(0, 256);
|
||||||
let b = RandUtils.randInt(0, 256);
|
let b = RandUtils.randInt(0, 256);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import GameLoop from "./Loop/GameLoop";
|
import GameLoop from "./Loop/GameLoop";
|
||||||
import Player from "./Player";
|
import Player from "./Player";
|
||||||
import UIElement from "./Nodes/UIElement";
|
import UIElement from "./Nodes/UIElement";
|
||||||
import ColoredCircle from "./Nodes/ColoredCircle";
|
|
||||||
import Color from "./Utils/Color";
|
import Color from "./Utils/Color";
|
||||||
import Button from "./Nodes/UIElements/Button";
|
import Button from "./Nodes/UIElements/Button";
|
||||||
import {} from "./index";
|
import {} from "./index";
|
||||||
|
|
|
@ -33,9 +33,9 @@
|
||||||
"src/Nodes/UIElements/Button.ts",
|
"src/Nodes/UIElements/Button.ts",
|
||||||
"src/Nodes/UIElements/Label.ts",
|
"src/Nodes/UIElements/Label.ts",
|
||||||
"src/Nodes/CanvasNode.ts",
|
"src/Nodes/CanvasNode.ts",
|
||||||
"src/Nodes/ColoredCircle.ts",
|
"src/ColoredCircle.ts",
|
||||||
"src/Nodes/GameNode.ts",
|
"src/Nodes/GameNode.ts",
|
||||||
"src/Nodes/PlayerSprite.ts",
|
"src/PlayerSprite.ts",
|
||||||
"src/Nodes/Tilemap.ts",
|
"src/Nodes/Tilemap.ts",
|
||||||
"src/Nodes/UIElement.ts",
|
"src/Nodes/UIElement.ts",
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user