Skip to content

Instantly share code, notes, and snippets.

@joar
Created September 11, 2015 14:53
Show Gist options
  • Select an option

  • Save joar/73e966bae7ae1bd32814 to your computer and use it in GitHub Desktop.

Select an option

Save joar/73e966bae7ae1bd32814 to your computer and use it in GitHub Desktop.
/**
* Collision handler. Use with d3.quadtree.visit
* @param n Node
* @param responseCoefficient How much of the overlap should be eliminated
* each step. Range: 0..1
* @param state Optional state object to insert debug information into.
* @returns {Function}
*/
export function collide(n, {responseCoefficient=1, debugLines=null}) {
let nx = getExtent(n) // Node extent
return function collide_inner (quad, x1, y1, x2, y2) {
let p = quad.point // Point
debugLines = collide_cleanupDebugLines(debugLines)
// Abort if point is null or point and node are the same
if (!p || p === n) {
return
}
let collision = overlap(n, p)
let averageWidth = (n.width + p.width) / 2,
averageHeight = (n.height + p.height) / 2
if (collision !== undefined) {
let {tx, ty, th} = getCollisionTriangle(n, p)
let toNode = angle(getCenter(p), getCenter(n)),
toPoint = toNode + Math.PI / 2
let overlap
if (collision == UP || collision == DOWN) {
overlap = averageHeight - Math.abs(ty)
} else {
overlap = averageWidth - Math.abs(tx)
}
// The distance each object should move away.
let response = overlap / 2
if (n.fixed || p.fixed) {
response = overlap
}
// Take COLLISION_RESPONSE into account.
response *= responseCoefficient
let nodePos = getPoint(
n,
collision,
response
)
let pointPos = getPoint(
p,
collision + Math.PI,
response
)
debugLines = collide_addDebugLine(
debugLines,
n, p,
collision,
response)
if (!n.fixed) {
n.x = nodePos.x
n.y = nodePos.y
}
if (!p.fixed) {
p.x = pointPos.x
p.y = pointPos.y
}
}
return x1 > nx.x2 || x2 < nx.x1 || y1 > nx.y2 || y2 < nx.y1;
}
}
/**
* Check if two rectangles overlap and return the side of the rectangle that
* overlaps.
* @param a
* @param b
* @returns {*} The face of {a} that is hitting {b} in radians. 0 = right
*/
function overlap(a, b) {
let bCenter = getCenter(a),
aCenter = getCenter(b),
averageWidth = (a.width + b.width) / 2,
averageHeight = (a.height + b.height) / 2,
deltaX = bCenter.x - aCenter.x,
deltaY = bCenter.y - aCenter.y
if (Math.abs(deltaX) <= averageWidth && Math.abs(deltaY) <= averageHeight) {
// Collision
let wy = averageWidth * deltaY,
hx = averageHeight * deltaX
if (wy > hx) {
if (wy > -hx) {
return DOWN
} else {
return LEFT
}
} else {
if (wy > -hx) {
return RIGHT
} else {
return UP
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment