Browse Source

physics stuff

master
mortie 6 years ago
parent
commit
8bd00dac3f

+ 23
- 9
js/Entity.js View File

@@ -27,17 +27,25 @@ export class Trait {
}

export default class Entity {
constructor(level) {
constructor(level, layerName) {
this.layerName = layerName;
this.level = level;
this.bounds = new Rect();
this.time = 0;

this.traitOrder = [
"collider",
"platform",
"wall",
"keyboardController",
"physics",
];
this.t = {
physics: null,
keyboardController: null,
collider: null,
platform: null,
wall: null,
keyboardController: null,
physics: null,
};

this.traits = [];
@@ -46,6 +54,18 @@ export default class Entity {
}

_init() {
for (let traitName of this.traitOrder) {
let t = this.t[traitName];
if (t == null)
continue;

this.traits.push(t);
if (t.update !== Trait.prototype.update)
this.updateTraits.push(t);
if (t.postUpdate !== Trait.prototype.postUpdate)
this.postUpdateTraits.push(t);
}

for (let trait of this.traits) {
trait._init();
}
@@ -88,11 +108,5 @@ export default class Entity {
throw new Error("Invalid trait:", t);

this.t[t.name] = t;
this.traits.push(t);

if (t.update !== Trait.prototype.update)
this.updateTraits.push(t);
if (t.postUpdate !== Trait.prototype.postUpdate)
this.postUpdateTraits.push(t);
}
}

+ 22
- 4
js/Level.js View File

@@ -10,6 +10,11 @@ export default class Level {
this.minFPS = 5;
this.backgroundColor = "#87CEFA";

this.layerOrder = {
platform: 0,
player: 1,
};
this.layers = [];
this.entities = [];
this.colliders = [];

@@ -21,7 +26,16 @@ export default class Level {
spawnEntity(ent, x, y) {
ent.bounds.pos.set(x, y);

let layerIdx = this.layerOrder[ent.layerName];
console.log(ent.layerName, this.layerOrder, layerIdx);
if (layerIdx == null)
throw new Error("Unknown layer name: "+ent.layerName);

if (this.layers[layerIdx] == null)
this.layers[layerIdx] = [];

this.entities.push(ent);
this.layers[layerIdx].push(ent);
if (ent.has("collider"))
this.colliders.push(ent);

@@ -34,12 +48,14 @@ export default class Level {
structure.init();
}

physics(dt) {
this.entities.forEach(ent =>
physicsLayer(dt, layer) {
layer.forEach(ent =>
ent._update(dt));
this.entities.forEach(ent =>
layer.forEach(ent =>
ent._postUpdate(dt));
}

physics(dt) {
// Collide with structures
this.structures.forEach(s => {
if (!s.attrs.wall && !s.attrs.platform)
@@ -63,6 +79,8 @@ export default class Level {
ent.t.collider.collideEntity(ent2);
});
});

this.layers.forEach(l => this.physicsLayer(dt, l));
}

draw() {
@@ -70,7 +88,7 @@ export default class Level {
this.ctx.beginPath();
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

this.entities.forEach(ent => ent.draw(this.ctx));
this.layers.forEach(l => l.forEach(ent => ent.draw(this.ctx)));
this.structures.forEach(struct => struct.draw(this.ctx));
}


+ 6
- 2
js/entities/BrokenPlatform.js View File

@@ -10,7 +10,7 @@ import TPhysics from "../traits/TPhysics.js";

export default class BrokenPlatform extends Entity {
constructor(level, width = 5) {
super(level);
super(level, "platform");

this.bounds.size.set(width, 0.5);
this.addTrait(new TCollider(this));
@@ -58,7 +58,11 @@ export default class BrokenPlatform extends Entity {
update(dt) {
if (!this.shaking && !this.falling) {
this.t.collider.entities.forEach(e => {
if (e.has("physics")) {
let fall =
e.has("physics") &&
e.bounds.intersectSide(this.bounds) === "top";

if (fall) {
this.startShake();
}
});

+ 0
- 26
js/entities/FallingPlatform.js View File

@@ -1,26 +0,0 @@
import Entity from "../Entity.js";
import Texture from "../Texture.js";
import Tile from "../Tile.js";
import assets from "../assets.js";

import TPlatform from "../traits/TPlatform.js";
import TCollider from "../traits/TCollider.js";
import TPhysics from "../traits/TPhysics.js";

export default class FallingPlatform extends Entity {
constructor(level, width = 5) {
super(level);

this.bounds.size.set(width, 0.5);
this.addTrait(new TCollider(this));
this.addTrait(new TPlatform(this));
this.addTrait(new TPhysics(this));

this.texture = new Texture(assets.tiles,
Tile.createLine(this.bounds.size.x, "platform"));
}

draw(ctx) {
this.texture.drawAt(ctx, this.bounds.pos);
}
}

+ 1
- 1
js/entities/FloatingPlatform.js View File

@@ -9,7 +9,7 @@ import TPhysics from "../traits/TPhysics.js";

export default class FloatingPlatform extends Entity {
constructor(level, width = 5) {
super(level);
super(level, "platform");

this.bounds.size.set(width, 0.5);
this.addTrait(new TCollider(this));

+ 1
- 1
js/entities/Player.js View File

@@ -9,7 +9,7 @@ import TCollider from "../traits/TCollider.js";

export default class Player extends Entity {
constructor(level) {
super(level);
super(level, "player");

this.bounds.size.set(1, 2);
this.addTrait(new TCollider(this));

+ 0
- 5
js/main.js View File

@@ -3,7 +3,6 @@ import Vec2 from "./Vec2.js";

import Player from "./entities/Player.js";
import FloatingPlatform from "./entities/FloatingPlatform.js";
import FallingPlatform from "./entities/FallingPlatform.js";
import BrokenPlatform from "./entities/BrokenPlatform.js";
import structures from "./structures.js";

@@ -13,10 +12,6 @@ let level = new Level(canvas);

level.spawnEntity(new Player(level), 10, 1);
level.spawnEntity(new FloatingPlatform(level), 16, 4);
level.spawnEntity(new FallingPlatform(level), 20, 1);
level.spawnEntity(new FallingPlatform(level), 20, 0);
level.spawnEntity(new FallingPlatform(level), 20, -1);
level.spawnEntity(new FallingPlatform(level), 20, -2);
level.spawnStructure(structures.floor(8, 6), 4, 4);

level.spawnEntity(new BrokenPlatform(level), 27, 4);

+ 1
- 1
js/traits/TKeyboardController.js View File

@@ -53,7 +53,7 @@ export default class TKeyboardController extends Trait {
this.entity.time -phys.timeLastOnGround < this.jumpLeeway;

if (this.pressed.jump && canJump) {
phys.velocity.y = -this.jump;
phys.velocity.y -= this.jump;
this.entity.bounds.pos.y += phys.velocity.y * dt;
this.jumpTime = this.jumpTimeMax;
this.jumping = true;

+ 47
- 88
js/traits/TPhysics.js View File

@@ -7,109 +7,75 @@ export default class TPhysics extends Trait {
constructor(entity) {
super(entity, "physics");

this.velocity = new Vec2();
this.gravity = 40;
this.groundFriction = 6;
this.airFriction = 2;

this.absVelocity = new Vec2();
this.velocity = new Vec2();

this.timeLastOnGround = 0;
this.onGround = false;
this.groundBounds = null;
this.groundVelocity = null;
this.oldGroundBounds = null;
this.timeLastOnGround = 0;
}

collideTop(bounds, absVelocity) {
if (this.onGround || bounds === this.oldGroundBounds)
return;

this.onGround = true;
this.groundBounds = bounds;
this.groundVelocity = absVelocity;

this.velocity.x -= absVelocity.x;
this.velocity.y = 0;
this.entity.bounds.bottom = bounds.top;
collideTop(bounds, velocity) {
if (!this.groundBounds || bounds.top < this.groundBounds.top) {
this.groundBounds = bounds;
this.groundVelocity = velocity;
}
}

collideWall(bounds, absVelocity) {
collideWall(bounds, velocity) {
let side = this.entity.bounds.intersectSide(bounds);

if (side === "top")
return this.collideTop(bounds, absVelocity);
return this.collideTop(bounds, velocity);
}

collidePlatform(bounds, absVelocity) {
collidePlatform(bounds, velocity) {
let side = this.entity.bounds.intersectSide(bounds);

if (side === "top")
return this.collideTop(bounds, absVelocity);
return this.collideTop(bounds, velocity);
}

update(dt) {

// Gravity
if (!this.onGround)
this.velocity.y += this.gravity * dt;

// Collide
if (this.entity.has("collider")) {

let jumping =
this.groundVelocity &&
this.velocity.y < this.groundVelocity.y;

// Check if we're still on the same ground
if (this.onGround) {
let stillOnGround =
(this.entity.bounds.intersects(this.groundBounds)) &&
(this.entity.bounds.intersectSide(this.groundBounds) === "top") &&
!jumping;

if (stillOnGround) {
this.entity.bounds.bottom = this.groundBounds.top;
} else {
this.velocity.x += this.groundVelocity.x;
this.velocity.y += this.groundVelocity.y;

this.onGround = false;
this.oldGroundBounds = this.groundBounds;
this.groundBounds = null;
this.groundVelocity = null;
}
}

// Collide with new stuff
if (!jumping) {
let collider = this.entity.t.collider;
collider.entities.forEach(e => {
let vel;
if (e.has("physics"))
vel = e.t.physics.absVelocity;
else
vel = zeroVector;

if (e.has("wall"))
this.collideWall(e.bounds, vel);
else if (e.has("platform"))
this.collidePlatform(e.bounds, vel);
});
collider.structures.forEach((s, i) => {
let bounds = collider.structureBounds[i];
if (s.attrs.wall)
this.collideWall(bounds, zeroVector);
else if (s.attrs.platform)
this.collidePlatform(bounds, zeroVector);
});
}

this.oldGroundBounds = null;
let collider = this.entity.t.collider;
this.groundBounds = null;
this.groundVelocity = null;

collider.entities.forEach(e => {
let vel = zeroVector;
if (e.has("physics"))
vel = e.t.physics.velocity;

if (e.has("wall"))
this.collideWall(e.bounds, vel);
else if (e.has("platform"))
this.collidePlatform(e.bounds, vel);
});
collider.structures.forEach((s, i) => {
let bounds = collider.structureBounds[i];
if (s.attrs.wall)
this.collideWall(bounds, zeroVector);
else if (s.attrs.platform)
this.collidePlatform(bounds, zeroVector);
});
}

// Track the last time we were on the ground
if (this.onGround)
this.onGround =
(this.groundVelocity && this.velocity.y >= this.groundVelocity.y);

if (this.onGround) {
this.timeLastOnGround = this.entity.time;
this.velocity.y = this.groundVelocity.y;
}

if (!this.onGround)
this.velocity.y += this.gravity * dt;

// Apply friction
var fric = this.onGround ? this.groundFriction : this.airFriction;
@@ -118,19 +84,12 @@ export default class TPhysics extends Trait {
}

postUpdate(dt) {
this.jumped = false;

// Update absVelocity
if (this.onGround) {
this.absVelocity.x = this.velocity.x + this.groundVelocity.x;
this.absVelocity.y = this.velocity.y + this.groundVelocity.y;
} else {
this.absVelocity.x = this.velocity.x;
this.absVelocity.y = this.velocity.y;
}

// Move
this.entity.bounds.pos.x += this.absVelocity.x * dt;
this.entity.bounds.pos.y += this.absVelocity.y * dt;
this.entity.bounds.pos.x += this.velocity.x * dt;
this.entity.bounds.pos.y += this.velocity.y * dt;

if (this.onGround)
this.entity.bounds.bottom = this.groundBounds.top;
}
}

Loading…
Cancel
Save