Skip to content
Snippets Groups Projects
Verified Commit f66ac5d6 authored by Louis's avatar Louis :fire:
Browse files

Refactor ship spawning & implement basic input

- Add a macro for implementing deref
- Add a spawner struct that will spawn entities
- Implement basic motion
- Implement basic input handling for user, via motion
parent fbd584c5
No related branches found
No related merge requests found
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;
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;
}
}
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;
}
}
}
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()
}
}
pub mod entities;
pub mod system; pub mod system;
pub mod utilities;
use bevy::asset::AssetServer; use bevy::prelude::{App, PluginGroup, Window, WindowPlugin};
use bevy::prelude::{App, Commands, PluginGroup, Res, Transform, Window, WindowPlugin};
use bevy::sprite::SpriteBundle;
use bevy::window::{WindowMode, WindowResolution}; use bevy::window::{WindowMode, WindowResolution};
use bevy::DefaultPlugins; 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() { fn main() {
App::new() App::new()
...@@ -29,6 +16,6 @@ fn main() { ...@@ -29,6 +16,6 @@ fn main() {
..Default::default() ..Default::default()
})) }))
.add_plugin(shoot_the_revival::system::SystemPlugin) .add_plugin(shoot_the_revival::system::SystemPlugin)
.add_startup_system(spawn_ship) .add_plugin(shoot_the_revival::entities::EntityPlugin)
.run(); .run();
} }
...@@ -29,7 +29,7 @@ pub fn spawn_2d_camera(mut commands: Commands) { ...@@ -29,7 +29,7 @@ pub fn spawn_2d_camera(mut commands: Commands) {
camera_2d: Camera2d { camera_2d: Camera2d {
clear_color: ClearColorConfig::Custom(Color::WHITE), 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() ..Default::default()
}, },
)); ));
......
#[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
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment