Skip to content

Commit

Permalink
Spawn minions per level increase
Browse files Browse the repository at this point in the history
  • Loading branch information
myisaak committed Mar 4, 2022
1 parent d354439 commit e32d559
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ serde_derive = "1.0"
wasm-bindgen-futures = "0.4"
futures = "0.3"
futures-lite = "1.12"
rand = "0.8.5"

[profile.release]
opt-level = 's'
Expand Down
104 changes: 98 additions & 6 deletions src/enemy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use bevy_inspector_egui::Inspectable;
use bevy_rapier2d::{na::UnitComplex, prelude::*};

use crate::{
game::{GameState, Health},
game::{GameGlobals, GameState, Health},
physics::PhysicsGlobals,
player::Player,
shooting::ShootEvent,
Expand All @@ -26,24 +26,26 @@ impl Plugin for EnemyPlugin {
.add_system_set(
SystemSet::on_update(GameState::Playing)
.with_system(enemy_movement)
.with_system(enemy_state_control),
.with_system(enemy_state_control)
.with_system(spawn_minions),
)
.insert_resource(EnemyParams::default());
.insert_resource(EnemyParams::default())
.insert_resource(MinionParams::default());
//.register_inspectable::<Enemy>()
//.add_plugin(InspectorPlugin::<EnemyParams>::new())
}
}

