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 bevy_rapier2d::prelude::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::{player::Player, scene::SceneObj, METER};
|
use crate::{
|
||||||
|
player::{LifeChangeEvent, Player},
|
||||||
|
scene::SceneObj,
|
||||||
|
METER,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct SpawnTimer(pub Timer);
|
struct SpawnTimer(pub Timer);
|
||||||
|
@ -27,7 +31,13 @@ pub fn spawner_plugin(app: &mut App) {
|
||||||
.add_systems(Startup, add_timer)
|
.add_systems(Startup, add_timer)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
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 {
|
if let CollisionType::Player(_) = with {
|
||||||
continue;
|
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 bevy_rapier2d::prelude::*;
|
||||||
use drops::spawner_plugin;
|
use drops::spawner_plugin;
|
||||||
|
use player::LifeChangeEvent;
|
||||||
const METER: f32 = 48.;
|
const METER: f32 = 48.;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -19,12 +20,12 @@ fn main() {
|
||||||
.insert_resource(rapier_config)
|
.insert_resource(rapier_config)
|
||||||
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(METER))
|
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(METER))
|
||||||
.add_plugins(RapierDebugRenderPlugin::default())
|
.add_plugins(RapierDebugRenderPlugin::default())
|
||||||
.add_plugins((spawner_plugin))
|
.add_plugins((
|
||||||
.add_systems(Startup, (scene::setup_scene, setup_cam, player::add_player))
|
spawner_plugin,
|
||||||
.add_systems(
|
game_state::state_and_ui_plugin,
|
||||||
Update,
|
player::player_plugin,
|
||||||
(player::move_player, player::player_ground_collision),
|
))
|
||||||
)
|
.add_systems(Startup, (scene::setup_scene, setup_cam))
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,3 +39,62 @@ fn setup_cam(mut commands: Commands) {
|
||||||
mod drops;
|
mod drops;
|
||||||
mod player;
|
mod player;
|
||||||
mod scene;
|
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::{
|
use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sprite::{MaterialMesh2dBundle, Mesh2dHandle},
|
sprite::{MaterialMesh2dBundle, Mesh2dHandle},
|
||||||
|
utils::{HashMap, HashSet},
|
||||||
};
|
};
|
||||||
use bevy_rapier2d::prelude::*;
|
use bevy_rapier2d::prelude::*;
|
||||||
|
|
||||||
|
@ -10,6 +11,21 @@ use crate::METER;
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
move_cooldown: Timer,
|
move_cooldown: Timer,
|
||||||
grounded: bool,
|
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(
|
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),
|
||||||
// move_cooldown: Timer::from_seconds(0.01, TimerMode::Repeating),
|
// move_cooldown: Timer::from_seconds(0.01, TimerMode::Repeating),
|
||||||
grounded: false,
|
grounded: false,
|
||||||
|
lives: DEFAULT_LIVES,
|
||||||
})
|
})
|
||||||
.insert(MaterialMesh2dBundle {
|
.insert(MaterialMesh2dBundle {
|
||||||
mesh: shape,
|
mesh: shape,
|
||||||
|
@ -40,25 +57,49 @@ pub fn add_player(
|
||||||
.insert(KinematicCharacterController { ..default() });
|
.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(
|
pub fn player_ground_collision(
|
||||||
mut player: Query<(Entity, &mut Player)>,
|
mut player: Query<(Entity, &mut Player)>,
|
||||||
scene_objs: Query<Entity, With<super::scene::SceneObj>>,
|
scene_objs: Query<Entity, With<super::scene::SceneObj>>,
|
||||||
mut collision_events: EventReader<CollisionEvent>,
|
mut collision_events: EventReader<CollisionEvent>,
|
||||||
) {
|
) {
|
||||||
let (p, mut player) = player.single_mut();
|
let (p, mut player) = player.single_mut();
|
||||||
|
let scene_objs = scene_objs.iter().collect::<HashSet<_>>();
|
||||||
|
|
||||||
for collision_event in collision_events.read() {
|
for collision_event in collision_events.read() {
|
||||||
match collision_event {
|
match collision_event {
|
||||||
CollisionEvent::Started(e1, e2, _) => {
|
CollisionEvent::Started(e1, e2, _) => {
|
||||||
if (e1 == &p && scene_objs.iter().any(|obj| *e2 == obj))
|
if (e1 == &p && scene_objs.contains(e2)) || (e2 == &p && scene_objs.contains(e1)) {
|
||||||
|| (e2 == &p && scene_objs.iter().any(|obj| *e1 == obj))
|
|
||||||
{
|
|
||||||
player.grounded = true;
|
player.grounded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CollisionEvent::Stopped(e1, e2, _) => {
|
CollisionEvent::Stopped(e1, e2, _) => {
|
||||||
if (e1 == &p && scene_objs.iter().any(|obj| *e2 == obj))
|
if (e1 == &p && scene_objs.contains(e2)) || (e2 == &p && scene_objs.contains(e1)) {
|
||||||
|| (e2 == &p && scene_objs.iter().any(|obj| *e1 == obj))
|
|
||||||
{
|
|
||||||
player.grounded = false;
|
player.grounded = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue