From 29f027e3fd634dfa7785311ec18b9a2eb23a52d5 Mon Sep 17 00:00:00 2001 From: Jacek Pietal Date: Wed, 28 Feb 2024 08:25:53 +0100 Subject: [PATCH] feat: refactor / small optimize --- README.md | 2 +- dist/base-system.d.ts | 50 ++++-- dist/base-system.js | 112 ++++++++++--- dist/bodies/circle.d.ts | 4 +- dist/demo/demo.js | 216 +++++++++++++------------ dist/model.d.ts | 5 +- dist/system.d.ts | 32 +--- dist/system.js | 98 +++-------- dist/utils.d.ts | 1 + dist/utils.js | 6 +- docs/assets/navigation.js | 2 +- docs/assets/search.js | 2 +- docs/classes/Circle.html | 74 ++++----- docs/classes/System.html | 63 ++++---- docs/demo/demo.js | 216 +++++++++++++------------ docs/enums/BodyType.html | 4 +- docs/functions/returnTrue.html | 1 + docs/index.html | 2 +- docs/interfaces/BodyOptions.html | 12 +- docs/interfaces/BodyProps.html | 42 ++--- docs/interfaces/ChildrenData.html | 4 +- docs/interfaces/Data.html | 4 +- docs/interfaces/GetAABBAsBox.html | 4 +- docs/interfaces/PotentialVector.html | 4 +- docs/interfaces/RaycastHit.html | 4 +- docs/interfaces/Vector.html | 4 +- docs/modules.html | 2 + docs/types/Body.html | 2 +- docs/types/CheckCollisionCallback.html | 2 +- docs/types/Leaf.html | 2 +- docs/types/SATTest.html | 2 +- docs/types/TraverseFunction.html | 1 + package.json | 2 +- src/base-system.ts | 144 +++++++++++++---- src/bodies/box.spec.js | 6 +- src/bodies/circle.ts | 3 +- src/model.ts | 9 +- src/system.ts | 129 +++------------ src/utils.ts | 4 + 39 files changed, 675 insertions(+), 601 deletions(-) create mode 100644 docs/functions/returnTrue.html create mode 100644 docs/types/TraverseFunction.html diff --git a/README.md b/README.md index 754b175a..e07e99ff 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ $ npm install detect-collisions For detailed documentation on the library's API, refer to the following link: -https://prozi.github.io/detect-collisions/modules.html +https://prozi.github.io/detect-collisions/ ## Usage diff --git a/dist/base-system.d.ts b/dist/base-system.d.ts index 07f349ac..afb2d99d 100644 --- a/dist/base-system.d.ts +++ b/dist/base-system.d.ts @@ -4,20 +4,12 @@ import { Ellipse } from "./bodies/ellipse"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; -import { Body, BodyOptions, ChildrenData, Data, PotentialVector, RBush, Vector } from "./model"; +import { Body, BodyOptions, ChildrenData, Data, Leaf, PotentialVector, RBush, TraverseFunction, Vector } from "./model"; /** - * very base collision system + * very base collision system (create, insert, update, draw, remove) */ -export declare class BaseSystem extends RBush implements Data { +export declare class BaseSystem extends RBush implements Data { data: ChildrenData; - /** - * draw exact bodies colliders outline - */ - draw(context: CanvasRenderingContext2D): void; - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context: CanvasRenderingContext2D): void; /** * create point at position with options and add to system */ @@ -42,4 +34,40 @@ export declare class BaseSystem extends RBush impleme * create polygon at position with options and add to system */ createPolygon(position: PotentialVector, points: PotentialVector[], options?: BodyOptions): Polygon; + /** + * re-insert body into collision tree and update its aabb + * every body can be part of only one system + */ + insert(body: TBody): RBush; + /** + * updates body in collision tree + */ + updateBody(body: TBody): void; + /** + * update all bodies aabb + */ + update(): void; + /** + * draw exact bodies colliders outline + */ + draw(context: CanvasRenderingContext2D): void; + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context: CanvasRenderingContext2D): void; + /** + * remove body aabb from collision tree + */ + remove(body: TBody, equals?: (a: TBody, b: TBody) => boolean): RBush; + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body: TBody): TBody[]; + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse(traverseFunction: TraverseFunction, { children }?: { + children?: Leaf[]; + }): TBody | undefined; } diff --git a/dist/base-system.js b/dist/base-system.js index f695b2c1..0d04de1a 100644 --- a/dist/base-system.js +++ b/dist/base-system.js @@ -11,29 +11,9 @@ const model_1 = require("./model"); const optimized_1 = require("./optimized"); const utils_1 = require("./utils"); /** - * very base collision system + * very base collision system (create, insert, update, draw, remove) */ class BaseSystem extends model_1.RBush { - /** - * draw exact bodies colliders outline - */ - draw(context) { - (0, optimized_1.forEach)(this.all(), (body) => { - body.draw(context); - }); - } - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context) { - const drawChildren = (body) => { - (0, utils_1.drawBVH)(context, body); - if (body.children) { - (0, optimized_1.forEach)(body.children, drawChildren); - } - }; - (0, optimized_1.forEach)(this.data.children, drawChildren); - } /** * create point at position with options and add to system */ @@ -82,5 +62,95 @@ class BaseSystem extends model_1.RBush { this.insert(polygon); return polygon; } + /** + * re-insert body into collision tree and update its aabb + * every body can be part of only one system + */ + insert(body) { + body.bbox = body.getAABBAsBBox(); + if (body.system) { + // allow end if body inserted and not moved + if (!(0, utils_1.bodyMoved)(body)) { + return this; + } + // old bounding box *needs* to be removed + body.system.remove(body); + } + // only then we update min, max + body.minX = body.bbox.minX - body.padding; + body.minY = body.bbox.minY - body.padding; + body.maxX = body.bbox.maxX + body.padding; + body.maxY = body.bbox.maxY + body.padding; + // set system for later body.system.updateBody(body) + body.system = this; + // reinsert bounding box to collision tree + return super.insert(body); + } + /** + * updates body in collision tree + */ + updateBody(body) { + body.updateBody(); + } + /** + * update all bodies aabb + */ + update() { + (0, optimized_1.forEach)(this.all(), (body) => { + this.updateBody(body); + }); + } + /** + * draw exact bodies colliders outline + */ + draw(context) { + (0, optimized_1.forEach)(this.all(), (body) => { + body.draw(context); + }); + } + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context) { + const drawChildren = (body) => { + (0, utils_1.drawBVH)(context, body); + if (body.children) { + (0, optimized_1.forEach)(body.children, drawChildren); + } + }; + (0, optimized_1.forEach)(this.data.children, drawChildren); + } + /** + * remove body aabb from collision tree + */ + remove(body, equals) { + body.system = undefined; + return super.remove(body, equals); + } + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body) { + // filter here is required as collides with self + return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); + } + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse(traverseFunction, { children } = this.data) { + return children === null || children === void 0 ? void 0 : children.find((body, index) => { + if (!body) { + return false; + } + if (body.type && traverseFunction(body, children, index)) { + return true; + } + // if callback returns true, ends forEach + if (body.children) { + this.traverse(traverseFunction, body); + } + }); + } } exports.BaseSystem = BaseSystem; diff --git a/dist/bodies/circle.d.ts b/dist/bodies/circle.d.ts index 5634d973..df997491 100644 --- a/dist/bodies/circle.d.ts +++ b/dist/bodies/circle.d.ts @@ -1,7 +1,7 @@ import { BBox } from "rbush"; import { Circle as SATCircle } from "sat"; import { BodyOptions, BodyProps, PotentialVector, SATVector, BodyType, Vector } from "../model"; -import { System } from "../system"; +import { BaseSystem } from "../base-system"; /** * collider - circle */ @@ -53,7 +53,7 @@ export declare class Circle extends SATCircle implements BBox, BodyProps { /** * reference to collision system */ - system?: System; + system?: BaseSystem; /** * was the polygon modified and needs update in the next checkCollision */ diff --git a/dist/demo/demo.js b/dist/demo/demo.js index e27c8312..9caf6f6f 100644 --- a/dist/demo/demo.js +++ b/dist/demo/demo.js @@ -21,29 +21,9 @@ const model_1 = __webpack_require__(/*! ./model */ "./dist/model.js"); const optimized_1 = __webpack_require__(/*! ./optimized */ "./dist/optimized.js"); const utils_1 = __webpack_require__(/*! ./utils */ "./dist/utils.js"); /** - * very base collision system + * very base collision system (create, insert, update, draw, remove) */ class BaseSystem extends model_1.RBush { - /** - * draw exact bodies colliders outline - */ - draw(context) { - (0, optimized_1.forEach)(this.all(), (body) => { - body.draw(context); - }); - } - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context) { - const drawChildren = (body) => { - (0, utils_1.drawBVH)(context, body); - if (body.children) { - (0, optimized_1.forEach)(body.children, drawChildren); - } - }; - (0, optimized_1.forEach)(this.data.children, drawChildren); - } /** * create point at position with options and add to system */ @@ -92,6 +72,96 @@ class BaseSystem extends model_1.RBush { this.insert(polygon); return polygon; } + /** + * re-insert body into collision tree and update its aabb + * every body can be part of only one system + */ + insert(body) { + body.bbox = body.getAABBAsBBox(); + if (body.system) { + // allow end if body inserted and not moved + if (!(0, utils_1.bodyMoved)(body)) { + return this; + } + // old bounding box *needs* to be removed + body.system.remove(body); + } + // only then we update min, max + body.minX = body.bbox.minX - body.padding; + body.minY = body.bbox.minY - body.padding; + body.maxX = body.bbox.maxX + body.padding; + body.maxY = body.bbox.maxY + body.padding; + // set system for later body.system.updateBody(body) + body.system = this; + // reinsert bounding box to collision tree + return super.insert(body); + } + /** + * updates body in collision tree + */ + updateBody(body) { + body.updateBody(); + } + /** + * update all bodies aabb + */ + update() { + (0, optimized_1.forEach)(this.all(), (body) => { + this.updateBody(body); + }); + } + /** + * draw exact bodies colliders outline + */ + draw(context) { + (0, optimized_1.forEach)(this.all(), (body) => { + body.draw(context); + }); + } + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context) { + const drawChildren = (body) => { + (0, utils_1.drawBVH)(context, body); + if (body.children) { + (0, optimized_1.forEach)(body.children, drawChildren); + } + }; + (0, optimized_1.forEach)(this.data.children, drawChildren); + } + /** + * remove body aabb from collision tree + */ + remove(body, equals) { + body.system = undefined; + return super.remove(body, equals); + } + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body) { + // filter here is required as collides with self + return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); + } + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse(traverseFunction, { children } = this.data) { + return children === null || children === void 0 ? void 0 : children.find((body, index) => { + if (!body) { + return false; + } + if (body.type && traverseFunction(body, children, index)) { + return true; + } + // if callback returns true, ends forEach + if (body.children) { + this.traverse(traverseFunction, body); + } + }); + } } exports.BaseSystem = BaseSystem; @@ -1300,51 +1370,6 @@ class System extends base_system_1.BaseSystem { */ this.response = new model_1.Response(); } - /** - * remove body aabb from collision tree - */ - remove(body, equals) { - body.system = undefined; - return super.remove(body, equals); - } - /** - * re-insert body into collision tree and update its aabb - * every body can be part of only one system - */ - insert(body) { - body.bbox = body.getAABBAsBBox(); - if (body.system) { - // allow end if body inserted and not moved - if (!(0, utils_1.bodyMoved)(body)) { - return this; - } - // old bounding box *needs* to be removed - body.system.remove(body); - } - // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; - // set system for later body.system.updateBody(body) - body.system = this; - // reinsert bounding box to collision tree - return super.insert(body); - } - /** - * updates body in collision tree - */ - updateBody(body) { - body.updateBody(); - } - /** - * update all bodies aabb - */ - update() { - (0, optimized_1.forEach)(this.all(), (body) => { - this.updateBody(body); - }); - } /** * separate (move away) bodies */ @@ -1373,7 +1398,7 @@ class System extends base_system_1.BaseSystem { /** * check one body collisions with callback */ - checkOne(body, callback = () => true, response = this.response) { + checkOne(body, callback = utils_1.returnTrue, response = this.response) { // no need to check static body collision if (body.isStatic) { return false; @@ -1396,49 +1421,51 @@ class System extends base_system_1.BaseSystem { }; return (0, optimized_1.some)(this.all(), checkOne); } - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body) { - // filter here is required as collides with self - return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); - } /** * check do 2 objects collide */ checkCollision(bodyA, bodyB, response = this.response) { - // if any of bodies has padding, we can short return false by assesing the bbox without padding + // if any of bodies is not inserted + if (!bodyA.bbox || !bodyB.bbox) { + return false; + } + // if any of bodies has padding, we can assess the bboxes without padding if ((bodyA.padding || bodyB.padding) && - (0, utils_1.notIntersectAABB)(bodyA.bbox || bodyA, bodyB.bbox || bodyB)) { + (0, utils_1.notIntersectAABB)(bodyA.bbox, bodyB.bbox)) { return false; } const sat = (0, utils_1.getSATTest)(bodyA, bodyB); // 99% of cases if (bodyA.isConvex && bodyB.isConvex) { + // always first clear response response.clear(); return sat(bodyA, bodyB, response); } // more complex (non convex) cases const convexBodiesA = (0, intersect_1.ensureConvex)(bodyA); const convexBodiesB = (0, intersect_1.ensureConvex)(bodyB); - const overlapV = new model_1.SATVector(); + let overlapX = 0; + let overlapY = 0; let collided = false; (0, optimized_1.forEach)(convexBodiesA, (convexBodyA) => { (0, optimized_1.forEach)(convexBodiesB, (convexBodyB) => { + // always first clear response response.clear(); if (sat(convexBodyA, convexBodyB, response)) { collided = true; - overlapV.add(response.overlapV); + overlapX += response.overlapV.x; + overlapY += response.overlapV.y; } }); }); if (collided) { + const vector = new model_1.SATVector(overlapX, overlapY); response.a = bodyA; response.b = bodyB; - response.overlapV = overlapV; - response.overlapN = overlapV.clone().normalize(); - response.overlap = overlapV.len(); + response.overlapV.x = overlapX; + response.overlapV.y = overlapY; + response.overlapN = vector.normalize(); + response.overlap = vector.len(); response.aInB = (0, utils_1.checkAInB)(bodyA, bodyB); response.bInA = (0, utils_1.checkAInB)(bodyB, bodyA); } @@ -1447,7 +1474,7 @@ class System extends base_system_1.BaseSystem { /** * raycast to get collider of ray from start to end */ - raycast(start, end, allow = () => true) { + raycast(start, end, allow = utils_1.returnTrue) { let minDistance = Infinity; let result = null; if (!this.ray) { @@ -1476,23 +1503,6 @@ class System extends base_system_1.BaseSystem { this.remove(this.ray); return result; } - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse(find, { children } = this.data) { - return children === null || children === void 0 ? void 0 : children.find((body, index) => { - if (!body) { - return false; - } - if (body.type && find(body, children, index)) { - return true; - } - // if callback returns true, ends forEach - if (body.children) { - this.traverse(find, body); - } - }); - } } exports.System = System; @@ -1508,7 +1518,7 @@ exports.System = System; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.returnTrue = exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); const intersect_1 = __webpack_require__(/*! ./intersect */ "./dist/intersect.js"); const model_1 = __webpack_require__(/*! ./model */ "./dist/model.js"); @@ -1765,6 +1775,10 @@ function cloneResponse(response) { return clone; } exports.cloneResponse = cloneResponse; +function returnTrue() { + return true; +} +exports.returnTrue = returnTrue; /***/ }), diff --git a/dist/model.d.ts b/dist/model.d.ts index 811cd5fe..8a171d8b 100644 --- a/dist/model.d.ts +++ b/dist/model.d.ts @@ -6,7 +6,7 @@ import { Ellipse } from "./bodies/ellipse"; import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; -import { System } from "./system"; +import { BaseSystem } from "./base-system"; export { Polygon as DecompPolygon, Point as DecompPoint } from "poly-decomp"; export { RBush, BBox, Response, SATVector, SATPolygon, SATCircle }; export type CheckCollisionCallback = (response: Response) => void | boolean; @@ -122,7 +122,7 @@ export interface BodyProps extends Required; + system?: BaseSystem; /** * was the body modified and needs update in the next checkCollision */ @@ -165,3 +165,4 @@ export interface BodyProps extends Required = (bodyA: T, bodyB: Y, response: Response) => boolean; +export type TraverseFunction = (child: Leaf, children: Leaf[], index: number) => boolean | void; diff --git a/dist/system.d.ts b/dist/system.d.ts index 71c65d1d..b721957d 100644 --- a/dist/system.d.ts +++ b/dist/system.d.ts @@ -1,8 +1,7 @@ /// -import RBush from "rbush"; import { BaseSystem } from "./base-system"; import { Line } from "./bodies/line"; -import { Leaf, RaycastHit, Response, Vector, Body, CheckCollisionCallback } from "./model"; +import { RaycastHit, Response, Vector, Body, CheckCollisionCallback } from "./model"; /** * collision system */ @@ -11,24 +10,10 @@ export declare class System extends BaseSystem * the last collision result */ response: Response; - protected ray: Line; - /** - * remove body aabb from collision tree - */ - remove(body: TBody, equals?: (a: TBody, b: TBody) => boolean): RBush; - /** - * re-insert body into collision tree and update its aabb - * every body can be part of only one system - */ - insert(body: TBody): RBush; - /** - * updates body in collision tree - */ - updateBody(body: TBody): void; /** - * update all bodies aabb + * for raycasting */ - update(): void; + protected ray: Line; /** * separate (move away) bodies */ @@ -45,11 +30,6 @@ export declare class System extends BaseSystem * check all bodies collisions with callback */ checkAll(callback: (response: Response) => void | boolean, response?: Response): boolean; - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body: TBody): TBody[]; /** * check do 2 objects collide */ @@ -58,10 +38,4 @@ export declare class System extends BaseSystem * raycast to get collider of ray from start to end */ raycast(start: Vector, end: Vector, allow?: (body: TBody) => boolean): RaycastHit | null; - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse(find: (child: Leaf, children: Leaf[], index: number) => boolean | void, { children }?: { - children?: Leaf[]; - }): TBody | undefined; } diff --git a/dist/system.js b/dist/system.js index 0fcfd564..fbfca193 100644 --- a/dist/system.js +++ b/dist/system.js @@ -18,51 +18,6 @@ class System extends base_system_1.BaseSystem { */ this.response = new model_1.Response(); } - /** - * remove body aabb from collision tree - */ - remove(body, equals) { - body.system = undefined; - return super.remove(body, equals); - } - /** - * re-insert body into collision tree and update its aabb - * every body can be part of only one system - */ - insert(body) { - body.bbox = body.getAABBAsBBox(); - if (body.system) { - // allow end if body inserted and not moved - if (!(0, utils_1.bodyMoved)(body)) { - return this; - } - // old bounding box *needs* to be removed - body.system.remove(body); - } - // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; - // set system for later body.system.updateBody(body) - body.system = this; - // reinsert bounding box to collision tree - return super.insert(body); - } - /** - * updates body in collision tree - */ - updateBody(body) { - body.updateBody(); - } - /** - * update all bodies aabb - */ - update() { - (0, optimized_1.forEach)(this.all(), (body) => { - this.updateBody(body); - }); - } /** * separate (move away) bodies */ @@ -91,7 +46,7 @@ class System extends base_system_1.BaseSystem { /** * check one body collisions with callback */ - checkOne(body, callback = () => true, response = this.response) { + checkOne(body, callback = utils_1.returnTrue, response = this.response) { // no need to check static body collision if (body.isStatic) { return false; @@ -114,49 +69,51 @@ class System extends base_system_1.BaseSystem { }; return (0, optimized_1.some)(this.all(), checkOne); } - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body) { - // filter here is required as collides with self - return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); - } /** * check do 2 objects collide */ checkCollision(bodyA, bodyB, response = this.response) { - // if any of bodies has padding, we can short return false by assesing the bbox without padding + // if any of bodies is not inserted + if (!bodyA.bbox || !bodyB.bbox) { + return false; + } + // if any of bodies has padding, we can assess the bboxes without padding if ((bodyA.padding || bodyB.padding) && - (0, utils_1.notIntersectAABB)(bodyA.bbox || bodyA, bodyB.bbox || bodyB)) { + (0, utils_1.notIntersectAABB)(bodyA.bbox, bodyB.bbox)) { return false; } const sat = (0, utils_1.getSATTest)(bodyA, bodyB); // 99% of cases if (bodyA.isConvex && bodyB.isConvex) { + // always first clear response response.clear(); return sat(bodyA, bodyB, response); } // more complex (non convex) cases const convexBodiesA = (0, intersect_1.ensureConvex)(bodyA); const convexBodiesB = (0, intersect_1.ensureConvex)(bodyB); - const overlapV = new model_1.SATVector(); + let overlapX = 0; + let overlapY = 0; let collided = false; (0, optimized_1.forEach)(convexBodiesA, (convexBodyA) => { (0, optimized_1.forEach)(convexBodiesB, (convexBodyB) => { + // always first clear response response.clear(); if (sat(convexBodyA, convexBodyB, response)) { collided = true; - overlapV.add(response.overlapV); + overlapX += response.overlapV.x; + overlapY += response.overlapV.y; } }); }); if (collided) { + const vector = new model_1.SATVector(overlapX, overlapY); response.a = bodyA; response.b = bodyB; - response.overlapV = overlapV; - response.overlapN = overlapV.clone().normalize(); - response.overlap = overlapV.len(); + response.overlapV.x = overlapX; + response.overlapV.y = overlapY; + response.overlapN = vector.normalize(); + response.overlap = vector.len(); response.aInB = (0, utils_1.checkAInB)(bodyA, bodyB); response.bInA = (0, utils_1.checkAInB)(bodyB, bodyA); } @@ -165,7 +122,7 @@ class System extends base_system_1.BaseSystem { /** * raycast to get collider of ray from start to end */ - raycast(start, end, allow = () => true) { + raycast(start, end, allow = utils_1.returnTrue) { let minDistance = Infinity; let result = null; if (!this.ray) { @@ -194,22 +151,5 @@ class System extends base_system_1.BaseSystem { this.remove(this.ray); return result; } - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse(find, { children } = this.data) { - return children === null || children === void 0 ? void 0 : children.find((body, index) => { - if (!body) { - return false; - } - if (body.type && find(body, children, index)) { - return true; - } - // if callback returns true, ends forEach - if (body.children) { - this.traverse(find, body); - } - }); - } } exports.System = System; diff --git a/dist/utils.d.ts b/dist/utils.d.ts index 2ad03683..ecec6c05 100644 --- a/dist/utils.d.ts +++ b/dist/utils.d.ts @@ -95,3 +95,4 @@ export declare function drawBVH(context: CanvasRenderingContext2D, body: Body): * clone response object returning new response with previous ones values */ export declare function cloneResponse(response: Response): Response; +export declare function returnTrue(): boolean; diff --git a/dist/utils.js b/dist/utils.js index 220cdb22..ec7b32d4 100644 --- a/dist/utils.js +++ b/dist/utils.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.returnTrue = exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; const sat_1 = require("sat"); const intersect_1 = require("./intersect"); const model_1 = require("./model"); @@ -257,3 +257,7 @@ function cloneResponse(response) { return clone; } exports.cloneResponse = cloneResponse; +function returnTrue() { + return true; +} +exports.returnTrue = returnTrue; diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js index 4949bf31..40ab04d3 100644 --- a/docs/assets/navigation.js +++ b/docs/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE52Xy27bMBBF/0Vrp2ncJm29k+w0CZAigWNkU3RBSxObME0KJJ1YKPrvhR62SGo0MrzlvfdI4mtGv/9GFvY2mkSJyopFkUM0inJm19EkArnbmsvD+Ke13YpoFG24zKLJ938jJ7lvQ6lgxkAZ2/uJq7GbmXKdCujG6nEqeSsEzw0SbQQq+8glEixHqdSz4tJ2Y9UwnRPFSkksWQlUdp7szLqbrIY7uVGtR5PImuyCmwvYW9CSicglgsmVxCbuoJzHfYkXfYt5lM4m905hq53NfoXUKo2ia+lMcmEsbBFsNU6teeIdJC4t6DeWlmepc5jG1zcnvUx5eJ9yy5U0OLnVOw8IMM9a5f2QSqUQ0zUXmQY5Y5ahFNdAgXoBQ8E7sHGcJLHpm2bXQIGelQVpORPhDnJYgYfCzVmRMmPvuUVJrUxBiFcZfoNyAduoLfJmUYPM5x/frq7H3ppCupkqIbjhSk6ZEEuWbkIS7hpizyBV2zy4emugI51KCW4Rn4NcI13SI7C3EFCODeVe4sUCTOcbmuHB97+9G8/jWZt+Z5qzpSjfvpZ8whc3PI9n49ntHRZuJCK8VFnxS71D1sbfdjKtrorLo+gDbr46gLRc9vhBJhjgKFKAqnQ8yLC6OBTPcQKqsxG6LHQ7ILCnnTU8g0Gi76OwQqWbD27wLz2INEBCdSpMrDUrejieZwjXbRoCFt47+CANzIJ36TqQgzgI6PR9IQTt/zxQxsy6bPYWCqO0KoWA1Vgz9FA00sUVFefGMpmiX3HQqLhmH8nrPZqupYEwsV0dmYCANDsNUyXfAV1PVx/ENI+r92M/zbMNQutyFxSOEOmYKODegsz86uiQjiqBWIFN1E6mMOMaqiCG6rpoZKeoeCi0tniIqjswkFb9DkbxDKeAyoPTf1EjtlOh/i9bD7L7B0cDfzJ88lDjqWDibGE+Cmte+DbvmcpGI+JblleX+0KFXWGLCT00rvYsVG9dCT0ETir7MLT9Qg+By8szTFZ23zGEeiL6Dc9AgqpHUa1LYDkFRn6i7yFwmmXjDFYYpZGQAvbnP1WNOGAnEgAA" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE52XXW+bMBSG/wvX6bpma7flDpJ+SZ1apag30y5cOE2sEBvZJgua9t8nPhKwfThEufX7vg9g+/iYX38DA3sTzIJIpmVc5hBMgpyZdTALQBRbfXkY/7Q22yyYBBsu0mD2/d+kl9x3oSRjWkMV29uJq2k/M+cqycCPNeNU8jbLeK6RaCtQ2ScukGA1SqVeJBfGj9XDdC4rV1JgyVqgssuo0Gs/WQ97uUmjB7PA6PSC6wvYG1CCZUGfCDqXApu4g3Ie9zWMhxbzKJ1NHpzCTjub/QaJkQpFN9KZ5FIb2CLYepxa88gqJC4MqA+WVLXkFdP0+uakl6mK9zk3XAqNkzvde4CDeVEyH4bUKoWYr3mWKhALZhhK6Rso0CBgLHgPJgyjKNRD09w3UKAXaUAYzjJ3B/VYjofCLVmZMG0euEFJnUxBiFcZf4NqAbuoKfN2UZ3M5x/frq6n1ppCspnLLOOaSzFnWfbOko1Lwl1j7AUkcps7R28D7EmnUpxTxOYgx4hPegL24QKqsbHcaxjHoL1vaIfH0rFiO1Aa7gqRVFXqYlx9dD5u76fLcNFhdkxx9p5Vs9FINuFLP7wMF9PF7T0WbiUi/C7T8qfcQdrFP9qX1pdH0QbcfO0BkmobhY8iwgBHkQLUrehRuN2qR7EcJ6C8jeWz0O2FwJ4Lo3kKo0TbR2EzmWz+cI1/6UGkAQLqKtOhUqwc4FieMZx/CXFY+F3EBilgBqxDvAc5iKMA7x7pQtD7pAVKmV5Xl8dYYpROpRCwmiqGFkUrXVxRca4NEwn6FQeNiiv2J3p7QNONNBImtmtPJiAgdKFgLsUO0PXs66OY9nHNfhymWbZRaNM+nUbkInsmCrg3IFK72/ZIR5VArMBEshAJLLgCpyV0KN9FI70mZaHQXmUh6tuGhqS+P2EUy3AKqCqc4YMasZ0KtX8BB5D+HyENvGP45KHGU8FEbWE+Cqtf+TYfmMpWI+JblteHeyzdW2aHcT00rvHEcrCvuB4CJ6R5HNt+rofA5VUNk53ddoyhnon7hmUgQfWjqKuLYzkFRn6i7SFwiqXTFFYYpZXIBqbAFErEqkC/qlM9xO//nJ8SULoSAAA=" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js index e3e94478..b6fea198 100644 --- a/docs/assets/search.js +++ b/docs/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/docs/classes/Circle.html b/docs/classes/Circle.html index c2780e29..c81bf810 100644 --- a/docs/classes/Circle.html +++ b/docs/classes/Circle.html @@ -1,5 +1,5 @@ Circle | Detect-Collisions

