diff --git a/src/entities/mod.rs b/src/entities/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..e587cb61f12e20c4f1f47659683d3a3a746677e0 --- /dev/null +++ b/src/entities/mod.rs @@ -0,0 +1,24 @@ +mod motion; +mod player; +mod spawning; + +mod _plugin { + use bevy::app::App; + use bevy::prelude::Plugin; + + pub struct EntityPlugin; + impl Plugin for EntityPlugin { + fn build(&self, app: &mut App) { + app.add_startup_system(super::player::spawn_player) + .add_systems(( + super::player::process_player_input, + super::motion::apply_velocity, + )); + } + } +} + +pub use _plugin::EntityPlugin; +pub use motion::Velocity; +pub use player::Player; +pub use spawning::EntitySpawner; diff --git a/src/entities/motion.rs b/src/entities/motion.rs new file mode 100644 index 0000000000000000000000000000000000000000..e4a96d4b899e988775b83cb5abedb87d855dab49 --- /dev/null +++ b/src/entities/motion.rs @@ -0,0 +1,41 @@ +use crate::deref_as; +use bevy::math::Vec2; +use bevy::prelude::{Component, Query, Res, Time, Transform}; +use std::ops::Mul; + +#[derive(Clone, Copy, Debug, Component)] +pub struct Velocity(Vec2); +deref_as!(mut Velocity => Vec2); + +impl From<Vec2> for Velocity { + fn from(value: Vec2) -> Self { + Velocity(value) + } +} +impl Default for Velocity { + fn default() -> Self { + Self(Vec2::new(100.0, 100.0)) + } +} + +impl<T> Mul<T> for Velocity +where + Vec2: Mul<T, Output = Vec2>, +{ + type Output = Velocity; + + fn mul(self, rhs: T) -> Self::Output { + Velocity::from(self.0.mul(rhs)) + } +} + +impl Velocity { + pub const ZERO: Velocity = Velocity(Vec2::ZERO); +} + +pub fn apply_velocity(delta: Res<Time>, mut entity_query: Query<(&Velocity, &mut Transform)>) { + let dt = delta.delta_seconds(); + for (velocity, mut transform) in &mut entity_query { + transform.translation += velocity.extend(0.0) * dt; + } +} diff --git a/src/entities/player.rs b/src/entities/player.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab1bd70edb97fcc8fc0823a79c56bbc736722ed4 --- /dev/null +++ b/src/entities/player.rs @@ -0,0 +1,45 @@ +use crate::entities::spawning::EntitySpawner; +use crate::entities::Velocity; +use crate::system::window_bounds; +use bevy::math::Vec2; +use bevy::prelude::{Component, DetectChangesMut, Input, KeyCode, Query, Res, With}; + +#[derive(Component)] +pub struct Player; + +pub fn spawn_player(mut spawner: EntitySpawner) { + let bounds = window_bounds(); + spawner.spawn_player_at(bounds.half_size()); +} + +macro_rules! any_pressed { + ($input: expr, $key: expr $(, $more: expr),*) => {$input.pressed($key) $(|| any_pressed!($input, $more))*}; +} + +pub fn process_player_input( + mut player_query: Query<&mut Velocity, With<Player>>, + input: Res<Input<KeyCode>>, +) { + let mut delta = Vec2::default(); + + if any_pressed!(input, KeyCode::A, KeyCode::Left) { + delta.x -= 1.0; + } + if any_pressed!(input, KeyCode::D, KeyCode::Right) { + delta.x += 1.0; + } + if any_pressed!(input, KeyCode::S, KeyCode::Down) { + delta.y -= 1.0; + } + if any_pressed!(input, KeyCode::W, KeyCode::Up) { + delta.y += 1.0; + } + + for mut velocity in &mut player_query { + if delta != Vec2::ZERO { + *velocity = Velocity::default() * delta; + } else if **(velocity.bypass_change_detection()) != Vec2::ZERO { + *velocity = Velocity::ZERO; + } + } +} diff --git a/src/entities/spawning.rs b/src/entities/spawning.rs new file mode 100644 index 0000000000000000000000000000000000000000..27d3422be0e57cb5a49ce8b267982b1b47b3930e --- /dev/null +++ b/src/entities/spawning.rs @@ -0,0 +1,31 @@ +use crate::entities::motion::Velocity; +use crate::entities::Player; +use bevy::ecs::system::SystemParam; +use bevy::prelude::{AssetServer, Commands, Entity, Res, SpriteBundle, Transform, Vec2}; + +#[derive(SystemParam)] +pub struct EntitySpawner<'w, 's> { + commands: Commands<'w, 's>, + assets: Res<'w, AssetServer>, +} + +static Z_PLAYER: f32 = 300.0; +static Z_ITEMS: f32 = 200.0; +static Z_ENEMY: f32 = 250.0; +static Z_BACKGROUND: f32 = 50.0; + +impl<'w, 's> EntitySpawner<'w, 's> { + pub fn spawn_player_at(&mut self, position: Vec2) -> Entity { + self.commands + .spawn(( + SpriteBundle { + texture: self.assets.load("sprites/ship.png"), + transform: Transform::from_translation(position.extend(Z_PLAYER)), + ..Default::default() + }, + Velocity::ZERO, + Player, + )) + .id() + } +} diff --git a/src/lib.rs b/src/lib.rs index ac77f6383d401844e7ed78028f18fca9b16b4877..f4e402d620461fba88f54e504ad4b05ed1bf327f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,3 @@ +pub mod entities; pub mod system; +pub mod utilities; diff --git a/src/main.rs b/src/main.rs index dfe777435ae9b5c1be0c760990634385d01ffd1e..2f567b59d415c5425bcedbc7c38b6428a59fce8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,6 @@ -use bevy::asset::AssetServer; -use bevy::prelude::{App, Commands, PluginGroup, Res, Transform, Window, WindowPlugin}; -use bevy::sprite::SpriteBundle; +use bevy::prelude::{App, PluginGroup, Window, WindowPlugin}; use bevy::window::{WindowMode, WindowResolution}; use bevy::DefaultPlugins; -use shoot_the_revival::system::window_bounds; - -fn spawn_ship(mut commands: Commands, assets: Res<AssetServer>) { - let bounds = window_bounds(); - - commands.spawn(SpriteBundle { - texture: assets.load("sprites/ship.png"), - transform: Transform::from_translation(bounds.half_size().extend(0.0)), - ..Default::default() - }); -} fn main() { App::new() @@ -29,6 +16,6 @@ fn main() { ..Default::default() })) .add_plugin(shoot_the_revival::system::SystemPlugin) - .add_startup_system(spawn_ship) + .add_plugin(shoot_the_revival::entities::EntityPlugin) .run(); } diff --git a/src/system/camera.rs b/src/system/camera.rs index ee29be94e7c4945256d6e325bc37067be52a5662..dd74861d53868e42837c0e9a424c455929930986 100644 --- a/src/system/camera.rs +++ b/src/system/camera.rs @@ -29,7 +29,7 @@ pub fn spawn_2d_camera(mut commands: Commands) { camera_2d: Camera2d { clear_color: ClearColorConfig::Custom(Color::WHITE), }, - transform: Transform::from_translation(bounds.half_size().extend(0.0)), + transform: Transform::from_translation(bounds.half_size().extend(1000.0)), ..Default::default() }, )); diff --git a/src/utilities.rs b/src/utilities.rs new file mode 100644 index 0000000000000000000000000000000000000000..9d1010488208d59005b16f472744cb85518087c4 --- /dev/null +++ b/src/utilities.rs @@ -0,0 +1,20 @@ +#[macro_export] +macro_rules! deref_as { + ($outer:ty => $inner:ty) => { + impl ::std::ops::Deref for $outer { + type Target = $inner; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + }; + + (mut $outer:ty => $inner:ty) => { + deref_as!($outer => $inner); + impl ::std::ops::DerefMut for $outer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + } +}