UNPKG

@rpgjs/physic

Version:

A deterministic 2D top-down physics library for RPG, sandbox and MMO games

156 lines (155 loc) 3.98 kB
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