collider - circle

-

Hierarchy (view full)

Implements

Constructors

Hierarchy (view full)

Implements

Constructors

Properties

angle bbox dirty @@ -35,39 +35,39 @@ setScale updateBody

Constructors

Properties

angle: number

for compatibility reasons circle has angle

-
bbox: BBox

bounding box cache, without padding

-
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

-
isCentered: true = true

always centered

-
isConvex: true = true

flag to show is it a convex body or non convex polygon

-
isStatic: boolean

static bodies don't move but they collide

-
isTrigger: boolean

trigger bodies move but are like ghosts

-
maxX: number

maximum x bound of body

-
maxY: number

maximum y bound of body

-
minX: number

minimum x bound of body

-
minY: number

minimum y bound of body

-
offset: SATVector

offset

-
offsetCopy: Vector = ...

offset copy without angle applied

-
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

-
r: number
system?: System<Body>

reference to collision system

-
type: Circle = BodyType.Circle

circle type

-
unscaledRadius: number

saved initial radius - internal

-

Accessors

  • get scaleX(): number
  • scaleX = scale in case of Circles

    -

    Returns number

  • get scaleY(): number
  • scaleY = scale in case of Circles

    -

    Returns number

Methods

  • Draws collider on a CanvasRenderingContext2D's current path

    -

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • update instantly or mark as dirty

    -

    Parameters

    • update: boolean = false

    Returns void

  • inner function for after position change update aabb in system

    -

    Parameters

    • update: boolean = ...

    Returns void