/// Values we might want to tweak and that are used to define specific properties of the entities.
#[derive(Inspectable)]
struct EnemyParams {
pub struct EnemyParams {
speed: f32,
rot_offset: f32,
spawn_pos: Vec2,
follow_threshold: f32,
attack_dist: f32,
visibility_dist: f32,
start_health: f32,
pub start_health: f32,
body_scale: Vec2,
left_arm_pos: Vec2,
left_arm_scale: Vec2,
Expand All @@ -68,7 +70,7 @@ impl Default for EnemyParams {
Self {
speed: 80.0,
rot_offset: -PI / 2.0,
attack_dist: 140.0,
attack_dist: 400.0,
start_health: 100.0,
follow_threshold: 30.0,
visibility_dist: 400.0,
Expand Down Expand Up @@ -97,6 +99,37 @@ impl Default for EnemyParams {
}
}

#[derive(Inspectable)]
struct MinionParams {
speed: f32,
rot_offset: f32,
spawn_pos: Vec2,
follow_threshold: f32,
attack_dist: f32,
visibility_dist: f32,
start_health: f32,
body_scale: Vec2,
weapon_pos: Vec2,
weapon_scale: Vec2,
}

impl Default for MinionParams {
fn default() -> Self {
Self {
speed: 160.0,
rot_offset: -PI / 2.0,
attack_dist: 140.0,
start_health: 50.0,
follow_threshold: 30.0,
visibility_dist: 400.0,
spawn_pos: Vec2::new(150.0, 0.0),
body_scale: Vec2::new(50.0, 50.0),
weapon_pos: Vec2::new(-75.0, 20.0),
weapon_scale: Vec2::new(10.0, 30.0),
}
}
}

#[derive(Component, Inspectable)]
pub struct Enemy(EnemyState);

Expand Down Expand Up @@ -324,6 +357,65 @@ fn spawn_boss(
ev_writer.send(BossSpawnEvent);
}

fn spawn_minions(
mut commands: Commands,
params: Res<MinionParams>,
game_globals: Res<GameGlobals>,
rapier_config: ResMut<RapierConfiguration>,
physics_globals: Res<PhysicsGlobals>,
q_minions: Query<&Minion>,
mut ev_writer: EventWriter<BossSpawnEvent>,
_time: Res<Time>,
) {
if q_minions.iter().count() as u32 >= game_globals.minions {
return;
}

let collider_flags = ColliderFlags {
collision_groups: InteractionGroups::new(physics_globals.enemy_mask, u32::MAX),
..Default::default()
};

info!("SPAWN_MINION");
commands
.spawn_bundle(RigidBodyBundle {
position: (params.spawn_pos / rapier_config.scale).into(),
..Default::default()
})
.insert(RigidBodyPositionSync::Discrete)
.insert(Transform::from_rotation(Quat::from_euler(
EulerRot::XYZ,
0.0,
0.0,
-PI / 2.0,
)))
.insert_bundle(SpriteBundle {
sprite: Sprite {
custom_size: Some(params.body_scale),
color: Color::RED,
..Default::default()
},
..Default::default()
})
.insert(ColliderPositionSync::Discrete)
.insert_bundle(ColliderBundle {
flags: collider_flags.clone().into(),
position: Vec2::ZERO.into(),
// Since the physics world is scaled, we divide pixel size by it to get the collider size
shape: ColliderShapeComponent(ColliderShape::cuboid(
params.body_scale.x * 0.5 / rapier_config.scale,
params.body_scale.y * 0.5 / rapier_config.scale,
)),
..Default::default()
})
.insert(Enemy(EnemyState::IDLE))
.insert(Minion)
.insert(Health(params.start_health))
.id();

ev_writer.send(BossSpawnEvent);
}

fn enemy_movement(
mut q_enemy: Query<
(
Expand Down
37 changes: 33 additions & 4 deletions src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use serde::{Deserialize, Serialize};
use wasm_bindgen_futures::JsFuture;
use web_sys::Response;

use crate::player::Player;
use crate::{
enemy::{Boss, EnemyParams},
player::Player,
};

/// Plugin that handles when game restarts and tracks the player's score.
/// The game restarts when player dies, so player's health is tracked
Expand All @@ -23,6 +26,8 @@ impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.insert_resource(GameGlobals {
level: 1,
minions: 0,
min_upgrade_health: 20.0,
time_until_restart: Duration::from_secs(15),
scores: vec![],
..Default::default()
Expand All @@ -32,7 +37,8 @@ impl Plugin for GamePlugin {
.add_system_set(
SystemSet::on_update(GameState::Playing)
.with_system(restart_game_when_player_dies)
.with_system(update_score),
.with_system(update_score)
.with_system(update_level_over_time),
)
.add_system_set(SystemSet::on_enter(GameState::Playing).with_system(reset_game_globals))
.add_system_set(SystemSet::on_exit(GameState::Playing).with_system(teardown))
Expand All @@ -54,9 +60,11 @@ pub enum GameState {

#[derive(Default)]
pub struct GameGlobals {
pub score: u32,
pub level: u32,
pub score: u32,
pub time_started: Duration,
pub minions: u32,
pub min_upgrade_health: f32,
pub scores: Vec<LeaderboardScore>,
pub time_stopped: Duration,
pub time_until_restart: Duration,
Expand All @@ -69,6 +77,7 @@ fn reset_game_globals(mut globals: ResMut<GameGlobals>, time: Res<Time>) {
globals.time_started = time.time_since_startup();
globals.level = 1;
globals.score = 0;
globals.minions = 0;
}

pub fn run_when_enter_playing_state(
Expand All @@ -83,6 +92,22 @@ pub fn run_when_enter_playing_state(
}
}

fn update_level_over_time(
mut q_health: Query<&mut Health, With<Boss>>,
enemy_params: ResMut<EnemyParams>,
mut state: ResMut<State<GameState>>,
time: Res<Time>,
mut globals: ResMut<GameGlobals>,
) {
if let Ok(mut health) = q_health.get_single_mut() {
if health.0 < globals.min_upgrade_health {
health.0 = enemy_params.start_health;
globals.level += 1;
globals.minions += globals.level;
}
}
}

fn restart_game_when_player_dies(
q_player: Query<&Health, With<Player>>,
mut state: ResMut<State<GameState>>,
Expand All @@ -101,7 +126,8 @@ fn upload_highscores(globals: Res<GameGlobals>, thread_pool: Res<AsyncComputeTas
// publish highscores to web api
let score = globals.score;
thread_pool.spawn(async move {
let _ = Leaderboard::add_score(score, "player1").await;
let _ = Leaderboard::add_score(score, format!("player-{}", rand::random::<u32>()).as_str())
.await;
let res = Leaderboard::leaderboard().await.unwrap();
res.scores
});
Expand Down Expand Up @@ -179,6 +205,9 @@ impl Leaderboard {
}

pub async fn add_score(score: u32, user: &str) -> Result<(), JsValue> {
let _ = web_sys::window()
.unwrap()
.alert_with_message(format!("You died... well it's unfair because the boss never dies!!!.\n\nYou scored {} Points under the name {}\n\nCheck out the leaderboard at https://gamejolt.com/dashboard/games/697047/api/scoreboards/705726", score, user).as_str());
Self::fetch_api(
"/scores/add",
Some(format!(
Expand Down
16 changes: 15 additions & 1 deletion src/shooting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,11 @@ fn shoot(

/// A system that listens to contact events triggered only by bullets
fn check_bullet_hit(
mut commands: Commands,
mut contact_events: EventReader<ContactEvent>,
q_bullet: Query<(Entity, &Bullet)>,
mut commands: Commands,
mut q_health: Query<&mut Health>,
q_parent: Query<&Parent>,
params: Res<BulletParams>,
time: Res<Time>,
) {
Expand All @@ -208,6 +209,19 @@ fn check_bullet_hit(
} else if let Ok(mut health) = q_health.get_mut(h2.entity()) {
health.0 -= dmg;
info!("DAMAGE -> HEALTH {}", health.0);
} else if let Ok(Parent(parent_e)) = q_parent.get(h1.entity()) {
// modify health on parent
if let Ok(mut health) = q_health.get_mut(*parent_e) {
health.0 -= dmg;
} else if let Ok(Parent(parent_e)) = q_parent.get(h2.entity()) {
if let Ok(mut health) = q_health.get_mut(*parent_e) {
health.0 -= dmg;
}
}
} else if let Ok(Parent(parent_e)) = q_parent.get(h2.entity()) {
if let Ok(mut health) = q_health.get_mut(*parent_e) {
health.0 -= dmg;
}
}

commands.entity(e).insert(DespawnTimer(
Expand Down

0 comments on commit e32d559

Please sign in to comment.