Skip to content

Commit 5ecbe42

Browse files
committed
Add enemies, sorta
1 parent 8b8ac36 commit 5ecbe42

19 files changed

+704
-487
lines changed

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ bevy-panic-handler = "3.0.0"
1212
avian3d = "0.1.2"
1313
leafwing-input-manager = "0.15.0"
1414
bevy_mod_billboard = "0.7.0"
15-
bevy-inspector-egui = "0.25.2"

src/game/enemy/components.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use bevy::prelude::*;
2+
3+
#[derive(Component)]
4+
pub struct Enemy {
5+
pub speed: f32,
6+
}
7+
8+
impl Default for Enemy {
9+
fn default() -> Self {
10+
Self { speed: 0.01 }
11+
}
12+
}

src/game/enemy/mod.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::AppState;
2+
use bevy::{animation::animate_targets, prelude::*};
3+
use systems::*;
4+
5+
pub mod components;
6+
pub mod resources;
7+
mod systems;
8+
9+
pub struct EnemyPlugin;
10+
11+
impl Plugin for EnemyPlugin {
12+
fn build(&self, app: &mut App) {
13+
app.add_systems(
14+
Update,
15+
enemies_once_loaded
16+
.before(animate_targets)
17+
.run_if(in_state(AppState::Game)),
18+
)
19+
.add_systems(
20+
Update,
21+
(enemies_update, enemies_animation).run_if(in_state(AppState::Game)),
22+
);
23+
}
24+
}

src/game/enemy/resources.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use bevy::prelude::*;
2+
3+
#[derive(Resource)]
4+
pub struct Animations {
5+
pub animations: Vec<AnimationNodeIndex>,
6+
#[allow(dead_code)]
7+
pub graph: Handle<AnimationGraph>,
8+
}

src/game/enemy/systems.rs

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use super::{components::Enemy, resources::Animations};
2+
use crate::game::player::components::Player;
3+
use avian3d::prelude::*;
4+
use bevy::prelude::*;
5+
use std::time::Duration;
6+
7+
pub fn enemies_once_loaded(
8+
mut commands: Commands,
9+
animations: Res<Animations>,
10+
mut players: Query<(Entity, &mut AnimationPlayer), Added<AnimationPlayer>>,
11+
) {
12+
for (entity, mut player) in &mut players {
13+
let mut transitions = AnimationTransitions::new();
14+
15+
// Make sure to start the animation via the `AnimationTransitions`
16+
// component. The `AnimationTransitions` component wants to manage all
17+
// the animations and will get confused if the animations are started
18+
// directly via the `AnimationPlayer`.
19+
transitions
20+
.play(&mut player, animations.animations[0], Duration::ZERO)
21+
.repeat();
22+
23+
commands
24+
.entity(entity)
25+
.insert(animations.graph.clone())
26+
.insert(transitions);
27+
}
28+
}
29+
30+
pub fn enemies_update(
31+
mut e_query: Query<(&mut Transform, &mut LinearVelocity, &Visibility, &Enemy), Without<Player>>,
32+
p_query: Query<&Transform, (With<Player>, Without<Enemy>)>,
33+
) {
34+
if let Ok(p_transform) = p_query.get_single() {
35+
for (mut e_transform, mut linear_velocity, visibility, enemy) in &mut e_query {
36+
if *visibility != Visibility::Hidden {
37+
e_transform.look_at(p_transform.translation, Vec3::Y);
38+
let direction = p_transform.translation - e_transform.translation;
39+
if direction.length() > 1.5 {
40+
let movement_direction = direction.normalize();
41+
linear_velocity.0 += movement_direction * enemy.speed;
42+
}
43+
// BlurTimer = 200;
44+
}
45+
}
46+
}
47+
}
48+
49+
pub fn enemies_animation(
50+
mut animation_players: Query<
51+
(
52+
&mut AnimationPlayer,
53+
&mut AnimationTransitions,
54+
&LinearVelocity,
55+
),
56+
With<Enemy>,
57+
>,
58+
animations: Res<Animations>,
59+
) {
60+
for (mut player, mut transitions, linear_velocity) in &mut animation_players {
61+
let current_animation = if linear_velocity.length() > 0.0 {
62+
animations.animations[1]
63+
} else {
64+
animations.animations[0]
65+
};
66+
67+
if !player.is_playing_animation(current_animation) {
68+
transitions
69+
.play(&mut player, current_animation, Duration::ZERO)
70+
.repeat();
71+
}
72+
}
73+
}