Generated using TypeDoc

\ No newline at end of file +

Parameters

Returns Circle

Properties

angle: number

for compatibility reasons circle has angle

+
bbox: BBox

bounding box cache, without padding

+
dirty: boolean = false

was the polygon modified and needs update in the next checkCollision

+
isCentered: true = true

always centered

+
isConvex: true = true

flag to show is it a convex body or non convex polygon

+
isStatic: boolean

static bodies don't move but they collide

+
isTrigger: boolean

trigger bodies move but are like ghosts

+
maxX: number

maximum x bound of body

+
maxY: number

maximum y bound of body

+
minX: number

minimum x bound of body

+
minY: number

minimum y bound of body

+
offset: SATVector

offset

+
offsetCopy: Vector = ...

offset copy without angle applied

+
padding: number

bodies are not reinserted during update if their bbox didnt move outside bbox + padding

+
r: number
system?: BaseSystem<Body>

reference to collision system

+
type: Circle = BodyType.Circle

circle type

+
unscaledRadius: number

saved initial radius - internal

+

Accessors

  • get scaleX(): number
  • scaleX = scale in case of Circles

    +

    Returns number

  • get scaleY(): number
  • scaleY = scale in case of Circles

    +

    Returns number

Methods

  • Draws collider on a CanvasRenderingContext2D's current path

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • update instantly or mark as dirty

    +

    Parameters

    • update: boolean = false

    Returns void

  • inner function for after position change update aabb in system

    +

    Parameters

    • update: boolean = ...

    Returns void

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/classes/System.html b/docs/classes/System.html index 321be469..3f89496e 100644 --- a/docs/classes/System.html +++ b/docs/classes/System.html @@ -1,5 +1,5 @@ System | Detect-Collisions

