Skip to content

Commit

Permalink
Towers now shoot rocks at enemies and the enemies die
Browse files Browse the repository at this point in the history
  • Loading branch information
rparrett committed Dec 7, 2023
1 parent 22d8d1f commit 6df924d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 10 deletions.
Binary file modified assets/urizen_onebit_tileset__v1d0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion src/enemy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl Plugin for EnemyPlugin {
fn build(&self, app: &mut App) {
app.add_event::<SpawnEnemyEvent>().add_systems(
Update,
(spawn, pathfinding, behavior, tick_cooldown, attack)
(spawn, pathfinding, behavior, tick_cooldown, attack, die)
.run_if(in_state(GameState::Playing)),
);
}
Expand Down Expand Up @@ -215,6 +215,18 @@ fn attack(
}
}

fn die(mut commands: Commands, query: Query<(Entity, &HitPoints), With<Enemy>>) {
for (entity, hp) in &query {
if !hp.is_zero() {
continue;
}

// TODO particle spam

commands.entity(entity).despawn();
}
}

fn tick_cooldown(mut query: Query<&mut AttackCooldown>, time: Res<Time>) {
for mut cooldown in &mut query {
cooldown.0.tick(time.delta());
Expand Down
1 change: 1 addition & 0 deletions src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
GameState,
};

/// This is the speed in "tiles lengths per second."
#[derive(Component)]
pub struct Speed(pub f32);
impl Default for Speed {
Expand Down
143 changes: 134 additions & 9 deletions src/tower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,123 @@ use bevy::prelude::*;

use crate::{
designate_tool::Designations,
tilemap::{AtlasHandle, TileEntities, TileKind, TilePos, Tilemap, SCALE},
enemy::Enemy,
hit_points::HitPoints,
movement::Speed,
tilemap::{AtlasHandle, TileEntities, TileKind, TilePos, Tilemap, SCALE, TILE_SIZE},
GameState,
};

pub struct TowerPlugin;
impl Plugin for TowerPlugin {
fn build(&self, app: &mut App) {
app.add_event::<BuildTowerEvent>()
.add_systems(Update, build_tower.run_if(in_state(GameState::Playing)));
app.add_event::<BuildTowerEvent>().add_systems(
Update,
(build_tower, attack, bullet_movement).run_if(in_state(GameState::Playing)),
);
}
}

#[derive(Component)]
pub struct Tower;

#[derive(Component, Default)]
struct Upgrades(u32);

#[derive(Component)]
struct CooldownTimer(Timer);

#[derive(Component)]
struct Range(f32);

#[derive(Component)]
struct Bullet {
damage: u32,
target: Entity,
}

#[derive(Bundle)]

pub struct TowerBundle {
sprite: SpriteSheetBundle,
tower: Tower,
kind: TileKind,
cooldown: CooldownTimer,
upgrades: Upgrades,
pos: TilePos,
range: Range,
}
impl Default for TowerBundle {
fn default() -> Self {
Self {
sprite: SpriteSheetBundle::default(),
tower: Tower,
kind: TileKind::Tower,
cooldown: CooldownTimer(Timer::from_seconds(1.0, TimerMode::Once)),
upgrades: Upgrades::default(),
pos: TilePos::default(),
range: Range(TILE_SIZE.x * SCALE.x * 2.),
}
}
}

#[derive(Bundle)]
pub struct BulletBundle {
sprite: SpriteSheetBundle,
bullet: Bullet,
speed: Speed,
}

#[derive(Event, Debug)]
pub struct BuildTowerEvent(pub TilePos);

fn attack(
mut commands: Commands,
mut query: Query<(&Transform, &Range, &Upgrades, &mut CooldownTimer), With<Tower>>,
time: Res<Time>,
enemies: Query<(Entity, &Transform), With<Enemy>>,
atlas_handle: Res<AtlasHandle>,
) {
for (transform, range, upgrades, mut timer) in &mut query {
timer.0.tick(time.delta());
if !timer.0.finished() {
continue;
}

let range_sq = range.0 * range.0;
let pos = transform.translation.truncate();

for (entity, enemy_transform) in &enemies {
let enemy_pos = enemy_transform.translation.truncate();
if pos.distance_squared(enemy_pos) > range_sq {
continue;
}

commands.spawn(BulletBundle {
sprite: SpriteSheetBundle {
texture_atlas: atlas_handle.0.clone(),
sprite: TextureAtlasSprite::new(103 * 49 + 52),
transform: Transform {
scale: SCALE.extend(1.),
translation: pos.extend(2.),
..default()
},
..default()
},
bullet: Bullet {
damage: 1 + upgrades.0,
target: entity,
},
speed: Speed(4.),
});

timer.0.reset();

break;
}
}
}

fn build_tower(
mut commands: Commands,
mut events: EventReader<BuildTowerEvent>,
Expand Down Expand Up @@ -53,8 +152,8 @@ fn build_tower(
}

let id = commands
.spawn((
SpriteSheetBundle {
.spawn(TowerBundle {
sprite: SpriteSheetBundle {
texture_atlas: atlas_handle.0.clone(),
sprite: TextureAtlasSprite::new(TileKind::Tower.atlas_index()),
transform: Transform {
Expand All @@ -64,10 +163,9 @@ fn build_tower(
},
..default()
},
Tower,
TileKind::Tower,
event.0.clone(),
))
pos: event.0.clone(),
..default()
})
.id();

*maybe_tile_entity = Some(id);
Expand All @@ -78,3 +176,30 @@ fn build_tower(
}
}
}

fn bullet_movement(
mut commands: Commands,
mut query: Query<(Entity, &Bullet, &Speed, &mut Transform)>,
mut enemy_query: Query<(&mut HitPoints, &Transform), (With<Enemy>, Without<Bullet>)>,
time: Res<Time>,
) {
for (bullet_entity, bullet, speed, mut transform) in query.iter_mut() {
if let Ok((mut hp, enemy)) = enemy_query.get_mut(bullet.target) {
let diff = enemy.translation.truncate() - transform.translation.truncate();
let dist = diff.length();
let dir = diff.normalize();
let step = time.delta_seconds() * speed.0 * TILE_SIZE.x * SCALE.x;

if dist > step {
transform.translation.x += step * dir.x;
transform.translation.y += step * dir.y;
} else {
hp.sub(bullet.damage);

commands.entity(bullet_entity).despawn_recursive();
}
} else {
commands.entity(bullet_entity).despawn_recursive();
}
}
}

0 comments on commit 6df924d

Please sign in to comment.