Initial port to Bevy 0.7.

This commit is contained in:
Nolan Darilek 2022-05-06 11:07:59 -05:00
parent 37d0f0fcde
commit 9307852eda
10 changed files with 159 additions and 377 deletions

View File

@ -11,7 +11,7 @@ edition = "2021"
speech_dispatcher_0_10 = ["bevy_tts/speech_dispatcher_0_10"]
[dependencies.bevy]
version = "0.6"
version = "0.7"
default-features = false
features = [
"bevy_gilrs",
@ -22,18 +22,13 @@ features = [
"serialize",
]
[dependencies.bevy_rapier2d]
git = "https://github.com/dimforge/bevy_rapier"
branch = "rapier-master"
features = ["simd-stable"]
[dependencies]
backtrace = "0.3"
bevy_input_actionmap = { git = "https://github.com/lightsoutgames/bevy_input_actionmap" }
bevy_openal = { git = "https://github.com/lightsoutgames/bevy_openal" }
bevy_rapier2d = "0.13"
bevy_tts = { git = "https://github.com/lightsoutgames/bevy_tts", default-features = false, features = ["tolk"] }
coord_2d = "0.3"
derive_more = "0.99"
futures-lite = "1"
gilrs = "0.8"
here_be_dragons = "0.1"
@ -43,7 +38,4 @@ pathfinding = "3"
rand = "0.8"
sentry = "0.25"
serde = "1"
shadowcast = "0.8"
[patch.crates-io]
rapier2d = { git = "https://github.com/dimforge/rapier", rev = "7efcff615e821" }
shadowcast = "0.8"

View File

@ -9,7 +9,6 @@ use std::{
use bevy::{core::FloatOrd, ecs::query::WorldQuery, prelude::*, transform::TransformSystem};
use bevy_rapier2d::prelude::*;
use derive_more::{Deref, DerefMut};
use once_cell::sync::Lazy;
use rand::prelude::*;
use serde::{Deserialize, Serialize};
@ -614,24 +613,14 @@ where
}
}
fn setup(core_config: Res<CoreConfig>, mut rapier_config: ResMut<RapierConfiguration>) {
rapier_config.scale = core_config.pixels_per_unit as f32;
fn setup(core_config: Res<CoreConfig>) {
let mut mode = RELATIVE_DIRECTION_MODE.write().unwrap();
*mode = core_config.relative_direction_mode;
}
fn copy_coordinates_to_transform(
config: Res<CoreConfig>,
mut query: Query<
(&Coordinates, &mut Transform),
(
Changed<Transform>,
Without<RigidBodyPositionComponent>,
Without<RigidBodyPositionSync>,
Without<ColliderPositionComponent>,
Without<ColliderPositionSync>,
),
>,
mut query: Query<(&Coordinates, &mut Transform), Changed<Transform>>,
) {
for (coordinates, mut transform) in query.iter_mut() {
let x = coordinates.0 .0 * config.pixels_per_unit as f32;
@ -645,45 +634,6 @@ fn copy_coordinates_to_transform(
}
}
fn copy_rigid_body_position_to_coordinates(
mut query: Query<
(&mut Coordinates, &RigidBodyPositionComponent),
(
Changed<RigidBodyPositionComponent>,
With<RigidBodyPositionSync>,
),
>,
) {
for (mut coordinates, position) in query.iter_mut() {
if coordinates.0 .0 != position.position.translation.x {
coordinates.0 .0 = position.position.translation.x;
}
if coordinates.0 .1 != position.position.translation.y {
coordinates.0 .1 = position.position.translation.y;
}
}
}
fn copy_collider_position_to_coordinates(
mut query: Query<
(&mut Coordinates, &ColliderPositionComponent),
(
Without<RigidBodyPositionComponent>,
Changed<ColliderPositionComponent>,
With<ColliderPositionSync>,
),
>,
) {
for (mut coordinates, position) in query.iter_mut() {
if coordinates.0 .0 != position.translation.x {
coordinates.0 .0 = position.translation.x;
}
if coordinates.0 .1 != position.translation.y {
coordinates.0 .1 = position.translation.y;
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct CoreConfig {
pub relative_direction_mode: RelativeDirectionMode,
@ -706,24 +656,29 @@ fn sync_config(config: Res<CoreConfig>) {
}
}
pub struct CorePlugin;
pub struct CorePlugin<RapierUserData>(PhantomData<RapierUserData>);
impl Plugin for CorePlugin {
impl<RapierUserData> Default for CorePlugin<RapierUserData> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<RapierUserData: 'static + WorldQuery + Send + Sync> Plugin for CorePlugin<RapierUserData> {
fn build(&self, app: &mut App) {
if !app.world.contains_resource::<CoreConfig>() {
app.insert_resource(CoreConfig::default());
}
let config = *app.world.get_resource::<CoreConfig>().unwrap();
app.register_type::<Coordinates>()
.add_plugin(RapierPhysicsPlugin::<RapierUserData>::pixels_per_meter(
config.pixels_per_unit as f32,
))
.add_startup_system(setup)
.add_system_to_stage(
CoreStage::PostUpdate,
copy_coordinates_to_transform.before(TransformSystem::TransformPropagate),
)
.add_system_to_stage(
CoreStage::PostUpdate,
copy_rigid_body_position_to_coordinates,
)
.add_system_to_stage(CoreStage::PostUpdate, copy_collider_position_to_coordinates)
.add_system(sync_config);
}
}
@ -743,7 +698,6 @@ impl<RapierUserData: 'static + WorldQuery + Send + Sync> PluginGroup
group
.add(crate::bevy_tts::TtsPlugin)
.add(crate::bevy_openal::OpenAlPlugin)
.add(RapierPhysicsPlugin::<RapierUserData>::default())
.add(CorePlugin);
.add(CorePlugin::<RapierUserData>::default());
}
}

View File

@ -4,7 +4,6 @@ use bevy::prelude::*;
use bevy_input_actionmap::InputMap;
use bevy_rapier2d::prelude::*;
use bevy_tts::Tts;
use derive_more::{Deref, DerefMut};
use crate::{
core::{Coordinates, Player, PointLike},
@ -330,16 +329,14 @@ fn exploration_changed_announcement<D: 'static + Clone + Default + Send + Sync>(
names: Query<&Name>,
types: Query<&ExplorationType>,
mappables: Query<&Mappable>,
query_pipeline: Res<QueryPipeline>,
collider_query: QueryPipelineColliderComponentsQuery,
rapier_context: Res<RapierContext>,
) -> Result<(), Box<dyn Error>> {
if let Ok((coordinates, exploring, viewshed)) = explorer.get_single() {
let collider_set = QueryPipelineColliderComponentsSet(&collider_query);
let coordinates = coordinates.floor();
for (map, revealed_tiles) in map.iter() {
let point = **exploring;
let idx = point.to_index(map.width);
let shape = Cuboid::new(Vec2::new(0.49, 0.49).into());
let shape = Collider::cuboid(0.49, 0.49);
let known = revealed_tiles[idx];
let visible = viewshed.is_point_visible(exploring);
let fog_of_war = known && !visible;
@ -348,15 +345,14 @@ fn exploration_changed_announcement<D: 'static + Clone + Default + Send + Sync>(
for entity in focused.iter() {
commands.entity(entity).remove::<ExplorationFocused>();
}
let shape_pos = (Vec2::new(exploring.x(), exploring.y()), 0.);
query_pipeline.intersections_with_shape(
&collider_set,
&shape_pos.into(),
let exploring = Vec2::new(exploring.x(), exploring.y());
rapier_context.intersections_with_shape(
exploring,
0.,
&shape,
InteractionGroups::all(),
Some(&|v| explorable.get(v.entity()).is_ok()),
|handle| {
let entity = handle.entity();
Some(&|v| explorable.get(v).is_ok()),
|entity| {
commands.entity(entity).insert(ExplorationFocused);
if visible || mappables.get(entity).is_ok() {
if let Ok(name) = names.get(entity) {

View File

@ -10,7 +10,6 @@ pub mod commands;
pub use coord_2d;
#[macro_use]
pub mod core;
pub use derive_more;
pub mod error;
pub mod exploration;
pub use futures_lite;

View File

@ -2,7 +2,6 @@ use std::{error::Error, time::Instant};
use bevy::prelude::*;
use bevy_tts::Tts;
use derive_more::{Deref, DerefMut};
use crate::error::error_handler;

View File

@ -1,8 +1,11 @@
use std::marker::PhantomData;
use bevy::prelude::*;
use bevy_rapier2d::prelude::*;
use derive_more::{Deref, DerefMut};
use bevy_rapier2d::{
na::{Isometry2, Vector2},
prelude::*,
rapier::prelude::AABB,
};
pub use here_be_dragons::Map as MapgenMap;
use here_be_dragons::{geometry::Rect as MRect, MapFilter, Tile};
use maze_generator::{prelude::*, recursive_backtracking::RbGenerator};
@ -238,21 +241,16 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
.entity(map_entity)
.remove::<SpawnColliders>()
.remove::<SpawnColliderPerTile>()
.insert_bundle(RigidBodyBundle {
body_type: RigidBodyTypeComponent(RigidBodyType::Fixed),
..Default::default()
});
.insert(RigidBody::Fixed);
if **spawn_collider_per_tile {
for y in 0..map.height {
for x in 0..map.width {
let tile = map.at(x, y);
if tile.blocks_motion() {
let id = commands
.spawn_bundle(ColliderBundle {
shape: ColliderShape::cuboid(0.5, 0.5).into(),
position: Vec2::new(x as f32 + 0.5, y as f32 + 0.5).into(),
..Default::default()
})
.spawn()
.insert(Collider::cuboid(0.5, 0.5))
.insert(Transform::from_xyz(x as f32 + 0.5, y as f32 + 0.5, 0.))
.insert(MapObstruction)
.id();
if tile.blocks_visibility() {
@ -334,11 +332,9 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
height
);
let id = commands
.spawn_bundle(ColliderBundle {
shape: ColliderShape::cuboid(half_width, half_height).into(),
position: Vec2::new(center.x(), center.y()).into(),
..Default::default()
})
.spawn()
.insert(Collider::cuboid(half_width, half_height))
.insert(Transform::from_xyz(center.x(), center.y(), 0.))
.insert(MapObstruction)
.id();
if map.at(x as usize, y as usize).blocks_visibility() {
@ -352,19 +348,20 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
}
}
for room in &map.rooms {
let shape =
ColliderShape::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32);
let position: ColliderPositionComponent =
point!(room.center().x(), room.center().y()).into();
let aabb = shape.compute_aabb(&position);
let shape = Collider::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32);
let position =
Isometry2::new(Vector2::new(room.center().x(), room.center().y()), 0.);
let aabb = shape.raw.compute_aabb(&position);
let id = commands
.spawn_bundle(ColliderBundle {
collider_type: ColliderType::Sensor.into(),
shape: shape.clone().into(),
flags: ActiveEvents::COLLISION_EVENTS.into(),
position,
..Default::default()
})
.spawn()
.insert(shape)
.insert(Sensor(true))
.insert(ActiveEvents::COLLISION_EVENTS)
.insert(Transform::from_xyz(
position.translation.x,
position.translation.y,
0.,
))
.insert(Area(aabb))
.id();
commands.entity(map_entity).push_children(&[id]);
@ -431,22 +428,18 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
fn spawn_portal_colliders<D: 'static + Clone + Default + Send + Sync>(
mut commands: Commands,
map: Query<(Entity, &SpawnColliders), With<Map<D>>>,
portals: Query<(Entity, &Coordinates), Without<ColliderShapeComponent>>,
portals: Query<(Entity, &Coordinates), Without<Collider>>,
) {
for (map_entity, spawn_colliders) in map.iter() {
if **spawn_colliders {
for (portal_entity, coordinates) in portals.iter() {
let position = Vec2::new(coordinates.x() + 0.5, coordinates.y() + 0.5).into();
let position = Vec2::new(coordinates.x() + 0.5, coordinates.y() + 0.5);
commands
.entity(portal_entity)
.insert_bundle(ColliderBundle {
collider_type: ColliderTypeComponent(ColliderType::Sensor),
shape: ColliderShape::cuboid(0.5, 0.5).into(),
position,
flags: ActiveEvents::COLLISION_EVENTS.into(),
..Default::default()
})
.insert(ColliderPositionSync::Discrete);
.insert(Transform::from_xyz(position.x(), position.y(), 0.))
.insert(Collider::cuboid(0.5, 0.5))
.insert(Sensor(true))
.insert(ActiveEvents::COLLISION_EVENTS);
commands.entity(map_entity).push_children(&[portal_entity]);
}
}
@ -462,14 +455,11 @@ fn area_description(
) {
for event in events.iter() {
let (entity1, entity2, started) = match event {
CollisionEvent::Started(collider1, collider2) => {
(collider1.entity(), collider2.entity(), true)
}
CollisionEvent::Stopped(collider1, collider2, _) => {
(collider1.entity(), collider2.entity(), false)
}
CollisionEvent::Started(collider1, collider2, _) => (collider1, collider2, true),
CollisionEvent::Stopped(collider1, collider2, _) => (collider1, collider2, false),
};
if let Some((area, other)) = target_and_other(entity1, entity2, &|v| areas.get(v).is_ok()) {
if let Some((area, other)) = target_and_other(*entity1, *entity2, &|v| areas.get(v).is_ok())
{
if players.get(other).is_ok() {
if let Ok((aabb, area_name)) = areas.get(area) {
let name = if let Some(name) = area_name {

View File

@ -2,9 +2,8 @@ use std::{error::Error, f32::consts::PI, fmt::Debug, hash::Hash, marker::Phantom
use bevy::prelude::*;
use bevy_input_actionmap::InputMap;
use bevy_rapier2d::{na::UnitComplex, prelude::*};
use bevy_rapier2d::prelude::*;
use bevy_tts::Tts;
use derive_more::{Deref, DerefMut};
use crate::{
core::{Angle, CardinalDirection, Player},
@ -53,11 +52,11 @@ fn movement_controls<S, A: 'static>(
mut query: Query<
(
Entity,
&mut RigidBodyVelocityComponent,
&mut Velocity,
&mut Speed,
&MaxSpeed,
Option<&RotationSpeed>,
&mut RigidBodyPositionComponent,
&mut Transform,
Option<&Destination>,
),
With<Player>,
@ -65,16 +64,16 @@ fn movement_controls<S, A: 'static>(
exploration_focused: Query<Entity, With<ExplorationFocused>>,
) where
S: 'static + Clone + Debug + Eq + Hash + Send + Sync,
A: Hash + Eq + Clone + Send + Sync,
A: Hash + Eq + Copy + Send + Sync,
{
for (entity, mut velocity, mut speed, max_speed, rotation_speed, mut position, destination) in
for (entity, mut velocity, mut speed, max_speed, rotation_speed, mut transform, destination) in
query.iter_mut()
{
if **snapping {
if let (Some(_), Some(rotate_left), Some(rotate_right)) = (
rotation_speed,
config.action_rotate_left.clone(),
config.action_rotate_right.clone(),
config.action_rotate_left,
config.action_rotate_right,
) {
if input.active(rotate_left) {
continue;
@ -86,7 +85,7 @@ fn movement_controls<S, A: 'static>(
**snapping = false;
continue;
} else {
let sprinting = if let Some(action) = config.action_sprint.clone() {
let sprinting = if let Some(action) = config.action_sprint {
input.active(action)
} else {
false
@ -97,38 +96,39 @@ fn movement_controls<S, A: 'static>(
commands.entity(entity).remove::<Sprinting>();
}
let mut direction = Vec2::default();
if let Some(action) = config.action_forward.clone() {
if let Some(action) = config.action_forward {
if input.active(action) {
direction.x += 1.;
}
}
if let Some(action) = config.action_backward.clone() {
if let Some(action) = config.action_backward {
if input.active(action) {
direction.x -= 1.;
}
}
if let Some(action) = config.action_left.clone() {
if let Some(action) = config.action_left {
if input.active(action) {
direction.y += 1.;
}
}
if let Some(action) = config.action_right.clone() {
if let Some(action) = config.action_right {
if input.active(action) {
direction.y -= 1.;
}
}
if let (Some(rotation_speed), Some(rotate_left), Some(rotate_right)) = (
rotation_speed,
config.action_rotate_left.clone(),
config.action_rotate_right.clone(),
config.action_rotate_left,
config.action_rotate_right,
) {
let delta = rotation_speed.radians() * time.delta_seconds();
if input.active(rotate_left) {
position.position.rotation *= UnitComplex::new(delta);
transform.rotate(Quat::from_rotation_z(delta));
}
if input.active(rotate_right) {
position.position.rotation *= UnitComplex::new(-delta);
} else {
transform.rotate(Quat::from_rotation_z(-delta));
}
if !input.active(rotate_left) && !input.active(rotate_right) {
velocity.angvel = 0.;
}
} else {
@ -150,10 +150,10 @@ fn movement_controls<S, A: 'static>(
direction.y *= config.strafe_movement_factor;
}
let strength = if let (Some(forward), Some(backward), Some(left), Some(right)) = (
config.action_forward.clone(),
config.action_backward.clone(),
config.action_left.clone(),
config.action_right.clone(),
config.action_forward,
config.action_backward,
config.action_left,
config.action_right,
) {
let forward_x = input.strength(forward).abs();
let backward_x = input.strength(backward).abs();
@ -178,17 +178,19 @@ fn movement_controls<S, A: 'static>(
if let Some(strength) = strength {
direction *= strength;
}
let mut v: Vector<Real> = (direction * **speed).into();
v = position.position.rotation.transform_vector(&v);
let mut v = direction * **speed;
v = transform
.compute_matrix()
.transform_vector3(v.extend(0.))
.truncate();
velocity.linvel = v;
//velocity.linvel = position.position.rotation.transform_vector(&velocity.linvel);
} else if destination.is_none() {
velocity.linvel = Vec2::ZERO.into();
velocity.linvel = Vec2::ZERO;
**speed = 0.;
} else if sprinting {
**speed = **max_speed;
} else {
velocity.linvel = Vec2::ZERO.into();
velocity.linvel = Vec2::ZERO;
**speed = **max_speed / 3.;
}
}
@ -200,24 +202,17 @@ fn snap<S, A: 'static>(
input: Res<InputMap<A>>,
config: Res<NavigationConfig<S, A>>,
mut snapping: ResMut<Snapping>,
mut query: Query<
(
&mut RigidBodyPositionComponent,
&mut RigidBodyVelocityComponent,
&CardinalDirection,
),
With<Player>,
>,
mut query: Query<(&mut Transform, &mut Velocity, &CardinalDirection), With<Player>>,
) -> Result<(), Box<dyn Error>>
where
S: 'static + Clone + Debug + Eq + Hash + Send + Sync,
S: 'static + Copy + Debug + Eq + Hash + Send + Sync,
A: Hash + Eq + Clone + Send + Sync,
{
if let Some(action) = config.action_snap_left.clone() {
if input.just_active(action) {
for (mut position, mut velocity, direction) in query.iter_mut() {
**snapping = true;
position.position.rotation = UnitComplex::new(match direction {
position.rotation = Quat::from_rotation_z(match direction {
CardinalDirection::North => PI,
CardinalDirection::East => PI / 2.,
CardinalDirection::South => 0.,
@ -229,9 +224,9 @@ where
}
if let Some(action) = config.action_snap_right.clone() {
if input.just_active(action) {
for (mut position, mut velocity, direction) in query.iter_mut() {
for (mut transform, mut velocity, direction) in query.iter_mut() {
**snapping = true;
position.position.rotation = UnitComplex::new(match direction {
transform.rotation = Quat::from_rotation_z(match direction {
CardinalDirection::North => 0.,
CardinalDirection::East => PI * 1.5,
CardinalDirection::South => PI,
@ -243,11 +238,11 @@ where
}
if let Some(action) = config.action_snap_cardinal.clone() {
if input.just_active(action) {
for (mut position, mut velocity, direction) in query.iter_mut() {
for (mut transform, mut velocity, direction) in query.iter_mut() {
**snapping = true;
let yaw: Angle = direction.into();
let yaw = yaw.radians();
position.position.rotation = UnitComplex::new(yaw);
transform.rotation = Quat::from_rotation_z(yaw);
velocity.angvel = 0.;
tts.speak(direction.to_string(), true)?;
}
@ -255,9 +250,9 @@ where
}
if let Some(action) = config.action_snap_reverse.clone() {
if input.just_active(action) {
for (mut position, mut velocity, _) in query.iter_mut() {
for (mut transform, mut velocity, _) in query.iter_mut() {
**snapping = true;
position.position.rotation *= UnitComplex::new(PI);
transform.rotate(Quat::from_rotation_z(PI));
velocity.angvel = 0.;
}
}
@ -302,13 +297,10 @@ fn speak_direction(
Ok(())
}
fn remove_speed(
removed: RemovedComponents<Speed>,
mut query: Query<&mut RigidBodyVelocityComponent>,
) {
fn remove_speed(removed: RemovedComponents<Speed>, mut query: Query<&mut Velocity>) {
for entity in removed.iter() {
if let Ok(mut velocity) = query.get_mut(entity) {
velocity.linvel = Vec2::ZERO.into();
velocity.linvel = Vec2::ZERO;
}
}
}
@ -366,8 +358,8 @@ impl<'a, S, A> Default for NavigationPlugin<'a, S, A> {
impl<'a, S, A> Plugin for NavigationPlugin<'a, S, A>
where
S: 'static + Clone + Debug + Eq + Hash + Send + Sync,
A: Hash + Eq + Clone + Send + Sync,
S: 'static + Clone + Copy + Debug + Eq + Hash + Send + Sync,
A: Hash + Eq + Copy + Send + Sync,
'a: 'static,
{
fn build(&self, app: &mut App) {

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, marker::PhantomData};
use std::marker::PhantomData;
use bevy::{
ecs::entity::Entities,
@ -6,11 +6,10 @@ use bevy::{
tasks::{prelude::*, Task},
};
use bevy_rapier2d::{
na::UnitComplex,
na::{Isometry2, Vector2},
prelude::*,
rapier::data::{ComponentSet, ComponentSetOption, Index},
rapier::prelude::{ColliderHandle, ColliderSet, QueryPipeline},
};
use derive_more::{Deref, DerefMut};
use futures_lite::future;
use pathfinding::prelude::*;
@ -60,107 +59,14 @@ pub fn find_path<D: 'static + Clone + Default + Send + Sync>(
)
}
struct StaticColliderComponentsSet(
HashMap<Entity, (ColliderPosition, ColliderShape, ColliderFlags)>,
);
impl<'world, 'state>
From<(
&Query<
'world,
'state,
(
Entity,
&ColliderPositionComponent,
&ColliderShapeComponent,
&ColliderFlagsComponent,
),
>,
&Query<'world, 'state, &MapObstruction>,
)> for StaticColliderComponentsSet
{
fn from(
query: (
&Query<(
Entity,
&ColliderPositionComponent,
&ColliderShapeComponent,
&ColliderFlagsComponent,
)>,
&Query<&MapObstruction>,
),
) -> Self {
let entries = query
.0
.iter()
.filter(|(a, _, _, _)| query.1.get(*a).is_ok())
.map(|(a, b, c, d)| (a, **b, (*c).clone(), **d))
.collect::<Vec<(Entity, ColliderPosition, ColliderShape, ColliderFlags)>>();
let mut m = HashMap::new();
for (e, a, b, c) in entries {
m.insert(e, (a, b, c));
}
Self(m)
}
}
impl ComponentSet<ColliderShape> for StaticColliderComponentsSet {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, _f: impl FnMut(Index, &ColliderShape)) {
unimplemented!()
}
}
impl ComponentSetOption<ColliderShape> for StaticColliderComponentsSet {
fn get(&self, index: Index) -> Option<&ColliderShape> {
self.0.get(&index.entity()).map(|v| &v.1)
}
}
impl ComponentSet<ColliderFlags> for StaticColliderComponentsSet {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, _f: impl FnMut(Index, &ColliderFlags)) {
unimplemented!()
}
}
impl ComponentSetOption<ColliderFlags> for StaticColliderComponentsSet {
fn get(&self, index: Index) -> Option<&ColliderFlags> {
self.0.get(&index.entity()).map(|v| &v.2)
}
}
impl ComponentSet<ColliderPosition> for StaticColliderComponentsSet {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, _f: impl FnMut(Index, &ColliderPosition)) {
unimplemented!()
}
}
impl ComponentSetOption<ColliderPosition> for StaticColliderComponentsSet {
fn get(&self, index: Index) -> Option<&ColliderPosition> {
let v = self.0.get(&index.entity()).map(|v| &v.0);
v
}
}
fn find_path_for_shape<D: 'static + Clone + Default + Send + Sync>(
initiator: Entity,
initiator: ColliderHandle,
start: Coordinates,
destination: Destination,
query_pipeline: QueryPipeline,
map: Map<D>,
collider_set: StaticColliderComponentsSet,
shape: ColliderShape,
query_pipeline: QueryPipeline,
collider_set: ColliderSet,
shape: Collider,
) -> Option<Path> {
let path = astar(
&start.i32(),
@ -169,13 +75,13 @@ fn find_path_for_shape<D: 'static + Clone + Default + Send + Sync>(
if map.at(p.0 as usize, p.1 as usize).is_walkable() {
for tile in map.get_available_exits(p.0 as usize, p.1 as usize) {
let mut should_push = true;
let shape_pos = Isometry::new(vector![tile.0 as f32, tile.1 as f32], 0.);
let shape_pos = Isometry2::new(Vector2::new(tile.0 as f32, tile.1 as f32), 0.);
query_pipeline.intersections_with_shape(
&collider_set,
&shape_pos,
&*shape,
&*shape.raw,
InteractionGroups::all(),
Some(&|v| v.entity() != initiator),
Some(&|v| v != initiator),
|_handle| {
should_push = false;
false
@ -201,16 +107,21 @@ fn find_path_for_shape<D: 'static + Clone + Default + Send + Sync>(
fn calculate_path<D: 'static + Clone + Default + Send + Sync>(
mut commands: Commands,
pool: Res<AsyncComputeTaskPool>,
query_pipeline: Res<QueryPipeline>,
rapier_context: Res<RapierContext>,
obstructions: Query<&MapObstruction>,
collider_query: QueryPipelineColliderComponentsQuery,
query: Query<
(Entity, &Destination, &Coordinates, &ColliderShapeComponent),
(
Entity,
&RapierColliderHandle,
&Destination,
&Coordinates,
&Collider,
),
Changed<Destination>,
>,
map: Query<&Map<D>>,
) {
for (entity, destination, coordinates, shape) in query.iter() {
for (entity, handle, destination, coordinates, shape) in query.iter() {
if coordinates.i32() == **destination {
commands
.entity(entity)
@ -224,17 +135,18 @@ fn calculate_path<D: 'static + Clone + Default + Send + Sync>(
if let Ok(map) = map.get_single() {
let coordinates_clone = *coordinates;
let destination_clone = *destination;
let query_pipeline_clone = query_pipeline.clone();
let query_pipeline = rapier_context.query_pipeline.clone();
let map_clone = map.clone();
let handle_clone = *handle;
let collider_set = rapier_context.colliders.clone();
let shape_clone = (*shape).clone();
let collider_set: StaticColliderComponentsSet = (&collider_query, &obstructions).into();
let task = pool.spawn(async move {
find_path_for_shape(
entity,
handle_clone.0,
coordinates_clone,
destination_clone,
query_pipeline_clone,
map_clone,
query_pipeline,
collider_set,
shape_clone,
)
@ -278,18 +190,14 @@ fn negotiate_path(
mut query: Query<(
Entity,
&mut Path,
&mut RigidBodyPositionComponent,
&mut RigidBodyVelocityComponent,
&mut Transform,
&mut Velocity,
&Speed,
Option<&RotationSpeed>,
)>,
) {
for (entity, mut path, mut position, mut velocity, speed, rotation_speed) in query.iter_mut() {
let start_i32 = (
position.position.translation.x,
position.position.translation.y,
)
.i32();
for (entity, mut path, mut transform, mut velocity, speed, rotation_speed) in query.iter_mut() {
let start_i32 = (transform.translation.x, transform.translation.y).i32();
let mut new_path = path
.iter()
.cloned()
@ -298,19 +206,16 @@ fn negotiate_path(
new_path.retain(|v| *v != start_i32);
**path = new_path;
if let Some(next) = path.first() {
let start = Vec2::new(
position.position.translation.x,
position.position.translation.y,
);
let start = Vec2::new(transform.translation.x, transform.translation.y);
let next = Vec2::new(next.0 as f32 + 0.5, next.1 as f32 + 0.5);
let mut direction = next - start;
direction = direction.normalize();
direction *= **speed;
velocity.linvel = direction.into();
velocity.linvel = direction;
if rotation_speed.is_some() {
let v = next - start;
let angle = v.y.atan2(v.x);
position.position.rotation = UnitComplex::new(angle);
transform.rotation = Quat::from_rotation_z(angle);
}
continue;
} else {
@ -320,7 +225,7 @@ fn negotiate_path(
.remove::<NoPath>()
.remove::<Destination>()
.remove::<Speed>();
velocity.linvel = Vec2::ZERO.into();
velocity.linvel = Vec2::ZERO;
}
}
}

View File

@ -5,7 +5,6 @@ use bevy::prelude::*;
use crate::{
bevy_openal::{Listener, Sound},
commands::RunIfExistsExt,
derive_more::{Deref, DerefMut},
sound::SoundIcon,
};

View File

@ -8,9 +8,8 @@ use bevy::{
core::{FixedTimestep, FloatOrd},
prelude::*,
};
use bevy_rapier2d::na;
use bevy_rapier2d::na::{self, Point2};
use coord_2d::{Coord, Size};
use derive_more::{Deref, DerefMut};
use shadowcast::{vision_distance, Context, InputGrid};
use crate::{
@ -52,13 +51,13 @@ impl Viewshed {
pub fn is_point_visible(&self, point: &dyn PointLike) -> bool {
self.visible_points.contains(&point.into())
}
fn update<D: 'static + Clone + Default + Send + Sync>(
&mut self,
viewer_entity: &Entity,
visible_entities: &mut VisibleEntities,
start: &dyn PointLike,
query_pipeline: &QueryPipeline,
collider_query: &QueryPipelineColliderComponentsQuery,
rapier_context: &RapierContext,
map: &Map<D>,
visible_query: &Query<&Visible>,
events: &mut EventWriter<VisibilityChanged>,
@ -66,15 +65,14 @@ impl Viewshed {
) {
let mut context: Context<u8> = Context::default();
let vision_distance = vision_distance::Circle::new(self.range);
let shape = ColliderShape::cuboid(0.5, 0.5);
let origin = point!(start.x(), start.y());
let shape = Collider::cuboid(0.5, 0.5);
let origin = Point2::new(start.x(), start.y());
let coord = Coord::new(start.x_i32(), start.y_i32());
let collider_set = QueryPipelineColliderComponentsSet(collider_query);
let mut new_visible_entities = HashSet::new();
let visibility_grid = VisibilityGrid(
map,
RefCell::new(Box::new(|coord: Coord| {
let dest = point!(coord.x as f32 + 0.5, coord.y as f32 + 0.5);
let dest = Point2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5);
if let Some((opacity, entities)) = cache.get(&(FloatOrd(dest.x), FloatOrd(dest.y)))
{
for e in entities {
@ -95,17 +93,14 @@ impl Viewshed {
}
let mut opacity = 0;
let mut entities = HashSet::new();
let shape_pos = (Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5), 0.);
query_pipeline.intersections_with_shape(
&collider_set,
&shape_pos.into(),
&*shape,
let shape_pos = Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5);
rapier_context.intersections_with_shape(
shape_pos,
0.,
&shape,
InteractionGroups::all(),
Some(&|v| {
v.entity() != *viewer_entity && visible_query.get(v.entity()).is_ok()
}),
|handle| {
let entity = handle.entity();
Some(&|v| v != *viewer_entity && visible_query.get(v).is_ok()),
|entity| {
entities.insert(entity);
if let Ok(visible) = visible_query.get(entity) {
opacity = **visible;
@ -267,18 +262,7 @@ where
fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
mut commands: Commands,
config: Res<RapierConfiguration>,
positions: Query<
(
Entity,
Option<&RigidBodyPositionComponent>,
Option<&ColliderPositionComponent>,
Option<&LastCoordinates>,
),
Or<(
Changed<RigidBodyPositionComponent>,
Changed<ColliderPositionComponent>,
)>,
>,
positions: Query<(Entity, &Transform, Option<&LastCoordinates>), Changed<Transform>>,
visible: Query<&Visible>,
mut viewers: Query<(
Entity,
@ -288,30 +272,18 @@ fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
Option<&LastCoordinates>,
)>,
map: Query<&Map<D>>,
query_pipeline: Res<QueryPipeline>,
collider_query: QueryPipelineColliderComponentsQuery,
rapier_context: Res<RapierContext>,
mut changed: EventWriter<VisibilityChanged>,
) {
if !config.query_pipeline_active {
return;
}
let mut to_update = HashSet::new();
for (entity, body_position, collider_position, last_coordinates) in positions.iter() {
for (entity, transform, last_coordinates) in positions.iter() {
if to_update.contains(&entity) {
continue;
}
let coordinates = if let Some(body_position) = body_position {
(
body_position.position.translation.x,
body_position.position.translation.y,
)
} else {
let collider_position = collider_position.unwrap();
(
collider_position.translation.x,
collider_position.translation.y,
)
};
let coordinates = (transform.translation.x, transform.translation.y);
let coordinates_i32 = coordinates.i32();
if viewers.get_mut(entity).is_ok() {
commands.run_if_exists(entity, move |mut entity| {
@ -363,8 +335,7 @@ fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
&viewer_entity,
&mut visible_entities,
viewer_coordinates,
&*query_pipeline,
&collider_query,
&*rapier_context,
map,
&visible,
&mut changed,
@ -379,8 +350,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
removed: RemovedComponents<Visible>,
mut viewers: Query<(Entity, &mut Viewshed, &mut VisibleEntities, &Coordinates)>,
map: Query<&Map<D>>,
query_pipeline: Res<QueryPipeline>,
collider_query: QueryPipelineColliderComponentsQuery,
rapier_context: Res<RapierContext>,
visible: Query<&Visible>,
mut changed: EventWriter<VisibilityChanged>,
) {
@ -396,8 +366,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
&viewer_entity,
&mut visible_entities,
start,
&*query_pipeline,
&collider_query,
&*rapier_context,
map,
&visible,
&mut changed,
@ -431,14 +400,7 @@ fn log_visible(
mut events: EventReader<VisibilityChanged>,
mut log: Query<&mut Log>,
viewers: Query<(Entity, &Coordinates, &Transform), (With<Player>, With<Viewshed>)>,
visible: Query<
(
&Name,
Option<&RigidBodyPositionComponent>,
Option<&ColliderPositionComponent>,
),
Without<DontLogWhenVisible>,
>,
visible: Query<(&Name, &Transform), Without<DontLogWhenVisible>>,
) {
for timer in recently_lost.values_mut() {
timer.tick(time.delta());
@ -454,20 +416,14 @@ fn log_visible(
if *viewed == viewer_entity || recently_lost.contains_key(viewed) {
continue;
}
if let Ok((name, body_position, collider_position)) = visible.get(*viewed) {
let viewed_coordinates = if let Some(p) = body_position {
(p.position.translation.x, p.position.translation.y)
} else if let Some(p) = collider_position {
(p.translation.x, p.translation.y)
} else {
(0., 0.)
};
if let Ok((name, transform)) = visible.get(*viewed) {
let viewed_coordinates = (transform.translation.x, transform.translation.y);
let forward = viewer_transform.local_x();
let yaw = Angle::Radians(forward.y.atan2(forward.x));
let location =
viewer_coordinates.direction_and_distance(&viewed_coordinates, Some(yaw));
if let Ok(mut log) = log.get_single_mut() {
log.push(format!("{}: {location}", **name));
log.push(format!("{}: {location}", name));
}
}
} else if let VisibilityChanged::Lost { viewed, .. } = event {