mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
entity collisions
This commit is contained in:
parent
b0bd992adc
commit
ca2e0b3922
5 changed files with 86 additions and 74 deletions
|
@ -17,7 +17,7 @@ _Currently supported Minecraft version: `1.21.4`._
|
|||
|
||||
## Features
|
||||
|
||||
- [Accurate physics](https://github.com/azalea-rs/azalea/blob/main/azalea-physics/src/lib.rs) (but some features like entity collisions and elytras aren't yet implemented)
|
||||
- [Accurate physics](https://github.com/azalea-rs/azalea/blob/main/azalea-physics/src/lib.rs) (but some features like entity pushing and elytras aren't yet implemented)
|
||||
- [Pathfinder](https://azalea.matdoes.dev/azalea/pathfinder/index.html)
|
||||
- [Swarms](https://azalea.matdoes.dev/azalea/swarm/index.html)
|
||||
- [Breaking blocks](https://azalea.matdoes.dev/azalea/struct.Client.html#method.mine)
|
||||
|
|
|
@ -125,6 +125,16 @@ macro_rules! vec3_impl {
|
|||
z: self.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_x(&self, x: $type) -> Self {
|
||||
Self { x, ..*self }
|
||||
}
|
||||
pub fn with_y(&self, y: $type) -> Self {
|
||||
Self { y, ..*self }
|
||||
}
|
||||
pub fn with_z(&self, z: $type) -> Self {
|
||||
Self { z, ..*self }
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for &$name {
|
||||
|
|
|
@ -15,9 +15,10 @@ use azalea_core::{
|
|||
position::{BlockPos, Vec3},
|
||||
};
|
||||
use azalea_world::{ChunkStorage, Instance, MoveEntityError};
|
||||
use bevy_ecs::world::Mut;
|
||||
use bevy_ecs::{entity::Entity, world::Mut};
|
||||
pub use blocks::BlockWithShape;
|
||||
pub use discrete_voxel_shape::*;
|
||||
use entity_collisions::{CollidableEntityQuery, PhysicsQuery, get_entity_collisions};
|
||||
pub use shape::*;
|
||||
use tracing::warn;
|
||||
|
||||
|
@ -32,50 +33,27 @@ pub enum MoverType {
|
|||
Shulker,
|
||||
}
|
||||
|
||||
// private Vec3 collide(Vec3 var1) {
|
||||
// AABB var2 = this.getBoundingBox();
|
||||
// List var3 = this.level.getEntityCollisions(this,
|
||||
// var2.expandTowards(var1)); Vec3 var4 = var1.lengthSqr() == 0.0D ?
|
||||
// var1 : collideBoundingBox(this, var1, var2, this.level, var3);
|
||||
// boolean var5 = var1.x != var4.x;
|
||||
// boolean var6 = var1.y != var4.y;
|
||||
// boolean var7 = var1.z != var4.z;
|
||||
// boolean var8 = this.onGround || var6 && var1.y < 0.0D;
|
||||
// if (this.maxUpStep > 0.0F && var8 && (var5 || var7)) {
|
||||
// Vec3 var9 = collideBoundingBox(this, new Vec3(var1.x,
|
||||
// (double)this.maxUpStep, var1.z), var2, this.level, var3); Vec3
|
||||
// var10 = collideBoundingBox(this, new Vec3(0.0D, (double)this.maxUpStep,
|
||||
// 0.0D), var2.expandTowards(var1.x, 0.0D, var1.z), this.level, var3);
|
||||
// if (var10.y < (double)this.maxUpStep) {
|
||||
// Vec3 var11 = collideBoundingBox(this, new Vec3(var1.x, 0.0D,
|
||||
// var1.z), var2.move(var10), this.level, var3).add(var10); if
|
||||
// (var11.horizontalDistanceSqr() > var9.horizontalDistanceSqr()) {
|
||||
// var9 = var11;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (var9.horizontalDistanceSqr() > var4.horizontalDistanceSqr()) {
|
||||
// return var9.add(collideBoundingBox(this, new Vec3(0.0D, -var9.y +
|
||||
// var1.y, 0.0D), var2.move(var9), this.level, var3)); }
|
||||
// }
|
||||
|
||||
// return var4;
|
||||
// }
|
||||
fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics) -> Vec3 {
|
||||
// Entity.collide
|
||||
fn collide(
|
||||
movement: &Vec3,
|
||||
world: &Instance,
|
||||
physics: &azalea_entity::Physics,
|
||||
source_entity: Option<Entity>,
|
||||
physics_query: &PhysicsQuery,
|
||||
collidable_entity_query: &CollidableEntityQuery,
|
||||
) -> Vec3 {
|
||||
let entity_bounding_box = physics.bounding_box;
|
||||
// TODO: get_entity_collisions
|
||||
// let entity_collisions = world.get_entity_collisions(self,
|
||||
// entity_bounding_box.expand_towards(movement));
|
||||
let entity_collisions = Vec::new();
|
||||
let entity_collisions = get_entity_collisions(
|
||||
world,
|
||||
&entity_bounding_box.expand_towards(movement),
|
||||
source_entity,
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
);
|
||||
let collided_delta = if movement.length_squared() == 0.0 {
|
||||
*movement
|
||||
} else {
|
||||
collide_bounding_box(
|
||||
movement,
|
||||
&entity_bounding_box,
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
)
|
||||
collide_bounding_box(movement, &entity_bounding_box, world, &entity_collisions)
|
||||
};
|
||||
|
||||
let x_collision = movement.x != collided_delta.x;
|
||||
|
@ -87,35 +65,23 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
|
|||
let max_up_step = 0.6;
|
||||
if max_up_step > 0. && on_ground && (x_collision || z_collision) {
|
||||
let mut step_to_delta = collide_bounding_box(
|
||||
&Vec3 {
|
||||
x: movement.x,
|
||||
y: max_up_step,
|
||||
z: movement.z,
|
||||
},
|
||||
&movement.with_y(max_up_step),
|
||||
&entity_bounding_box,
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
&entity_collisions,
|
||||
);
|
||||
let directly_up_delta = collide_bounding_box(
|
||||
&Vec3 {
|
||||
x: 0.,
|
||||
y: max_up_step,
|
||||
z: 0.,
|
||||
},
|
||||
&Vec3::ZERO.with_y(max_up_step),
|
||||
&entity_bounding_box.expand_towards(&Vec3::new(movement.x, 0., movement.z)),
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
&entity_collisions,
|
||||
);
|
||||
if directly_up_delta.y < max_up_step {
|
||||
let target_movement = collide_bounding_box(
|
||||
&Vec3 {
|
||||
x: movement.x,
|
||||
y: 0.,
|
||||
z: movement.z,
|
||||
},
|
||||
&movement.with_y(0.),
|
||||
&entity_bounding_box.move_relative(directly_up_delta),
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
&entity_collisions,
|
||||
)
|
||||
.add(directly_up_delta);
|
||||
if target_movement.horizontal_distance_squared()
|
||||
|
@ -129,14 +95,10 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
|
|||
> collided_delta.horizontal_distance_squared()
|
||||
{
|
||||
return step_to_delta.add(collide_bounding_box(
|
||||
&Vec3 {
|
||||
x: 0.,
|
||||
y: -step_to_delta.y + movement.y,
|
||||
z: 0.,
|
||||
},
|
||||
&Vec3::ZERO.with_y(-step_to_delta.y + movement.y),
|
||||
&entity_bounding_box.move_relative(step_to_delta),
|
||||
world,
|
||||
entity_collisions.clone(),
|
||||
&entity_collisions,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -147,12 +109,16 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
|
|||
/// Move an entity by a given delta, checking for collisions.
|
||||
///
|
||||
/// In Mojmap, this is `Entity.move`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn move_colliding(
|
||||
_mover_type: MoverType,
|
||||
movement: &Vec3,
|
||||
world: &Instance,
|
||||
position: &mut Mut<azalea_entity::Position>,
|
||||
physics: &mut azalea_entity::Physics,
|
||||
source_entity: Option<Entity>,
|
||||
physics_query: &PhysicsQuery,
|
||||
collidable_entity_query: &CollidableEntityQuery,
|
||||
) -> Result<(), MoveEntityError> {
|
||||
// TODO: do all these
|
||||
|
||||
|
@ -175,7 +141,14 @@ pub fn move_colliding(
|
|||
|
||||
// movement = this.maybeBackOffFromEdge(movement, moverType);
|
||||
|
||||
let collide_result = collide(movement, world, physics);
|
||||
let collide_result = collide(
|
||||
movement,
|
||||
world,
|
||||
physics,
|
||||
source_entity,
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
);
|
||||
|
||||
let move_distance = collide_result.length_squared();
|
||||
|
||||
|
@ -269,12 +242,12 @@ fn collide_bounding_box(
|
|||
movement: &Vec3,
|
||||
entity_bounding_box: &AABB,
|
||||
world: &Instance,
|
||||
entity_collisions: Vec<VoxelShape>,
|
||||
entity_collisions: &[VoxelShape],
|
||||
) -> Vec3 {
|
||||
let mut collision_boxes: Vec<VoxelShape> = Vec::with_capacity(entity_collisions.len() + 1);
|
||||
|
||||
if !entity_collisions.is_empty() {
|
||||
collision_boxes.extend(entity_collisions);
|
||||
collision_boxes.extend_from_slice(entity_collisions);
|
||||
}
|
||||
|
||||
// TODO: world border
|
||||
|
|
|
@ -21,13 +21,18 @@ use azalea_entity::{
|
|||
use azalea_world::{Instance, InstanceContainer, InstanceName};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
query::With,
|
||||
schedule::{IntoSystemConfigs, SystemSet},
|
||||
system::{Query, Res},
|
||||
world::Mut,
|
||||
};
|
||||
use clip::box_traverse_blocks;
|
||||
use collision::{BLOCK_SHAPE, BlockWithShape, MoverType, VoxelShape, move_colliding};
|
||||
use collision::{
|
||||
BLOCK_SHAPE, BlockWithShape, MoverType, VoxelShape,
|
||||
entity_collisions::{CollidableEntityQuery, PhysicsQuery},
|
||||
move_colliding,
|
||||
};
|
||||
|
||||
/// A Bevy [`SystemSet`] for running physics that makes entities do things.
|
||||
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
||||
|
@ -352,7 +357,7 @@ fn get_block_pos_below_that_affects_movement(position: &Position) -> BlockPos {
|
|||
}
|
||||
|
||||
/// Options for [`handle_relative_friction_and_calculate_movement`]
|
||||
struct HandleRelativeFrictionAndCalculateMovementOpts<'a> {
|
||||
struct HandleRelativeFrictionAndCalculateMovementOpts<'a, 'b, 'world, 'state> {
|
||||
block_friction: f32,
|
||||
world: &'a Instance,
|
||||
physics: &'a mut Physics,
|
||||
|
@ -363,6 +368,9 @@ struct HandleRelativeFrictionAndCalculateMovementOpts<'a> {
|
|||
on_climbable: &'a OnClimbable,
|
||||
pose: Option<&'a Pose>,
|
||||
jumping: &'a Jumping,
|
||||
entity: Entity,
|
||||
physics_query: &'a PhysicsQuery<'world, 'state, 'b>,
|
||||
collidable_entity_query: &'a CollidableEntityQuery<'world, 'state>,
|
||||
}
|
||||
fn handle_relative_friction_and_calculate_movement(
|
||||
HandleRelativeFrictionAndCalculateMovementOpts {
|
||||
|
@ -376,7 +384,10 @@ fn handle_relative_friction_and_calculate_movement(
|
|||
on_climbable,
|
||||
pose,
|
||||
jumping,
|
||||
}: HandleRelativeFrictionAndCalculateMovementOpts<'_>,
|
||||
entity,
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
}: HandleRelativeFrictionAndCalculateMovementOpts<'_, '_, '_, '_>,
|
||||
) -> Vec3 {
|
||||
move_relative(
|
||||
physics,
|
||||
|
@ -397,6 +408,9 @@ fn handle_relative_friction_and_calculate_movement(
|
|||
world,
|
||||
&mut position,
|
||||
physics,
|
||||
Some(entity),
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
)
|
||||
.expect("Entity should exist");
|
||||
// let delta_movement = entity.delta;
|
||||
|
|
|
@ -83,6 +83,8 @@ pub fn travel(
|
|||
);
|
||||
} else {
|
||||
travel_in_air(
|
||||
&world,
|
||||
entity,
|
||||
&mut physics,
|
||||
&direction,
|
||||
position,
|
||||
|
@ -91,7 +93,8 @@ pub fn travel(
|
|||
on_climbable,
|
||||
pose,
|
||||
jumping,
|
||||
&world,
|
||||
&physics_query,
|
||||
&collidable_entity_query,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +103,8 @@ pub fn travel(
|
|||
/// The usual movement when we're not in water or using an elytra.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn travel_in_air(
|
||||
world: &Instance,
|
||||
entity: Entity,
|
||||
physics: &mut Physics,
|
||||
direction: &LookDirection,
|
||||
position: Mut<Position>,
|
||||
|
@ -108,7 +113,8 @@ fn travel_in_air(
|
|||
on_climbable: &OnClimbable,
|
||||
pose: Option<&Pose>,
|
||||
jumping: &Jumping,
|
||||
world: &Instance,
|
||||
physics_query: &PhysicsQuery,
|
||||
collidable_entity_query: &CollidableEntityQuery,
|
||||
) {
|
||||
let gravity = get_effective_gravity();
|
||||
|
||||
|
@ -140,6 +146,9 @@ fn travel_in_air(
|
|||
on_climbable,
|
||||
pose,
|
||||
jumping,
|
||||
entity,
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -210,6 +219,9 @@ fn travel_in_fluid(
|
|||
world,
|
||||
&mut position,
|
||||
physics,
|
||||
Some(entity),
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
)
|
||||
.expect("Entity should exist");
|
||||
|
||||
|
@ -231,6 +243,9 @@ fn travel_in_fluid(
|
|||
world,
|
||||
&mut position,
|
||||
physics,
|
||||
Some(entity),
|
||||
physics_query,
|
||||
collidable_entity_query,
|
||||
)
|
||||
.expect("Entity should exist");
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue