Skip to content

Commit

Permalink
Added HashGrid.getCollisionPairs() for getting colliding pairs
Browse files Browse the repository at this point in the history
  • Loading branch information
waynemwashuma committed Mar 6, 2024
1 parent 4db824c commit 69d0f46
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 27 deletions.
19 changes: 10 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ renderer.setViewport(innerWidth, innerHeight)
setTimeout(_ => renderer.play())
renderer.bindTo("#can")
const canvasBound = new BoundingBox(
0, 0,
renderer.width, renderer.height
20, 20,
renderer.width - 20, renderer.height - 20
)
const bound = new BoundingBox(-20, -20, renderer.width + 20, renderer.height + 20)
const bound = new BoundingBox(0, 0, renderer.width + 20, renderer.height + 20)
const quadtree = new QuadTree(bound, 3);
const aabbtree = new AabbTree(new Vector2(15, 15))
const GRID_NUMBER = 20
Expand All @@ -21,7 +21,7 @@ const grid = new HashGrid(
new Vector2(0, 0)
)

demoGrid(quadtree, renderer, 300)
demoGrid(grid, renderer, 30)
renderer.update()

function demoGrid(grid, renderer, number = 10) {
Expand All @@ -32,17 +32,18 @@ function demoGrid(grid, renderer, number = 10) {
translate_bound(bounds, i => [velocity[i].x, velocity[i].y])
bounceoff(canvasBound, velocity, bounds)
grid.update(clients, bounds)
const collided = quadtree.getCollisionPairs(checker)
.map(e => [bounds[e.a], bounds[e.b]])
.reduce((a, b) => b.concat(a), [])
const collided = grid.getCollisionPairs(checker,clients)
.flatMap(e => [bounds[e.b], bounds[e.b]])

grid.draw(ctx)
ctx.strokeStyle = "white"
bounds.forEach(b => renderObj(ctx, b))
ctx.strokeStyle = "red"

//we are actually redrawing more than
//twice if the object is involved in
//more than one collision
//more than one collision but it doesn't
//matter in a test.
collided.forEach(b => renderObj(ctx, b))
}
})
Expand Down
96 changes: 78 additions & 18 deletions src/hashGrid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BoundingBox,Vector2,clamp } from "../chaos.module.js"
import { BoundingBox, Vector2, clamp, naturalizePair } from "../chaos.module.js"
import { Utils } from "../chaos.module.js"
import { Client } from "./client.js"
/**
Expand All @@ -21,7 +21,7 @@ export class HashGrid {
* @param {number} numberY
* @param {Vector2} offset
*/
constructor(binWidth,binHeight,numberX,numberY,offset = new Vector2(0,0)) {
constructor(binWidth, binHeight, numberX, numberY, offset = new Vector2(0, 0)) {
this.binWidth = binWidth
this.binHeight = binHeight
this.binsX = numberX
Expand All @@ -41,7 +41,7 @@ export class HashGrid {
* @param {number} yoffset
* @returns {number}
*/
_getBinIndex(xoffset,yoffset) {
_getBinIndex(xoffset, yoffset) {
return this.binsX * yoffset + xoffset
}
/**
Expand All @@ -51,8 +51,8 @@ export class HashGrid {
* @param {number} width
* @param {number} number
*/
_getkey(value,offset,width,number) {
return clamp(Math.floor((value - offset) / width),0,number - 1)
_getkey(value, offset, width, number) {
return clamp(Math.floor((value - offset) / width), 0, number - 1)
}
/**
*
Expand All @@ -64,15 +64,15 @@ export class HashGrid {
const maxX = bounds.max.x
const maxY = bounds.max.y

const keyx1 = this._getkey(minX,this.offset.x,this.binWidth,this.binsX)
const keyx2 = this._getkey(maxX,this.offset.x,this.binWidth,this.binsX)
const keyy1 = this._getkey(minY,this.offset.y,this.binHeight,this.binsY)
const keyy2 = this._getkey(maxY,this.offset.y,this.binHeight,this.binsY)
const keyx1 = this._getkey(minX, this.offset.x, this.binWidth, this.binsX)
const keyx2 = this._getkey(maxX, this.offset.x, this.binWidth, this.binsX)
const keyy1 = this._getkey(minY, this.offset.y, this.binHeight, this.binsY)
const keyy2 = this._getkey(maxY, this.offset.y, this.binHeight, this.binsY)

const indices = []
for (let x = keyx1; x <= keyx2; x++) {
for (let y = keyy1; y <= keyy2; y++) {
indices.push(this._getBinIndex(x,y))
indices.push(this._getBinIndex(x, y))
}
}

Expand All @@ -82,7 +82,7 @@ export class HashGrid {
* @param {Client<T,number[]>} client
* @param {BoundingBox} bounds
*/
insert(client,bounds) {
insert(client, bounds) {
const indices = this._getbinIndices(bounds)
for (let i = 0; i < indices.length; i++) {
this.bins[indices[i]].push(client)
Expand All @@ -101,7 +101,7 @@ export class HashGrid {
const bin = this.bins[indices[i]]
const index = bin.indexOf(client)

Utils.removeElement(bin,index)
Utils.removeElement(bin, index)
}
client.node.length = 0
}
Expand All @@ -110,18 +110,18 @@ export class HashGrid {
* @param {Client<T,number[]>[]} clients
* @param {BoundingBox[]} bounds
*/
update(clients,bounds) {
update(clients, bounds) {
for (let i = 0; i < clients.length; i++) {
this.remove(clients[i])
this.insert(clients[i],bounds[i])
this.insert(clients[i], bounds[i])
}
}
/**
* @param {BoundingBox} bound
* @param {T[]} out
* @param {QueryFunc<number[],T>} func
*/
query(bound,out = [],func = () => true) {
query(bound, out = [], func = () => true) {
this.queryid++
const list = this._getbinIndices(bound)
for (var i = 0; i < list.length; i++) {
Expand All @@ -131,7 +131,7 @@ export class HashGrid {
const client = bin[j]
if (client.queryid === this.queryid) continue
client.queryid = this.queryid
if (func(client,bound))
if (func(client, bound))
out.push(client.value)
}
}
Expand All @@ -141,12 +141,66 @@ export class HashGrid {
* @param {TraverserFunc<Client<T,number[]>[],U[]>} func
* @param {U[]} out
*/
traverseAll(func,out) {
traverseAll(func, out) {
for (let i = 0; i < this.bins.length; i++) {
func(this.bins[i],out)
func(this.bins[i], out)
}
return out
}
/**
* @ignore
*/
getCollisionPairs(func, client) {
return HashGrid.getCollisionPairs(this, func, client, [])
}
/**
* @template T
* @template U
* @param {HashGrid<T>} grid
* @param {CollisionChecker<T,number[],U>} func
* @param {Client<T,number[]>}
* @param {U[]} target
*/
static getCollisionPairs(grid, func, clients, target = []) {
for (let i = 0; i < clients.length; i++) {
HashGrid.getCollidingPairsFor(grid, clients[i], func, target)
}
return target
}
/**
* @template T
* @template U
* @param {Client<T,number[]>} client
* @param {CollisionChecker<T,number[],U>} func
* @param {U[]} target
*/
static getCollidingPairsFor(grid, client, func, target) {

for (let i = 0; i < client.node.length; i++) {
const bin = grid.bins[client.node[i]]
for (let j = 0; j < bin.length; j++) {
if (bin[j] === client) continue
const t = func(client, bin[j])
if (t) target.push(t)
}
}
}
/**
* @template T
* @template U
* @param {Client<T,number[]>[]} bin
* @param {CollisionChecker<T,number[],U>} func
* @param {U[]} target
*/
static getBinPairs(bin, func, target) {
for (let i = 0; i < bin.length; i++) {
for (let j = 0; j < bin.length; j++) {
if(i === j)continue
const pair = func(bin[i], bin[j])
if (pair) target.push(pair)
}
}
}
/**
* @param {CanvasRenderingContext2D} ctx
*/
Expand Down Expand Up @@ -196,4 +250,10 @@ export class HashGrid {
* @template T
* @template U
* @typedef {import("./types.js").TraverserFunc<T,U>} TraverserFunc
*/
/**
* @template T
* @template U
* @template V
* @typedef {import("./types.js").CollisionChecker<T,U,V>} CollisionChecker
*/

0 comments on commit 69d0f46

Please sign in to comment.