Class System<TBody>

collision system

-

Type Parameters

Hierarchy

Constructors

Type Parameters

Hierarchy

Constructors

  • Constructs an RBush, a high-performance 2D spatial index for points and rectangles. Based on an optimized R-tree data structure with bulk-insertion support.

    @@ -41,12 +41,13 @@ is a reasonable choice for most applications. Higher value means faster insertion and slower search, and vice versa.

    -

Returns System<TBody>

Properties

ray: Line
response: Response = ...

the last collision result

-

Methods

  • Returns all items contained in the tree.

    +

Returns System<TBody>

Properties

ray: Line

for raycasting

+
response: Response = ...

the last collision result

+

Methods

  • Returns all items contained in the tree.

    Returns TBody[]

  • check all bodies collisions with callback

    -

    Parameters

    • callback: ((response) => boolean | void)
        • (response): boolean | void
        • Parameters

          Returns boolean | void

    • response: Response = ...

    Returns boolean

  • check do 2 objects collide

    -

    Parameters

    Returns boolean

  • Removes all items.

    +

    Parameters

    • callback: ((response) => boolean | void)
        • (response): boolean | void
        • Parameters

          Returns boolean | void

    • response: Response = ...

    Returns boolean

  • check do 2 objects collide

    +

    Parameters

    Returns boolean

  • Removes all items.

    Returns RBush<TBody>

  • Returns true if there are any items intersecting the given bounding box, otherwise false.

    Parameters

    • box: BBox

      The bounding box in which to search.

      @@ -73,14 +74,14 @@

    Returns number

    Example

    class MyRBush<T> extends RBush<T> {
    toBBox([x, y]) { return { minX: x, minY: y, maxX: x, maxY: y }; }
    compareMinX(a, b) { return a.x - b.x; }
    compareMinY(a, b) { return a.y - b.y; }
    }
    const tree = new MyRBush<[number, number]>();
    tree.insert([20, 50]); // accepts [x, y] points
  • create box at position with options and add to system

    -

    Parameters

    Returns Box

  • create ellipse at position with options and add to system

    -

    Parameters

    Returns Ellipse

  • draw exact bodies colliders outline

    -

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw bounding boxes hierarchy outline

    -

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • create ellipse at position with options and add to system

    +

    Parameters

    Returns Ellipse

  • draw exact bodies colliders outline

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw bounding boxes hierarchy outline

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • Imports previously exported data into the tree (i.e., data that was emitted by toJSON()).

    Importing and exporting as JSON allows you to use RBush on both the server (using Node.js) and the browser combined, e.g. first indexing the @@ -89,11 +90,11 @@

    Note that the maxEntries option from the constructor must be the same in both trees for export/import to work properly.

    Parameters

    • data: any

      The previously exported JSON data.

      -

    Returns RBush<TBody>

  • get object potential colliders

    +

