@@ -6,12 +6,17 @@ use flecs_ecs::{
66 macros:: { Component , system} ,
77 prelude:: Module ,
88} ;
9- use geometry:: aabb:: Aabb ;
9+ use geometry:: { aabb:: Aabb , ray :: Ray } ;
1010use hyperion:: {
1111 egress:: player_join:: RayonWorldStages ,
1212 glam:: Vec3 ,
13- simulation:: { EntitySize , Position , aabb} ,
13+ simulation:: {
14+ EntitySize , Position , aabb,
15+ blocks:: { Blocks , RayCollision } ,
16+ } ,
1417} ;
18+ use ordered_float:: NotNan ;
19+ use rayon:: iter:: Either ;
1520
1621#[ derive( Component ) ]
1722pub struct SpatialModule ;
@@ -22,6 +27,39 @@ pub struct SpatialIndex {
2227 query : bvh_region:: Bvh < Entity > ,
2328}
2429
30+ #[ must_use]
31+ pub fn get_first_collision (
32+ ray : Ray ,
33+ world : & World ,
34+ ) -> Option < Either < EntityView < ' _ > , RayCollision > > {
35+ // Check for collisions with entities
36+ let entity = world. get :: < & SpatialIndex > ( |index| index. closest_to_ray ( ray, world) ) ;
37+ let block = world. get :: < & Blocks > ( |blocks| blocks. first_collision ( ray) ) ;
38+
39+ // check which one is closest to the Ray don't forget to account for entity size
40+ entity. map_or ( block. map ( Either :: Right ) , |( entity, _) | {
41+ let entity_data = entity. get :: < ( & Position , & EntitySize ) > ( |( position, size) | {
42+ let entity_aabb = aabb ( * * position, * size) ;
43+
44+ #[ allow( clippy:: redundant_closure_for_method_calls) ]
45+ let distance_to_entity = entity_aabb
46+ . intersect_ray ( & ray)
47+ . map_or ( f32:: MAX , |distance| distance. into_inner ( ) ) ;
48+
49+ ( entity, distance_to_entity)
50+ } ) ;
51+
52+ let ( entity, distance_to_entity) = entity_data;
53+ block. map_or ( Some ( Either :: Left ( entity) ) , |block_collision| {
54+ if distance_to_entity < block_collision. distance {
55+ Some ( Either :: Left ( entity) )
56+ } else {
57+ Some ( Either :: Right ( block_collision) )
58+ }
59+ } )
60+ } )
61+ }
62+
2563fn get_aabb_func < ' a > ( world : & ' a World ) -> impl Fn ( & Entity ) -> Aabb + Send + Sync {
2664 let stages: & ' a RayonWorldStages = world. get :: < & RayonWorldStages > ( |stages| {
2765 // we can properly extend lifetimes here
@@ -61,6 +99,18 @@ impl SpatialIndex {
6199 let ( target, _) = self . query . get_closest ( point, & get_aabb) ?;
62100 Some ( world. entity_from_id ( * target) )
63101 }
102+
103+ #[ must_use]
104+ pub fn closest_to_ray < ' a > (
105+ & self ,
106+ ray : Ray ,
107+ world : & ' a World ,
108+ ) -> Option < ( EntityView < ' a > , NotNan < f32 > ) > {
109+ let get_aabb = get_aabb_func ( world) ;
110+ let ( entity, distance) = self . query . get_closest_ray ( ray, get_aabb) ?;
111+ let entity = world. entity_from_id ( * entity) ;
112+ Some ( ( entity, distance) )
113+ }
64114}
65115
66116/// If we want the entity to be spatially indexed, we need to add this component.
0 commit comments