Compare commits
5 Commits
afca116394
...
f19beaa73a
Author | SHA1 | Date | |
---|---|---|---|
f19beaa73a | |||
65c9c6db46 | |||
03d963bed4 | |||
0accbb4789 | |||
3d000a4d7f |
21
Cargo.toml
21
Cargo.toml
|
@ -13,25 +13,14 @@ speech_dispatcher_0_9 = ["bevy_tts/speech_dispatcher_0_9"]
|
||||||
speech_dispatcher_0_10 = ["bevy_tts/speech_dispatcher_0_10"]
|
speech_dispatcher_0_10 = ["bevy_tts/speech_dispatcher_0_10"]
|
||||||
speech_dispatcher_0_11 = ["bevy_tts/speech_dispatcher_0_11"]
|
speech_dispatcher_0_11 = ["bevy_tts/speech_dispatcher_0_11"]
|
||||||
|
|
||||||
[dependencies.bevy]
|
|
||||||
version = "0.13"
|
|
||||||
default-features = false
|
|
||||||
features = [
|
|
||||||
"bevy_gilrs",
|
|
||||||
"bevy_winit",
|
|
||||||
"x11",
|
|
||||||
"wayland",
|
|
||||||
"multi-threaded",
|
|
||||||
"serialize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_rapier2d = "0.25"
|
bevy = "0.14"
|
||||||
bevy_synthizer = "0.6"
|
bevy_rapier2d = "0.27"
|
||||||
bevy_tts = { version = "0.8", default-features = false, features = ["tolk"] }
|
bevy_synthizer = "0.7"
|
||||||
|
bevy_tts = { version = "0.9", default-features = false, features = ["tolk"] }
|
||||||
coord_2d = "0.3"
|
coord_2d = "0.3"
|
||||||
here_be_dragons = { version = "0.3", features = ["serde"] }
|
here_be_dragons = { version = "0.3", features = ["serde"] }
|
||||||
leafwing-input-manager = "0.13"
|
leafwing-input-manager = "0.14"
|
||||||
maze_generator = "2"
|
maze_generator = "2"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
pathfinding = "4"
|
pathfinding = "4"
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
sync::RwLock,
|
sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::{app::PluginGroupBuilder, prelude::*, utils::FloatOrd};
|
use bevy::{app::PluginGroupBuilder, math::FloatOrd, prelude::*};
|
||||||
use bevy_rapier2d::{
|
use bevy_rapier2d::{
|
||||||
parry::query::{closest_points, distance, ClosestPoints},
|
parry::query::{closest_points, distance, ClosestPoints},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
|
131
src/map.rs
131
src/map.rs
|
@ -82,8 +82,7 @@ impl ITileType for Tile {
|
||||||
pub struct PortalBundle {
|
pub struct PortalBundle {
|
||||||
pub portal: Portal,
|
pub portal: Portal,
|
||||||
pub mappable: Mappable,
|
pub mappable: Mappable,
|
||||||
pub transform: Transform,
|
pub transform: TransformBundle,
|
||||||
pub global_transform: GlobalTransform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Bundle, Clone, Default)]
|
#[derive(Bundle, Clone, Default)]
|
||||||
|
@ -91,8 +90,75 @@ pub struct MapBundle<D: 'static + Clone + Default + Send + Sync> {
|
||||||
pub map: Map<D>,
|
pub map: Map<D>,
|
||||||
pub spawn_colliders: SpawnColliders,
|
pub spawn_colliders: SpawnColliders,
|
||||||
pub spawn_portals: SpawnPortals,
|
pub spawn_portals: SpawnPortals,
|
||||||
pub transform: Transform,
|
pub transform: TransformBundle,
|
||||||
pub global_transform: GlobalTransform,
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle, Clone, Debug)]
|
||||||
|
pub struct TileBundle {
|
||||||
|
pub transform: TransformBundle,
|
||||||
|
pub collider: Collider,
|
||||||
|
pub rigid_body: RigidBody,
|
||||||
|
pub active_collision_types: ActiveCollisionTypes,
|
||||||
|
pub map_obstruction: MapObstruction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TileBundle {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
transform: default(),
|
||||||
|
collider: Collider::cuboid(0.5, 0.5),
|
||||||
|
rigid_body: RigidBody::Fixed,
|
||||||
|
active_collision_types: ActiveCollisionTypes::default()
|
||||||
|
| ActiveCollisionTypes::KINEMATIC_STATIC
|
||||||
|
| ActiveCollisionTypes::DYNAMIC_STATIC,
|
||||||
|
map_obstruction: MapObstruction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TileBundle {
|
||||||
|
pub fn new(x: i32, y: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
transform: Transform::from_xyz(x as f32 + 0.5, y as f32 + 0.5, 0.).into(),
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle, Clone, Debug)]
|
||||||
|
pub struct ZoneBundle {
|
||||||
|
pub collider: Collider,
|
||||||
|
pub transform: TransformBundle,
|
||||||
|
pub area: Area,
|
||||||
|
pub zone: Zone,
|
||||||
|
pub sensor: Sensor,
|
||||||
|
pub active_events: ActiveEvents,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZoneBundle {
|
||||||
|
fn new(collider: Collider, position: (f32, f32)) -> Self {
|
||||||
|
let point = Isometry2::new(Vector2::new(position.0, position.1), 0.);
|
||||||
|
let aabb = collider.raw.compute_aabb(&point);
|
||||||
|
Self {
|
||||||
|
collider,
|
||||||
|
area: Area(aabb),
|
||||||
|
transform: Transform::from_translation(Vec3::new(position.0, position.1, 0.)).into(),
|
||||||
|
zone: default(),
|
||||||
|
sensor: default(),
|
||||||
|
active_events: ActiveEvents::COLLISION_EVENTS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&MRect> for ZoneBundle {
|
||||||
|
fn from(rect: &MRect) -> Self {
|
||||||
|
let collider = Collider::cuboid(
|
||||||
|
rect.width() as f32 / 2. + 0.5,
|
||||||
|
rect.height() as f32 / 2. + 0.5,
|
||||||
|
);
|
||||||
|
let position = (rect.center().x(), rect.center().y());
|
||||||
|
Self::new(collider, position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GridBuilder {
|
pub struct GridBuilder {
|
||||||
|
@ -125,14 +191,13 @@ impl<D: Clone + Default> MapFilter<D> for GridBuilder {
|
||||||
if let Ok(maze) =
|
if let Ok(maze) =
|
||||||
generator.generate(self.width_in_rooms as i32, self.height_in_rooms as i32)
|
generator.generate(self.width_in_rooms as i32, self.height_in_rooms as i32)
|
||||||
{
|
{
|
||||||
let total_height = (self.room_height + 1) * self.height_in_rooms + 1;
|
let total_height = self.room_height * self.height_in_rooms + self.height_in_rooms + 1;
|
||||||
let half_width = self.room_width / 2;
|
let half_width = self.room_width / 2;
|
||||||
let half_height = self.room_height / 2;
|
let half_height = self.room_height / 2;
|
||||||
for y in 0..self.height_in_rooms {
|
for y in 0..self.height_in_rooms {
|
||||||
for x in 0..self.width_in_rooms {
|
for x in 0..self.width_in_rooms {
|
||||||
let x_offset = x * (self.room_width + 1);
|
let x_offset = x * (self.room_width + 1);
|
||||||
let y_offset =
|
let y_offset = total_height - (y + 1) * (self.room_height + 1) - 1;
|
||||||
total_height - (y * (self.room_height + 1)) - self.room_height - 2;
|
|
||||||
let room = MRect::new_i32(
|
let room = MRect::new_i32(
|
||||||
x_offset as i32 + 1,
|
x_offset as i32 + 1,
|
||||||
y_offset as i32 + 1,
|
y_offset as i32 + 1,
|
||||||
|
@ -190,21 +255,7 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
|
||||||
for x in 0..map.width {
|
for x in 0..map.width {
|
||||||
if let Some(tile) = map.at(x, y) {
|
if let Some(tile) = map.at(x, y) {
|
||||||
if tile.blocks_motion() {
|
if tile.blocks_motion() {
|
||||||
let id = commands
|
let id = commands.spawn(TileBundle::new(x as i32, y as i32)).id();
|
||||||
.spawn((
|
|
||||||
RigidBody::Fixed,
|
|
||||||
TransformBundle::from_transform(Transform::from_xyz(
|
|
||||||
x as f32 + 0.5,
|
|
||||||
y as f32 + 0.5,
|
|
||||||
0.,
|
|
||||||
)),
|
|
||||||
Collider::cuboid(0.5, 0.5),
|
|
||||||
ActiveCollisionTypes::default()
|
|
||||||
| ActiveCollisionTypes::KINEMATIC_STATIC
|
|
||||||
| ActiveCollisionTypes::DYNAMIC_STATIC,
|
|
||||||
MapObstruction,
|
|
||||||
))
|
|
||||||
.id();
|
|
||||||
if tile.blocks_visibility() {
|
if tile.blocks_visibility() {
|
||||||
commands.entity(id).insert(Visible::opaque());
|
commands.entity(id).insert(Visible::opaque());
|
||||||
}
|
}
|
||||||
|
@ -214,26 +265,8 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for room in &map.rooms {
|
for room in &map.rooms {
|
||||||
let shape = Collider::cuboid(
|
|
||||||
(room.width() / 2) as f32 + 0.5,
|
|
||||||
(room.height() / 2) as f32 + 0.5,
|
|
||||||
);
|
|
||||||
let position =
|
|
||||||
Isometry2::new(Vector2::new(room.center().x(), room.center().y()), 0.);
|
|
||||||
let aabb = shape.raw.compute_aabb(&position);
|
|
||||||
commands.entity(map_entity).with_children(|parent| {
|
commands.entity(map_entity).with_children(|parent| {
|
||||||
parent.spawn((
|
parent.spawn(ZoneBundle::from(room));
|
||||||
TransformBundle::from_transform(Transform::from_xyz(
|
|
||||||
position.translation.x,
|
|
||||||
position.translation.y,
|
|
||||||
0.,
|
|
||||||
)),
|
|
||||||
shape,
|
|
||||||
Sensor,
|
|
||||||
ActiveEvents::COLLISION_EVENTS,
|
|
||||||
Area(aabb),
|
|
||||||
Zone,
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,21 +281,19 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
|
||||||
if **spawn_portals {
|
if **spawn_portals {
|
||||||
commands.entity(map_entity).remove::<SpawnPortals>();
|
commands.entity(map_entity).remove::<SpawnPortals>();
|
||||||
let mut portals: Vec<(f32, f32)> = vec![];
|
let mut portals: Vec<(f32, f32)> = vec![];
|
||||||
for x in 1..map.width {
|
for x in 0..map.width {
|
||||||
for y in 1..map.height {
|
for y in 0..map.height {
|
||||||
|
let idx = (x, y).to_index(map.width);
|
||||||
let mut spawn_portal = false;
|
let mut spawn_portal = false;
|
||||||
if map.get_available_exits(x, y).len() > 2 {
|
if map.get_available_exits(x, y).len() > 2 && map.tiles[idx].is_walkable() {
|
||||||
let idx = (x, y).to_index(map.width);
|
if (x > 1 && map.tiles[idx - 1].is_walkable())
|
||||||
if map.tiles[idx].is_walkable()
|
|
||||||
&& (x > 1 && map.tiles[idx - 1].is_walkable())
|
|
||||||
&& (x < map.width - 2 && map.tiles[idx + 1].is_walkable())
|
&& (x < map.width - 2 && map.tiles[idx + 1].is_walkable())
|
||||||
&& (y > 1 && map.tiles[idx - map.width].is_blocked())
|
&& (y > 1 && map.tiles[idx - map.width].is_blocked())
|
||||||
&& (y < map.height - 2 && map.tiles[idx + map.width].is_blocked())
|
&& (y < map.height - 2 && map.tiles[idx + map.width].is_blocked())
|
||||||
{
|
{
|
||||||
spawn_portal = true;
|
spawn_portal = true;
|
||||||
}
|
}
|
||||||
if map.tiles[idx].is_walkable()
|
if (x > 1 && map.tiles[idx - 1].is_blocked())
|
||||||
&& (x > 1 && map.tiles[idx - 1].is_blocked())
|
|
||||||
&& (x < map.width - 2 && map.tiles[idx + 1].is_blocked())
|
&& (x < map.width - 2 && map.tiles[idx + 1].is_blocked())
|
||||||
&& (y > 1 && map.tiles[idx - map.width].is_walkable())
|
&& (y > 1 && map.tiles[idx - map.width].is_walkable())
|
||||||
&& (y < map.height - 2 && map.tiles[idx + map.width].is_walkable())
|
&& (y < map.height - 2 && map.tiles[idx + map.width].is_walkable())
|
||||||
|
@ -282,7 +313,7 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
|
||||||
for (x, y) in portals {
|
for (x, y) in portals {
|
||||||
commands.entity(map_entity).with_children(|parent| {
|
commands.entity(map_entity).with_children(|parent| {
|
||||||
parent.spawn(PortalBundle {
|
parent.spawn(PortalBundle {
|
||||||
transform: Transform::from_translation(Vec3::new(x, y, 0.)),
|
transform: Transform::from_translation(Vec3::new(x, y, 0.)).into(),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -237,8 +237,10 @@ fn controls(
|
||||||
transform.yaw().radians(),
|
transform.yaw().radians(),
|
||||||
vel,
|
vel,
|
||||||
collider,
|
collider,
|
||||||
1.,
|
ShapeCastOptions {
|
||||||
true,
|
max_time_of_impact: 1.,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
QueryFilter::new()
|
QueryFilter::new()
|
||||||
.exclude_sensors()
|
.exclude_sensors()
|
||||||
.exclude_collider(entity),
|
.exclude_collider(entity),
|
||||||
|
|
|
@ -312,8 +312,10 @@ fn negotiate_path(
|
||||||
transform.yaw().radians(),
|
transform.yaw().radians(),
|
||||||
direction,
|
direction,
|
||||||
collider,
|
collider,
|
||||||
1.,
|
ShapeCastOptions {
|
||||||
true,
|
max_time_of_impact: 1.,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
QueryFilter::new()
|
QueryFilter::new()
|
||||||
.exclude_sensors()
|
.exclude_sensors()
|
||||||
.exclude_collider(entity),
|
.exclude_collider(entity),
|
||||||
|
@ -404,7 +406,7 @@ impl Plugin for PathfindingPlugin {
|
||||||
.register_type::<Path>()
|
.register_type::<Path>()
|
||||||
.register_type::<CostMap>()
|
.register_type::<CostMap>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
FixedPreUpdate,
|
||||||
(poll_tasks, apply_deferred, negotiate_path).chain(),
|
(poll_tasks, apply_deferred, negotiate_path).chain(),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
@ -413,6 +415,6 @@ impl Plugin for PathfindingPlugin {
|
||||||
.chain()
|
.chain()
|
||||||
.after(InputManagerSystem::Tick),
|
.after(InputManagerSystem::Tick),
|
||||||
)
|
)
|
||||||
.add_systems(PostUpdate, remove_destination);
|
.add_systems(FixedPostUpdate, remove_destination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn tag_behind(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let v = transform.translation() - listener_transform.translation();
|
let v = transform.translation() - listener_transform.translation();
|
||||||
let dot = v.dot(listener_forward);
|
let dot = v.dot(*listener_forward);
|
||||||
let is_behind = dot <= 0.;
|
let is_behind = dot <= 0.;
|
||||||
if is_behind {
|
if is_behind {
|
||||||
commands.entity(entity).insert(Behind);
|
commands.entity(entity).insert(Behind);
|
||||||
|
|
|
@ -430,13 +430,13 @@ impl<MapData: 'static + Clone + Default + Send + Sync> Plugin for VisibilityPlug
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<VisibilityChanged>()
|
app.add_event::<VisibilityChanged>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
FixedPreUpdate,
|
||||||
(
|
(
|
||||||
add_visibility_indices::<MapData>,
|
add_visibility_indices::<MapData>,
|
||||||
update_viewshed,
|
update_viewshed,
|
||||||
update_revealed_tiles::<MapData>,
|
update_revealed_tiles::<MapData>,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.add_systems(PostUpdate, (log_visible, viewshed_removed, remove_visible));
|
.add_systems(FixedPostUpdate, (log_visible, viewshed_removed, remove_visible));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user