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"); this.gravity = 40; this.groundFriction = 6; this.airFriction = 2; this.absVelocity = new Vec2(); this.velocity = new Vec2(); 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; } 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 (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; } // 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)); this.velocity.x *= xRatio; } 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; } }