src/game/glimpse/components.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
use bevy::prelude::*;
2+
3+
#[derive(Component)]
4+
pub struct Glimpse;

src/game/glimpse/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use crate::AppState;
2+
use bevy::prelude::*;
3+
use systems::update_glimpses;
4+
5+
pub mod components;
6+
mod systems;
7+
8+
pub struct GlimpsePlugin;
9+
10+
impl Plugin for GlimpsePlugin {
11+
fn build(&self, app: &mut App) {
12+
app.add_systems(Update, update_glimpses.run_if(in_state(AppState::Game)));
13+
}
14+
}

src/game/glimpse/systems.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use super::components::Glimpse;
2+
use crate::{game::player::components::Player, resources::AudioAssets};
3+
use bevy::prelude::*;
4+
5+
#[allow(clippy::type_complexity)]
6+
pub fn update_glimpses(
7+
mut commands: Commands,
8+
audio_assets: Res<AudioAssets>,
9+
g_query: Query<(&Transform, Entity), (With<Glimpse>, Without<Player>)>,
10+
p_query: Query<(&Player, &Transform), Without<Glimpse>>,
11+
) {
12+
for (player, p_transform) in &p_query {
13+
for (g_transform, g_entity) in &g_query {
14+
if player.floor_index - 1 == ((-g_transform.translation.y - 0.5) / 2.0) as usize
15+
&& p_transform.translation.distance(Vec3::new(
16+
g_transform.translation.x,
17+
g_transform.translation.y,
18+
g_transform.translation.z,
19+
)) < 2.3
20+
{
21+
// TODO: Make a 3d audio
22+
commands.spawn(AudioBundle {
23+
source: audio_assets.no_sfx.clone(),
24+
settings: PlaybackSettings::DESPAWN,
25+
});
26+
27+
commands.entity(g_entity).despawn();
28+
}
29+
}
30+
}
31+
}

src/game/components.rs src/game/map/components.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
use bevy::prelude::*;
22

3-
#[derive(Component)]
4-
pub struct Glimpse;
5-
63
#[derive(Component)]
74
pub struct FloorLabelUi;
85

src/game/map/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use crate::AppState;
2+
use bevy::prelude::*;
3+
use resources::ObjectPool;
4+
use systems::*;
5+
6+
pub mod components;
7+
pub mod resources;
8+
pub mod systems;
9+
10+
pub const FLOOR_AMOUNT: usize = 210;
11+
12+
pub struct MapPlugin;
13+
14+
impl Plugin for MapPlugin {
15+
fn build(&self, app: &mut App) {
16+
app.insert_resource(ObjectPool::default())
17+
.add_systems(OnEnter(AppState::Game), spawn_map)
18+
.add_systems(Update, update_floors.run_if(in_state(AppState::Game)));
19+
}
20+
}

src/game/map_gen.rs src/game/map/resources.rs