Returns RBush<TBody>

  • get object potential colliders

    Parameters

    Returns TBody[]

    Deprecated

    because it's slower to use than checkOne() or checkAll()

    -
  • re-insert body into collision tree and update its aabb every body can be part of only one system

    -

    Parameters

    Returns RBush<TBody>

  • Bulk-inserts the given items into the tree.

    Bulk insertion is usually ~2-3 times faster than inserting items one by one. After bulk loading (bulk insertion into an empty tree), subsequent query performance is also ~20-30% better.

    @@ -104,14 +105,14 @@ performance worse if the data is scattered.

    Parameters

    • items: readonly TBody[]

      The items to load.

    Returns RBush<TBody>

  • remove body aabb from collision tree

    -

    Parameters

    • body: TBody
    • Optional equals: ((a, b) => boolean)
        • (a, b): boolean
        • Parameters

          Returns boolean

    Returns RBush<TBody>

  • Returns an array of data items (points or rectangles) that the given +

    Parameters

    • start: Vector
    • end: Vector
    • allow: ((body) => boolean) = returnTrue
        • (body): boolean
        • Parameters

          Returns boolean

    Returns null | RaycastHit<TBody>

  • Returns an array of data items (points or rectangles) that the given bounding box intersects.

    Note that the search method accepts a bounding box in {minX, minY, maxX, maxY} format regardless of the data format.

    Parameters

    • box: BBox

      The bounding box in which to search.

    Returns TBody[]

  • separate (move away) bodies

    -

    Returns void

  • separate (move away) 1 body

    -

    Parameters

    Returns void

  • Returns the bounding box for the provided item.

    +

    Returns void

  • separate (move away) 1 body

    +

    Parameters

    Returns void

  • Returns the bounding box for the provided item.

    By default, RBush assumes the format of data points to be an object with minX, minY, maxX, and maxY. However, you can specify a custom item format by overriding toBBox(), compareMinX(), and @@ -126,7 +127,7 @@ client for searching.

    Note that the maxEntries option from the constructor must be the same in both trees for export/import to work properly.

    -

    Returns any

  • used to find body deep inside data with finder function returning boolean found or not

    -

    Parameters

    • find: ((child, children, index) => boolean | void)
        • (child, children, index): boolean | void
        • Parameters

          Returns boolean | void

    • __namedParameters: {
          children?: Leaf<TBody>[];
      } = ...

    Returns undefined | TBody

  • updates body in collision tree

    -

    Parameters

    Returns void

Generated using TypeDoc

\ No newline at end of file +

