Skip to content

Commit

Permalink
feat: add portals
Browse files Browse the repository at this point in the history
  • Loading branch information
regnarock committed Sep 21, 2024
1 parent 7b908f8 commit 243674a
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 196 deletions.
4 changes: 2 additions & 2 deletions src/board/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use bevy::{
};
use bevy_mod_picking::prelude::*;

use crate::{actions::cursor::CursorScreenPos, enemy::SpawnEnemy, GameState};
use crate::{actions::cursor::CursorScreenPos, enemy::SpawnEnemyCmd, GameState};

use self::{
image::BoardRenderImage,
Expand Down Expand Up @@ -71,7 +71,7 @@ pub fn spawn_enemy_on_click(
_click: Listener<Pointer<Click>>,
mycoords: Res<CursorScreenPos>,
) {
commands.add(SpawnEnemy {
commands.add(SpawnEnemyCmd {
position: mycoords.0,
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/bullet.rs → src/entities/bullet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::{ecs::system::Command, prelude::*};

use crate::{
enemy::Enemy,
entities::enemy::Enemy,
primitives::{
destructible::Damage,
movable::{move_towards_target, AutoMovable},
Expand All @@ -10,7 +10,7 @@ use crate::{
GameState,
};

pub struct BulletPlugin;
pub(super) struct BulletPlugin;

impl Plugin for BulletPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
Expand Down
4 changes: 2 additions & 2 deletions src/crystal.rs → src/entities/crystal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use bevy::{
transform::components::Transform,
};

use crate::{enemy::Enemy, GameState};
use crate::{entities::enemy::Enemy, GameState};

pub struct CrystalPlugin;
pub(super) struct CrystalPlugin;

impl Plugin for CrystalPlugin {
fn build(&self, app: &mut App) {
Expand Down
24 changes: 12 additions & 12 deletions src/enemy.rs → src/entities/enemy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use bevy::{
};
use rand::{seq::SliceRandom, thread_rng};

pub struct EnemyPlugin;
pub(super) struct EnemyPlugin;

// TODO: make this a config resource
const FIXED_TIMESTEP: f32 = 0.1;
Expand Down Expand Up @@ -61,11 +61,11 @@ pub struct EnemyAnimation(Vec<Handle<Image>>);
#[derive(Event)]
pub struct EventSpawnedEnemy(pub Entity);

pub struct SpawnEnemy {
pub struct SpawnEnemyCmd {
pub position: Vec2,
}

impl Command for SpawnEnemy {
impl Command for SpawnEnemyCmd {
fn apply(self, world: &mut World) {
let mut textures: Vec<Handle<Image>> = Vec::new();
// TODO: make this a resource
Expand Down Expand Up @@ -132,24 +132,24 @@ pub fn move_towards_center(
for enemy in &mut enemies {
let mut all_neighbors = grid
.layout
.world_pos_to_hex(enemy.transform.translation.xy())
.world_pos_to_hex(enemy.global_transform.compute_transform().translation.xy())
.all_neighbors();
all_neighbors.shuffle(&mut thread_rng());
let target_position = all_neighbors
.iter()
.filter_map(|hex| {
grid.entities
.get(hex)
grid.hex_to_entity(hex)
.and_then(|e| hexes.get(*e).ok().map(|cell| (hex, cell.dist)))
})
.min_by(|(_, dist1), (_, dist2)| dist1.cmp(dist2));

if let Some((target_hex, _dist)) = target_position {
let hex_entity = grid.entities[target_hex];
commands.entity(enemy.entity).insert((
Target::new(hex_entity, OnTargetDespawned::DoNothing),
AutoLookAtTarget,
));
if let Some(hex_entity) = grid.hex_to_entity(target_hex) {
commands.entity(enemy.entity).insert((
Target::new(*hex_entity, OnTargetDespawned::DoNothing),
AutoLookAtTarget,
));
}
}
}
}
Expand All @@ -163,7 +163,7 @@ pub fn remove_reached_target(
let distance = target
.transform
.translation
.distance(enemy.transform.translation);
.distance(enemy.global_transform.translation());
if distance <= TARGET_REACHED_EPSILON {
commands.entity(enemy.entity).remove::<Target>();
}
Expand Down
26 changes: 26 additions & 0 deletions src/entities/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use bevy::prelude::*;
use bullet::BulletPlugin;
use crystal::CrystalPlugin;
use enemy::EnemyPlugin;
use portal::PortalsPlugin;
use turret::TurretPlugin;

pub mod bullet;
pub mod crystal;
pub mod enemy;
pub mod portal;
pub mod turret;

pub(super) struct EntityPlugin;

impl Plugin for EntityPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
BulletPlugin,
CrystalPlugin,
EnemyPlugin,
PortalsPlugin,
TurretPlugin,
));
}
}
88 changes: 88 additions & 0 deletions src/entities/portal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::time::Duration;

use bevy::{ecs::system::EntityCommand, prelude::*};

use crate::{entities::enemy::SpawnEnemyCmd, loading::TextureAssets, GameState};

pub(super) struct PortalsPlugin;

impl Plugin for PortalsPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(
Update,
(update_all_portals).run_if(in_state(GameState::Playing)),
);
}
}

#[derive(Component)]
pub struct Portal {
// track when to spawn a new enemy
timer: Timer,
capacity: u32,
delay_ms: Duration,
spawn_pattern: SpawnPattern,
}

pub enum SpawnPattern {
Slow,
Immediate,
}

pub fn update_all_portals(
mut command: Commands,
mut portals: Query<(&mut Portal, &GlobalTransform, Entity)>,
time: Res<Time>,
) {
portals.for_each_mut(|mut portal| {
portal.0.timer.tick(time.delta());
if portal.0.timer.just_finished() {
spawn_enemy(&mut command, portal);
}
});
}

fn spawn_enemy(command: &mut Commands, mut portal: (Mut<Portal>, &GlobalTransform, Entity)) {
command.add(SpawnEnemyCmd {
position: portal.1.translation().xy(),
});
portal.0.capacity -= 1;
// despawn immediatly the portal if it was the last enemy to spawn
// TODO: special closing animation?
if portal.0.capacity < 1 {
command.entity(portal.2).remove_parent().despawn();
}
}

pub struct SpawnPortalCmd {
pub parent_hex: Entity,
}

impl EntityCommand for SpawnPortalCmd {
fn apply(self, id: Entity, world: &mut World) {
world.resource_scope(|world, texture_assets: Mut<TextureAssets>| {
println!("Spawning a new portal");
let spawn_delay_ms = Duration::from_millis(3000);
world
.entity_mut(id)
.insert((
SpriteBundle {
transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)),
texture: texture_assets.portal.clone_weak(),
..Default::default()
},
Portal {
capacity: 2,
delay_ms: spawn_delay_ms,
timer: Timer::new(spawn_delay_ms, TimerMode::Repeating),
spawn_pattern: SpawnPattern::Immediate,
},
Name::new("Portal"),
))
.set_parent(self.parent_hex);
});
}
}

#[derive(Event)]
pub struct EventDespawnedPortal(pub Entity);
59 changes: 31 additions & 28 deletions src/turret.rs → src/entities/turret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use std::{f32::consts::FRAC_PI_2, time::Duration};

use crate::{
buildings::{self, BuildingInventory},
bullet::SpawnBullet,
enemy::Enemy,
grid::HexGrid,
entities::{bullet::SpawnBullet, enemy::Enemy},
grid::{HexCell, HexGrid},
primitives::{
target::{SourceWithTargetAccessor, Target},
view::{
Expand All @@ -21,7 +20,7 @@ use bevy::{
};
use bevy_easings::{Ease, EaseFunction};

pub struct TurretPlugin;
pub(super) struct TurretPlugin;

impl Plugin for TurretPlugin {
fn build(&self, app: &mut App) {
Expand All @@ -43,9 +42,7 @@ impl Plugin for TurretPlugin {
}

#[derive(Component)]
pub struct Turret {
pub parent_hex: Entity,
}
pub struct Turret;

#[derive(Event)]
pub struct EventSpawnedTower(pub Entity);
Expand All @@ -64,12 +61,11 @@ impl AutoGun {
}
}

pub struct SpawnTurret {
pub position: Vec2,
pub at_hex: Entity,
pub struct SpawnTurretCmd {
pub parent_hex: Entity,
}

impl EntityCommand for SpawnTurret {
impl EntityCommand for SpawnTurretCmd {
fn apply(self, id: Entity, world: &mut World) {
// TODO: attach building to the turret
let _building =
Expand All @@ -86,19 +82,18 @@ impl EntityCommand for SpawnTurret {
.entity_mut(id)
.insert((
SpriteBundle {
transform: Transform::from_xyz(self.position.x, self.position.y, 0.)
.with_scale(Vec3::new(0.5, 0.5, 1.)),
transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)),
texture,
..Default::default()
},
Turret {
parent_hex: self.at_hex,
},
Turret,
Name::new("Turret"),
AutoGun::new(1.),
View::new(2. * hex_radius),
))
.set_parent(self.parent_hex)
.id();
// FIXME: Not sure this is useful since there is bevy::event::Changed<Turret> that could do the same thing?
let mut q_event: SystemState<EventWriter<EventSpawnedTower>> = SystemState::new(world);

let mut event_writer = q_event.get_mut(world);
Expand All @@ -112,14 +107,16 @@ pub fn animate_targeting(
) {
for turret in &accessor.srcs_query {
if let Ok(enemy) = accessor.targets_query.get(turret.target.entity) {
let direction = enemy.transform.translation - turret.transform.translation;
let direction = enemy.transform.translation - turret.global_transform.translation();
// TODO: FRAC_PI_2 is a bit hacky, because the turret asset is rotated by 90 degrees
let angle = direction.y.atan2(direction.x) + FRAC_PI_2;

commands
.entity(turret.entity)
.insert((turret.transform.ease_to(
turret.transform.with_rotation(Quat::from_rotation_z(angle)),
.insert((turret.local_transform.ease_to(
turret
.local_transform
.with_rotation(Quat::from_rotation_z(angle)),
EaseFunction::QuadraticOut,
bevy_easings::EasingType::Once {
duration: Duration::from_millis(500),
Expand Down Expand Up @@ -155,18 +152,24 @@ pub fn process_enemy_exit_range(
pub fn auto_fire(
mut commands: Commands,
// make sure that the turret has a target and is in view
mut turrets_query: Query<(&Transform, &Target, &mut AutoGun), (With<Turret>, With<View>)>,
mut turrets_query: Query<
(&Transform, &Target, &mut AutoGun, &Parent),
(With<Turret>, With<View>),
>,
hex_query: Query<&Transform, (Without<Turret>, With<HexCell>)>,
time: Res<Time>,
) {
for (transform, target, mut gun) in &mut turrets_query {
for (global_transform, target, mut gun, parent) in &mut turrets_query {
if gun.next_shot.tick(time.delta()).just_finished() {
let spaw_bullet = SpawnBullet {
position: transform.translation,
velocity: 200.,
damage: 1.,
target: target.entity,
};
commands.add(spaw_bullet);
if let Ok(transform) = hex_query.get(parent.get()) {
let spaw_bullet = SpawnBullet {
position: transform.translation,
velocity: 200.,
damage: 1.,
target: target.entity,
};
commands.add(spaw_bullet);
}
}
}
}
2 changes: 1 addition & 1 deletion src/game_over.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy::prelude::*;

use crate::{crystal::CrystalTouched, overload::OverloadDepleted};
use crate::{entities::crystal::CrystalTouched, overload::OverloadDepleted};

pub struct GameOverPlugin;

Expand Down
Loading

0 comments on commit 243674a

Please sign in to comment.