Compare commits
3 commits
7ea28fd358
...
9de729fb7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9de729fb7f | ||
|
|
a703f6ab85 | ||
|
|
92c8c288bc |
9 changed files with 532 additions and 100 deletions
151
Cargo.lock
generated
151
Cargo.lock
generated
|
|
@ -1074,6 +1074,18 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_prototype_lyon"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb09bb9cadacae3238d1bdc856b71a164a17f93e1e94db62011dd969dacbe75b"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
"lyon_algorithms",
|
||||||
|
"lyon_tessellation",
|
||||||
|
"svgtypes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_ptr"
|
name = "bevy_ptr"
|
||||||
version = "0.17.3"
|
version = "0.17.3"
|
||||||
|
|
@ -1310,7 +1322,10 @@ name = "bevy_stock_photo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
|
"bevy_prototype_lyon",
|
||||||
|
"enumset",
|
||||||
"rand",
|
"rand",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2013,6 +2028,40 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
|
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.21.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dasp_sample"
|
name = "dasp_sample"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -2146,6 +2195,27 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumset"
|
||||||
|
version = "1.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634"
|
||||||
|
dependencies = [
|
||||||
|
"enumset_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumset_derive"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -2240,6 +2310,12 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "float_next_after"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
|
@ -2637,6 +2713,12 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.9"
|
version = "0.25.9"
|
||||||
|
|
@ -2799,6 +2881,17 @@ dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kurbo"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"euclid",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
@ -2892,6 +2985,48 @@ version = "0.4.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lyon_algorithms"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c0829e28c4f336396f250d850c3987e16ce6db057ffe047ce0dd54aab6b647"
|
||||||
|
dependencies = [
|
||||||
|
"lyon_path",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lyon_geom"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e260b6de923e6e47adfedf6243013a7a874684165a6a277594ee3906021b2343"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"euclid",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lyon_path"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aeca86bcfd632a15984ba029b539ffb811e0a70bf55e814ef8b0f54f506fdeb"
|
||||||
|
dependencies = [
|
||||||
|
"lyon_geom",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lyon_tessellation"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3f586142e1280335b1bc89539f7c97dd80f08fc43e9ab1b74ef0a42b04aa353"
|
||||||
|
dependencies = [
|
||||||
|
"float_next_after",
|
||||||
|
"lyon_path",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mach2"
|
name = "mach2"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
|
@ -4058,6 +4193,12 @@ version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "skrifa"
|
name = "skrifa"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
|
|
@ -4174,6 +4315,16 @@ version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
|
checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "svgtypes"
|
||||||
|
version = "0.15.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
|
||||||
|
dependencies = [
|
||||||
|
"kurbo",
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swash"
|
name = "swash"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,7 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.17.3"
|
bevy = "0.17.3"
|
||||||
|
bevy_prototype_lyon = "0.15.0"
|
||||||
|
enumset = "1.1.10"
|
||||||
rand = "0.9.2"
|
rand = "0.9.2"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
|
|
||||||
BIN
assets/fonts/GloriaHalleluja.ttf
Normal file
BIN
assets/fonts/GloriaHalleluja.ttf
Normal file
Binary file not shown.
2
src/gameplay/mod.rs
Normal file
2
src/gameplay/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod navi;
|
||||||
|
pub mod pause;
|
||||||
135
src/gameplay/navi.rs
Normal file
135
src/gameplay/navi.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
use bevy::{
|
||||||
|
camera::visibility::RenderLayers, post_process::bloom::Bloom, prelude::*, sprite::Anchor,
|
||||||
|
};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
GameState, PauseState,
|
||||||
|
utils::input::{GameInputPlugin, InputButton, InputPressStatus},
|
||||||
|
};
|
||||||
|
|
||||||
|
const PLAYER_SPEED: f32 = 100.;
|
||||||
|
|
||||||
|
pub struct NaviGameplayPlugin;
|
||||||
|
|
||||||
|
impl Plugin for NaviGameplayPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(Startup, (setup_scene, spawn_bus, spawn_enemy))
|
||||||
|
.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
move_player
|
||||||
|
.run_if(in_state(GameState::Navi).and(in_state(PauseState::Running))),
|
||||||
|
follow_player,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PlayerVWBus;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[require(Camera2d)]
|
||||||
|
struct MainCamera;
|
||||||
|
|
||||||
|
pub fn setup_scene(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
) {
|
||||||
|
commands.spawn((
|
||||||
|
Mesh2d(meshes.add(Rectangle::new(1000., 70.))),
|
||||||
|
MeshMaterial2d(materials.add(Color::srgb(0.2, 0.2, 0.3))),
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
|
MainCamera,
|
||||||
|
Camera {
|
||||||
|
order: 1,
|
||||||
|
// clear_color: ClearColorConfig::None,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Bloom::NATURAL,
|
||||||
|
RenderLayers::layer(0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_bus(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
let texture = asset_server.load("bus/basicbus.png");
|
||||||
|
commands.spawn((
|
||||||
|
PlayerVWBus,
|
||||||
|
Sprite {
|
||||||
|
image: texture,
|
||||||
|
custom_size: Some(Vec2::new(192., 133.)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(2., 0., 3.),
|
||||||
|
Anchor::CENTER,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_enemy(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
) {
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
for _ in 0..10 {
|
||||||
|
commands.spawn((
|
||||||
|
Mesh2d(meshes.add(Circle::new(10.))),
|
||||||
|
MeshMaterial2d(materials.add(Color::srgb(1.1, 0.2, 0.3))),
|
||||||
|
Transform::from_xyz(
|
||||||
|
rng.random_range(-600..600) as f32,
|
||||||
|
rng.random_range(-600..600) as f32,
|
||||||
|
1.,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_player(
|
||||||
|
mut player: Single<&mut Transform, With<PlayerVWBus>>,
|
||||||
|
mut player_sprite: Single<&mut Sprite, With<PlayerVWBus>>,
|
||||||
|
time: Res<Time>,
|
||||||
|
buttons_pressed: Res<InputPressStatus>,
|
||||||
|
) {
|
||||||
|
let mut direction = Vec2::ZERO;
|
||||||
|
|
||||||
|
if buttons_pressed.contains(InputButton::Up) {
|
||||||
|
direction.y += 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons_pressed.contains(InputButton::Down) {
|
||||||
|
direction.y -= 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons_pressed.contains(InputButton::Left) {
|
||||||
|
direction.x -= 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if buttons_pressed.contains(InputButton::Right) {
|
||||||
|
direction.x += 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
let move_delta = direction.normalize_or_zero() * PLAYER_SPEED * time.delta_secs();
|
||||||
|
player.translation += move_delta.extend(0.);
|
||||||
|
|
||||||
|
if direction.x > 0. {
|
||||||
|
player_sprite.flip_x = true;
|
||||||
|
} else if direction.x < 0. {
|
||||||
|
player_sprite.flip_x = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn follow_player(
|
||||||
|
mut camera: Single<&mut Transform, (With<MainCamera>, Without<PlayerVWBus>)>,
|
||||||
|
player: Single<&Transform, (With<PlayerVWBus>, Without<MainCamera>)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
let Vec3 { x, y, .. } = player.translation;
|
||||||
|
let direction = Vec3::new(x, y, camera.translation.z);
|
||||||
|
|
||||||
|
camera
|
||||||
|
.translation
|
||||||
|
.smooth_nudge(&direction, 10., time.delta_secs());
|
||||||
|
}
|
||||||
115
src/gameplay/pause.rs
Normal file
115
src/gameplay/pause.rs
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
use bevy::{
|
||||||
|
camera::visibility::RenderLayers, post_process::bloom::Bloom, prelude::*, sprite::Anchor,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
GameState, PauseState,
|
||||||
|
utils::input::{GameInputPlugin, InputButton, InputMessage, InputPressStatus},
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLOR_BG: Color = Color::srgba_u8(249, 226, 156, 255);
|
||||||
|
const COLOR_HL1: Color = Color::srgba_u8(187, 241, 241, 255);
|
||||||
|
const COLOR_HL2: Color = Color::srgba_u8(192, 149, 145, 255);
|
||||||
|
|
||||||
|
pub struct PausePlugin;
|
||||||
|
|
||||||
|
impl Plugin for PausePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(Startup, setup_pause).add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
listen_for_pause.run_if(in_state(PauseState::Running)),
|
||||||
|
listen_for_unpause.run_if(in_state(PauseState::Paused)),
|
||||||
|
animate_in.run_if(in_state(PauseState::AnimatingIntoPause)),
|
||||||
|
animate_out.run_if(in_state(PauseState::AnimatingOutOfPause)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct PauseMenuRoot;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[require(Camera2d)]
|
||||||
|
struct PauseCamera;
|
||||||
|
|
||||||
|
fn setup_pause(
|
||||||
|
mut commands: Commands,
|
||||||
|
assets: Res<AssetServer>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
|
) {
|
||||||
|
commands.spawn((
|
||||||
|
PauseCamera,
|
||||||
|
Camera {
|
||||||
|
order: 3,
|
||||||
|
clear_color: ClearColorConfig::None,
|
||||||
|
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
// Bloom::NATURAL,
|
||||||
|
RenderLayers::layer(3),
|
||||||
|
));
|
||||||
|
commands.spawn((
|
||||||
|
Mesh2d(meshes.add(Triangle2d::new(
|
||||||
|
Vec2::new(-100., -100.),
|
||||||
|
Vec2::new(-100., 100.),
|
||||||
|
Vec2::new(-100., 100.),
|
||||||
|
))),
|
||||||
|
MeshMaterial2d(materials.add(Color::srgb(0.2, 0.2, 0.3))),
|
||||||
|
RenderLayers::layer(3),
|
||||||
|
));
|
||||||
|
commands.spawn((
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
width: percent(80),
|
||||||
|
height: percent(80),
|
||||||
|
align_items: AlignItems::Center,
|
||||||
|
justify_content: JustifyContent::Center,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
UiTransform::from_translation(Val2::px(0., 0.)),
|
||||||
|
BackgroundColor(COLOR_BG),
|
||||||
|
Visibility::Visible,
|
||||||
|
PauseMenuRoot,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listen_for_pause(
|
||||||
|
mut next: ResMut<NextState<PauseState>>,
|
||||||
|
mut btn_msgs: MessageReader<InputMessage>,
|
||||||
|
) {
|
||||||
|
for btn_msg in btn_msgs.read() {
|
||||||
|
if btn_msg.just_pressed(InputButton::Pause) {
|
||||||
|
next.set(PauseState::AnimatingIntoPause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listen_for_unpause(
|
||||||
|
mut next: ResMut<NextState<PauseState>>,
|
||||||
|
mut btn_msgs: MessageReader<InputMessage>,
|
||||||
|
) {
|
||||||
|
for btn_msg in btn_msgs.read() {
|
||||||
|
if btn_msg.just_pressed(InputButton::Pause) {
|
||||||
|
next.set(PauseState::AnimatingOutOfPause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate_in(
|
||||||
|
mut menu_visibility: Single<&mut Visibility, With<PauseMenuRoot>>,
|
||||||
|
mut next_state: ResMut<NextState<PauseState>>,
|
||||||
|
) {
|
||||||
|
**menu_visibility = Visibility::Visible;
|
||||||
|
next_state.set(PauseState::Paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate_out(
|
||||||
|
mut menu_visibility: Single<&mut Visibility, With<PauseMenuRoot>>,
|
||||||
|
mut next_state: ResMut<NextState<PauseState>>,
|
||||||
|
) {
|
||||||
|
**menu_visibility = Visibility::Hidden;
|
||||||
|
next_state.set(PauseState::Running);
|
||||||
|
}
|
||||||
131
src/main.rs
131
src/main.rs
|
|
@ -1,109 +1,40 @@
|
||||||
use bevy::{post_process::bloom::Bloom, prelude::*, sprite::Anchor};
|
use bevy::{post_process::bloom::Bloom, prelude::*, sprite::Anchor};
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
#[derive(Component)]
|
use crate::{
|
||||||
pub struct PlayerVWBus;
|
gameplay::{navi::NaviGameplayPlugin, pause::PausePlugin},
|
||||||
|
utils::input::{GameInputPlugin, InputButton, InputPressStatus},
|
||||||
|
};
|
||||||
|
|
||||||
const PLAYER_SPEED: f32 = 100.;
|
mod gameplay;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum GameState {
|
||||||
|
#[default]
|
||||||
|
Navi,
|
||||||
|
Combat,
|
||||||
|
MainMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum PauseState {
|
||||||
|
#[default]
|
||||||
|
Running,
|
||||||
|
Paused,
|
||||||
|
AnimatingIntoPause,
|
||||||
|
AnimatingOutOfPause,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins((
|
||||||
.add_systems(Startup, (setup_scene, spawn_bus, spawn_enemy))
|
DefaultPlugins,
|
||||||
.add_systems(Update, (move_player, follow_player))
|
GameInputPlugin,
|
||||||
|
NaviGameplayPlugin,
|
||||||
|
PausePlugin,
|
||||||
|
))
|
||||||
|
.init_state::<GameState>()
|
||||||
|
.init_state::<PauseState>()
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_scene(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
||||||
) {
|
|
||||||
commands.spawn((
|
|
||||||
Mesh2d(meshes.add(Rectangle::new(1000., 70.))),
|
|
||||||
MeshMaterial2d(materials.add(Color::srgb(0.2, 0.2, 0.3))),
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.spawn((Camera2d, Bloom::NATURAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_bus(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
||||||
let texture = asset_server.load("bus/basicbus.png");
|
|
||||||
commands.spawn((
|
|
||||||
PlayerVWBus,
|
|
||||||
Sprite {
|
|
||||||
image: texture,
|
|
||||||
custom_size: Some(Vec2::new(192., 133.)),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
Transform::from_xyz(2., 0., 3.),
|
|
||||||
Anchor::CENTER,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_enemy(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
||||||
) {
|
|
||||||
let mut rng = rand::rng();
|
|
||||||
for _ in 0..10 {
|
|
||||||
commands.spawn((
|
|
||||||
Mesh2d(meshes.add(Circle::new(10.))),
|
|
||||||
MeshMaterial2d(materials.add(Color::srgb(1.1, 0.2, 0.3))),
|
|
||||||
Transform::from_xyz(
|
|
||||||
rng.random_range(-600..600) as f32,
|
|
||||||
rng.random_range(-600..600) as f32,
|
|
||||||
1.,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_player(
|
|
||||||
mut player: Single<&mut Transform, With<PlayerVWBus>>,
|
|
||||||
mut player_sprite: Single<&mut Sprite, With<PlayerVWBus>>,
|
|
||||||
time: Res<Time>,
|
|
||||||
kb_input: Res<ButtonInput<KeyCode>>,
|
|
||||||
) {
|
|
||||||
let mut direction = Vec2::ZERO;
|
|
||||||
|
|
||||||
if kb_input.pressed(KeyCode::KeyW) {
|
|
||||||
direction.y += 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
if kb_input.pressed(KeyCode::KeyS) {
|
|
||||||
direction.y -= 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
if kb_input.pressed(KeyCode::KeyA) {
|
|
||||||
direction.x -= 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
if kb_input.pressed(KeyCode::KeyD) {
|
|
||||||
direction.x += 1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
let move_delta = direction.normalize_or_zero() * PLAYER_SPEED * time.delta_secs();
|
|
||||||
player.translation += move_delta.extend(0.);
|
|
||||||
|
|
||||||
if direction.x > 0. {
|
|
||||||
player_sprite.flip_x = true;
|
|
||||||
} else if direction.x < 0. {
|
|
||||||
player_sprite.flip_x = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_player(
|
|
||||||
mut camera: Single<&mut Transform, (With<Camera2d>, Without<PlayerVWBus>)>,
|
|
||||||
player: Single<&Transform, (With<PlayerVWBus>, Without<Camera2d>)>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
let Vec3 { x, y, .. } = player.translation;
|
|
||||||
let direction = Vec3::new(x, y, camera.translation.z);
|
|
||||||
|
|
||||||
camera
|
|
||||||
.translation
|
|
||||||
.smooth_nudge(&direction, 10., time.delta_secs());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
94
src/utils/input.rs
Normal file
94
src/utils/input.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
|
|
||||||
|
pub struct GameInputPlugin;
|
||||||
|
|
||||||
|
impl Plugin for GameInputPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.insert_resource(InputPressStatus::default())
|
||||||
|
.add_message::<InputMessage>()
|
||||||
|
.add_systems(Update, (process_input, input_debug_logger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_input(
|
||||||
|
kb_input: Res<ButtonInput<KeyCode>>,
|
||||||
|
mut ev_input: MessageWriter<InputMessage>,
|
||||||
|
mut pressed: ResMut<InputPressStatus>,
|
||||||
|
) {
|
||||||
|
for m in DEFAULT_KEY_MAP {
|
||||||
|
if kb_input.just_pressed(m.key) {
|
||||||
|
ev_input.write(InputMessage::new(m.button, InputAction::Pressed));
|
||||||
|
pressed.insert(m.button);
|
||||||
|
}
|
||||||
|
if kb_input.just_released(m.key) {
|
||||||
|
ev_input.write(InputMessage::new(m.button, InputAction::Released));
|
||||||
|
pressed.remove(m.button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(EnumSetType, Debug)]
|
||||||
|
pub enum InputButton {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Select,
|
||||||
|
Back,
|
||||||
|
Pause,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum InputAction {
|
||||||
|
Pressed,
|
||||||
|
Released,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message, Debug)]
|
||||||
|
pub struct InputMessage {
|
||||||
|
button: InputButton,
|
||||||
|
action: InputAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Resource, Deref, DerefMut)]
|
||||||
|
pub struct InputPressStatus(EnumSet<InputButton>);
|
||||||
|
|
||||||
|
pub struct KeyboardMapping {
|
||||||
|
key: KeyCode,
|
||||||
|
button: InputButton,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_KEY_MAP: [KeyboardMapping; 8] = [
|
||||||
|
KeyboardMapping::new(KeyCode::KeyW, InputButton::Up),
|
||||||
|
KeyboardMapping::new(KeyCode::ArrowUp, InputButton::Up),
|
||||||
|
KeyboardMapping::new(KeyCode::KeyA, InputButton::Left),
|
||||||
|
KeyboardMapping::new(KeyCode::KeyS, InputButton::Down),
|
||||||
|
KeyboardMapping::new(KeyCode::KeyD, InputButton::Right),
|
||||||
|
KeyboardMapping::new(KeyCode::KeyI, InputButton::Select),
|
||||||
|
KeyboardMapping::new(KeyCode::KeyO, InputButton::Back),
|
||||||
|
KeyboardMapping::new(KeyCode::Escape, InputButton::Pause),
|
||||||
|
];
|
||||||
|
|
||||||
|
impl InputMessage {
|
||||||
|
pub fn new(button: InputButton, action: InputAction) -> Self {
|
||||||
|
Self { button, action }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn just_pressed(&self, button: InputButton) -> bool {
|
||||||
|
self.button == button && self.action == InputAction::Pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardMapping {
|
||||||
|
pub const fn new(key: KeyCode, button: InputButton) -> Self {
|
||||||
|
Self { key, button }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input_debug_logger(mut input_reader: MessageReader<InputMessage>) {
|
||||||
|
for msg in input_reader.read() {
|
||||||
|
info!("Input Event: {:?}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/utils/mod.rs
Normal file
1
src/utils/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod input;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue