11//! Module for performing entity physics, including velocity, drag
22//! and position updates each tick.
33
4- use crate :: entity:: { EntityComponent , EntityType , VelocityComponent } ;
4+ use crate :: entity:: { EntityComponent , EntityMoveEvent , EntityType , VelocityComponent } ;
5+ use feather_core:: world:: block:: Block ;
56use feather_core:: world:: ChunkMap ;
6- use nalgebra:: Vector3 ;
77use rayon:: prelude:: * ;
88use shrev:: EventChannel ;
99use specs:: { Entities , ParJoin , Read , ReadStorage , System , Write , WriteStorage } ;
@@ -33,20 +33,64 @@ impl<'a> System<'a> for EntityPhysicsSystem {
3333 // Go through entities and update position and velocity in parallel.
3434 ( & mut entity_comps, & mut velocities, & entities, & types)
3535 . par_join ( )
36- . for_each ( |( mut entity_comp, mut velocity, entity, ty) | {
37- let mut new_pos = entity_comp. position . clone ( ) ;
36+ . for_each ( |( entity_comp, velocity, entity, ty) | {
37+ let position = entity_comp. position ;
3838 // First, add velocity to position, accounting for blocks
3939 // at the new position.
40- let pending_new_pos = new_pos + velocity;
41- if chunk_map. block_at ( pending_new_pos. block_pos ( ) ) . is_some ( ) {
42- velocity. velocity = Vector3 :: new ( 0.0 , 0.0 , 0.0 ) ;
40+ let pending_position = position + velocity. 0 ;
41+ let pending_block = chunk_map. block_at ( pending_position. block_pos ( ) ) ;
42+
43+ // If block is `None`, the chunk at pending_position isn't
44+ // loading. If so, unload the entity.
45+ if let Some ( block) = pending_block {
46+ // Check that block isn't solid.
47+ // If it is, update velocity accordingly.
48+ if block != Block :: Air {
49+ let pending_pos_x = position + glm:: vec3 ( velocity. 0 . x , 0.0 , 0.0 ) ;
50+ if chunk_map. block_at ( pending_pos_x. block_pos ( ) ) != Some ( Block :: Air ) {
51+ velocity. 0 . x = 0.0 ;
52+ }
53+
54+ let pending_pos_y = position + glm:: vec3 ( velocity. 0 . y , 0.0 , 0.0 ) ;
55+ if chunk_map. block_at ( pending_pos_y. block_pos ( ) ) != Some ( Block :: Air ) {
56+ velocity. 0 . y = 0.0 ;
57+ }
58+
59+ let pending_pos_z = position + glm:: vec3 ( velocity. 0 . z , 0.0 , 0.0 ) ;
60+ if chunk_map. block_at ( pending_pos_z. block_pos ( ) ) != Some ( Block :: Air ) {
61+ velocity. 0 . z = 0.0 ;
62+ }
63+ } else {
64+ // Depending on the type of entity, apply drag and gravity.
65+ // See https://minecraft.gamepedia.com/Entity for more information.
66+ let gravity = gravitational_acceleration ( * ty) ;
67+ // let terminal = terminal_velocity(*ty);
68+ let drag = drag_force ( * ty) ;
69+
70+ velocity. 0 . y = drag * velocity. 0 . y + gravity;
71+ }
72+
73+ // Set new position and trigger event.
74+ let event = EntityMoveEvent {
75+ entity,
76+ old_pos : position,
77+ new_pos : pending_position,
78+ } ;
79+
80+ tx. send ( event) . unwrap ( ) ;
81+
82+ entity_comp. position = pending_position;
4383 } else {
44- new_pos = pending_new_pos;
84+ // Chunk isn't loaded. Unload entity.
85+ entities. delete ( entity) . unwrap ( ) ;
86+ return ;
4587 }
46-
47- // Depending on the type of entity, apply drag and gravity.
48- // See https://minecraft.gamepedia.com/Entity for more information.
4988 } ) ;
89+
90+ // Go through events and trigger them.
91+ while let Ok ( event) = rx. try_recv ( ) {
92+ move_events. single_write ( event) ;
93+ }
5094 }
5195}
5296
@@ -55,35 +99,59 @@ impl<'a> System<'a> for EntityPhysicsSystem {
5599///
56100/// This information was fetched from
57101/// [the Minecraft wiki](https://minecraft.gamepedia.com/Entity#Motion_of_entities).
58- fn gravitational_acceleration ( ty : EntityType ) -> f64 {
102+ fn gravitational_acceleration ( ty : EntityType ) -> f32 {
59103 if ty. is_living ( ) {
60104 -0.08
61105 } else if ty. is_item ( ) {
62106 -0.04
63107 } else if ty. is_other ( ) {
64108 0.0
109+ } else {
110+ 0.0
65111 }
66112}
67113
114+ /*
68115/// Retrieves the terminal velocity in blocks per tick
69116/// for a given entity type.
70- fn terminal_velocity ( ty : EntityType ) -> f64 {
117+ fn terminal_velocity(ty: EntityType) -> f32 {
71118 if ty.is_living() {
72119 -3.92
73120 } else if ty.is_item() {
74121 -1.96
75122 } else if ty.is_other() {
76123 0.0
124+ } else {
125+ 0.0
77126 }
78127}
128+ */
79129
80130/// Retrieves the drag force for a given entity type.
81- fn drag_force ( ty : EntityType ) -> f64 {
131+ fn drag_force ( ty : EntityType ) -> f32 {
82132 if ty. is_living ( ) {
83133 0.98
84134 } else if ty. is_item ( ) {
85135 0.04
86136 } else if ty. is_other ( ) {
87137 0.0
138+ } else {
139+ 0.0
140+ }
141+ }
142+
143+ #[ cfg( test) ]
144+ mod tests {
145+ use super :: * ;
146+ use crate :: testframework as t;
147+ use feather_core:: world:: Position ;
148+
149+ #[ test]
150+ fn test_entity_physics_basic ( ) {
151+ let ( mut w, mut d) = t:: init_world ( ) ;
152+
153+ let pos = Position :: new ( 0.0 , 0.0 , 0.0 ) ;
154+ let vel = glm:: vec3 ( 0.0 , 1.0 , 0.0 ) ;
155+ let entity = t:: add_entity_with_pos_and_vel ( & mut w, pos, vel) ;
88156 }
89157}
0 commit comments