diff options
| author | iamcheeseman <[hidden email]> | 2026-02-13 20:42:28 -0500 |
|---|---|---|
| committer | iamcheeseman <[hidden email]> | 2026-02-13 20:42:28 -0500 |
| commit | 1ff729f696c895f81f0cf0d1b8a2cca1d6e43eb8 (patch) | |
| tree | 040bf0ffe933d424951159380af83c927a55a9fe /src/phys/body.odin | |
| parent | c6261cc09f97568ad5ea966662697e01ea17b861 (diff) | |
simple raycasting mmmmmm
Diffstat (limited to 'src/phys/body.odin')
| -rw-r--r-- | src/phys/body.odin | 74 |
1 files changed, 68 insertions, 6 deletions
diff --git a/src/phys/body.odin b/src/phys/body.odin index 5a7838f..4793e42 100644 --- a/src/phys/body.odin +++ b/src/phys/body.odin @@ -1,5 +1,9 @@ package phys +import "core:math" +import "core:math/linalg" +import "core:log" + Vec2 :: [2]f32 Rect :: struct { @@ -8,8 +12,7 @@ Rect :: struct { } Layer :: enum (u16) { - Default, - Hard, // hard collisions; don't let bodies intersect at all + Hard, // hard collisions; don't let bodies intersect at all. default Soft, // soft collisions; push away other bodies with a force Enemy, // enemy hitboxes Player, // player hitboxes @@ -17,6 +20,8 @@ Layer :: enum (u16) { Player_Projectile, } +Layer_Set :: bit_set[Layer;u16] + Collision_Type :: enum (u8) { Up, Down, @@ -26,6 +31,12 @@ Collision_Type :: enum (u8) { Vertical, } +Raycast :: struct { + start: Vec2, + dir: Vec2, + mask: Layer_Set, +} + Body :: struct { handle: Body_Handle, bin_idx: i32, @@ -34,14 +45,14 @@ Body :: struct { pos: Vec2, vel: Vec2, collisions: bit_set[Collision_Type;u8], - layers: bit_set[Layer;u16], - mask: bit_set[Layer;u16], + layers: Layer_Set, + mask: Layer_Set, } make_body :: proc( rect: Rect, - layers := bit_set[Layer;u16]{.Default}, - mask := bit_set[Layer;u16]{.Default}, + layers := Layer_Set{.Hard}, + mask := Layer_Set{.Hard}, ) -> Body_Handle { b := Body { rect = rect, @@ -52,26 +63,77 @@ make_body :: proc( return add_body(b) } +@(require_results) +make_raycast :: #force_inline proc( + start: Vec2, + end: Vec2, + mask := Layer_Set{.Hard}, +) -> Raycast { + return Raycast{ + start, + end, + mask, + } +} + +@(require_results) aabb_hori :: proc(a: Rect, b: Rect) -> bool { return a.start.x < b.start.x + b.size.x && b.start.x < a.start.x + a.size.x } +@(require_results) aabb_vert :: proc(a: Rect, b: Rect) -> bool { return a.start.y < b.start.y + b.size.y && b.start.y < a.start.y + a.size.y } +@(require_results) aabb :: proc(a: Rect, b: Rect) -> bool { return aabb_hori(a, b) && aabb_vert(a, b) } +@(require_results) point_aabb_hori :: proc(r: Rect, p: Vec2) -> bool { return r.start.x < p.x && r.start.x + r.size.x > p.x } +@(require_results) point_aabb_vert :: proc(r: Rect, p: Vec2) -> bool { return r.start.y < p.y && r.start.y + r.size.y > p.y } +@(require_results) point_aabb :: proc(r: Rect, p: Vec2) -> bool { return point_aabb_hori(r, p) && point_aabb_vert(r, p) } + +@(require_results) +raycast_to_aabb :: proc(rc: Raycast, body: Body) -> bool { + body_min := body.pos + body.rect.start + body_max := body_min + body.rect.size + + rc_dir_to_body := linalg.normalize0((body_min + body_max) * 0.5 - rc.start) + + // Don't consider bodies behind the ray + if linalg.dot(rc_dir_to_body, rc.dir) < 0 { + return false; + } + + tmin := -math.INF_F32 + tmax := math.INF_F32 + + dir_inv := 1.0 / rc.dir + + tx_min := (body_min.x - rc.start.x) * dir_inv.x + tx_max := (body_max.x - rc.start.x) * dir_inv.x + + tmin = max(tmin, min(tx_max, tx_min)) + tmax = min(tmax, max(tx_max, tx_min)) + + ty_min := (body_min.y - rc.start.y) * dir_inv.y + ty_max := (body_max.y - rc.start.y) * dir_inv.y + + tmin = max(tmin, min(ty_max, ty_min)) + tmax = min(tmax, max(ty_max, ty_min)) + + return tmax >= tmin +} |