+82-37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,80 @@
1-
use bevy::prelude::*;
1+
use super::FLOOR_AMOUNT;
2+
use crate::resources::MapAssets;
3+
use avian3d::prelude::*;
4+
use bevy::{prelude::*, utils::HashMap};
25
use bevy_rand::prelude::*;
3-
use rand::Rng;
6+
use rand::prelude::*;
7+
8+
#[derive(Resource, Default)]
9+
pub struct ObjectPool {
10+
available_rooms: HashMap<RoomType, Vec<Entity>>,
11+
pub active_rooms: HashMap<usize, Entity>,
12+
}
13+
14+
impl ObjectPool {
15+
pub fn get_or_spawn(
16+
&mut self,
17+
room_index: usize,
18+
room: &Room,
19+
commands: &mut Commands,
20+
map_assets: &Res<MapAssets>,
21+
transform: Transform,
22+
) -> Entity {
23+
// Check if the room is already active
24+
if let Some(&entity) = self.active_rooms.get(&room_index) {
25+
// Update the transform if the room is already active
26+
commands.entity(entity).insert(transform);
27+
return entity;
28+
}
29+
30+
// Get the available rooms list, or create an empty list if none exists
31+
let available_rooms = self.available_rooms.entry(room.kind).or_default();
32+
33+
let entity = if let Some(entity) = available_rooms.pop() {
34+
commands.entity(entity).insert(transform);
35+
entity
36+
} else {
37+
// Spawn a new entity if none are available
38+
let scene = match room.kind {
39+
RoomType::Map => map_assets.map.clone(),
40+
RoomType::Map0 => map_assets.map0.clone(),
41+
RoomType::Map1 => map_assets.map1.clone(),
42+
RoomType::Map2 => map_assets.map2.clone(),
43+
RoomType::Map3 => map_assets.map3.clone(),
44+
RoomType::Map4 => map_assets.map4.clone(),
45+
RoomType::Map5 => map_assets.map5.clone(),
46+
RoomType::Map6 => map_assets.map6.clone(),
47+
RoomType::Maze => map_assets.map7.clone(),
48+
};
49+
50+
let new_entity = commands
51+
.spawn((
52+
SceneBundle {
53+
scene,
54+
transform,
55+
..default()
56+
},
57+
ColliderConstructorHierarchy::new(Some(ColliderConstructor::TrimeshFromMesh)),
58+
RigidBody::Static,
59+
))
60+
.id();
61+
new_entity
62+
};
63+
64+
// Mark this room as active
65+
self.active_rooms.insert(room_index, entity);
66+
entity
67+
}
68+
69+
pub fn release(&mut self, room_index: usize, room_type: RoomType) {
70+
if let Some(entity) = self.active_rooms.remove(&room_index) {
71+
self.available_rooms
72+
.entry(room_type)
73+
.or_default()
74+
.push(entity);
75+
}
76+
}
77+
}
478

579
#[derive(PartialEq, Eq, Default, Clone, Copy, Debug)]
680
pub enum FloorAction {
@@ -57,15 +131,17 @@ pub struct Map {
57131
pub rooms: Vec<Room>,
58132
}
59133

60-
impl Map {
61-
pub fn new(floor_amount: usize) -> Self {
134+
impl Default for Map {
135+
fn default() -> Self {
62136
Self {
63-
floor_amount,
64-
floors: vec![Floor::default(); floor_amount],
137+
floor_amount: FLOOR_AMOUNT,
138+
floors: vec![Floor::default(); FLOOR_AMOUNT],
65139
rooms: Default::default(),
66140
}
67141
}
142+
}
68143

144+
impl Map {
69145
pub fn generate(&mut self, rng: &mut ResMut<GlobalEntropy<WyRand>>) {
70146
self.assign_floor_action(1, FloorAction::Proceed, 1.0);
71147

@@ -245,34 +321,3 @@ impl Map {
245321
[above_room, current_room, bottom_room]
246322
}
247323
}
248-
249-
pub fn floor_transform(i: usize) -> Transform {
250-
let mut transform = Transform::default();
251-
252-
if (i as f32 / 2.0).floor() == (i as f32 / 2.0).ceil() {
253-
// parillinen
254-
transform.translation = Vec3::new(0.0, -(i as f32) * 2.0, 0.0);
255-
} else {
256-
// pariton
257-
transform.rotate_y(f32::to_radians(180.0));
258-
transform.translation = Vec3::new(8.0, -(i as f32) * 2.0, 7.0);
259-
}
260-
261-
transform
262-
}
263-
264-
pub fn room_label_transform(i: usize) -> Transform {
265-
let mut transform = Transform {
266-
rotation: Quat::from_rotation_x(f32::to_radians(-90.0)),
267-
..default()
268-
};
269-
270-
if (i as f32 / 2.0).floor() == (i as f32 / 2.0).ceil() {
271-
transform.translation = Vec3::new(-0.24, -(i as f32) * 2.0 - 0.6, 0.5);
272-
transform.rotate_y(f32::to_radians(180.0));
273-
} else {
274-
transform.translation = Vec3::new(7.4 + 0.6 + 0.24, -(i as f32) * 2.0 - 0.6, 6.0 + 0.5);
275-
}
276-
277-
transform
278-
}

0 commit comments

Comments
 (0)