cleaned up typescript inconsistencies in code

This commit is contained in:
Joe Weaver 2020-08-24 18:54:52 -04:00
parent 2dd60b5197
commit bd49258d30
29 changed files with 166 additions and 181 deletions

View File

@ -1,7 +1,7 @@
import CanvasNode from "./CanvasNode";
import Color from "../Utils/Color";
import Vec2 from "../DataTypes/Vec2";
import RandUtils from "../Utils/RandUtils";
import CanvasNode from "./Nodes/CanvasNode";
import Color from "./Utils/Color";
import Vec2 from "./DataTypes/Vec2";
import RandUtils from "./Utils/RandUtils";
export default class ColoredCircle extends CanvasNode{
private color: Color;

View File

@ -1,7 +1,7 @@
import Collection from "./Collection";
export default class Queue<T> implements Collection{
readonly MAX_ELEMENTS: number;
private readonly MAX_ELEMENTS: number;
private q: Array<T>;
private head: number;
private tail: number;

View File

@ -34,13 +34,6 @@ export default class Stack<T> implements Collection{
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
*/
@ -51,6 +44,13 @@ export default class Stack<T> implements Collection{
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
*/

View File

@ -4,8 +4,8 @@ export class TiledTilemapData {
tileheight: number;
tilewidth: number;
orientation: string;
layers: TiledLayerData[];
tilesets: TiledTilesetData[];
layers: Array<TiledLayerData>;
tilesets: Array<TiledTilesetData>;
}
export class TiledLayerProperty {

View File

@ -15,11 +15,12 @@ export default class Tileset {
protected numRows: number;
protected numCols: number;
// TODO: Change this to be more general and work with other tileset formats
constructor(tilesetData: TiledTilesetData){
this.initFromTiledData(tilesetData);
}
initFromTiledData(tiledData: TiledTilesetData){
initFromTiledData(tiledData: TiledTilesetData): void {
this.numRows = tiledData.tilecount/tiledData.columns;
this.numCols = tiledData.columns;
this.startIndex = tiledData.firstgid;
@ -57,6 +58,7 @@ export default class Tileset {
return this.numCols;
}
// TODO: This should probably be a thing that is tracked in the resource loader, not here
isReady(): boolean {
return this.image !== null;
}

View File

@ -45,7 +45,7 @@ export default class Vec2 {
return this;
}
rotate(angle: number): Vec2 {
rotateCCW(angle: number): Vec2 {
let cs = Math.cos(angle);
let sn = Math.sin(angle);
let tempX = this.x*cs - this.y*sn;
@ -74,11 +74,11 @@ export default class Vec2 {
}
toString(): string {
return "(" + this.x + ", " + this.y + ")";
return this.toFixed();
}
toFixed(): string {
return "(" + this.x.toFixed(1) + ", " + this.y.toFixed(1) + ")";
toFixed(numDecimalPoints: number = 1): string {
return "(" + this.x.toFixed(numDecimalPoints) + ", " + this.y.toFixed(numDecimalPoints) + ")";
}
clone(): Vec2 {

View File

@ -1,30 +1,16 @@
import Map from "../DataTypes/Map";
export default class Debug {
private static instance: Debug = null;
logIds: number;
logMessages: Map<string>;
private static logMessages: Map<string> = new Map();
constructor(){
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 {
static log(id: string, message: string): void {
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;
ctx.font = "20px Arial";
ctx.fillStyle = "#000000";

View File

@ -1,13 +1,11 @@
import Scene from "../Scene";
import Viewport from "../../SceneGraph/Viewport";
import CanvasItem from "../../Nodes/CanvasNode"
import PlayerSprite from "../../Nodes/PlayerSprite";
export default class CanvasNodeFactory {
private scene: Scene;
private viewport: Viewport;
constructor(scene: Scene, viewport: Viewport){
constructor(scene: Scene){
this.scene = scene;
}

View File

@ -9,10 +9,10 @@ import Vec2 from "../../DataTypes/Vec2";
export default class TilemapFactory {
private scene: Scene;
private viewport: Viewport;
// TODO: get the resource manager OUT of here, it does not belong
private resourceManager: ResourceManager;
constructor(scene: Scene, viewport: Viewport){
constructor(scene: Scene){
this.scene = scene;
this.resourceManager = ResourceManager.getInstance();
}
@ -30,18 +30,6 @@ export default class TilemapFactory {
if(tilemap.isCollidable()){
// Register in physics as a 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

View File

@ -15,7 +15,7 @@ export default class Scene {
private gameState: GameState;
private viewport: Viewport
private parallax: Vec2;
sceneGraph: SceneGraph;
private sceneGraph: SceneGraph;
private physicsManager: PhysicsManager;
private tilemaps: Array<Tilemap>;
private paused: boolean;
@ -38,8 +38,8 @@ export default class Scene {
this.physicsManager = new PhysicsManager();
// Factories
this.canvasNode = new CanvasNodeFactory(this, this.viewport);
this.tilemap = new TilemapFactory(this, this.viewport);
this.canvasNode = new CanvasNodeFactory(this);
this.tilemap = new TilemapFactory(this);
this.physics = new PhysicsNodeFactory(this, this.physicsManager);
}
@ -47,16 +47,16 @@ export default class Scene {
this.paused = pauseValue;
}
setAlpha(alpha: number): void {
this.alpha = MathUtils.clamp(alpha, 0, 1);
}
isPaused(): boolean {
return this.paused;
}
setHidden(hiddenValue: boolean): void {
this.hidden = hiddenValue;
setAlpha(alpha: number): void {
this.alpha = MathUtils.clamp(alpha, 0, 1);
}
setHidden(hidden: boolean): void {
this.hidden = hidden;
}
isHidden(): boolean {
@ -85,8 +85,8 @@ export default class Scene {
return this.parallax;
}
add(children: CanvasNode): void {
this.sceneGraph.addNode(children);
add(child: CanvasNode): void {
this.sceneGraph.addNode(child);
}
addTilemap(tilemap: Tilemap): void {

View File

@ -38,7 +38,6 @@ export default class GameLoop{
private inputReceiver: InputReceiver;
private recorder: Recorder;
private gameState: GameState;
private debug: Debug;
private resourceManager: ResourceManager;
constructor(){
@ -68,7 +67,6 @@ export default class GameLoop{
this.inputReceiver.setViewport(this.viewport);
this.recorder = new Recorder();
this.gameState = new GameState(this.viewport);
this.debug = Debug.getInstance();
this.resourceManager = ResourceManager.getInstance();
}
@ -99,7 +97,7 @@ export default class GameLoop{
this.runningFrameSum = 0;
}
this.debug.log("fps", "FPS: " + this.fps.toFixed(1));
Debug.log("fps", "FPS: " + this.fps.toFixed(1));
}
start(): void {
@ -157,6 +155,6 @@ export default class GameLoop{
render(): void {
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
this.gameState.render(this.ctx);
this.debug.render(this.ctx);
Debug.render(this.ctx);
}
}

View File

@ -39,11 +39,11 @@ export default abstract class GameNode{
}
}
subscribe(eventType: string){
subscribe(eventType: string): void {
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);
this.eventQueue.addEvent(event);
}

View File

@ -16,6 +16,7 @@ export default abstract class Tilemap extends GameNode {
protected collidable: boolean;
protected scale: Vec2;
// TODO: Make this no longer be specific to Tiled
constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData) {
super();
this.tilesets = new Array<Tileset>();
@ -71,7 +72,8 @@ export default abstract class Tilemap extends GameNode {
/**
* 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;
}

View File

@ -6,7 +6,7 @@ import Tileset from "../../DataTypes/Tilesets/Tileset";
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.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight);
this.data = layer.data;

View File

@ -4,16 +4,16 @@ import Vec2 from "../DataTypes/Vec2";
export default class UIElement extends CanvasNode{
// Style attributes
textColor: Color;
backgroundColor: Color;
borderColor: Color;
text: string;
font: string;
fontSize: number;
hAlign: string;
vAlign: string;
borderRadius: number;
borderWidth: number;
protected textColor: Color;
protected backgroundColor: Color;
protected borderColor: Color;
protected text: string;
protected font: string;
protected fontSize: number;
protected hAlign: string;
protected vAlign: string;
protected borderRadius: number;
protected borderWidth: number;
// EventAttributes
onClick: Function;

View File

@ -8,6 +8,7 @@ export default abstract class Collider extends GameNode {
return this.size;
}
// TODO: Make this accept vector arguments and number arguments
setSize(size: Vec2): void {
this.size = size;
}

View File

@ -8,9 +8,9 @@ import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
export default class PhysicsManager {
physicsNodes: Array<PhysicsNode>;
tilemaps: Array<Tilemap>;
movements: Array<MovementData>;
private physicsNodes: Array<PhysicsNode>;
private tilemaps: Array<Tilemap>;
private movements: Array<MovementData>;
constructor(){
this.physicsNodes = new Array();
@ -26,63 +26,17 @@ export default class PhysicsManager {
this.tilemaps.push(tilemap);
}
addMovement(node: PhysicsNode, velocity: Vec2){
addMovement(node: PhysicsNode, velocity: Vec2): void {
this.movements.push(new MovementData(node, velocity));
}
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.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){
private collideWithTilemap(node: PhysicsNode, tilemap: Tilemap, velocity: Vec2): void {
if(tilemap instanceof OrthogonalTilemap){
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 endPos = startPos.clone().add(velocity);
let size = node.getCollider().getSize();
@ -95,12 +49,12 @@ export default class PhysicsManager {
let tilemapCollisions = new Array<TileCollisionData>();
let tileSize = tilemap.getTileSize();
Debug.getInstance().log("tilemapCollision", "");
Debug.log("tilemapCollision", "");
// Loop over all possible tiles
for(let col = minIndex.x; col <= maxIndex.x; col++){
for(let row = minIndex.y; row <= maxIndex.y; row++){
if(tilemap.isTileCollidable(col, row)){
Debug.getInstance().log("tilemapCollision", "Colliding with Tile");
Debug.log("tilemapCollision", "Colliding with Tile");
// Tile position
let tilePos = new Vec2(col * tileSize.x, row * tileSize.y);
@ -124,7 +78,7 @@ export default class PhysicsManager {
// Resolve the collisions
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
if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){
@ -142,7 +96,7 @@ export default class PhysicsManager {
}
if(yScale !== 1){
node.setIsGrounded(true);
node.setGrounded(true);
}
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 posA = movingNode.getPosition();
let velA = velocity;
@ -159,7 +113,7 @@ export default class PhysicsManager {
let posB = staticNode.getPosition();
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(collidingX && collidingY){
@ -170,7 +124,7 @@ export default class PhysicsManager {
let xScale = MathUtils.clamp(firstContact.x, 0, 1);
let yScale = MathUtils.clamp(firstContact.y, 0, 1);
if(yScale !== 1){
movingNode.setIsGrounded(true);
movingNode.setGrounded(true);
}
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
* (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 lastContact = new Vec2(0, 0);
@ -258,9 +212,56 @@ export default class PhysicsManager {
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
// TODO: Move these to data
class MovementData {
node: PhysicsNode;
velocity: Vec2;

View File

@ -8,17 +8,18 @@ export default abstract class PhysicsNode extends GameNode {
protected collider: Collider = null;
protected children: Array<GameNode>;
private manager: PhysicsManager;
isMoving: boolean;
protected isGrounded: boolean;
protected moving: boolean;
protected grounded: boolean;
constructor(){
super();
this.children = new Array();
this.isMoving = false;
this.grounded = false;
this.moving = false;
}
setIsGrounded(isGrounded: boolean): void {
this.isGrounded = isGrounded;
setGrounded(grounded: boolean): void {
this.grounded = grounded;
}
addManager(manager: PhysicsManager): void {
@ -33,8 +34,16 @@ export default abstract class PhysicsNode extends GameNode {
return this.collider;
}
move(velocity: Vec2): void {
this.isMoving = true;
setMoving(moving: boolean): void {
this.moving = moving;
}
isMoving(): boolean {
return this.moving;
}
protected move(velocity: Vec2): void {
this.moving = true;
this.manager.addMovement(this, velocity);
}

View File

@ -2,7 +2,7 @@ import PhysicsNode from "./Physics/PhysicsNode";
import Vec2 from "./DataTypes/Vec2";
import Debug from "./Debug/Debug";
import AABB from "./Physics/Colliders/AABB";
import PlayerSprite from "./Nodes/PlayerSprite";
import PlayerSprite from "./PlayerSprite";
export default class Player extends PhysicsNode {
velocity: Vec2;
@ -24,7 +24,6 @@ export default class Player extends PhysicsNode {
if(this.type === "topdown"){
this.position = new Vec2(100, 100);
}
this.debug = Debug.getInstance();
}
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.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 {
@ -70,7 +69,7 @@ export default class Player extends PhysicsNode {
dir.x += this.input.isPressed('a') ? -1 : 0;
dir.x += this.input.isPressed('d') ? 1 : 0;
if(this.isGrounded){
if(this.grounded){
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 {
let vel = new Vec2(0, this.velocity.y);
if(this.isGrounded){
if(this.grounded){
vel.y = dir.y*1800;
}

View File

@ -1,6 +1,6 @@
import CanvasNode from "./CanvasNode";
import Vec2 from "../DataTypes/Vec2";
import Debug from "../Debug/Debug";
import CanvasNode from "./Nodes/CanvasNode";
import Vec2 from "./DataTypes/Vec2";
import Debug from "./Debug/Debug";
export default class Player extends CanvasNode{
debug: Debug;

View File

@ -2,14 +2,17 @@ import Viewport from "./Viewport";
import CanvasNode from "../Nodes/CanvasNode";
import Map from "../DataTypes/Map";
import Vec2 from "../DataTypes/Vec2";
import Scene from "../GameState/Scene";
export default abstract class SceneGraph{
protected viewport: Viewport;
protected nodeMap: Map<CanvasNode>;
protected idCounter: number;
protected scene: Scene;
constructor(viewport: Viewport){
constructor(viewport: Viewport, scene: Scene){
this.viewport = viewport;
this.scene = scene;
this.nodeMap = new Map<CanvasNode>();
this.idCounter = 0;
}

View File

@ -6,11 +6,9 @@ import Scene from "../GameState/Scene";
export default class SceneGraphArray extends SceneGraph{
private nodeList: Array<CanvasNode>;
private turnOffViewportCulling_demoTool: boolean;
private scene: Scene;
constructor(viewport: Viewport, scene: Scene){
super(viewport);
this.scene = scene;
super(viewport, scene);
this.nodeList = new Array<CanvasNode>();
this.turnOffViewportCulling_demoTool = false;

View File

@ -1,5 +1,6 @@
import MathUtils from "./MathUtils";
// TODO: This should be moved to the datatypes folder
export default class Color{
public r: number;
public g: number;

View File

@ -1,7 +1,6 @@
import GameLoop from "./Loop/GameLoop";
import Player from "./Player";
import UIElement from "./Nodes/UIElement";
import ColoredCircle from "./Nodes/ColoredCircle";
import Color from "./Utils/Color";
import Button from "./Nodes/UIElements/Button";
import {} from "./index";

View File

@ -33,9 +33,9 @@
"src/Nodes/UIElements/Button.ts",
"src/Nodes/UIElements/Label.ts",
"src/Nodes/CanvasNode.ts",
"src/Nodes/ColoredCircle.ts",
"src/ColoredCircle.ts",
"src/Nodes/GameNode.ts",
"src/Nodes/PlayerSprite.ts",
"src/PlayerSprite.ts",
"src/Nodes/Tilemap.ts",
"src/Nodes/UIElement.ts",