UNPKG

blaze-2d

Version:

A fast and simple WebGL 2 2D game engine written in TypeScript

153 lines 5.14 kB
import { vec2 } from "gl-matrix"; import CollisionObject from "../collisionObject"; import Ray from "../ray"; /** * Represents an axis aligned bounding box in 2D world space. * * A minimum (bottom left) and maximum (top right) vertex is used to represent the {@link AABB}. */ export default class AABB { constructor(min, max, margin) { if (min instanceof CollisionObject) { this.setMinMaxFromCollisionObj(min, max); } else if (margin !== undefined) { this.union(min, max, margin); } else { this.min = min; this.max = max; } } /** * Sets the AABB's min and max so that the AABB contains the object's collider. * * @param obj The {@link CollisionObject} to bound * @param margin A margin to add to the new min and max points */ setMinMaxFromCollisionObj(obj, margin) { this.margin = margin; this.obj = obj; const c = obj.collider; const vertices = c.getVertices(); let minX = Infinity; let maxX = -Infinity; let minY = Infinity; let maxY = -Infinity; // find min and max points for (let i = 0; i < vertices.length; i++) { const p = vertices[i]; // x coord if (i % 2 === 0) { if (p < minX) minX = p; if (p > maxX) maxX = p; } else { // y coord if (p < minY) minY = p; if (p > maxY) maxY = p; } } this.min = vec2.fromValues(minX - margin, minY - margin); this.max = vec2.fromValues(maxX + margin, maxY + margin); } /** * Sets the AABB's min and max to the union of `a` and `b`. * * @param a An {@link AABB} * @param b An {@link AABB} * @param margin A margin to add to the new min and max points */ union(a, b, margin = 0) { const minX = a.min[0] < b.min[0] ? a.min[0] : b.min[0]; const maxX = a.max[0] > b.max[0] ? a.max[0] : b.max[0]; const minY = a.min[1] < b.min[1] ? a.min[1] : b.min[1]; const maxY = a.max[1] > b.max[1] ? a.max[1] : b.max[1]; this.margin = margin; this.min = vec2.fromValues(minX - margin, minY - margin); this.max = vec2.fromValues(maxX + margin, maxY + margin); } /** * Computes the area of the {@link AABB}. * * @returns The area of the {@link AABB} */ area() { const width = Math.abs(this.max[0] - this.min[0]); const height = Math.abs(this.max[1] - this.min[1]); return width * height; } intersects(b) { if (b instanceof AABB) { return this.max[0] > b.min[0] && this.min[0] < b.max[0] && this.max[1] > b.min[1] && this.min[1] < b.max[1]; } else if (b instanceof Ray) { const v0 = b.getStart(); const v1 = b.getEnd(); let fLow = 0; let fHigh = 1; let res = this.clipLine(0, v0, v1, fLow, fHigh); if (!res) return false; else { fLow = res.fLow; fHigh = res.fHigh; } res = this.clipLine(1, v0, v1, fLow, fHigh); if (!res) return false; else { fLow = res.fLow; fHigh = res.fHigh; } return true; } else { return this.max[0] >= b[0] && this.min[0] <= b[0] && this.max[1] >= b[1] && this.min[1] <= b[1]; } } /** * Determines wether or not the given {@link AABB} is contained within this {@link AABB}. * * @param b The {@link AABB} to check */ contains(b) { return this.min[0] <= b.min[0] && this.max[0] >= b.max[0] && this.min[1] <= b.min[1] && this.max[1] >= b.max[1]; } /** * Clips a line based on the {@link AABB}'s min and max to determine if the line intersects with the AABB. * * @param dim The dimension to clip in (0 = x, 1 = y) * @param v0 The line's start point * @param v1 The line's end point * @param fLow The current fLow * @param fHigh The current fHigh * @returns false when no intersection possible, otherwise new fLow and fHigh */ clipLine(dim, v0, v1, fLow, fHigh) { let fDimLow = (this.min[dim] - v0[dim]) / (v1[dim] - v0[dim]); let fDimHigh = (this.max[dim] - v0[dim]) / (v1[dim] - v0[dim]); if (fDimHigh < fDimLow) { const temp = fDimLow; fDimLow = fDimHigh; fDimHigh = temp; } if (fDimHigh < fLow) return false; if (fDimLow > fHigh) return false; const newFLow = Math.max(fDimLow, fLow); const newFHigh = Math.min(fDimHigh, fHigh); if (newFLow > newFHigh) return false; return { fLow: newFLow, fHigh: newFHigh, }; } } //# sourceMappingURL=aabb.js.map