split apart modules

This commit is contained in:
2025-12-14 01:36:35 -06:00
parent a223d3d2b3
commit 828db06c74
13 changed files with 2212 additions and 2941 deletions

235
collision.cm Normal file
View File

@@ -0,0 +1,235 @@
// Collision module for lance3d
// Private collider storage
var _colliders = []
var _collider_id = 0
function clear() {
_colliders = []
}
function add_sphere(transform, radius, opts) {
opts = opts || {}
var c = {
id: _collider_id++,
type: "sphere",
transform: transform,
radius: radius,
layer_mask: opts.layer_mask || 1,
user: opts.user
}
_colliders.push(c)
return c
}
function add_box(transform, sx, sy, sz, opts) {
opts = opts || {}
var c = {
id: _collider_id++,
type: "box",
transform: transform,
sx: sx, sy: sy, sz: sz,
layer_mask: opts.layer_mask || 1,
user: opts.user
}
_colliders.push(c)
return c
}
function remove(collider) {
for (var i = 0; i < _colliders.length; i++) {
if (_colliders[i].id == collider.id) {
_colliders.splice(i, 1)
return true
}
}
return false
}
function overlaps(layer_mask_a, layer_mask_b) {
var results = []
for (var i = 0; i < _colliders.length; i++) {
for (var j = i + 1; j < _colliders.length; j++) {
var a = _colliders[i]
var b = _colliders[j]
if (layer_mask_a != null && !(a.layer_mask & layer_mask_a)) continue
if (layer_mask_b != null && !(b.layer_mask & layer_mask_b)) continue
if (_check_collision(a, b)) {
results.push({a: a, b: b})
}
}
}
return results
}
function raycast(ox, oy, oz, dx, dy, dz, opts) {
opts = opts || {}
var max_dist = opts.max_dist || 1000000
var layer_mask = opts.layer_mask || 0xFFFFFFFF
// Normalize direction
var len = Math.sqrt(dx*dx + dy*dy + dz*dz)
if (len < 0.0001) return null
dx /= len
dy /= len
dz /= len
var closest = null
var closest_dist = max_dist
for (var i = 0; i < _colliders.length; i++) {
var c = _colliders[i]
if (!(c.layer_mask & layer_mask)) continue
var hit = null
if (c.type == "sphere") {
hit = _ray_sphere(ox, oy, oz, dx, dy, dz, c)
} else if (c.type == "box") {
hit = _ray_box(ox, oy, oz, dx, dy, dz, c)
}
if (hit && hit.distance < closest_dist) {
closest = hit
closest_dist = hit.distance
}
}
return closest
}
function _get_position(transform) {
if (!transform) return {x: 0, y: 0, z: 0}
// If transform is a matrix (array of 16), extract translation
if (transform.length == 16) {
return {x: transform[12], y: transform[13], z: transform[14]}
}
// If transform is an object with x,y,z
if (transform.x != null) {
return {x: transform.x, y: transform.y, z: transform.z}
}
return {x: 0, y: 0, z: 0}
}
function _check_collision(a, b) {
var pa = _get_position(a.transform)
var pb = _get_position(b.transform)
var dx = pb.x - pa.x
var dy = pb.y - pa.y
var dz = pb.z - pa.z
var dist = Math.sqrt(dx*dx + dy*dy + dz*dz)
// Simple sphere-sphere approximation
var ra = a.radius || Math.max(a.sx || 0, a.sy || 0, a.sz || 0)
var rb = b.radius || Math.max(b.sx || 0, b.sy || 0, b.sz || 0)
return dist < ra + rb
}
function _ray_sphere(ox, oy, oz, dx, dy, dz, sphere) {
var pos = _get_position(sphere.transform)
var r = sphere.radius
// Vector from ray origin to sphere center
var lx = pos.x - ox
var ly = pos.y - oy
var lz = pos.z - oz
// Project onto ray direction
var tca = lx*dx + ly*dy + lz*dz
if (tca < 0) return null
var d2 = lx*lx + ly*ly + lz*lz - tca*tca
var r2 = r*r
if (d2 > r2) return null
var thc = Math.sqrt(r2 - d2)
var t = tca - thc
if (t < 0) t = tca + thc
if (t < 0) return null
var hx = ox + dx*t
var hy = oy + dy*t
var hz = oz + dz*t
// Normal at hit point
var nx = (hx - pos.x) / r
var ny = (hy - pos.y) / r
var nz = (hz - pos.z) / r
return {
x: hx, y: hy, z: hz,
nx: nx, ny: ny, nz: nz,
distance: t,
collider: sphere
}
}
function _ray_box(ox, oy, oz, dx, dy, dz, box) {
var pos = _get_position(box.transform)
var hx = (box.sx || 1) / 2
var hy = (box.sy || 1) / 2
var hz = (box.sz || 1) / 2
var minx = pos.x - hx, maxx = pos.x + hx
var miny = pos.y - hy, maxy = pos.y + hy
var minz = pos.z - hz, maxz = pos.z + hz
var tmin = -1000000, tmax = 1000000
var nx = 0, ny = 0, nz = 0
// X slab
if (Math.abs(dx) > 0.0001) {
var t1 = (minx - ox) / dx
var t2 = (maxx - ox) / dx
if (t1 > t2) { var tmp = t1; t1 = t2; t2 = tmp }
if (t1 > tmin) { tmin = t1; nx = dx > 0 ? -1 : 1; ny = 0; nz = 0 }
if (t2 < tmax) tmax = t2
} else if (ox < minx || ox > maxx) {
return null
}
// Y slab
if (Math.abs(dy) > 0.0001) {
var t1 = (miny - oy) / dy
var t2 = (maxy - oy) / dy
if (t1 > t2) { var tmp = t1; t1 = t2; t2 = tmp }
if (t1 > tmin) { tmin = t1; nx = 0; ny = dy > 0 ? -1 : 1; nz = 0 }
if (t2 < tmax) tmax = t2
} else if (oy < miny || oy > maxy) {
return null
}
// Z slab
if (Math.abs(dz) > 0.0001) {
var t1 = (minz - oz) / dz
var t2 = (maxz - oz) / dz
if (t1 > t2) { var tmp = t1; t1 = t2; t2 = tmp }
if (t1 > tmin) { tmin = t1; nx = 0; ny = 0; nz = dz > 0 ? -1 : 1 }
if (t2 < tmax) tmax = t2
} else if (oz < minz || oz > maxz) {
return null
}
if (tmin > tmax || tmax < 0) return null
var t = tmin > 0 ? tmin : tmax
if (t < 0) return null
return {
x: ox + dx*t, y: oy + dy*t, z: oz + dz*t,
nx: nx, ny: ny, nz: nz,
distance: t,
collider: box
}
}
return {
clear: clear,
add_sphere: add_sphere,
add_box: add_box,
remove: remove,
overlaps: overlaps,
raycast: raycast
}