Returns any

  • used to find body deep inside data with finder function returning boolean found or not

    +

    Parameters

    Returns undefined | TBody

  • update all bodies aabb

    +

    Returns void

  • updates body in collision tree

    +

    Parameters

    Returns void

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/demo/demo.js b/docs/demo/demo.js index e27c8312..9caf6f6f 100644 --- a/docs/demo/demo.js +++ b/docs/demo/demo.js @@ -21,29 +21,9 @@ const model_1 = __webpack_require__(/*! ./model */ "./dist/model.js"); const optimized_1 = __webpack_require__(/*! ./optimized */ "./dist/optimized.js"); const utils_1 = __webpack_require__(/*! ./utils */ "./dist/utils.js"); /** - * very base collision system + * very base collision system (create, insert, update, draw, remove) */ class BaseSystem extends model_1.RBush { - /** - * draw exact bodies colliders outline - */ - draw(context) { - (0, optimized_1.forEach)(this.all(), (body) => { - body.draw(context); - }); - } - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context) { - const drawChildren = (body) => { - (0, utils_1.drawBVH)(context, body); - if (body.children) { - (0, optimized_1.forEach)(body.children, drawChildren); - } - }; - (0, optimized_1.forEach)(this.data.children, drawChildren); - } /** * create point at position with options and add to system */ @@ -92,6 +72,96 @@ class BaseSystem extends model_1.RBush { this.insert(polygon); return polygon; } + /** + * re-insert body into collision tree and update its aabb + * every body can be part of only one system + */ + insert(body) { + body.bbox = body.getAABBAsBBox(); + if (body.system) { + // allow end if body inserted and not moved + if (!(0, utils_1.bodyMoved)(body)) { + return this; + } + // old bounding box *needs* to be removed + body.system.remove(body); + } + // only then we update min, max + body.minX = body.bbox.minX - body.padding; + body.minY = body.bbox.minY - body.padding; + body.maxX = body.bbox.maxX + body.padding; + body.maxY = body.bbox.maxY + body.padding; + // set system for later body.system.updateBody(body) + body.system = this; + // reinsert bounding box to collision tree + return super.insert(body); + } + /** + * updates body in collision tree + */ + updateBody(body) { + body.updateBody(); + } + /** + * update all bodies aabb + */ + update() { + (0, optimized_1.forEach)(this.all(), (body) => { + this.updateBody(body); + }); + } + /** + * draw exact bodies colliders outline + */ + draw(context) { + (0, optimized_1.forEach)(this.all(), (body) => { + body.draw(context); + }); + } + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context) { + const drawChildren = (body) => { + (0, utils_1.drawBVH)(context, body); + if (body.children) { + (0, optimized_1.forEach)(body.children, drawChildren); + } + }; + (0, optimized_1.forEach)(this.data.children, drawChildren); + } + /** + * remove body aabb from collision tree + */ + remove(body, equals) { + body.system = undefined; + return super.remove(body, equals); + } + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body) { + // filter here is required as collides with self + return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); + } + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse(traverseFunction, { children } = this.data) { + return children === null || children === void 0 ? void 0 : children.find((body, index) => { + if (!body) { + return false; + } + if (body.type && traverseFunction(body, children, index)) { + return true; + } + // if callback returns true, ends forEach + if (body.children) { + this.traverse(traverseFunction, body); + } + }); + } } exports.BaseSystem = BaseSystem; @@ -1300,51 +1370,6 @@ class System extends base_system_1.BaseSystem { */ this.response = new model_1.Response(); } - /** - * remove body aabb from collision tree - */ - remove(body, equals) { - body.system = undefined; - return super.remove(body, equals); - } - /** - * re-insert body into collision tree and update its aabb - * every body can be part of only one system - */ - insert(body) { - body.bbox = body.getAABBAsBBox(); - if (body.system) { - // allow end if body inserted and not moved - if (!(0, utils_1.bodyMoved)(body)) { - return this; - } - // old bounding box *needs* to be removed - body.system.remove(body); - } - // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; - // set system for later body.system.updateBody(body) - body.system = this; - // reinsert bounding box to collision tree - return super.insert(body); - } - /** - * updates body in collision tree - */ - updateBody(body) { - body.updateBody(); - } - /** - * update all bodies aabb - */ - update() { - (0, optimized_1.forEach)(this.all(), (body) => { - this.updateBody(body); - }); - } /** * separate (move away) bodies */ @@ -1373,7 +1398,7 @@ class System extends base_system_1.BaseSystem { /** * check one body collisions with callback */ - checkOne(body, callback = () => true, response = this.response) { + checkOne(body, callback = utils_1.returnTrue, response = this.response) { // no need to check static body collision if (body.isStatic) { return false; @@ -1396,49 +1421,51 @@ class System extends base_system_1.BaseSystem { }; return (0, optimized_1.some)(this.all(), checkOne); } - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body) { - // filter here is required as collides with self - return (0, optimized_1.filter)(this.search(body), (candidate) => candidate !== body); - } /** * check do 2 objects collide */ checkCollision(bodyA, bodyB, response = this.response) { - // if any of bodies has padding, we can short return false by assesing the bbox without padding + // if any of bodies is not inserted + if (!bodyA.bbox || !bodyB.bbox) { + return false; + } + // if any of bodies has padding, we can assess the bboxes without padding if ((bodyA.padding || bodyB.padding) && - (0, utils_1.notIntersectAABB)(bodyA.bbox || bodyA, bodyB.bbox || bodyB)) { + (0, utils_1.notIntersectAABB)(bodyA.bbox, bodyB.bbox)) { return false; } const sat = (0, utils_1.getSATTest)(bodyA, bodyB); // 99% of cases if (bodyA.isConvex && bodyB.isConvex) { + // always first clear response response.clear(); return sat(bodyA, bodyB, response); } // more complex (non convex) cases const convexBodiesA = (0, intersect_1.ensureConvex)(bodyA); const convexBodiesB = (0, intersect_1.ensureConvex)(bodyB); - const overlapV = new model_1.SATVector(); + let overlapX = 0; + let overlapY = 0; let collided = false; (0, optimized_1.forEach)(convexBodiesA, (convexBodyA) => { (0, optimized_1.forEach)(convexBodiesB, (convexBodyB) => { + // always first clear response response.clear(); if (sat(convexBodyA, convexBodyB, response)) { collided = true; - overlapV.add(response.overlapV); + overlapX += response.overlapV.x; + overlapY += response.overlapV.y; } }); }); if (collided) { + const vector = new model_1.SATVector(overlapX, overlapY); response.a = bodyA; response.b = bodyB; - response.overlapV = overlapV; - response.overlapN = overlapV.clone().normalize(); - response.overlap = overlapV.len(); + response.overlapV.x = overlapX; + response.overlapV.y = overlapY; + response.overlapN = vector.normalize(); + response.overlap = vector.len(); response.aInB = (0, utils_1.checkAInB)(bodyA, bodyB); response.bInA = (0, utils_1.checkAInB)(bodyB, bodyA); } @@ -1447,7 +1474,7 @@ class System extends base_system_1.BaseSystem { /** * raycast to get collider of ray from start to end */ - raycast(start, end, allow = () => true) { + raycast(start, end, allow = utils_1.returnTrue) { let minDistance = Infinity; let result = null; if (!this.ray) { @@ -1476,23 +1503,6 @@ class System extends base_system_1.BaseSystem { this.remove(this.ray); return result; } - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse(find, { children } = this.data) { - return children === null || children === void 0 ? void 0 : children.find((body, index) => { - if (!body) { - return false; - } - if (body.type && find(body, children, index)) { - return true; - } - // if callback returns true, ends forEach - if (body.children) { - this.traverse(find, body); - } - }); - } } exports.System = System; @@ -1508,7 +1518,7 @@ exports.System = System; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; +exports.returnTrue = exports.cloneResponse = exports.drawBVH = exports.drawPolygon = exports.getSATTest = exports.getBounceDirection = exports.mapArrayToVector = exports.mapVectorToArray = exports.dashLineTo = exports.clonePointsArray = exports.checkAInB = exports.intersectAABB = exports.notIntersectAABB = exports.bodyMoved = exports.extendBody = exports.clockwise = exports.distance = exports.ensurePolygonPoints = exports.ensureVectorPoint = exports.createBox = exports.createEllipse = exports.rad2deg = exports.deg2rad = exports.RAD2DEG = exports.DEG2RAD = void 0; const sat_1 = __webpack_require__(/*! sat */ "./node_modules/sat/SAT.js"); const intersect_1 = __webpack_require__(/*! ./intersect */ "./dist/intersect.js"); const model_1 = __webpack_require__(/*! ./model */ "./dist/model.js"); @@ -1765,6 +1775,10 @@ function cloneResponse(response) { return clone; } exports.cloneResponse = cloneResponse; +function returnTrue() { + return true; +} +exports.returnTrue = returnTrue; /***/ }), diff --git a/docs/enums/BodyType.html b/docs/enums/BodyType.html index 47bb541a..73153fac 100644 --- a/docs/enums/BodyType.html +++ b/docs/enums/BodyType.html @@ -1,8 +1,8 @@ BodyType | Detect-Collisions

Enumeration BodyType

types

-

Enumeration Members

Box +

Enumeration Members

Enumeration Members

Box: "Box"
Circle: "Circle"
Ellipse: "Ellipse"
Line: "Line"
Point: "Point"
Polygon: "Polygon"

Generated using TypeDoc

\ No newline at end of file +

Enumeration Members

Box: "Box"
Circle: "Circle"
Ellipse: "Ellipse"
Line: "Line"
Point: "Point"
Polygon: "Polygon"

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/functions/returnTrue.html b/docs/functions/returnTrue.html new file mode 100644 index 00000000..53ad2136 --- /dev/null +++ b/docs/functions/returnTrue.html @@ -0,0 +1 @@ +returnTrue | Detect-Collisions

Function returnTrue

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 060fef6f..8bb809a5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,7 +10,7 @@

Installation

$ npm install detect-collisions
 

API Documentation

For detailed documentation on the library's API, refer to the following link:

-

https://prozi.github.io/detect-collisions/modules.html

+

https://prozi.github.io/detect-collisions/

Usage

Step 1: Initialize Collision System

Detect-Collisions extends functionalities from RBush. To begin, establish a unique collision system.

const { System } = require("detect-collisions")
const system = new System()
diff --git a/docs/interfaces/BodyOptions.html b/docs/interfaces/BodyOptions.html index 692ba86e..bd567c4e 100644 --- a/docs/interfaces/BodyOptions.html +++ b/docs/interfaces/BodyOptions.html @@ -1,12 +1,12 @@ BodyOptions | Detect-Collisions

Interface BodyOptions

BodyOptions for body creation

-
interface BodyOptions {
    angle?: number;
    isCentered?: boolean;
    isStatic?: boolean;
    isTrigger?: boolean;
    padding?: number;
}

Properties

interface BodyOptions {
    angle?: number;
    isCentered?: boolean;
    isStatic?: boolean;
    isTrigger?: boolean;
    padding?: number;
}

Properties

angle?: number

body angle in radians use deg2rad to convert

-
isCentered?: boolean

is body offset centered for rotation purpouses

-
isStatic?: boolean

system.separate() doesn't move this body

-
isTrigger?: boolean

system.separate() doesn't trigger collision of this body

-
padding?: number

BHV padding for bounding box, preventing costly updates

-

Generated using TypeDoc

\ No newline at end of file +
isCentered?: boolean

is body offset centered for rotation purpouses

+
isStatic?: boolean

system.separate() doesn't move this body

+
isTrigger?: boolean

system.separate() doesn't trigger collision of this body

+
padding?: number

BHV padding for bounding box, preventing costly updates

+

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/BodyProps.html b/docs/interfaces/BodyProps.html index 9ac46724..22137e31 100644 --- a/docs/interfaces/BodyProps.html +++ b/docs/interfaces/BodyProps.html @@ -1,5 +1,5 @@ BodyProps | Detect-Collisions

Interface BodyProps<TBody>

each body contains those regardless of type

-
interface BodyProps<TBody> {
    angle: number;
    bbox: BBox;
    dirty: boolean;
    isCentered: boolean;
    isConvex: boolean;
    isStatic: boolean;
    isTrigger: boolean;
    offset: SATVector;
    padding: number;
    system?: System<TBody>;
    type: BodyType;
    get scaleX(): number;
    get scaleY(): number;
    draw(context): void;
    drawBVH(context): void;
    getAABBAsBBox(): BBox;
    setAngle(angle, update?): SATPolygon | Circle;
    setOffset(offset, update?): SATPolygon | Circle;
    setPosition(x, y, update?): SATPolygon | Circle;
    setScale(x, y, update?): SATPolygon | Circle;
}

Type Parameters

Hierarchy

Implemented by

Properties

interface BodyProps<TBody> {
    angle: number;
    bbox: BBox;
    dirty: boolean;
    isCentered: boolean;
    isConvex: boolean;
    isStatic: boolean;
    isTrigger: boolean;
    offset: SATVector;
    padding: number;
    system?: BaseSystem<Body>;
    type: BodyType;
    get scaleX(): number;
    get scaleY(): number;
    draw(context): void;
    drawBVH(context): void;
    getAABBAsBBox(): BBox;
    setAngle(angle, update?): SATPolygon | Circle;
    setOffset(offset, update?): SATPolygon | Circle;
    setPosition(x, y, update?): SATPolygon | Circle;
    setScale(x, y, update?): SATPolygon | Circle;
}

Type Parameters

Hierarchy

Implemented by

Properties

Properties

angle: number

body angle in radians use deg2rad to convert

-
bbox: BBox

bounding box cache, without padding

-
dirty: boolean

was the body modified and needs update in the next checkCollision

-
isCentered: boolean

is body offset centered for rotation purpouses

-
isConvex: boolean

flag to show is it a convex body or non convex polygon

-
isStatic: boolean

system.separate() doesn't move this body

-
isTrigger: boolean

system.separate() doesn't trigger collision of this body

-
offset: SATVector

each body may have offset from center

-
padding: number

BHV padding for bounding box, preventing costly updates

-
system?: System<TBody>

collisions system reference

-
type: BodyType

type of body

-

Accessors

  • get scaleY(): number
  • scale getter (y = x for Circle)

    -

    Returns number

Methods

  • draw the collider

    -

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw the bounding box

    -

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

Generated using TypeDoc

\ No newline at end of file +
bbox: BBox

bounding box cache, without padding

+
dirty: boolean

was the body modified and needs update in the next checkCollision

+
isCentered: boolean

is body offset centered for rotation purpouses

+
isConvex: boolean

flag to show is it a convex body or non convex polygon

+
isStatic: boolean

system.separate() doesn't move this body

+
isTrigger: boolean

system.separate() doesn't trigger collision of this body

+
offset: SATVector

each body may have offset from center

+
padding: number

BHV padding for bounding box, preventing costly updates

+
system?: BaseSystem<Body>

collisions system reference

+
type: BodyType

type of body

+

Accessors

  • get scaleY(): number
  • scale getter (y = x for Circle)

    +

    Returns number

Methods

  • draw the collider

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

  • draw the bounding box

    +

    Parameters

    • context: CanvasRenderingContext2D

    Returns void

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/ChildrenData.html b/docs/interfaces/ChildrenData.html index 8e0ca6fc..5f48d87a 100644 --- a/docs/interfaces/ChildrenData.html +++ b/docs/interfaces/ChildrenData.html @@ -1,3 +1,3 @@ ChildrenData | Detect-Collisions

Interface ChildrenData<TBody>

rbush data

-
interface ChildrenData<TBody> {
    children: Leaf<TBody>[];
}

Type Parameters

Properties

Properties

children: Leaf<TBody>[]

Generated using TypeDoc

\ No newline at end of file +
interface ChildrenData<TBody> {
    children: Leaf<TBody>[];
}

Type Parameters

Properties

Properties

children: Leaf<TBody>[]

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/Data.html b/docs/interfaces/Data.html index e434f167..add67b77 100644 --- a/docs/interfaces/Data.html +++ b/docs/interfaces/Data.html @@ -1,3 +1,3 @@ Data | Detect-Collisions

Interface Data<TBody>

for use of private function of sat.js

-
interface Data<TBody> {
    data: ChildrenData<TBody>;
}

Type Parameters

Properties

Properties

Generated using TypeDoc

\ No newline at end of file +
interface Data<TBody> {
    data: ChildrenData<TBody>;
}

Type Parameters

Properties

Properties

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/GetAABBAsBox.html b/docs/interfaces/GetAABBAsBox.html index 05900726..b59fc83f 100644 --- a/docs/interfaces/GetAABBAsBox.html +++ b/docs/interfaces/GetAABBAsBox.html @@ -1,3 +1,3 @@ GetAABBAsBox | Detect-Collisions

Interface GetAABBAsBox

for use of private function of sat.js

-
interface GetAABBAsBox {
    getAABBAsBox(): {
        h: number;
        pos: Vector;
        w: number;
    };
}

Methods

Methods

  • Returns {
        h: number;
        pos: Vector;
        w: number;
    }

Generated using TypeDoc

\ No newline at end of file +
interface GetAABBAsBox {
    getAABBAsBox(): {
        h: number;
        pos: Vector;
        w: number;
    };
}

Methods

Methods

  • Returns {
        h: number;
        pos: Vector;
        w: number;
    }

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/PotentialVector.html b/docs/interfaces/PotentialVector.html index 085373a1..1f4e9af8 100644 --- a/docs/interfaces/PotentialVector.html +++ b/docs/interfaces/PotentialVector.html @@ -1,4 +1,4 @@ PotentialVector | Detect-Collisions

Interface PotentialVector

potential vector

-
interface PotentialVector {
    x?: number;
    y?: number;
}

Hierarchy (view full)

Properties

x? +
interface PotentialVector {
    x?: number;
    y?: number;
}

Hierarchy (view full)

Properties

x? y? -

Properties

x?: number
y?: number

Generated using TypeDoc

\ No newline at end of file +

Properties

x?: number
y?: number

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/RaycastHit.html b/docs/interfaces/RaycastHit.html index 2cd588cd..912919e8 100644 --- a/docs/interfaces/RaycastHit.html +++ b/docs/interfaces/RaycastHit.html @@ -1,4 +1,4 @@ RaycastHit | Detect-Collisions

Interface RaycastHit<TBody>

system.raycast(from, to) result

-
interface RaycastHit<TBody> {
    body: TBody;
    point: Vector;
}

Type Parameters

  • TBody

Properties

interface RaycastHit<TBody> {
    body: TBody;
    point: Vector;
}

Type Parameters

  • TBody

Properties

Properties

body: TBody
point: Vector

Generated using TypeDoc

\ No newline at end of file +

Properties

body: TBody
point: Vector

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/interfaces/Vector.html b/docs/interfaces/Vector.html index b75e5b33..e6bbb580 100644 --- a/docs/interfaces/Vector.html +++ b/docs/interfaces/Vector.html @@ -1,4 +1,4 @@ Vector | Detect-Collisions

Interface Vector

x, y vector

-
interface Vector {
    x: number;
    y: number;
}

Hierarchy (view full)

Properties

x +
interface Vector {
    x: number;
    y: number;
}

Hierarchy (view full)

Properties

x y -

Properties

x: number
y: number

Generated using TypeDoc

\ No newline at end of file +

Properties

x: number
y: number

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/modules.html b/docs/modules.html index be620375..bde5cad9 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -26,6 +26,7 @@ DecompPolygon Leaf SATTest +TraverseFunction

Variables

Functions

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/types/Body.html b/docs/types/Body.html index 2d392edd..bd181d5d 100644 --- a/docs/types/Body.html +++ b/docs/types/Body.html @@ -1,2 +1,2 @@ Body | Detect-Collisions

Generated using TypeDoc

\ No newline at end of file +

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/types/CheckCollisionCallback.html b/docs/types/CheckCollisionCallback.html index 12eaa6d4..f8efe3b9 100644 --- a/docs/types/CheckCollisionCallback.html +++ b/docs/types/CheckCollisionCallback.html @@ -1 +1 @@ -CheckCollisionCallback | Detect-Collisions

Type alias CheckCollisionCallback

CheckCollisionCallback: ((response) => void | boolean)

Type declaration

    • (response): void | boolean
    • Parameters

      Returns void | boolean

Generated using TypeDoc

\ No newline at end of file +CheckCollisionCallback | Detect-Collisions

Type alias CheckCollisionCallback

CheckCollisionCallback: ((response) => void | boolean)

Type declaration

    • (response): void | boolean
    • Parameters

      Returns void | boolean

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/types/Leaf.html b/docs/types/Leaf.html index c6f80612..b748e2b8 100644 --- a/docs/types/Leaf.html +++ b/docs/types/Leaf.html @@ -1,2 +1,2 @@ Leaf | Detect-Collisions

Type alias Leaf<TBody>

Leaf<TBody>: TBody & {
    children?: Leaf<TBody>[];
}

body with children (rbush)

-

Type Parameters

Type declaration

Generated using TypeDoc

\ No newline at end of file +

Type Parameters

Type declaration

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/types/SATTest.html b/docs/types/SATTest.html index 0e84dd4d..cd57a7f0 100644 --- a/docs/types/SATTest.html +++ b/docs/types/SATTest.html @@ -1 +1 @@ -SATTest | Detect-Collisions

Type alias SATTest<T, Y>

SATTest<T, Y>: ((bodyA, bodyB, response) => boolean)

Type Parameters

Type declaration

    • (bodyA, bodyB, response): boolean
    • Parameters

      Returns boolean

Generated using TypeDoc

\ No newline at end of file +SATTest | Detect-Collisions

Type alias SATTest<T, Y>

SATTest<T, Y>: ((bodyA, bodyB, response) => boolean)

Type Parameters

Type declaration

    • (bodyA, bodyB, response): boolean
    • Parameters

      Returns boolean

Generated using TypeDoc

\ No newline at end of file diff --git a/docs/types/TraverseFunction.html b/docs/types/TraverseFunction.html new file mode 100644 index 00000000..aad72da9 --- /dev/null +++ b/docs/types/TraverseFunction.html @@ -0,0 +1 @@ +TraverseFunction | Detect-Collisions

Type alias TraverseFunction<TBody>

TraverseFunction<TBody>: ((child, children, index) => boolean | void)

Type Parameters

Type declaration

    • (child, children, index): boolean | void
    • Parameters

      Returns boolean | void

Generated using TypeDoc

\ No newline at end of file diff --git a/package.json b/package.json index 36ada02b..861c1086 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "detect-collisions", - "version": "9.2.7", + "version": "9.3.0", "description": "detecting collisions between bodies: Points, Lines, Boxes, Polygons (Concave too), Ellipses and Circles. Also RayCasting. All bodies can have offset, rotation, scale, bounding box padding, can be static (non moving) or be trigger bodies (non colliding).", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/base-system.ts b/src/base-system.ts index 7aa937a3..f63dbe38 100644 --- a/src/base-system.ts +++ b/src/base-system.ts @@ -12,44 +12,21 @@ import { Leaf, PotentialVector, RBush, + TraverseFunction, Vector, } from "./model"; -import { forEach } from "./optimized"; -import { drawBVH } from "./utils"; +import { filter, forEach } from "./optimized"; +import { bodyMoved, drawBVH } from "./utils"; /** - * very base collision system + * very base collision system (create, insert, update, draw, remove) */ -export class BaseSystem +export class BaseSystem extends RBush implements Data { data!: ChildrenData; - /** - * draw exact bodies colliders outline - */ - draw(context: CanvasRenderingContext2D): void { - forEach(this.all(), (body: TBody) => { - body.draw(context); - }); - } - - /** - * draw bounding boxes hierarchy outline - */ - drawBVH(context: CanvasRenderingContext2D): void { - const drawChildren = (body: Leaf) => { - drawBVH(context, body as TBody); - - if (body.children) { - forEach(body.children, drawChildren); - } - }; - - forEach(this.data.children, drawChildren); - } - /** * create point at position with options and add to system */ @@ -134,4 +111,115 @@ export class BaseSystem return polygon; } + + /** + * re-insert body into collision tree and update its aabb + * every body can be part of only one system + */ + insert(body: TBody): RBush { + body.bbox = body.getAABBAsBBox(); + + if (body.system) { + // allow end if body inserted and not moved + if (!bodyMoved(body)) { + return this; + } + + // old bounding box *needs* to be removed + body.system.remove(body); + } + + // only then we update min, max + body.minX = body.bbox.minX - body.padding; + body.minY = body.bbox.minY - body.padding; + body.maxX = body.bbox.maxX + body.padding; + body.maxY = body.bbox.maxY + body.padding; + + // set system for later body.system.updateBody(body) + body.system = this; + + // reinsert bounding box to collision tree + return super.insert(body); + } + + /** + * updates body in collision tree + */ + updateBody(body: TBody): void { + body.updateBody(); + } + + /** + * update all bodies aabb + */ + update(): void { + forEach(this.all(), (body: TBody) => { + this.updateBody(body); + }); + } + + /** + * draw exact bodies colliders outline + */ + draw(context: CanvasRenderingContext2D): void { + forEach(this.all(), (body: TBody) => { + body.draw(context); + }); + } + + /** + * draw bounding boxes hierarchy outline + */ + drawBVH(context: CanvasRenderingContext2D): void { + const drawChildren = (body: Leaf) => { + drawBVH(context, body as TBody); + + if (body.children) { + forEach(body.children, drawChildren); + } + }; + + forEach(this.data.children, drawChildren); + } + + /** + * remove body aabb from collision tree + */ + remove(body: TBody, equals?: (a: TBody, b: TBody) => boolean): RBush { + body.system = undefined; + + return super.remove(body, equals); + } + + /** + * get object potential colliders + * @deprecated because it's slower to use than checkOne() or checkAll() + */ + getPotentials(body: TBody): TBody[] { + // filter here is required as collides with self + return filter(this.search(body), (candidate: TBody) => candidate !== body); + } + + /** + * used to find body deep inside data with finder function returning boolean found or not + */ + traverse( + traverseFunction: TraverseFunction, + { children }: { children?: Leaf[] } = this.data, + ): TBody | undefined { + return children?.find((body, index) => { + if (!body) { + return false; + } + + if (body.type && traverseFunction(body, children, index)) { + return true; + } + + // if callback returns true, ends forEach + if (body.children) { + this.traverse(traverseFunction, body); + } + }); + } } diff --git a/src/bodies/box.spec.js b/src/bodies/box.spec.js index a0bd34d5..a7335d2d 100644 --- a/src/bodies/box.spec.js +++ b/src/bodies/box.spec.js @@ -102,7 +102,7 @@ describe("GIVEN Box", () => { expect(box.y).toBe(y); }); - it("THEN even without inserting to system, gives collision results", () => { + it("THEN without inserting to system, gives 0 collision results", () => { const { Box, System } = require("../../src"); // initialize a collision detection system @@ -128,7 +128,7 @@ describe("GIVEN Box", () => { system.checkCollision(box, body), ); - // correct result is 3 - expect(collisions.length).toBe(3); + // correct result is 0 + expect(collisions.length).toBe(0); }); }); diff --git a/src/bodies/circle.ts b/src/bodies/circle.ts index 78c951fd..9950d8d9 100644 --- a/src/bodies/circle.ts +++ b/src/bodies/circle.ts @@ -11,6 +11,7 @@ import { } from "../model"; import { System } from "../system"; import { dashLineTo, drawBVH, ensureVectorPoint, extendBody } from "../utils"; +import { BaseSystem } from "../base-system"; /** * collider - circle @@ -74,7 +75,7 @@ export class Circle extends SATCircle implements BBox, BodyProps { /** * reference to collision system */ - system?: System; + system?: BaseSystem; /** * was the polygon modified and needs update in the next checkCollision diff --git a/src/model.ts b/src/model.ts index 0306e591..8963e772 100644 --- a/src/model.ts +++ b/src/model.ts @@ -13,6 +13,7 @@ import { Line } from "./bodies/line"; import { Point } from "./bodies/point"; import { Polygon } from "./bodies/polygon"; import { System } from "./system"; +import { BaseSystem } from "./base-system"; export { Polygon as DecompPolygon, Point as DecompPoint } from "poly-decomp"; export { RBush, BBox, Response, SATVector, SATPolygon, SATCircle }; @@ -146,7 +147,7 @@ export interface BodyProps /** * collisions system reference */ - system?: System; + system?: BaseSystem; /** * was the body modified and needs update in the next checkCollision @@ -203,3 +204,9 @@ export type SATTest< T extends {} = Circle | Polygon | SATPolygon, Y extends {} = Circle | Polygon | SATPolygon, > = (bodyA: T, bodyB: Y, response: Response) => boolean; + +export type TraverseFunction = ( + child: Leaf, + children: Leaf[], + index: number, +) => boolean | void; diff --git a/src/system.ts b/src/system.ts index 70e2941a..e6f8a9e7 100644 --- a/src/system.ts +++ b/src/system.ts @@ -1,5 +1,3 @@ -import RBush from "rbush"; - import { BaseSystem } from "./base-system"; import { Line } from "./bodies/line"; import { @@ -16,16 +14,16 @@ import { import { distance, checkAInB, - bodyMoved, getSATTest, notIntersectAABB, + returnTrue, } from "./utils"; import { intersectLineCircle, intersectLinePolygon, ensureConvex, } from "./intersect"; -import { filter, forEach, some } from "./optimized"; +import { forEach, some } from "./optimized"; /** * collision system @@ -36,62 +34,10 @@ export class System extends BaseSystem { */ response: Response = new Response(); - protected ray!: Line; - - /** - * remove body aabb from collision tree - */ - remove(body: TBody, equals?: (a: TBody, b: TBody) => boolean): RBush { - body.system = undefined; - - return super.remove(body, equals); - } - - /** - * re-insert body into collision tree and update its aabb - * every body can be part of only one system - */ - insert(body: TBody): RBush { - body.bbox = body.getAABBAsBBox(); - - if (body.system) { - // allow end if body inserted and not moved - if (!bodyMoved(body)) { - return this; - } - - // old bounding box *needs* to be removed - body.system.remove(body); - } - - // only then we update min, max - body.minX = body.bbox.minX - body.padding; - body.minY = body.bbox.minY - body.padding; - body.maxX = body.bbox.maxX + body.padding; - body.maxY = body.bbox.maxY + body.padding; - - // set system for later body.system.updateBody(body) - body.system = this; - - // reinsert bounding box to collision tree - return super.insert(body); - } - - /** - * updates body in collision tree - */ - updateBody(body: TBody): void { - body.updateBody(); - } - /** - * update all bodies aabb + * for raycasting */ - update(): void { - forEach(this.all(), (body: TBody) => { - this.updateBody(body); - }); - } + protected ray!: Line; /** * separate (move away) bodies @@ -128,7 +74,7 @@ export class System extends BaseSystem { */ checkOne( body: TBody, - callback: CheckCollisionCallback = () => true, + callback: CheckCollisionCallback = returnTrue, response = this.response, ): boolean { // no need to check static body collision @@ -163,15 +109,6 @@ export class System extends BaseSystem { return some(this.all(), checkOne); } - /** - * get object potential colliders - * @deprecated because it's slower to use than checkOne() or checkAll() - */ - getPotentials(body: TBody): TBody[] { - // filter here is required as collides with self - return filter(this.search(body), (candidate: TBody) => candidate !== body); - } - /** * check do 2 objects collide */ @@ -180,10 +117,15 @@ export class System extends BaseSystem { bodyB: TBody, response = this.response, ): boolean { - // if any of bodies has padding, we can short return false by assesing the bbox without padding + // if any of bodies is not inserted + if (!bodyA.bbox || !bodyB.bbox) { + return false; + } + + // if any of bodies has padding, we can assess the bboxes without padding if ( (bodyA.padding || bodyB.padding) && - notIntersectAABB(bodyA.bbox || bodyA, bodyB.bbox || bodyB) + notIntersectAABB(bodyA.bbox, bodyB.bbox) ) { return false; } @@ -192,6 +134,7 @@ export class System extends BaseSystem { // 99% of cases if (bodyA.isConvex && bodyB.isConvex) { + // always first clear response response.clear(); return sat(bodyA, bodyB, response); @@ -200,26 +143,33 @@ export class System extends BaseSystem { // more complex (non convex) cases const convexBodiesA = ensureConvex(bodyA); const convexBodiesB = ensureConvex(bodyB); - const overlapV = new SATVector(); + + let overlapX = 0; + let overlapY = 0; let collided = false; forEach(convexBodiesA, (convexBodyA) => { forEach(convexBodiesB, (convexBodyB) => { + // always first clear response response.clear(); if (sat(convexBodyA, convexBodyB, response)) { collided = true; - overlapV.add(response.overlapV); + overlapX += response.overlapV.x; + overlapY += response.overlapV.y; } }); }); if (collided) { + const vector = new SATVector(overlapX, overlapY); + response.a = bodyA; response.b = bodyB; - response.overlapV = overlapV; - response.overlapN = overlapV.clone().normalize(); - response.overlap = overlapV.len(); + response.overlapV.x = overlapX; + response.overlapV.y = overlapY; + response.overlapN = vector.normalize(); + response.overlap = vector.len(); response.aInB = checkAInB(bodyA, bodyB); response.bInA = checkAInB(bodyB, bodyA); } @@ -233,7 +183,7 @@ export class System extends BaseSystem { raycast( start: Vector, end: Vector, - allow: (body: TBody) => boolean = () => true, + allow: (body: TBody) => boolean = returnTrue, ): RaycastHit | null { let minDistance = Infinity; let result: RaycastHit | null = null; @@ -271,31 +221,4 @@ export class System extends BaseSystem { return result; } - - /** - * used to find body deep inside data with finder function returning boolean found or not - */ - traverse( - find: ( - child: Leaf, - children: Leaf[], - index: number, - ) => boolean | void, - { children }: { children?: Leaf[] } = this.data, - ): TBody | undefined { - return children?.find((body, index) => { - if (!body) { - return false; - } - - if (body.type && find(body, children, index)) { - return true; - } - - // if callback returns true, ends forEach - if (body.children) { - this.traverse(find, body); - } - }); - } } diff --git a/src/utils.ts b/src/utils.ts index 53fad341..c4a847b4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -324,3 +324,7 @@ export function cloneResponse(response: Response) { return clone; } + +export function returnTrue() { + return true; +}