Skip to content

Added a way to fire off multiple lazers after a certain cooldown #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub const PLAYER_SPAWN_DURATION: f32 = 0.1;

pub const LAZER_SPEED: f32 = 1250.0;
pub const LAZER_PARTICLE_INTERVAL: f32 = 0.02; // Duration in seconds between particles
pub const LAZER_FIRING_INTERVAL: f32 = 0.5; // Cooldown for lazers

pub const SCENE_WIDTH: f32 = RES_X / 2.0 - 100.0;
pub const SCENE_HEIGHT: f32 = RES_Y / 2.0 - 50.0;
Expand Down
11 changes: 9 additions & 2 deletions src/game_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
audio::PlayMusicEvent,
bunker::{self, Bunker},
common::*,
lazer::{LazerData}
};
use bevy::prelude::*;
use std::{default::Default, time::Duration};
Expand All @@ -29,6 +30,8 @@ pub struct Store {
pub lives: u8,
pub player_count_down: f32,
pub game_state: GameState,
pub lazers: Vec<LazerData>,
pub lazer_interval: f32,
pub show_state: bool,
}

Expand All @@ -44,6 +47,8 @@ impl Default for Store {
lives: 0,
player_count_down: 3.0,
game_state: GameState::InsertCoin,
lazers: vec![],
lazer_interval: 0.0,
show_state: false,
}
}
Expand Down Expand Up @@ -112,7 +117,7 @@ pub fn game_state_event_system(
GameStateEvent::LooseLife => {
if store.game_state == GameState::Play {
store.lives -= 1;
if store.lives == 0 {
if store.lives <= 0 {
store.game_state = GameState::GameOver;
timer.set(STATE_TRANSITION_MENU);
} else {
Expand Down Expand Up @@ -153,7 +158,9 @@ pub fn update_system(
timer.tick(time.delta());

// extra life(s)
if store.score >= store.score_new_life {
// I think this is what was causing your race condition. But honestly this could be a cool mechanic
// Like a final shot to revive mechanic
if store.score >= store.score_new_life && store.lives >= 1 {
store.lives += 1;
store.score_new_life += (store.score_new_life as f32 * SCORE_SCALE) as u32;
}
Expand Down
151 changes: 76 additions & 75 deletions src/hit_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
};
use bevy::prelude::*;


#[allow(clippy::too_many_arguments)]
pub fn update_system(
mut commands: Commands,
Expand All @@ -20,12 +21,10 @@ pub fn update_system(
mut play_sound_ew: EventWriter<PlaySoundEvent>,

alien_query: Query<(Entity, &Transform), With<Alien>>,
mut lazer_query: Query<(&mut Lazer, &Transform)>,
mut bunker_query: Query<(&mut TextureAtlas, Entity, &Transform), With<Bunker>>,
alien_bullet_query: Query<(Entity, &Transform), With<AlienBullet>>,
mut player_query: Query<&Transform, With<Player>>,
) {
// check if point:&Transform is in &target:Transform with size:Vec2
#[inline(always)]
fn in_rect(point: &Transform, target: &Transform, size: Vec2) -> bool {
let t_vec: Vec2 = (target.translation.x, target.translation.y).into();
Expand All @@ -35,39 +34,86 @@ pub fn update_system(
}

let commands = &mut commands;

// get lazer singleton
let (mut lazer, lazer_transform) = lazer_query.get_single_mut().unwrap();

// get a player singleton
let player_transform = player_query.single_mut();
// alien bullets

for i in 0..store.lazers.len(){

// alien bullets
for (bullet_entity, bullet_transform) in &alien_bullet_query {
// hit player missile
if in_rect(bullet_transform, &store.lazers[i].transform, (16.0, 32.0).into()) {
commands.entity(bullet_entity).despawn();
store.lazers[i].lazer = Lazer::Idle;
spawn_explosion(
commands,
&image,
10,
(
bullet_transform.translation.x,
bullet_transform.translation.y,
)
.into(),
150.0,
0.0,
(10.0, 10.0).into(),
);
}
}

if let Lazer::Fired(_) = store.lazers[i].lazer {
// check bunkers
for (atlas, entity, bunker_transform) in &mut bunker_query {
if in_rect(&store.lazers[i].transform, bunker_transform, BUNKER_SIZE) {
hit_bunker(commands, entity, atlas);
store.lazers[i].lazer = Lazer::Idle;
spawn_explosion(
commands,
&image,
5,
(store.lazers[i].transform.translation.x, store.lazers[i].transform.translation.y).into(),
50.0,
0.0,
(10.0, 10.0).into(),
);
}
}

for (alien_entity, enemy_transform) in &alien_query {
// Collision check
if in_rect(&store.lazers[i].transform, enemy_transform, ALIEN_SIZE) {
play_sound_ew.send(PlaySoundEvent::AlienHit);
commands.entity(alien_entity).despawn();
store.lazers[i].lazer = Lazer::Idle;
store.aliens_killed += 1;
store.alien_speed += ALIENS_SPEED_KILL;
store.score += SCORE_ALIEN;

spawn_explosion(
commands,
&image,
10,
(store.lazers[i].transform.translation.x, store.lazers[i].transform.translation.y).into(),
500.0,
0.0,
(10.0, 10.0).into(),
);

if store.aliens_killed == ALIENS_TOTAL {
debug!("-- send new wave --");
game_state_ew.send(GameStateEvent::NewWave);
}
}
}
}
}



for (bullet_entity, bullet_transform) in &alien_bullet_query {
// hit player missile
if in_rect(bullet_transform, lazer_transform, (16.0, 32.0).into()) {
commands.entity(bullet_entity).despawn();
*lazer = Lazer::Idle;
spawn_explosion(
commands,
&image,
10,
(
bullet_transform.translation.x,
bullet_transform.translation.y,
)
.into(),
150.0,
0.0,
(10.0, 10.0).into(),
);
} else
// hit player
if in_rect(bullet_transform, player_transform, PLAYER_SIZE) {
commands.entity(bullet_entity).despawn();
game_state_ew.send(GameStateEvent::LooseLife);
// to prevent the rare race-condition when outstanding missile would cause an extra life

*lazer = Lazer::Idle;

spawn_explosion(
commands,
Expand Down Expand Up @@ -108,50 +154,5 @@ pub fn update_system(
}
}

if let Lazer::Fired(_) = *lazer {
// check bunkers
for (atlas, entity, bunker_transform) in &mut bunker_query {
if in_rect(lazer_transform, bunker_transform, BUNKER_SIZE) {
hit_bunker(commands, entity, atlas);
*lazer = Lazer::Idle;
spawn_explosion(
commands,
&image,
5,
(lazer_transform.translation.x, lazer_transform.translation.y).into(),
50.0,
0.0,
(10.0, 10.0).into(),
);
}
}

// check aliens
for (alien_entity, enemy_transform) in &alien_query {
// Collision check
if in_rect(lazer_transform, enemy_transform, ALIEN_SIZE) {
play_sound_ew.send(PlaySoundEvent::AlienHit);
commands.entity(alien_entity).despawn();
*lazer = Lazer::Idle;
store.aliens_killed += 1;
store.alien_speed += ALIENS_SPEED_KILL;
store.score += SCORE_ALIEN;

spawn_explosion(
commands,
&image,
10,
(lazer_transform.translation.x, lazer_transform.translation.y).into(),
500.0,
0.0,
(10.0, 10.0).into(),
);

if store.aliens_killed == ALIENS_TOTAL {
debug!("-- send new wave --");
game_state_ew.send(GameStateEvent::NewWave);
}
}
}
}

}
121 changes: 63 additions & 58 deletions src/lazer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{common::*, particle::*, player::Player};
use crate::{common::*, particle::*, player::Player, game_state::Store};
use bevy::prelude::*;
use rand::random;
use std::time::Duration;
Expand All @@ -10,89 +10,94 @@ pub enum Lazer {
Idle,
}

pub struct LazerData {
pub lazer: Lazer,
pub transform: Transform
}

#[derive(Event)]
pub struct FireLazerEvent;

pub fn fire_lazer_system(
mut fire_lazer_event: EventReader<FireLazerEvent>,
mut lazer_query: Query<&mut Lazer>,
time: Res<Time>,
mut store: ResMut<Store>,
player_query: Query<&Transform, With<Player>>,
) {
if !fire_lazer_event.is_empty() {
debug!("-- fire lazer event received --");
fire_lazer_event.clear();
let mut lazer = lazer_query.single_mut();
if *lazer == Lazer::Idle {
*lazer = Lazer::Fire
if store.lazer_interval <= 0.0 {
if let Ok(player_transform) = player_query.get_single() {
store.lazers.push(LazerData {
lazer: Lazer::Fire,
transform: Transform::from_translation(player_transform.translation + Vec3::new(0.0, PLAYER_HEIGHT, 0.0)),
});

store.lazer_interval = LAZER_FIRING_INTERVAL;
}
}
}

store.lazer_interval -= time.delta_seconds();
}


/// lazer movement
pub fn update_system(
mut commands: Commands,
time: Res<Time>,
image: Res<CrossImage>,
mut player_query: Query<&mut Transform, With<Player>>,
mut lazer_position: Query<(&mut Lazer, &mut Visibility, &mut Transform), Without<Player>>,
player_query: Query<&Transform, With<Player>>,
mut store: ResMut<Store>,
) {
let player_transform = player_query.single_mut();
let (mut lazer, mut visibility, mut transform) = lazer_position.single_mut();
let player_transform = player_query.single();

match &mut *lazer {
Lazer::Fire => {
transform.translation =
player_transform.translation + Vec3::new(0.0, PLAYER_HEIGHT, 0.0);
*lazer = Lazer::Fired(Timer::new(
Duration::from_secs_f32(LAZER_PARTICLE_INTERVAL),
TimerMode::Repeating,
));
*visibility = Visibility::Visible;
spawn_explosion(
&mut commands,
&image,
50,
(
player_transform.translation.x,
player_transform.translation.y,
)
.into(),
100.0,
0.0,
(10.0, 10.0).into(),
);
}
Lazer::Fired(timer) => {
timer.tick(time.delta());
if timer.just_finished() {
spawn_particle(
commands,
image,
(transform.translation.x, transform.translation.y).into(),
(30.0 * (random::<f32>() - 0.5), -LAZER_SPEED * 0.1).into(),
(0.0, 0.0).into(),
store.lazers.retain_mut(|lazer_data| {
match &mut lazer_data.lazer {
Lazer::Fire => {
lazer_data.lazer = Lazer::Fired(Timer::new(
Duration::from_secs_f32(LAZER_PARTICLE_INTERVAL),
TimerMode::Repeating,
));
lazer_data.transform.translation = player_transform.translation + Vec3::new(0.0, PLAYER_HEIGHT, 0.0);

spawn_explosion(
&mut commands,
&image,
50,
lazer_data.transform.translation.truncate(),
100.0,
0.0,
(10.0, 10.0).into(),
);
}
Lazer::Fired(timer) => {
timer.tick(time.delta());
if timer.just_finished() {
spawn_particle(
&mut commands,
&image,
lazer_data.transform.translation.truncate(),
(30.0 * (random::<f32>() - 0.5), -LAZER_SPEED * 0.1).into(),
(0.0, 0.0).into(),
);
}

lazer_data.transform.translation.y += LAZER_SPEED * time.delta_seconds();

if transform.translation.y > SCENE_HEIGHT {
*lazer = Lazer::Idle;
} else {
transform.translation.y += LAZER_SPEED * time.delta_seconds()
if lazer_data.transform.translation.y > SCENE_HEIGHT {
return false;
}
}
Lazer::Idle => {
return false;
}
}
_ => {
*visibility = Visibility::Hidden;
}
}
true
});
}

pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
Lazer::Idle,
SpriteBundle {
texture: asset_server.load("sprites/lazer.png"),
transform: Transform::from_xyz(0., SCENE_HEIGHT, 0.),
visibility: Visibility::Hidden,
..default()
},
));
// Nothing to do here
}
Loading