diff --git a/src/DataTypes/Tilesets/TiledData.ts b/src/DataTypes/Tilesets/TiledData.ts index ad7818a..89fe3c2 100644 --- a/src/DataTypes/Tilesets/TiledData.ts +++ b/src/DataTypes/Tilesets/TiledData.ts @@ -1,6 +1,8 @@ export class TiledTilemapData { height: number; width: number; + tileheight: number; + tilewidth: number; orientation: string; layers: TiledLayerData[]; tilesets: TiledTilesetData[]; diff --git a/src/GameState/Factories/TilemapFactory.ts b/src/GameState/Factories/TilemapFactory.ts index 79edf69..7c8afd6 100644 --- a/src/GameState/Factories/TilemapFactory.ts +++ b/src/GameState/Factories/TilemapFactory.ts @@ -4,6 +4,8 @@ import Tilemap from "../../Nodes/Tilemap" import ResourceManager from "../../ResourceManager/ResourceManager"; import { TiledTilemapData } from "../../DataTypes/Tilesets/TiledData"; import StringUtils from "../../Utils/StringUtils"; +import StaticBody from "../../Physics/StaticBody"; +import Vec2 from "../../DataTypes/Vec2"; export default class TilemapFactory { private scene: Scene; @@ -25,6 +27,17 @@ export default class TilemapFactory { // Add to scene this.scene.addTilemap(tilemap); + 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.y) * 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 tilemap.getTilesets().forEach(tileset => { let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl(); diff --git a/src/Nodes/Tilemap.ts b/src/Nodes/Tilemap.ts index e950c37..bde88c0 100644 --- a/src/Nodes/Tilemap.ts +++ b/src/Nodes/Tilemap.ts @@ -10,11 +10,13 @@ export default abstract class Tilemap extends GameNode { protected data: number[]; protected tilesets: Tileset[]; protected worldSize: Vec2; + protected tileSize: Vec2; constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData){ super(); this.tilesets = new Array(); this.worldSize = new Vec2(0, 0); + this.tileSize = new Vec2(0, 0); this.parseTilemapData(tilemapData, layerData); } @@ -22,6 +24,14 @@ export default abstract class Tilemap extends GameNode { return this.tilesets; } + getWorldSize(): Vec2 { + return this.worldSize; + } + + getTileSize(): Vec2 { + return this.tileSize; + } + isReady(): boolean { if(this.tilesets.length !== 0){ for(let tileset of this.tilesets){ @@ -33,6 +43,8 @@ export default abstract class Tilemap extends GameNode { return true; } + abstract forEachTile(func: Function): void; + /** * Sets up the tileset using the data loaded from file */ diff --git a/src/Nodes/Tilemaps/OrthogonalTilemap.ts b/src/Nodes/Tilemaps/OrthogonalTilemap.ts index 4ec5f85..09ce47f 100644 --- a/src/Nodes/Tilemaps/OrthogonalTilemap.ts +++ b/src/Nodes/Tilemaps/OrthogonalTilemap.ts @@ -7,10 +7,17 @@ import Tileset from "../../DataTypes/Tilesets/Tileset"; export default class OrthogonalTilemap extends Tilemap { parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void { this.worldSize.set(tilemapData.width, tilemapData.height); + this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight); this.data = layer.data; tilemapData.tilesets.forEach(tilesetData => this.tilesets.push(new Tileset(tilesetData))); } + forEachTile(func: Function){ + for(let i = 0; i < this.data.length; i++){ + func(this.data[i], i); + } + } + update(deltaT: number): void {} render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) { diff --git a/src/Physics/PhysicsManager.ts b/src/Physics/PhysicsManager.ts index 71c023f..6b6e65e 100644 --- a/src/Physics/PhysicsManager.ts +++ b/src/Physics/PhysicsManager.ts @@ -1,5 +1,7 @@ import PhysicsNode from "./PhysicsNode"; import Vec2 from "../DataTypes/Vec2"; +import StaticBody from "./StaticBody"; +import Debug from "../Debug/Debug"; export default class PhysicsManager { @@ -47,11 +49,8 @@ export default class PhysicsManager { } } - for(let staticNode of staticSet){ - if(movingNode.getCollider().willCollideWith(staticNode.getCollider(), velocity, new Vec2(0, 0))){ - this.handleCollision(movingNode, staticNode, velocity); - } + this.handleCollision(movingNode, staticNode, velocity, (staticNode).id); } movingNode.finishMove(velocity); @@ -61,20 +60,94 @@ export default class PhysicsManager { this.movements = new Array(); } - handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2){ - let ASize = movingNode.getCollider().getSize(); - let A = new Vec2(movingNode.getPosition().x + ASize.x, movingNode.getPosition().y + ASize.y); - let BSize = staticNode.getCollider().getSize(); - let B = new Vec2(staticNode.getPosition().x + BSize.x, staticNode.getPosition().y + BSize.y); + handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2, id: String){ + let sizeA = movingNode.getCollider().getSize(); + let A = movingNode.getPosition(); + let velA = velocity; + let sizeB = staticNode.getCollider().getSize(); + let B = staticNode.getPosition(); + let velB = new Vec2(0, 0); let firstContact = new Vec2(0, 0); - firstContact.x = (B.x-(BSize.x/2) - (A.x + (ASize.x/2)))/(velocity.x - 0); - firstContact.y = (B.y-(BSize.y/2) - (A.y + (ASize.y/2)))/(velocity.y - 0); + let lastContact = new Vec2(0, 0); - if(firstContact.x < 1 || firstContact.y < 1){ - // We collided - let firstCollisionTime = Math.min(firstContact.x, firstContact.y); - velocity.scale(firstCollisionTime); + let collidingX = false; + let collidingY = false; + + // Sort by position + if(B.x < A.x){ + // Swap, because B is to the left of A + let temp: Vec2; + temp = sizeA; + sizeA = sizeB; + sizeB = temp; + + temp = A; + A = B; + B = temp; + + temp = velA; + velA = velB; + velB = temp; + } + + // A is left, B is right + firstContact.x = Infinity; + lastContact.x = Infinity; + + if (B.x >= A.x + sizeA.x){ + // If we aren't currently colliding + let relVel = velA.x - velB.x; + + if(relVel > 0){ + // If they are moving towards each other + firstContact.x = (B.x - (A.x + (sizeA.x)))/(relVel); + lastContact.x = ((B.x + sizeB.x) - A.x)/(relVel); + } + } else { + collidingX = true; + } + + if(B.y < A.y){ + // Swap, because B is above A + let temp: Vec2; + temp = sizeA; + sizeA = sizeB; + sizeB = temp; + + temp = A; + A = B; + B = temp; + + temp = velA; + velA = velB; + velB = temp; + } + + // A is top, B is bottom + firstContact.y = Infinity; + lastContact.y = Infinity; + + if (B.y >= A.y + sizeA.y){ + // If we aren't currently colliding + let relVel = velA.y - velB.y; + + if(relVel > 0){ + // If they are moving towards each other + firstContact.y = (B.y - (A.y + (sizeA.y)))/(relVel); + lastContact.y = ((B.y + sizeB.y) - A.y)/(relVel); + } + } else { + collidingY = true; + } + + if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){ + if(collidingX && collidingY){ + // If we're already intersecting, freak out I guess? + } else { + let contactTime = Math.min(firstContact.x, firstContact.y); + velocity.scale(contactTime); + } } } } diff --git a/src/Physics/PhysicsNode.ts b/src/Physics/PhysicsNode.ts index 5c32fad..a876615 100644 --- a/src/Physics/PhysicsNode.ts +++ b/src/Physics/PhysicsNode.ts @@ -35,6 +35,7 @@ export default abstract class PhysicsNode extends GameNode { finishMove(velocity: Vec2): void { this.position.add(velocity); + this.collider.getPosition().add(velocity); for(let child of this.children){ child.getPosition().add(velocity); } diff --git a/src/Physics/StaticBody.ts b/src/Physics/StaticBody.ts new file mode 100644 index 0000000..0f25c2d --- /dev/null +++ b/src/Physics/StaticBody.ts @@ -0,0 +1,24 @@ +import PhysicsNode from "./PhysicsNode"; +import Vec2 from "../DataTypes/Vec2"; +import AABB from "./Colliders/AABB"; + +export default class StaticBody extends PhysicsNode { + + id: string; + static numCreated: number = 0; + + constructor(position: Vec2, size: Vec2){ + super(); + this.setPosition(position.x, position.y); + this.collider = new AABB(); + this.collider.setPosition(position.x, position.y); + this.collider.setSize(new Vec2(size.x, size.y)); + this.id = StaticBody.numCreated.toString(); + StaticBody.numCreated += 1; + } + + create(): void {} + + update(deltaT: number): void {} + +} \ No newline at end of file diff --git a/src/Player.ts b/src/Player.ts index fb17e7d..dfb70f8 100644 --- a/src/Player.ts +++ b/src/Player.ts @@ -7,14 +7,16 @@ import PlayerSprite from "./Nodes/PlayerSprite"; export default class Player extends PhysicsNode { velocity: Vec2; speed: number; - debug: Debug; + debug: Debug; + size: Vec2; constructor(){ super(); this.velocity = new Vec2(0, 0); this.speed = 300; + this.size = new Vec2(50, 50); this.collider = new AABB(); - this.collider.setSize(new Vec2(50, 50)); + this.collider.setSize(this.size); this.position = new Vec2(0, 0); this.debug = Debug.getInstance(); } @@ -22,7 +24,7 @@ export default class Player extends PhysicsNode { create(): void { let sprite = this.scene.canvasNode.add(PlayerSprite); sprite.setPosition(this.position); - sprite.setSize(50, 50); + sprite.setSize(this.size); this.children.push(sprite); } @@ -38,7 +40,7 @@ export default class Player extends PhysicsNode { this.velocity = dir.scale(this.speed); this.move(this.velocity.scale(deltaT)); - this.debug.log("player", "Player Pos: " + this.position.toFixed()); + this.debug.log("player", "Player Pos: " + this.position.toFixed() + " " + this.velocity.toFixed()); } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 230e2eb..274caf8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,7 +78,7 @@ function main(){ pauseMenu.disable(); } - mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/MultiLayer.json"); + mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/SmallTest.json"); for(let i = 0; i < 30; i++){ let cc = foregroundLayer.canvasNode.add(ColoredCircle);