Compare commits
2 commits
c73b3c7066
...
0d945de135
Author | SHA1 | Date | |
---|---|---|---|
0d945de135 | |||
6a63d13395 |
3 changed files with 147 additions and 19 deletions
39
src/drops.rs
39
src/drops.rs
|
@ -7,7 +7,11 @@ use bevy_rand::prelude::*;
|
|||
use bevy_rapier2d::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{player::Player, scene::SceneObj, METER};
|
||||
use crate::{
|
||||
player::{LifeChangeEvent, Player},
|
||||
scene::SceneObj,
|
||||
METER,
|
||||
};
|
||||
|
||||
#[derive(Component)]
|
||||
struct SpawnTimer(pub Timer);
|
||||
|
@ -27,7 +31,13 @@ pub fn spawner_plugin(app: &mut App) {
|
|||
.add_systems(Startup, add_timer)
|
||||
.add_systems(
|
||||
Update,
|
||||
(drop_crates, do_drop, crate_collisions, delete_on_env_coll),
|
||||
(
|
||||
drop_crates,
|
||||
do_drop,
|
||||
crate_collisions,
|
||||
delete_on_env_coll,
|
||||
player_coll,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -130,10 +140,27 @@ fn delete_on_env_coll(mut ev_colls: EventReader<CrateCollision>, mut commands: C
|
|||
if let CollisionType::Player(_) = with {
|
||||
continue;
|
||||
}
|
||||
// let CollisionType::Scene(obj) = with else {
|
||||
// unreachable!()
|
||||
// };
|
||||
|
||||
commands.entity(*coll_crate).despawn();
|
||||
if let Some(mut e) = commands.get_entity(*coll_crate) {
|
||||
e.despawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn player_coll(
|
||||
mut ev_colls: EventReader<CrateCollision>,
|
||||
mut ev_lives: EventWriter<LifeChangeEvent>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for CrateCollision { coll_crate, with } in ev_colls.read() {
|
||||
if let CollisionType::Scene(_) = with {
|
||||
continue;
|
||||
}
|
||||
|
||||
ev_lives.send(LifeChangeEvent::Lost);
|
||||
|
||||
if let Some(mut e) = commands.get_entity(*coll_crate) {
|
||||
e.despawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
72
src/main.rs
72
src/main.rs
|
@ -4,6 +4,7 @@ use bevy::{
|
|||
};
|
||||
use bevy_rapier2d::prelude::*;
|
||||
use drops::spawner_plugin;
|
||||
use player::LifeChangeEvent;
|
||||
const METER: f32 = 48.;
|
||||
|
||||
fn main() {
|
||||
|
@ -19,12 +20,12 @@ fn main() {
|
|||
.insert_resource(rapier_config)
|
||||
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(METER))
|
||||
.add_plugins(RapierDebugRenderPlugin::default())
|
||||
.add_plugins((spawner_plugin))
|
||||
.add_systems(Startup, (scene::setup_scene, setup_cam, player::add_player))
|
||||
.add_systems(
|
||||
Update,
|
||||
(player::move_player, player::player_ground_collision),
|
||||
)
|
||||
.add_plugins((
|
||||
spawner_plugin,
|
||||
game_state::state_and_ui_plugin,
|
||||
player::player_plugin,
|
||||
))
|
||||
.add_systems(Startup, (scene::setup_scene, setup_cam))
|
||||
.run()
|
||||
}
|
||||
|
||||
|
@ -38,3 +39,62 @@ fn setup_cam(mut commands: Commands) {
|
|||
mod drops;
|
||||
mod player;
|
||||
mod scene;
|
||||
mod game_state {
|
||||
use bevy::{prelude::*, time::Stopwatch};
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct GameState {
|
||||
score: u32,
|
||||
game_time: Stopwatch,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct StateText;
|
||||
|
||||
pub fn state_and_ui_plugin(app: &mut App) {
|
||||
app.add_systems(Startup, (setup_gamestate, setup_ui))
|
||||
.add_systems(Update, (update_time));
|
||||
}
|
||||
|
||||
fn setup_gamestate(mut commands: Commands) {
|
||||
commands.spawn(GameState {
|
||||
score: 0,
|
||||
game_time: Stopwatch::new(),
|
||||
});
|
||||
}
|
||||
|
||||
fn setup_ui(mut commands: Commands) {
|
||||
commands.spawn((
|
||||
TextBundle::from_sections([
|
||||
TextSection::new("Score: ", TextStyle::default()),
|
||||
TextSection::new("0", TextStyle::default()),
|
||||
TextSection::new("\n", TextStyle::default()),
|
||||
TextSection::new("Time: ", TextStyle::default()),
|
||||
TextSection::new("0", TextStyle::default()),
|
||||
TextSection::new("s", TextStyle::default()),
|
||||
])
|
||||
.with_style(Style {
|
||||
position_type: PositionType::Absolute,
|
||||
top: Val::Px(5.0),
|
||||
right: Val::Px(5.0),
|
||||
..default()
|
||||
}),
|
||||
StateText,
|
||||
));
|
||||
}
|
||||
|
||||
fn update_time(
|
||||
mut state_txt: Query<&mut Text, With<StateText>>,
|
||||
mut game_state: Query<&mut GameState>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
let mut txt = state_txt.single_mut();
|
||||
let time = game_state
|
||||
.single_mut()
|
||||
.game_time
|
||||
.tick(time.delta())
|
||||
.elapsed_secs();
|
||||
|
||||
txt.sections[4].value = format!("{time:.2}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use bevy::{
|
||||
prelude::*,
|
||||
sprite::{MaterialMesh2dBundle, Mesh2dHandle},
|
||||
utils::{HashMap, HashSet},
|
||||
};
|
||||
use bevy_rapier2d::prelude::*;
|
||||
|
||||
|
@ -10,6 +11,21 @@ use crate::METER;
|
|||
pub struct Player {
|
||||
move_cooldown: Timer,
|
||||
grounded: bool,
|
||||
lives: u8,
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub enum LifeChangeEvent {
|
||||
Gained,
|
||||
Lost,
|
||||
}
|
||||
|
||||
const DEFAULT_LIVES: u8 = 5;
|
||||
|
||||
pub fn player_plugin(app: &mut App) {
|
||||
app.add_event::<LifeChangeEvent>()
|
||||
.add_systems(Startup, (add_player, add_lives_ui))
|
||||
.add_systems(Update, (move_player, player_ground_collision, update_lives));
|
||||
}
|
||||
|
||||
pub fn add_player(
|
||||
|
@ -23,6 +39,7 @@ pub fn add_player(
|
|||
move_cooldown: Timer::from_seconds(0.01, TimerMode::Repeating),
|
||||
// move_cooldown: Timer::from_seconds(0.01, TimerMode::Repeating),
|
||||
grounded: false,
|
||||
lives: DEFAULT_LIVES,
|
||||
})
|
||||
.insert(MaterialMesh2dBundle {
|
||||
mesh: shape,
|
||||
|
@ -40,25 +57,49 @@ pub fn add_player(
|
|||
.insert(KinematicCharacterController { ..default() });
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct LivesUi;
|
||||
fn add_lives_ui(mut commands: Commands) {
|
||||
commands.spawn((
|
||||
TextBundle::from("<3 ".repeat(DEFAULT_LIVES.into())),
|
||||
LivesUi,
|
||||
));
|
||||
}
|
||||
|
||||
fn update_lives(
|
||||
mut ev_lifechange: EventReader<LifeChangeEvent>,
|
||||
mut player: Query<&mut Player>,
|
||||
mut ui: Query<&mut Text, With<LivesUi>>,
|
||||
) {
|
||||
let mut txt = ui.single_mut();
|
||||
let mut p = player.single_mut();
|
||||
|
||||
for ev in ev_lifechange.read() {
|
||||
match ev {
|
||||
LifeChangeEvent::Lost => p.lives -= 1,
|
||||
LifeChangeEvent::Gained => p.lives += 1,
|
||||
}
|
||||
txt.sections[0].value = "<3 ".repeat(p.lives.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn player_ground_collision(
|
||||
mut player: Query<(Entity, &mut Player)>,
|
||||
scene_objs: Query<Entity, With<super::scene::SceneObj>>,
|
||||
mut collision_events: EventReader<CollisionEvent>,
|
||||
) {
|
||||
let (p, mut player) = player.single_mut();
|
||||
let scene_objs = scene_objs.iter().collect::<HashSet<_>>();
|
||||
|
||||
for collision_event in collision_events.read() {
|
||||
match collision_event {
|
||||
CollisionEvent::Started(e1, e2, _) => {
|
||||
if (e1 == &p && scene_objs.iter().any(|obj| *e2 == obj))
|
||||
|| (e2 == &p && scene_objs.iter().any(|obj| *e1 == obj))
|
||||
{
|
||||
if (e1 == &p && scene_objs.contains(e2)) || (e2 == &p && scene_objs.contains(e1)) {
|
||||
player.grounded = true;
|
||||
}
|
||||
}
|
||||
CollisionEvent::Stopped(e1, e2, _) => {
|
||||
if (e1 == &p && scene_objs.iter().any(|obj| *e2 == obj))
|
||||
|| (e2 == &p && scene_objs.iter().any(|obj| *e1 == obj))
|
||||
{
|
||||
if (e1 == &p && scene_objs.contains(e2)) || (e2 == &p && scene_objs.contains(e1)) {
|
||||
player.grounded = false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue