@rpgjs/physic
Version:
A deterministic 2D top-down physics library for RPG, sandbox and MMO games
156 lines (155 loc) • 3.98 kB
JavaScript
import { AABB } from "./index4.js";
import { Vector2 } from "./index2.js";
import { CircleCollider } from "./index11.js";
class AABBCollider {
/**
* Creates a new AABB collider
*
* @param entity - Entity this collider belongs to
*/
constructor(entity) {
this.entity = entity;
}
/**
* Gets the AABB bounds
*
* @returns AABB
*/
getBounds() {
const center = this.entity.position;
const halfWidth = this.entity.width / 2;
const halfHeight = this.entity.height / 2;
return new AABB(
center.x - halfWidth,
center.y - halfHeight,
center.x + halfWidth,
center.y + halfHeight
);
}
/**
* @inheritdoc
*/
testCollision(other) {
if (other instanceof CircleCollider) {
const collision = other.testCollision(this);
if (collision) {
return {
entityA: collision.entityB,
entityB: collision.entityA,
contacts: collision.contacts.map((c) => ({
point: c.point,
normal: c.normal.mul(-1),
depth: c.depth
})),
normal: collision.normal.mul(-1),
depth: collision.depth
};
}
return null;
} else if (other instanceof AABBCollider) {
return this.testAABBAABB(other);
}
return null;
}
/**
* Tests collision with another AABB
*
* @param other - Other AABB collider
* @returns Collision info or null
*/
testAABBAABB(other) {
const aabbA = this.getBounds();
const aabbB = other.getBounds();
if (!aabbA.intersects(aabbB)) {
return null;
}
const intersection = aabbA.intersection(aabbB);
if (!intersection) {
return null;
}
const overlapX = Math.min(
aabbA.maxX - aabbB.minX,
aabbB.maxX - aabbA.minX
);
const overlapY = Math.min(
aabbA.maxY - aabbB.minY,
aabbB.maxY - aabbA.minY
);
let normal;
let depth;
if (overlapX < overlapY) {
depth = overlapX;
normal = aabbA.getCenterX() < aabbB.getCenterX() ? new Vector2(1, 0) : new Vector2(-1, 0);
} else {
depth = overlapY;
normal = aabbA.getCenterY() < aabbB.getCenterY() ? new Vector2(0, 1) : new Vector2(0, -1);
}
const contactPoint = intersection.getCenter();
return {
entityA: this.entity,
entityB: other.entity,
contacts: [
{
point: contactPoint,
normal,
depth
}
],
normal,
depth
};
}
/**
* @inheritdoc
*/
getContactPoints(other) {
const collision = this.testCollision(other);
return collision?.contacts ?? [];
}
/**
* @inheritdoc
*/
getEntity() {
return this.entity;
}
/**
* @inheritdoc
*/
raycast(ray) {
const bounds = this.getBounds();
const tMin = (bounds.minX - ray.origin.x) / ray.direction.x;
const tMax = (bounds.maxX - ray.origin.x) / ray.direction.x;
const tymin = (bounds.minY - ray.origin.y) / ray.direction.y;
const tymax = (bounds.maxY - ray.origin.y) / ray.direction.y;
const t1 = Math.min(tMin, tMax);
const t2 = Math.max(tMin, tMax);
const t3 = Math.min(tymin, tymax);
const t4 = Math.max(tymin, tymax);
const tNear = Math.max(t1, t3);
const tFar = Math.min(t2, t4);
if (tNear > tFar || tFar < 0) {
return null;
}
if (tNear > ray.length) {
return null;
}
const t = tNear < 0 ? tFar : tNear;
if (t < 0) return null;
const point = ray.getPoint(t);
let normal = new Vector2(0, 0);
if (Math.abs(point.x - bounds.minX) < 1e-5) normal.set(-1, 0);
else if (Math.abs(point.x - bounds.maxX) < 1e-5) normal.set(1, 0);
else if (Math.abs(point.y - bounds.minY) < 1e-5) normal.set(0, -1);
else if (Math.abs(point.y - bounds.maxY) < 1e-5) normal.set(0, 1);
return {
entity: this.entity,
point,
normal,
distance: t
};
}
}
export {
AABBCollider
};
//# sourceMappingURL=index12.js.map