Skip to content
Merged
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
Binary file modified art/fonts.aseprite
Binary file not shown.
Binary file added art/shield.aseprite
Binary file not shown.
Binary file modified assets/font.ttf
Binary file not shown.
Binary file added assets/sprites/shield-empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/shield-low.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/shield.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/audio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ fn fade_out(
audio.set_volume(
current_volume.fade_towards(Volume::Linear(0.0), time.delta_secs() / fade_out.duration),
);
println!("fading out: {:?}", audio.volume().to_linear());
if audio.volume().to_linear() <= 0.15 {
commands.entity(entity).despawn();
}
Expand Down
98 changes: 77 additions & 21 deletions src/screens/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub(super) fn plugin(app: &mut App) {
update_projectiles,
projectile_asteroid_collision,
update_explosions,
shield_regen,
)
.in_set(GameSystems::Play)
.run_if(in_state(Screen::Game)),
Expand All @@ -113,13 +114,19 @@ pub(super) fn plugin(app: &mut App) {
#[derive(Component)]
struct Thruster;

#[derive(Component)]
struct Shield;

fn spawn_player(mut commands: Commands, asset_server: Res<AssetServer>) {
let default_speed = asset_server.load("sprites/ships/ship3-default.png");
commands.spawn((
Name::new("Player Ship"),
Player {
can_shoot: true,
timer: Timer::from_seconds(0.15, TimerMode::Once),
shield: 2,
shield_regen: Timer::from_seconds(5.0, TimerMode::Once),
shield_hit_cooldown: Timer::from_seconds(0.5, TimerMode::Once),
},
Sprite {
image: asset_server.load("sprites/ships/ship3.png"),
Expand All @@ -136,15 +143,25 @@ fn spawn_player(mut commands: Commands, asset_server: Res<AssetServer>) {
..default()
},
PIXEL_PERFECT_LAYERS,
children![(
Name::new("Player Ship Thruster"),
Thruster,
Sprite {
image: default_speed.clone(),
custom_size: Some(Vec2::splat(32.0)),
..default()
}
)],
children![
(
Name::new("Player Ship Thruster"),
Thruster,
Sprite {
image: default_speed.clone(),
custom_size: Some(Vec2::splat(32.0)),
..default()
}
),
(
Name::new("Player Shield"),
Shield,
Sprite {
image: asset_server.load("sprites/shield.png"),
..default()
}
)
],
));
}

Expand Down Expand Up @@ -185,6 +202,9 @@ fn enter_player(
pub struct Player {
pub can_shoot: bool,
pub timer: Timer,
pub shield: u8,
pub shield_regen: Timer,
pub shield_hit_cooldown: Timer,
}

#[derive(Component)]
Expand Down Expand Up @@ -216,7 +236,6 @@ fn stopwatch(
mut game_stats: ResMut<GameStats>,
mut end_game: ResMut<EndGame>,
) {
println!("time played: {:?}", game_stats.time_played);
if game_stats.time_played > 300.0 {
game_stats.time_played = 300.0;
end_game.0 = true;
Expand Down Expand Up @@ -454,26 +473,37 @@ fn spawn_asteroid(

fn collide_with_asteroid_check(
mut commands: Commands,
player: Query<&Transform, With<Player>>,
mut player: Single<(&Transform, &mut Player)>,
asteroids: Query<&Transform, With<Asteroid>>,
mut time: ResMut<Time<Virtual>>,
mut state: ResMut<NextState<GameState>>,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
mut shield: Single<&mut Sprite, With<Shield>>,
) {
let player = player.single();
if player.is_err() {
return;
}
let player_transform = player.unwrap();
let player_transform = player.0;
let player = &mut player.1;
let hitbox_size = 8.0;
for asteroid_transform in asteroids.iter() {
let distance = player_transform
.translation
.distance(asteroid_transform.translation);
if distance < (hitbox_size / 2.0) + (30.0 / 2.0) {
time.pause();
state.set(GameState::GameOver);
if distance < (hitbox_size / 2.0) + (30.0 / 2.0) && player.shield_hit_cooldown.is_finished()
{
if player.shield == 0 {
time.pause();
state.set(GameState::GameOver);
} else {
player.shield -= 1;
player.shield_regen.reset();
player.shield_hit_cooldown.reset();
if player.shield == 0 {
shield.image = asset_server.load("sprites/shield-empty.png");
} else if player.shield == 1 {
shield.image = asset_server.load("sprites/shield-low.png");
}
}

commands.trigger(PlaySfxEvent {
sfx: SoundEffect::Explosion,
});
Expand Down Expand Up @@ -501,6 +531,29 @@ fn collide_with_asteroid_check(
}
}

fn shield_regen(
time: Res<Time<Virtual>>,
mut player: Single<&mut Player>,
mut shield: Single<&mut Sprite, With<Shield>>,
asset_server: Res<AssetServer>,
) {
player.shield_regen.tick(time.delta());
player.shield_hit_cooldown.tick(time.delta());
if player.shield_regen.just_finished() {
player.shield_regen.reset();
player.shield += 1;
if player.shield > 2 {
player.shield = 2;
}
match player.shield {
0 => shield.image = asset_server.load("sprites/shield-empty.png"),
1 => shield.image = asset_server.load("sprites/shield-low.png"),
2 => shield.image = asset_server.load("sprites/shield.png"),
_ => {}
}
}
}

#[derive(Component)]
struct Explosion;

Expand Down Expand Up @@ -581,7 +634,7 @@ fn restart_game(
mut pause_state: ResMut<NextState<PauseState>>,
mut game_state: ResMut<NextState<GameState>>,
mut has_entered: ResMut<HasEntered>,
mut player: Query<&mut Transform, With<Player>>,
mut player: Query<(&mut Transform, &mut Player)>,
asteroids: Query<Entity, With<Asteroid>>,
projectiles: Query<Entity, With<Projectile>>,
mut end_game: ResMut<EndGame>,
Expand All @@ -597,8 +650,11 @@ fn restart_game(

end_game.0 = false;
pause_state.set(PauseState::NotPaused);
let mut player_transform = player.single_mut().unwrap();
let (mut player_transform, mut player) = player.single_mut().unwrap();
player_transform.translation = Vec3::new(0.0, -280.0, 0.0);
player.shield = 2;
player.shield_hit_cooldown.reset();
player.shield_regen.reset();

let mut planet_transform = planet.single_mut().unwrap();
planet_transform.translation = Vec3::new(0.0, 400.0, -11.0);
Expand Down
153 changes: 153 additions & 0 deletions src/screens/howtoplay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use bevy::{prelude::*, text::FontSmoothing};
use leafwing_input_manager::prelude::ActionState;

use crate::{PIXEL_PERFECT_LAYERS, ScaleFactor, input::Action, screens::Screen};

pub(super) fn plugin(app: &mut App) {
app.add_systems(OnEnter(Screen::HowToPlay), spawn_howtoplay);
app.add_systems(
Update,
(howtoplay_input, howtoplay_button).run_if(in_state(Screen::HowToPlay)),
);
}

fn spawn_howtoplay(
mut commands: Commands,
scale_factor: Res<ScaleFactor>,
asset_server: Res<AssetServer>,
) {
let scale = scale_factor.0;
let font_handle = asset_server.load("font.ttf");
commands.spawn((
Name::new("HowToPlay container"),
Node {
width: Val::Percent(80.0),
height: Val::Percent(80.0),
margin: UiRect::all(Val::Auto),
padding: UiRect::all(Val::Px(8.0 * scale)),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
flex_direction: FlexDirection::Column,
..default()
},
DespawnOnExit(Screen::HowToPlay),
PIXEL_PERFECT_LAYERS,
children![
(
Name::new("HowToPlay"),
Text::new("HOW TO PLAY"),
TextFont {
font_size: 16.0 * scale,
font: font_handle.clone(),
font_smoothing: FontSmoothing::None,
..default()
},
Node {
position_type: PositionType::Absolute,
top: Val::Px(0.0),
margin: UiRect {
left: Val::Auto,
right: Val::Auto,
..default()
},
..default()
}
),
(
Text::new("MOVE WITH WASD / ARROWS / ANALOG STICK / D PAD"),
TextFont {
font_size: 12.0 * scale,
font: font_handle.clone(),
font_smoothing: FontSmoothing::None,
..default()
},
Node {
padding: UiRect {
top: Val::Px(8.0 * scale),
bottom: Val::Px(8.0 * scale),
..default()
},
..default()
},
),
(
Text::new("SHOOT WITH SPACE / BOTTOM BUTTON ON GAMEPAD CLUSTER"),
TextFont {
font_size: 12.0 * scale,
font: font_handle.clone(),
font_smoothing: FontSmoothing::None,
..default()
},
Node {
padding: UiRect {
top: Val::Px(8.0 * scale),
bottom: Val::Px(8.0 * scale),
..default()
},
..default()
},
),
(
Text::new("PAUSE WITH ESCAPE / GAMEPAD START / GAMEPAD SELECT"),
TextFont {
font_size: 12.0 * scale,
font: font_handle.clone(),
font_smoothing: FontSmoothing::None,
..default()
},
Node {
padding: UiRect {
top: Val::Px(8.0 * scale),
bottom: Val::Px(8.0 * scale),
..default()
},
..default()
},
),
(
Name::new("Back to menu button"),
Button,
Node {
position_type: PositionType::Absolute,
bottom: Val::Px(0.0),
margin: UiRect {
left: Val::Auto,
right: Val::Auto,
..default()
},
..default()
},
children![(
Name::new("Back to menu text"),
Text::new("BACK TO MENU"),
TextFont {
font_size: 16.0 * scale,
font: font_handle.clone(),
font_smoothing: FontSmoothing::None,
..default()
}
)]
),
],
));
}

fn howtoplay_button(
interaction_query: Query<&Interaction, Changed<Interaction>>,
mut screen: ResMut<NextState<Screen>>,
) {
for interaction in interaction_query.iter() {
if *interaction == Interaction::Pressed {
screen.set(Screen::Title)
}
}
}

fn howtoplay_input(
action_state: Single<&ActionState<Action>>,
mut screen: ResMut<NextState<Screen>>,
) {
if action_state.just_pressed(&Action::Select) {
screen.set(Screen::Title);
}
}
3 changes: 3 additions & 0 deletions src/screens/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod credits;
mod endgame;
mod game;
mod gameover;
mod howtoplay;
mod pause;
mod splash;
mod title;
Expand All @@ -19,13 +20,15 @@ pub(super) fn plugin(app: &mut App) {
pause::plugin,
gameover::plugin,
endgame::plugin,
howtoplay::plugin,
));
}

#[derive(States, Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub enum Screen {
#[default]
Splash,
HowToPlay,
Title,
Game,
Credits,
Expand Down
Loading