Add a bunch of stuff (kill stats)
This commit is contained in:
parent
ce070ce4be
commit
ba8cc16782
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
|
*.DS_Store
|
||||||
|
BIN
assets/fonts/PressStart2P-Regular.ttf
Normal file
BIN
assets/fonts/PressStart2P-Regular.ttf
Normal file
Binary file not shown.
224
src/main.rs
224
src/main.rs
@ -4,11 +4,9 @@ use bevy::core::{FixedTimestep, Time, Timer};
|
|||||||
use bevy::input::system::exit_on_esc_system;
|
use bevy::input::system::exit_on_esc_system;
|
||||||
use bevy::input::Input;
|
use bevy::input::Input;
|
||||||
use bevy::math::Vec3;
|
use bevy::math::Vec3;
|
||||||
use bevy::prelude::{
|
use bevy::prelude::*;
|
||||||
App, AssetServer, Commands, Component, Entity, KeyCode, OrthographicCameraBundle, Query, Res,
|
|
||||||
SystemSet, Transform, Without,
|
|
||||||
};
|
|
||||||
use bevy::sprite::{Sprite, SpriteBundle};
|
use bevy::sprite::{Sprite, SpriteBundle};
|
||||||
|
use bevy::text::Text;
|
||||||
use bevy::window::Windows;
|
use bevy::window::Windows;
|
||||||
use bevy::DefaultPlugins;
|
use bevy::DefaultPlugins;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
@ -16,6 +14,7 @@ use rand::Rng;
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
|
.insert_resource(ArnoldStats::new())
|
||||||
.add_startup_system(setup)
|
.add_startup_system(setup)
|
||||||
.add_system_set(
|
.add_system_set(
|
||||||
SystemSet::new()
|
SystemSet::new()
|
||||||
@ -26,7 +25,8 @@ fn main() {
|
|||||||
.with_system(linear_movement_system)
|
.with_system(linear_movement_system)
|
||||||
.with_system(expiration_date_system)
|
.with_system(expiration_date_system)
|
||||||
.with_system(follow_arnold_system)
|
.with_system(follow_arnold_system)
|
||||||
.with_system(enemy_spawner_system),
|
.with_system(enemy_spawner_system)
|
||||||
|
.with_system(update_scoreboard_system),
|
||||||
)
|
)
|
||||||
.add_system(exit_on_esc_system)
|
.add_system(exit_on_esc_system)
|
||||||
.run();
|
.run();
|
||||||
@ -35,60 +35,162 @@ fn main() {
|
|||||||
fn setup(mut commands: Commands, assets: Res<AssetServer>) {
|
fn setup(mut commands: Commands, assets: Res<AssetServer>) {
|
||||||
let arnold_sh = assets.load("arno.png");
|
let arnold_sh = assets.load("arno.png");
|
||||||
|
|
||||||
|
// cameras
|
||||||
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
|
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
|
||||||
|
commands.spawn_bundle(UiCameraBundle::default());
|
||||||
|
// arnold himself
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(SpriteBundle {
|
.spawn_bundle(SpriteBundle {
|
||||||
texture: arnold_sh,
|
texture: arnold_sh,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.insert(EnemySpawner::new(Timer::from_seconds(3.0, true)))
|
|
||||||
.insert(Arnold::new())
|
.insert(Arnold::new())
|
||||||
.insert(Transform {
|
.insert(Transform {
|
||||||
translation: Vec3::new(0.0, 0.0, 0.0),
|
translation: Vec3::new(0.0, 0.0, 0.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
// enemy spawner
|
||||||
|
commands
|
||||||
|
.spawn()
|
||||||
|
.insert(EnemySpawner::new(Timer::from_seconds(3.0, true)));
|
||||||
|
// scoreboard
|
||||||
|
commands
|
||||||
|
.spawn_bundle(TextBundle {
|
||||||
|
text: Text {
|
||||||
|
sections: vec![
|
||||||
|
TextSection {
|
||||||
|
style: TextStyle {
|
||||||
|
font: assets.load("fonts/PressStart2P-Regular.ttf"),
|
||||||
|
font_size: 15.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
},
|
||||||
|
value: "kills: ".to_string(),
|
||||||
|
},
|
||||||
|
TextSection {
|
||||||
|
style: TextStyle {
|
||||||
|
font: assets.load("fonts/PressStart2P-Regular.ttf"),
|
||||||
|
font_size: 15.0,
|
||||||
|
color: Color::RED,
|
||||||
|
},
|
||||||
|
value: "0".to_string(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
style: Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
position: Rect {
|
||||||
|
top: Val::Px(5.0),
|
||||||
|
left: Val::Px(5.0),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(ScoreBoard);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unit struct for tracking the ScoreBoard Text UI
|
||||||
|
#[derive(Component)]
|
||||||
|
struct ScoreBoard;
|
||||||
|
|
||||||
|
fn update_scoreboard_system(
|
||||||
|
stats: Res<ArnoldStats>,
|
||||||
|
mut query: Query<&mut Text, With<ScoreBoard>>,
|
||||||
|
) {
|
||||||
|
query.single_mut().sections[1].value = format!("{}", stats.kills);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ArnoldStats {
|
||||||
|
damage_dealt: i32,
|
||||||
|
kills: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArnoldStats {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
damage_dealt: 0,
|
||||||
|
kills: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Projectile {
|
struct Projectile {
|
||||||
|
damage: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Projectile {
|
impl Projectile {
|
||||||
fn new() -> Self {
|
fn new(damage: i32) -> Self {
|
||||||
Self {}
|
Self { damage }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Hitpoints {
|
struct Hitpoints {
|
||||||
|
hp: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hitpoints {
|
impl Hitpoints {
|
||||||
fn new() -> Self {
|
fn new(hp: i32) -> Self {
|
||||||
Self {}
|
Self { hp }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn projectile_collide_system(
|
fn projectile_collide_system(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
mut stats: ResMut<ArnoldStats>,
|
||||||
|
assets: Res<AssetServer>,
|
||||||
projectile_query: Query<(&Projectile, &Transform)>,
|
projectile_query: Query<(&Projectile, &Transform)>,
|
||||||
target_query: Query<(Entity, &Hitpoints, &Transform)>
|
mut target_query: Query<(Entity, &mut Hitpoints, &Transform)>,
|
||||||
) {
|
) {
|
||||||
for (entity, _hp, target_transform) in target_query.iter() {
|
for (entity, mut hp, target_transform) in target_query.iter_mut() {
|
||||||
let mut has_been_hit = false;
|
for (projectile, projectile_transform) in projectile_query.iter() {
|
||||||
for (_projectile, projectile_transform) in projectile_query.iter() {
|
if target_transform
|
||||||
if target_transform.translation.distance(projectile_transform.translation) < 32.0 {
|
.translation
|
||||||
has_been_hit = true;
|
.distance(projectile_transform.translation)
|
||||||
|
< 32.0
|
||||||
|
{
|
||||||
|
hp.hp -= projectile.damage;
|
||||||
|
stats.damage_dealt += projectile.damage;
|
||||||
|
|
||||||
|
let font = assets.load("fonts/PressStart2P-Regular.ttf");
|
||||||
|
let text_style = TextStyle {
|
||||||
|
font,
|
||||||
|
font_size: 10.0,
|
||||||
|
color: Color::YELLOW,
|
||||||
|
};
|
||||||
|
let text_alignment = TextAlignment {
|
||||||
|
vertical: VerticalAlign::Center,
|
||||||
|
horizontal: HorizontalAlign::Center,
|
||||||
|
};
|
||||||
|
commands
|
||||||
|
.spawn_bundle(Text2dBundle {
|
||||||
|
text: Text::with_section(
|
||||||
|
&format!("{}", projectile.damage),
|
||||||
|
text_style,
|
||||||
|
text_alignment,
|
||||||
|
),
|
||||||
|
transform: Transform {
|
||||||
|
translation: target_transform.translation + Vec3::new(0.0, 10.0, 10.0),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(ExpirationDate::new(3.0))
|
||||||
|
.insert(LinearMovement::new(Vec3::new(0.0, 0.5, 0.0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_been_hit {
|
if hp.hp <= 0 {
|
||||||
|
stats.kills += 1;
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum Facing {
|
enum Facing {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
@ -141,8 +243,10 @@ struct ExpirationDate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExpirationDate {
|
impl ExpirationDate {
|
||||||
fn new(countdown: Timer) -> Self {
|
fn new(duration: f32) -> Self {
|
||||||
Self { countdown }
|
Self {
|
||||||
|
countdown: Timer::from_seconds(duration, false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,30 +304,14 @@ fn arnold_attack_system(
|
|||||||
let (mut arnold, arnold_transform) = query.single_mut();
|
let (mut arnold, arnold_transform) = query.single_mut();
|
||||||
|
|
||||||
if arnold.attack_timer.tick(time.delta()).just_finished() {
|
if arnold.attack_timer.tick(time.delta()).just_finished() {
|
||||||
let knife_velocity = match arnold.facing {
|
commands.spawn_bundle(KnifeBundle::new(
|
||||||
Facing::Left => Vec3::new(-1.0, 0.0, 0.0),
|
assets.load("knife.png"),
|
||||||
Facing::Right => Vec3::new(1.0, 0.0, 0.0),
|
arnold_transform.translation + Vec3::new(0.0, 0.0, 10.0),
|
||||||
} * 4.0;
|
arnold.facing,
|
||||||
|
4.0,
|
||||||
commands
|
5.0,
|
||||||
.spawn_bundle(SpriteBundle {
|
10,
|
||||||
texture: assets.load("knife.png"),
|
));
|
||||||
sprite: Sprite {
|
|
||||||
flip_x: arnold.facing == Facing::Left,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(Knife::new())
|
|
||||||
.insert(Transform {
|
|
||||||
translation: arnold_transform.translation
|
|
||||||
+ Vec3::new(0.0, 0.0, 10.0)
|
|
||||||
+ knife_velocity,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(LinearMovement::new(knife_velocity))
|
|
||||||
.insert(ExpirationDate::new(Timer::from_seconds(5.0, false)))
|
|
||||||
.insert(Projectile::new());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +355,53 @@ fn enemy_spawner_system(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.insert(FollowArnold::new(1.0))
|
.insert(FollowArnold::new(1.0))
|
||||||
.insert(Hitpoints::new());
|
.insert(Hitpoints::new(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle)]
|
||||||
|
struct KnifeBundle {
|
||||||
|
_knife: Knife,
|
||||||
|
#[bundle]
|
||||||
|
sprite: SpriteBundle,
|
||||||
|
lin_movement: LinearMovement,
|
||||||
|
exp_date: ExpirationDate,
|
||||||
|
projectile: Projectile,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KnifeBundle {
|
||||||
|
fn new(
|
||||||
|
texture: Handle<Image>,
|
||||||
|
translation: Vec3,
|
||||||
|
facing: Facing,
|
||||||
|
speed: f32,
|
||||||
|
lifetime: f32,
|
||||||
|
damage: i32,
|
||||||
|
) -> Self {
|
||||||
|
let velocity = match facing {
|
||||||
|
Facing::Left => Vec3::new(-1.0, 0.0, 0.0),
|
||||||
|
Facing::Right => Vec3::new(1.0, 0.0, 0.0),
|
||||||
|
} * speed;
|
||||||
|
let flip_x = velocity.x < 0.0;
|
||||||
|
|
||||||
|
KnifeBundle {
|
||||||
|
_knife: Knife::new(),
|
||||||
|
sprite: SpriteBundle {
|
||||||
|
texture,
|
||||||
|
sprite: Sprite {
|
||||||
|
flip_x,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
transform: Transform {
|
||||||
|
translation,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lin_movement: LinearMovement::new(velocity),
|
||||||
|
exp_date: ExpirationDate::new(lifetime),
|
||||||
|
projectile: Projectile::new(damage),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user