game_actor_component_physics_component.js
import ActorComponent from "./actor_component.js";
import Vec2 from "../../vector/vec2.js";
/**
* @module PhysicsComponent
* @fileoverview Contains PhysicsComponent class.
*/
/**
* @class
* @extends ActorComponent
* Handles physics attributes like velocity, friction, etc.
*/
class PhysicsComponent extends ActorComponent {
/**
* Create a new physics component.
* @param {number|Vec2} vel Initial velocity
* @param {number} angularVel Initial angular velocity
* @param {number} friction Friction to be applied
* @param {number} mass Mass of object
* @param {number} bounce Bounce percentage on collision
* @constructor
*/
constructor({
vel = 0,
angularVel = 0,
friction = 0,
mass = 1,
bounce = 0.5
} = {}) {
super();
this.vel = Vec2.from(vel);
this.angularVel = angularVel;
this.friction = friction;
this.mass = mass;
this.bounce = bounce;
}
update(elapsed) {
super.update(elapsed);
const dir = this.vel.norm();
const friction = dir.mulv(this.mass * this.friction * elapsed);
const vel = this.vel.sub(friction);
if (Math.sign(vel.x) !== Math.sign(this.vel.x))
vel.x = 0;
if (Math.sign(vel.y) !== Math.sign(this.vel.y))
vel.y = 0;
this.vel = vel;
this.doMove(elapsed);
const angularFriction = this.mass / 100 * this.friction * elapsed;
let angularVel = (Math.abs(this.angularVel) - angularFriction) * Math.sign(this.angularVel);
if (Math.sign(angularVel) !== Math.sign(this.angularVel))
angularVel = 0;
this.angularVel = angularVel;
this.actor.rotation += this.angularVel * elapsed;
}
/**
* Perform movement and check collisions as necessary.
* @param {number} elapsed Time since last update cycle in seconds
*/
doMove(elapsed) {
if (this.vel.isZero())
return;
const to = this.actor.pos.add(this.vel.mulv(elapsed));
let collision = {
result: false
};
let result = this.actor.space.checkUnitCollision(this.actor, to);
if (!result.result) {
for (const chunk of this.actor.overlappingChunks.values()) {
result = chunk.checkCollision(this.actor, to);
if (result.result)
collision = result;
}
} else {
collision = result;
}
if (collision.result) {
const pos = this.actor.pos;
const correction = collision.axes.mulv(collision.overlap + 1);
if (collision.axes.x !== 0)
pos.x = to.x - Math.sign(this.vel.x) * Math.abs(correction.x);
else
pos.x = to.x;
if (collision.axes.y !== 0)
pos.y = to.y - Math.sign(this.vel.y) * Math.abs(correction.y);
else
pos.y = to.y;
// if (collision.actor.components.physicsCount === 0)
this.vel = this.vel.mirrorOver(collision.axes).mulv(-1 * this.bounce);
// for (const comp of collision.actor.components.getPhysics()) {
// const e = (this.bounce + comp.bounce) / 2;
// const div = this.mass + comp.mass;
// const diff = this.vel.sub(comp.vel);
// const impulse = diff.mulv(-1 * e);
//
// this.vel = this.vel.sub(impulse.mulv(comp.mass / div));
// comp.vel = comp.vel.sub(impulse.mulv(this.mass / div));
// }
this.actor.pos = pos;
} else {
this.actor.pos = to.copy();
}
}
}
export default PhysicsComponent;