added basic collisions
This commit is contained in:
parent
e6d4d75cd5
commit
201e1624c4
|
@ -1,6 +1,8 @@
|
||||||
export class TiledTilemapData {
|
export class TiledTilemapData {
|
||||||
height: number;
|
height: number;
|
||||||
width: number;
|
width: number;
|
||||||
|
tileheight: number;
|
||||||
|
tilewidth: number;
|
||||||
orientation: string;
|
orientation: string;
|
||||||
layers: TiledLayerData[];
|
layers: TiledLayerData[];
|
||||||
tilesets: TiledTilesetData[];
|
tilesets: TiledTilesetData[];
|
||||||
|
|
|
@ -4,6 +4,8 @@ import Tilemap from "../../Nodes/Tilemap"
|
||||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||||
import { TiledTilemapData } from "../../DataTypes/Tilesets/TiledData";
|
import { TiledTilemapData } from "../../DataTypes/Tilesets/TiledData";
|
||||||
import StringUtils from "../../Utils/StringUtils";
|
import StringUtils from "../../Utils/StringUtils";
|
||||||
|
import StaticBody from "../../Physics/StaticBody";
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
|
||||||
export default class TilemapFactory {
|
export default class TilemapFactory {
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
|
@ -25,6 +27,17 @@ export default class TilemapFactory {
|
||||||
// Add to scene
|
// Add to scene
|
||||||
this.scene.addTilemap(tilemap);
|
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
|
// Load images for the tilesets
|
||||||
tilemap.getTilesets().forEach(tileset => {
|
tilemap.getTilesets().forEach(tileset => {
|
||||||
let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl();
|
let imagePath = StringUtils.getPathFromFilePath(path) + tileset.getImageUrl();
|
||||||
|
|
|
@ -10,11 +10,13 @@ export default abstract class Tilemap extends GameNode {
|
||||||
protected data: number[];
|
protected data: number[];
|
||||||
protected tilesets: Tileset[];
|
protected tilesets: Tileset[];
|
||||||
protected worldSize: Vec2;
|
protected worldSize: Vec2;
|
||||||
|
protected tileSize: Vec2;
|
||||||
|
|
||||||
constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData){
|
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);
|
||||||
|
this.tileSize = new Vec2(0, 0);
|
||||||
this.parseTilemapData(tilemapData, layerData);
|
this.parseTilemapData(tilemapData, layerData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +24,14 @@ export default abstract class Tilemap extends GameNode {
|
||||||
return this.tilesets;
|
return this.tilesets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWorldSize(): Vec2 {
|
||||||
|
return this.worldSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTileSize(): Vec2 {
|
||||||
|
return this.tileSize;
|
||||||
|
}
|
||||||
|
|
||||||
isReady(): boolean {
|
isReady(): boolean {
|
||||||
if(this.tilesets.length !== 0){
|
if(this.tilesets.length !== 0){
|
||||||
for(let tileset of this.tilesets){
|
for(let tileset of this.tilesets){
|
||||||
|
@ -33,6 +43,8 @@ export default abstract class Tilemap extends GameNode {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract forEachTile(func: Function): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the tileset using the data loaded from file
|
* Sets up the tileset using the data loaded from file
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,10 +7,17 @@ import Tileset from "../../DataTypes/Tilesets/Tileset";
|
||||||
export default class OrthogonalTilemap extends Tilemap {
|
export default class OrthogonalTilemap extends Tilemap {
|
||||||
parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void {
|
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.data = layer.data;
|
this.data = layer.data;
|
||||||
tilemapData.tilesets.forEach(tilesetData => this.tilesets.push(new Tileset(tilesetData)));
|
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 {}
|
update(deltaT: number): void {}
|
||||||
|
|
||||||
render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) {
|
render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import PhysicsNode from "./PhysicsNode";
|
import PhysicsNode from "./PhysicsNode";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
import StaticBody from "./StaticBody";
|
||||||
|
import Debug from "../Debug/Debug";
|
||||||
|
|
||||||
export default class PhysicsManager {
|
export default class PhysicsManager {
|
||||||
|
|
||||||
|
@ -47,11 +49,8 @@ export default class PhysicsManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(let staticNode of staticSet){
|
for(let staticNode of staticSet){
|
||||||
if(movingNode.getCollider().willCollideWith(staticNode.getCollider(), velocity, new Vec2(0, 0))){
|
this.handleCollision(movingNode, staticNode, velocity, (<StaticBody>staticNode).id);
|
||||||
this.handleCollision(movingNode, staticNode, velocity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
movingNode.finishMove(velocity);
|
movingNode.finishMove(velocity);
|
||||||
|
@ -61,20 +60,94 @@ export default class PhysicsManager {
|
||||||
this.movements = new Array();
|
this.movements = new Array();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2){
|
handleCollision(movingNode: PhysicsNode, staticNode: PhysicsNode, velocity: Vec2, id: String){
|
||||||
let ASize = movingNode.getCollider().getSize();
|
let sizeA = movingNode.getCollider().getSize();
|
||||||
let A = new Vec2(movingNode.getPosition().x + ASize.x, movingNode.getPosition().y + ASize.y);
|
let A = movingNode.getPosition();
|
||||||
let BSize = staticNode.getCollider().getSize();
|
let velA = velocity;
|
||||||
let B = new Vec2(staticNode.getPosition().x + BSize.x, staticNode.getPosition().y + BSize.y);
|
let sizeB = staticNode.getCollider().getSize();
|
||||||
|
let B = staticNode.getPosition();
|
||||||
|
let velB = new Vec2(0, 0);
|
||||||
|
|
||||||
let firstContact = 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);
|
let lastContact = new Vec2(0, 0);
|
||||||
firstContact.y = (B.y-(BSize.y/2) - (A.y + (ASize.y/2)))/(velocity.y - 0);
|
|
||||||
|
|
||||||
if(firstContact.x < 1 || firstContact.y < 1){
|
let collidingX = false;
|
||||||
// We collided
|
let collidingY = false;
|
||||||
let firstCollisionTime = Math.min(firstContact.x, firstContact.y);
|
|
||||||
velocity.scale(firstCollisionTime);
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
|
|
||||||
finishMove(velocity: Vec2): void {
|
finishMove(velocity: Vec2): void {
|
||||||
this.position.add(velocity);
|
this.position.add(velocity);
|
||||||
|
this.collider.getPosition().add(velocity);
|
||||||
for(let child of this.children){
|
for(let child of this.children){
|
||||||
child.getPosition().add(velocity);
|
child.getPosition().add(velocity);
|
||||||
}
|
}
|
||||||
|
|
24
src/Physics/StaticBody.ts
Normal file
24
src/Physics/StaticBody.ts
Normal file
|
@ -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 {}
|
||||||
|
|
||||||
|
}
|
|
@ -7,14 +7,16 @@ import PlayerSprite from "./Nodes/PlayerSprite";
|
||||||
export default class Player extends PhysicsNode {
|
export default class Player extends PhysicsNode {
|
||||||
velocity: Vec2;
|
velocity: Vec2;
|
||||||
speed: number;
|
speed: number;
|
||||||
debug: Debug;
|
debug: Debug;
|
||||||
|
size: Vec2;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
this.velocity = new Vec2(0, 0);
|
this.velocity = new Vec2(0, 0);
|
||||||
this.speed = 300;
|
this.speed = 300;
|
||||||
|
this.size = new Vec2(50, 50);
|
||||||
this.collider = new AABB();
|
this.collider = new AABB();
|
||||||
this.collider.setSize(new Vec2(50, 50));
|
this.collider.setSize(this.size);
|
||||||
this.position = new Vec2(0, 0);
|
this.position = new Vec2(0, 0);
|
||||||
this.debug = Debug.getInstance();
|
this.debug = Debug.getInstance();
|
||||||
}
|
}
|
||||||
|
@ -22,7 +24,7 @@ export default class Player extends PhysicsNode {
|
||||||
create(): void {
|
create(): void {
|
||||||
let sprite = this.scene.canvasNode.add(PlayerSprite);
|
let sprite = this.scene.canvasNode.add(PlayerSprite);
|
||||||
sprite.setPosition(this.position);
|
sprite.setPosition(this.position);
|
||||||
sprite.setSize(50, 50);
|
sprite.setSize(this.size);
|
||||||
this.children.push(sprite);
|
this.children.push(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ export default class Player extends PhysicsNode {
|
||||||
this.velocity = dir.scale(this.speed);
|
this.velocity = dir.scale(this.speed);
|
||||||
this.move(this.velocity.scale(deltaT));
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -78,7 +78,7 @@ function main(){
|
||||||
pauseMenu.disable();
|
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++){
|
for(let i = 0; i < 30; i++){
|
||||||
let cc = foregroundLayer.canvasNode.add(ColoredCircle);
|
let cc = foregroundLayer.canvasNode.add(ColoredCircle);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user