aboutsummaryrefslogtreecommitdiff
path: root/src/phys/body.odin
diff options
context:
space:
mode:
Diffstat (limited to 'src/phys/body.odin')
-rw-r--r--src/phys/body.odin74
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
+}