Files
prosperon/collision2d.cm
2026-02-26 08:13:27 -06:00

109 lines
2.7 KiB
Plaintext

var collision2d = {}
collision2d.body = function(config) {
var c = config || {}
return {
type: c.type || 'aabb',
width: c.width || 0,
height: c.height || 0,
radius: c.radius || 0,
offset: c.offset || {x: 0, y: 0},
layer: c.layer || 0,
mask: c.mask || 0xFFFF
}
}
function body_center(body, pos) {
return {
x: pos.x + body.offset.x,
y: pos.y + body.offset.y
}
}
function test_aabb_aabb(a, ap, b, bp) {
var ac = body_center(a, ap)
var bc = body_center(b, bp)
var ahw = a.width * 0.5
var ahh = a.height * 0.5
var bhw = b.width * 0.5
var bhh = b.height * 0.5
return abs(ac.x - bc.x) < ahw + bhw && abs(ac.y - bc.y) < ahh + bhh
}
function test_circle_circle(a, ap, b, bp) {
var ac = body_center(a, ap)
var bc = body_center(b, bp)
var dx = ac.x - bc.x
var dy = ac.y - bc.y
var r = a.radius + b.radius
return dx * dx + dy * dy < r * r
}
function test_aabb_circle(aabb, ap, circ, cp) {
var ac = body_center(aabb, ap)
var cc = body_center(circ, cp)
var hw = aabb.width * 0.5
var hh = aabb.height * 0.5
var cx = max(ac.x - hw, min(cc.x, ac.x + hw))
var cy = max(ac.y - hh, min(cc.y, ac.y + hh))
var dx = cc.x - cx
var dy = cc.y - cy
return dx * dx + dy * dy < circ.radius * circ.radius
}
collision2d.test = function(a, a_pos, b, b_pos) {
if (a.layer & b.mask == 0 || b.layer & a.mask == 0)
return false
if (a.type == 'aabb' && b.type == 'aabb')
return test_aabb_aabb(a, a_pos, b, b_pos)
if (a.type == 'circle' && b.type == 'circle')
return test_circle_circle(a, a_pos, b, b_pos)
if (a.type == 'aabb' && b.type == 'circle')
return test_aabb_circle(a, a_pos, b, b_pos)
if (a.type == 'circle' && b.type == 'aabb')
return test_aabb_circle(b, b_pos, a, a_pos)
return false
}
collision2d.overlap = function(body, pos, others) {
var results = []
var i = 0
var other = null
for (i = 0; i < length(others); i++) {
other = others[i]
if (collision2d.test(body, pos, other.body, other.pos))
results[] = other
}
return results
}
collision2d.overlap_point = function(point, bodies) {
var results = []
var i = 0
var b = null
var c = null
var hw = 0
var hh = 0
var dx = 0
var dy = 0
for (i = 0; i < length(bodies); i++) {
b = bodies[i]
c = body_center(b.body, b.pos)
if (b.body.type == 'aabb') {
hw = b.body.width * 0.5
hh = b.body.height * 0.5
if (abs(point.x - c.x) < hw && abs(point.y - c.y) < hh)
results[] = b
} else if (b.body.type == 'circle') {
dx = point.x - c.x
dy = point.y - c.y
if (dx * dx + dy * dy < b.body.radius * b.body.radius)
results[] = b
}
}
return results
}
return collision2d