Browse Source

lots of physics stuff

master
mortie 6 years ago
parent
commit
f10927e2d8
9 changed files with 169 additions and 68 deletions
  1. 3
    0
      js/Entity.js
  2. 10
    2
      js/Level.js
  3. 17
    4
      js/Rect.js
  4. 5
    4
      js/Structure.js
  5. 25
    1
      js/entities/Platform.js
  6. 1
    1
      js/structures.js
  7. 9
    9
      js/traits/TCollider.js
  8. 15
    4
      js/traits/TKeyboardController.js
  9. 84
    43
      js/traits/TPhysics.js

+ 3
- 0
js/Entity.js View File

@@ -30,12 +30,14 @@ export default class Entity {
constructor(level) {
this.level = level;
this.bounds = new Rect();
this.time = 0;

this.t = {
physics: null,
keyboardController: null,
collider: null,
platform: null,
wall: null,
};

this.traits = [];
@@ -58,6 +60,7 @@ export default class Entity {
}

this.update(dt);
this.time += dt;
}

_postUpdate(dt) {

+ 10
- 2
js/Level.js View File

@@ -6,6 +6,7 @@ export default class Level {
this.ctx = canvas.getContext("2d");
this.lastTime = null;
this.raf = null;
this.minFPS = 10;

this.entities = [];
this.colliders = [];
@@ -39,7 +40,7 @@ export default class Level {

// Collide with structures
this.structures.forEach(s => {
if (!s.attrs.collides)
if (!s.attrs.wall && !s.attrs.platform)
return;

this.colliders.forEach(ent => {
@@ -75,7 +76,14 @@ export default class Level {
if (this.lastTime != null) {
let dt = (time - this.lastTime) / 1000;

this.physics(dt);
if (1 / dt > this.minFPS) {
this.physics(dt);
} else {
console.log(
"Too long between updates ("+dt.toFixed(2)+"s, "+
(1 / dt).toFixed(2)+"FPS). Skipping.");
}

this.draw();
}


+ 17
- 4
js/Rect.js View File

@@ -20,10 +20,16 @@ export default class Rect {
(this.left <= other.right && this.right >= other.left) &&
(this.top <= other.bottom && this.bottom >= other.top));
}
bottomIntersects(other) {
return (
(this.left <= other.right && this.right >= other.left) &&
(this.bottom <= other.bottom && this.bottom >= other.top));

intersectSide(other) {
if (this.midY < other.top)
return "top";
else if (this.midY > other.bottom)
return "bottom";
else if (this.midX < other.left)
return "left";
else
return "right";
}

contains(other) {
@@ -32,6 +38,13 @@ export default class Rect {
(this.top <= other.top && this.bottom >= other.bottom));
}

get midX() {
return this.pos.x + (this.size.x / 2);
}
get midY() {
return this.pos.y + (this.size.y / 2);
}

get top() {
return this.pos.y;
}

+ 5
- 4
js/Structure.js View File

@@ -9,9 +9,9 @@ function findBounds(arr, bounds) {
let bottom = (e.y + 1) * assets.tiles.tileHeight;

if (right > bounds.size.x)
bounds.size.x = right;
bounds.size.pixelX = right;
if (bottom > bounds.size.y)
bounds.size.y = bottom;
bounds.size.pixelY = bottom;
});
}

@@ -102,7 +102,8 @@ export default class Structure {
this.texture = new Texture(nestedArr);

this.attrs = {
collides: false,
wall: false,
platform: false,
}

for (let a of attrs)
@@ -118,7 +119,7 @@ export default class Structure {

findBounds(arr, this.bounds);

if (this.attrs.collides) {
if (this.attrs.wall || this.attrs.platform) {
findGeometry(this.bounds, arr, this.geometry);
}
}

+ 25
- 1
js/entities/Platform.js View File

@@ -12,11 +12,35 @@ export default class Platform extends Entity {
this.addTrait(new TCollider(this));
this.addTrait(new TPlatform(this));
this.addTrait(new TPhysics(this));

this.targetSpeed = 3;
this.accel = 5;
this.dir = 1;
}

init() {
this.targetTop = this.bounds.pos.y;
this.targetBottom = this.targetTop + 5;

this.t.physics.gravity = 0;
this.t.physics.velocity.y = 0;
}

update(dt) {
let phys = this.t.physics;
phys.velocity.y -= phys.gravity * dt;

if (this.bounds.pos.y <= this.targetTop)
this.dir = 1;
else if (this.bounds.pos.y >= this.targetBottom)
this.dir = -1;

if (this.dir == 1) {
if (phys.velocity.y < this.targetSpeed)
phys.velocity.y += this.accel * dt;
} else {
if (phys.velocity.y > -this.targetSpeed)
phys.velocity.y -= this.accel * dt;
}
}

draw(ctx) {

+ 1
- 1
js/structures.js View File

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

export default {
floor: width => new Structure(
[ "collides" ],
[ "wall" ],
tiles.fromLine(width, "grass")),
};

+ 9
- 9
js/traits/TCollider.js View File

@@ -5,26 +5,26 @@ export default class Collider extends Trait {
super(entity, "collider");

this.collides = false;
this.cEntity = null;
this.cStructure = null;
this.cBounds = null;
this.entities = [];
this.structures = [];
this.structureBounds = [];
}

collideEntity(e) {
this.collides = true;
this.cEntity = e;
this.cBounds = e.bounds;
this.entities.push(e);
}

collideStructure(s, b) {
this.collides = true;
this.cStructure = s;
this.cBounds = b;
this.structures.push(s);
this.structureBounds.push(b);
}

postUpdate() {
this.cEntity = null;
this.cStructure = null;
this.entities.length = 0;
this.structures.length = 0;
this.structureBounds.length = 0;
this.collides = false;
}
}

+ 15
- 4
js/traits/TKeyboardController.js View File

@@ -10,6 +10,7 @@ export default class TKeyboardController extends Trait {
this.jump = 8;
this.jumpTimeMax = 0.4;
this.updrift = 100;
this.jumpLeeway = 0.4;

this.map = {
KeyA: 'left',
@@ -21,6 +22,7 @@ export default class TKeyboardController extends Trait {

this.jumpTime = 0;
this.jumping = false;
this.jumped = false
}

onkey(evt) {
@@ -37,6 +39,7 @@ export default class TKeyboardController extends Trait {

update(dt) {
let phys = this.entity.t.physics;
let onGround = phys.onGround;

let speed = phys.onGround ? this.speed : this.speedAir;

@@ -44,16 +47,24 @@ export default class TKeyboardController extends Trait {
phys.velocity.x -= speed * dt;
if (this.pressed.right)
phys.velocity.x += speed * dt;
if (phys.onGround && this.pressed.jump) {

let canJump =
!this.jumped && onGround &&
this.entity.time -phys.timeLastOnGround < this.jumpLeeway;

if (this.pressed.jump && canJump) {
phys.velocity.y = -this.jump;
console.log("jumping to", phys.velocity.y);
this.entity.bounds.pos.y += phys.velocity.y * dt;
this.jumpTime = this.jumpTimeMax;
this.jumping = true;
phys.onGround = false;
this.jumped = true;
onGround = false;
}

if (phys.onGround || !this.pressed.jump || this.jumpTime <= 0)
if (onGround || !this.pressed.jump || this.jumpTime <= 0)
this.jumping = false;
if (onGround)
this.jumped = false;

if (this.jumping) {
phys.velocity.y -= this.updrift * this.jumpTime * dt;

+ 84
- 43
js/traits/TPhysics.js View File

@@ -1,6 +1,8 @@
import {Trait} from "../Entity.js";
import Vec2 from "../Vec2.js";

let zeroVector = new Vec2(0, 0);

export default class TPhysics extends Trait {
constructor(entity) {
super(entity, "physics");
@@ -13,57 +15,95 @@ export default class TPhysics extends Trait {
this.velocity = new Vec2();

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

update(dt) {
let collider = this.entity.t.collider;
collideTop(bounds, absVelocity) {
if (this.onGround || bounds === this.oldGroundBounds)
return;

this.prevRelativeTo = this.relativeTo;
this.relativeTo = null;
this.onGround = false;
this.onGround = true;
this.groundBounds = bounds;
this.groundVelocity = absVelocity;

if (
this.entity.has("collider") &&
collider.collides &&
this.velocity.y >= 0 &&
this.entity.bounds.bottomIntersects(collider.cBounds)) {

// Structures are static; just teleport us to the top of them
if (collider.cStructure) {
this.velocity.y = 0;
this.entity.bounds.bottom = collider.cBounds.top;
this.onGround = true;

// If we're colliding with an entity, and that entity is
// a platform, teleport us to the top of them.
} else if (collider.cEntity.has("platform")) {
this.velocity.y = 0;
this.entity.bounds.bottom = collider.cBounds.top;
this.onGround = true;

if (collider.cEntity.has("physics")) {
let cPhys = collider.cEntity.t.physics;
this.relativeTo = cPhys;
}
}
}
this.velocity.x -= absVelocity.x;
this.velocity.y = 0;
this.entity.bounds.bottom = bounds.top;
}

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

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

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

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

update(dt) {

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

// If we just started riding something, adjust relative absVelocity
if (!this.prevRelativeTo && this.relativeTo) {
this.velocity.x = this.absVelocity.x - this.relativeTo.absVelocity.x;
this.velocity.y = this.absVelocity.y - this.relativeTo.absVelocity.y;
if (this.entity.has("collider")) {

// 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");

// If we just stopped riding something, adjust relative absVelocity
} else if (this.prevRelativeTo && !this.relativeTo) {
this.velocity.x += this.prevRelativeTo.absVelocity.x;
this.velocity.y += this.prevRelativeTo.absVelocity.y;
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
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;
}

// Track the last time we were on the ground
if (this.onGround)
this.timeLastOnGround = this.entity.time;

// Apply friction
var fric = this.onGround ? this.groundFriction : this.airFriction;
var xRatio = 1 / (1 + (dt * fric));
@@ -71,11 +111,12 @@ export default class TPhysics extends Trait {
}

postUpdate(dt) {
this.jumped = false;

// Update absVelocity
if (this.relativeTo) {
this.absVelocity.x = this.velocity.x + this.relativeTo.absVelocity.x;
this.absVelocity.y = this.velocity.y + this.relativeTo.absVelocity.y;
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;

Loading…
Cancel
Save