Ported to bevy 0.15
parent
b72d550b4d
commit
ea93d50e44
File diff suppressed because it is too large
Load Diff
|
@ -2,11 +2,11 @@ cargo-features = ["codegen-backend"]
|
|||
|
||||
[package]
|
||||
name = "avoid-rs"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.14", features = ["wav"] }
|
||||
bevy = { version = "0.15", features = ["wav"] }
|
||||
fastrand = "*"
|
||||
|
||||
[profile.dev]
|
||||
|
|
|
@ -10,39 +10,41 @@ impl Plugin for AnimationPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Bundle, Default)]
|
||||
pub struct AnimationBundle {
|
||||
pub timer: AnimationTimer,
|
||||
|
||||
pub atlas: TextureAtlas,
|
||||
|
||||
pub indices: AnimationIndices,
|
||||
}
|
||||
|
||||
#[derive(Component, Default)]
|
||||
pub struct AnimationIndices {
|
||||
pub first_index: usize,
|
||||
pub last_index: usize,
|
||||
pub struct SpriteAnimation {
|
||||
pub first: usize,
|
||||
pub last: usize,
|
||||
pub timer: Timer,
|
||||
}
|
||||
|
||||
#[derive(Component, Default, Deref, DerefMut)]
|
||||
pub struct AnimationTimer(pub Timer);
|
||||
impl SpriteAnimation {
|
||||
pub fn new(last: usize, timer: Timer) -> Self {
|
||||
Self {
|
||||
first: 0,
|
||||
last,
|
||||
timer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Component, Default, Deref, DerefMut)]
|
||||
// pub struct AnimationTimer(pub Timer);
|
||||
|
||||
fn animation_tick(
|
||||
time: Res<Time>,
|
||||
mut query: Query<(
|
||||
&mut AnimationTimer,
|
||||
&mut TextureAtlas,
|
||||
&AnimationIndices,
|
||||
&Velocity,
|
||||
)>,
|
||||
mut query: Query<(&mut Sprite, &mut SpriteAnimation, &Velocity)>,
|
||||
) {
|
||||
for (mut timer, mut atlas, anim_indicies, velocity) in &mut query {
|
||||
for (mut sprite, mut anim, velocity) in &mut query {
|
||||
let Some(atlas) = &mut sprite.texture_atlas
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if velocity.length() > 0.0 {
|
||||
timer.tick(time.delta());
|
||||
if timer.just_finished() {
|
||||
atlas.index = if atlas.index == anim_indicies.last_index {
|
||||
anim_indicies.first_index
|
||||
anim.timer.tick(time.delta());
|
||||
if anim.timer.just_finished() {
|
||||
atlas.index = if atlas.index == anim.last {
|
||||
anim.first
|
||||
}
|
||||
else {
|
||||
atlas.index + 1
|
||||
|
|
|
@ -7,6 +7,7 @@ impl Plugin for PathFollow2DPlugin {
|
|||
}
|
||||
|
||||
#[derive(Component, Default)]
|
||||
#[require(Transform)]
|
||||
pub struct PathFollow2D {
|
||||
pub progress: f32,
|
||||
|
||||
|
@ -82,10 +83,3 @@ impl PathFollow2D {
|
|||
(Vec2::default(), Vec2::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Bundle, Default)]
|
||||
pub struct PathFollow2DBundle {
|
||||
pub path: PathFollow2D,
|
||||
|
||||
pub transform: Transform,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct Velocity(pub Vec2);
|
|||
|
||||
fn apply_velocity(time: Res<Time>, mut query: Query<(&mut Transform, &Velocity)>) {
|
||||
for (mut transform, velocity) in &mut query {
|
||||
transform.translation.x += velocity.x * time.delta_seconds();
|
||||
transform.translation.y += velocity.y * time.delta_seconds();
|
||||
transform.translation.x += velocity.x * time.delta_secs();
|
||||
transform.translation.y += velocity.y * time.delta_secs();
|
||||
}
|
||||
}
|
||||
|
|
13
src/enemy.rs
13
src/enemy.rs
|
@ -1,6 +1,6 @@
|
|||
use bevy::{color::palettes::css::RED, prelude::*};
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::common::velocity::VelocityPlugin;
|
||||
use crate::{common::animation::SpriteAnimation, level::Unit};
|
||||
|
||||
pub struct EnemyPlugin;
|
||||
|
||||
|
@ -13,14 +13,15 @@ impl Plugin for EnemyPlugin {
|
|||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(Unit, SpriteAnimation)]
|
||||
pub struct Enemy;
|
||||
|
||||
fn debug_direction(query: Query<&Transform, With<Enemy>>, mut gizmos: Gizmos) {
|
||||
for enemy in &query {
|
||||
fn debug_direction(query: Query<&Transform, With<Enemy>>, gizmos: Gizmos) {
|
||||
// for enemy in &query {
|
||||
// let start = enemy.translation.truncate();
|
||||
// let end = enemy.rotation.xyz().truncate() - start;
|
||||
// let end = start + Vec2::new(10.0, 0.0);
|
||||
// gizmos.arrow_2d(start, end, RED);
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
fn outside_bounds(
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use bevy::{
|
||||
input::gamepad::{GamepadConnection, GamepadEvent},
|
||||
prelude::*,
|
||||
};
|
||||
use bevy::{input::gamepad::GamepadEvent, prelude::*};
|
||||
|
||||
pub struct GamepadPlugin;
|
||||
|
||||
|
@ -15,7 +12,7 @@ impl Plugin for GamepadPlugin {
|
|||
pub struct GamepadOne(pub Gamepad);
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
commands: Commands,
|
||||
gamepad1: Option<Res<GamepadOne>>,
|
||||
mut gamepad_events: EventReader<GamepadEvent>,
|
||||
) {
|
||||
|
@ -25,19 +22,19 @@ fn setup(
|
|||
continue;
|
||||
};
|
||||
|
||||
match &conn.connection {
|
||||
GamepadConnection::Connected(info) => {
|
||||
if gamepad1.is_none() {
|
||||
commands.insert_resource(GamepadOne(conn.gamepad));
|
||||
}
|
||||
}
|
||||
GamepadConnection::Disconnected => {
|
||||
if let Some(GamepadOne(id)) = gamepad1.as_deref() {
|
||||
if *id == conn.gamepad {
|
||||
commands.remove_resource::<GamepadOne>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// match &conn.connection {
|
||||
// GamepadConnection::Connected(_) => {
|
||||
// if gamepad1.is_none() {
|
||||
// commands.insert_resource(GamepadOne(conn.gamepad));
|
||||
// }
|
||||
// }
|
||||
// GamepadConnection::Disconnected => {
|
||||
// if let Some(GamepadOne(id)) = gamepad1.as_deref() {
|
||||
// if *id == conn.gamepad {
|
||||
// commands.remove_resource::<GamepadOne>();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
129
src/hud.rs
129
src/hud.rs
|
@ -1,14 +1,6 @@
|
|||
use std::path::Path;
|
||||
use bevy::{asset::AssetPath, prelude::*};
|
||||
|
||||
use bevy::{
|
||||
asset::{io::AssetSourceId, AssetPath},
|
||||
ecs::query::QueryIter,
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
gamepad::GamepadOne, player::Player, score::Score, GameStartEvent, GameState, START_POSITION,
|
||||
};
|
||||
use crate::{player::Player, score::Score, GameState, START_POSITION};
|
||||
|
||||
pub struct HUDPlugin;
|
||||
|
||||
|
@ -22,7 +14,7 @@ impl Plugin for HUDPlugin {
|
|||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// let asset_path: AssetPath = "embedded://avoid_rs/assets/Xolonium-Regular.ttf".into();
|
||||
let asset_path: AssetPath = "Xolonium-Regular.ttf".into();
|
||||
let font: Handle<_> = asset_server.load(asset_path);
|
||||
let font: Handle<Font> = asset_server.load(asset_path);
|
||||
|
||||
// let path = Path::new("avoid-rs").join("assets/Xolonium-Regular.ttf");
|
||||
// let source = AssetSourceId::from("embedded");
|
||||
|
@ -31,132 +23,104 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
|
||||
// score UI, top middle
|
||||
commands
|
||||
.spawn(NodeBundle {
|
||||
style: Style {
|
||||
.spawn((Node {
|
||||
width: Val::Percent(100.0),
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
TextBundle::from_section(
|
||||
"0",
|
||||
TextStyle {
|
||||
},))
|
||||
.with_child((
|
||||
ScoreText,
|
||||
Text::new("0"),
|
||||
TextFont {
|
||||
font: font.clone(),
|
||||
font_size: 64.0,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_text_justify(JustifyText::Center)
|
||||
.with_style(Style {
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..Default::default()
|
||||
}),
|
||||
ScoreText,
|
||||
TextLayout::new_with_justify(JustifyText::Center),
|
||||
));
|
||||
});
|
||||
|
||||
// game info, middle of the screen
|
||||
commands
|
||||
.spawn(NodeBundle {
|
||||
style: Style {
|
||||
.spawn((
|
||||
IntroMessageText,
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(100.0),
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.with_children(|parent| {
|
||||
// game info, middle of the screen
|
||||
parent.spawn((
|
||||
TextBundle::from_section(
|
||||
"Dodge the creeps!",
|
||||
TextStyle {
|
||||
))
|
||||
.with_child((
|
||||
Text::new("Dodge the creeps!"),
|
||||
TextFont {
|
||||
font: font.clone(),
|
||||
font_size: 64.0,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.with_text_justify(JustifyText::Center)
|
||||
.with_style(Style {
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..Default::default()
|
||||
}),
|
||||
IntroMessageText,
|
||||
StartMenuUI,
|
||||
TextLayout::new_with_justify(JustifyText::Center),
|
||||
));
|
||||
});
|
||||
|
||||
commands
|
||||
.spawn(NodeBundle {
|
||||
style: Style {
|
||||
.spawn((
|
||||
StartMenuUI,
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(90.0),
|
||||
align_items: AlignItems::End,
|
||||
justify_content: JustifyContent::Center,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent
|
||||
.spawn((
|
||||
ButtonBundle {
|
||||
style: Style {
|
||||
StartButton,
|
||||
Node {
|
||||
width: Val::Px(200.0),
|
||||
height: Val::Px(100.0),
|
||||
border: UiRect::all(Val::Px(5.0)),
|
||||
// horizontally center child text
|
||||
justify_content: JustifyContent::Center,
|
||||
// vertically center child text
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
..Default::default()
|
||||
},
|
||||
border_color: BorderColor(Color::BLACK),
|
||||
border_radius: BorderRadius::all(Val::Px(10.0)),
|
||||
background_color: Color::srgb(0.15, 0.15, 0.15).into(),
|
||||
..default()
|
||||
},
|
||||
StartButton,
|
||||
StartMenuUI,
|
||||
BorderColor(Color::BLACK),
|
||||
BorderRadius::all(Val::Px(10.0)),
|
||||
BackgroundColor::from(Color::srgb(0.15, 0.15, 0.15)),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn(TextBundle::from_section(
|
||||
"Start",
|
||||
TextStyle {
|
||||
.with_child((
|
||||
Text::new("Start"),
|
||||
TextFont {
|
||||
font: font.clone(),
|
||||
font_size: 64.0,
|
||||
color: Color::srgb(0.9, 0.9, 0.9),
|
||||
..Default::default()
|
||||
},
|
||||
TextColor::from(Color::srgb(0.9, 0.9, 0.9)),
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Default)]
|
||||
#[require(Text)]
|
||||
pub struct ScoreText;
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(StartMenuUI, Text)]
|
||||
pub struct IntroMessageText;
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(StartMenuUI, Button)]
|
||||
pub struct StartButton;
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Default)]
|
||||
pub struct StartMenuUI;
|
||||
|
||||
fn start_button_logic(
|
||||
current_state: Res<State<GameState>>,
|
||||
mut state: ResMut<NextState<GameState>>,
|
||||
mut score: ResMut<Score>,
|
||||
gamepads: Res<ButtonInput<GamepadButton>>,
|
||||
gamepad1: Option<Res<GamepadOne>>,
|
||||
gamepads: Query<&Gamepad>,
|
||||
mut button: Query<(&Interaction, &mut BorderColor), With<StartButton>>,
|
||||
mut player_query: Query<(&mut Transform, &mut Visibility), With<Player>>,
|
||||
mut ui_elems_query: Query<&mut Visibility, (With<StartMenuUI>, Without<Player>)>,
|
||||
|
@ -169,13 +133,9 @@ fn start_button_logic(
|
|||
let mut score_text = score_text_query.single_mut();
|
||||
let (mut player_transform, mut player_visibility) = player_query.single_mut();
|
||||
|
||||
if let Some(gamepad) = gamepad1.as_deref() {
|
||||
let start_btn = GamepadButton {
|
||||
gamepad: gamepad.0,
|
||||
button_type: GamepadButtonType::Start,
|
||||
};
|
||||
let gamepad = gamepads.single();
|
||||
|
||||
if gamepads.pressed(start_btn) {
|
||||
if gamepad.just_pressed(GamepadButton::Start) {
|
||||
start_game(
|
||||
&mut score_text,
|
||||
&mut score,
|
||||
|
@ -184,10 +144,11 @@ fn start_button_logic(
|
|||
&mut player_visibility,
|
||||
&mut player_transform,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let (interaction, mut border_color) = button.single_mut();
|
||||
|
||||
match *interaction {
|
||||
Interaction::Pressed => {
|
||||
start_game(
|
||||
|
@ -213,7 +174,7 @@ fn start_game(
|
|||
player_transform: &mut Transform,
|
||||
) {
|
||||
score.0 = 0;
|
||||
score_text.sections[0].value = format!("{}", score.0);
|
||||
score_text.0 = format!("{}", score.0);
|
||||
|
||||
state.set(GameState::Playing);
|
||||
|
||||
|
|
69
src/level.rs
69
src/level.rs
|
@ -1,20 +1,19 @@
|
|||
use std::f32::consts::PI;
|
||||
|
||||
use bevy::{
|
||||
color::palettes::css::{LIME, RED},
|
||||
math::bounding::{Aabb2d, BoundingCircle, BoundingVolume, IntersectsVolume},
|
||||
math::bounding::{Aabb2d, BoundingCircle, IntersectsVolume},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
// use rand::Rng;
|
||||
use crate::{
|
||||
common::{
|
||||
animation::{AnimationBundle, AnimationIndices, AnimationPlugin, AnimationTimer},
|
||||
path_follow::{PathFollow2D, PathFollow2DBundle, PathFollow2DPlugin},
|
||||
animation::{AnimationPlugin, SpriteAnimation},
|
||||
path_follow::{PathFollow2D, PathFollow2DPlugin},
|
||||
velocity::{Velocity, VelocityPlugin},
|
||||
},
|
||||
enemy::{Enemy, EnemyPlugin},
|
||||
hud::{HUDPlugin, ScoreText, StartMenuUI},
|
||||
hud::{HUDPlugin, StartMenuUI},
|
||||
player::{Player, PlayerPlugin},
|
||||
score::{Score, ScorePlugin},
|
||||
GameOverEvent, GameState,
|
||||
|
@ -42,8 +41,7 @@ impl Plugin for LevelPlugin {
|
|||
}
|
||||
|
||||
fn setup(mut commands: Commands) {
|
||||
commands.spawn(PathFollow2DBundle {
|
||||
path: PathFollow2D {
|
||||
commands.spawn(PathFollow2D {
|
||||
progress: 0.0,
|
||||
points: vec![
|
||||
Vec2::new(0.0, 720.0),
|
||||
|
@ -52,25 +50,17 @@ fn setup(mut commands: Commands) {
|
|||
Vec2::new(0.0, 0.0),
|
||||
],
|
||||
looping: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Resource, Deref, DerefMut)]
|
||||
struct SpawnTimer(Timer);
|
||||
|
||||
#[derive(Bundle, Default)]
|
||||
pub struct UnitBundle {
|
||||
pub sprite: SpriteBundle,
|
||||
#[derive(Component, Default)]
|
||||
#[require(Sprite, Velocity, Collider)]
|
||||
pub struct Unit;
|
||||
|
||||
pub velocity: Velocity,
|
||||
|
||||
pub animator: AnimationBundle,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Default)]
|
||||
pub struct Collider;
|
||||
|
||||
#[derive(Event, Default)]
|
||||
|
@ -115,43 +105,33 @@ fn spawn_enemy(
|
|||
|
||||
commands.spawn((
|
||||
Enemy,
|
||||
Collider,
|
||||
UnitBundle {
|
||||
sprite: SpriteBundle {
|
||||
transform: Transform {
|
||||
Transform {
|
||||
translation: spawn_pos.extend(1.0),
|
||||
rotation: direction,
|
||||
scale: Vec2::new(0.75, 0.75).extend(1.0),
|
||||
},
|
||||
texture: asset_server.load(idx),
|
||||
..Default::default()
|
||||
},
|
||||
animator: AnimationBundle {
|
||||
atlas: TextureAtlas {
|
||||
Sprite {
|
||||
image: asset_server.load(idx),
|
||||
texture_atlas: Some(TextureAtlas {
|
||||
layout: texture_atlas_layouts,
|
||||
index: 0,
|
||||
},
|
||||
timer: AnimationTimer(Timer::from_seconds(0.3, TimerMode::Repeating)),
|
||||
indices: AnimationIndices {
|
||||
first_index: 0,
|
||||
last_index: 1,
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
velocity: Velocity(velocity),
|
||||
},
|
||||
SpriteAnimation::new(1, Timer::from_seconds(0.3, TimerMode::Repeating)),
|
||||
Velocity(velocity),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_collisions(
|
||||
mut commands: Commands,
|
||||
mut score: ResMut<Score>,
|
||||
commands: Commands,
|
||||
score: ResMut<Score>,
|
||||
mut player_query: Query<(&mut Velocity, &Transform), With<Player>>,
|
||||
collider_query: Query<(Entity, &Transform), (With<Collider>, With<Enemy>)>,
|
||||
mut game_over_events: EventWriter<GameOverEvent>,
|
||||
) {
|
||||
let (mut player_velocity, player_transform) = player_query.single_mut();
|
||||
let (player_velocity, player_transform) = player_query.single_mut();
|
||||
|
||||
for (collider_entity, collider_transform) in &collider_query {
|
||||
let collision = player_collision(
|
||||
|
@ -193,11 +173,10 @@ fn game_over(
|
|||
commands.entity(enemy).despawn();
|
||||
}
|
||||
|
||||
commands.spawn(AudioBundle {
|
||||
source: asset_server.load("gameover.wav"),
|
||||
// auto-despawn the entity when playback finishes
|
||||
settings: PlaybackSettings::DESPAWN,
|
||||
});
|
||||
commands.spawn((
|
||||
AudioPlayer::new(asset_server.load("gameover.wav")),
|
||||
PlaybackSettings::DESPAWN,
|
||||
));
|
||||
}
|
||||
|
||||
fn player_collision(player: BoundingCircle, bounding_box: Aabb2d) -> bool {
|
||||
|
@ -208,7 +187,7 @@ fn player_collision(player: BoundingCircle, bounding_box: Aabb2d) -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
fn debug_gizmos(mut gizmos: Gizmos, query: Query<&PathFollow2D>) {
|
||||
fn debug_gizmos(gizmos: Gizmos, query: Query<&PathFollow2D>) {
|
||||
for path in &query {
|
||||
// let x = path.points.len();
|
||||
// for i in 0..x {
|
||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -1,18 +1,7 @@
|
|||
use std::default;
|
||||
|
||||
use bevy::{
|
||||
asset::{embedded_asset, embedded_path},
|
||||
diagnostic::FrameTimeDiagnosticsPlugin,
|
||||
prelude::*,
|
||||
render::camera::Viewport,
|
||||
window::{WindowMode, WindowResolution},
|
||||
};
|
||||
use bevy::{diagnostic::FrameTimeDiagnosticsPlugin, prelude::*, window::WindowResolution};
|
||||
use common::mouse::{Mouse, MousePlugin};
|
||||
use gamepad::GamepadPlugin;
|
||||
use hud::HUDPlugin;
|
||||
use level::LevelPlugin;
|
||||
use player::PlayerPlugin;
|
||||
use score::ScorePlugin;
|
||||
|
||||
mod common;
|
||||
mod enemy;
|
||||
|
@ -42,25 +31,10 @@ struct GameOverEvent;
|
|||
struct GameStartEvent;
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn(Camera2dBundle {
|
||||
camera: Camera {
|
||||
viewport: Some(Viewport {
|
||||
physical_position: UVec2::new(0, 0),
|
||||
physical_size: UVec2::new(480, 720),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
transform: Transform {
|
||||
translation: Vec3 {
|
||||
x: (SCREEN_WIDTH / 2) as f32,
|
||||
y: (SCREEN_HEIGHT / 2) as f32,
|
||||
z: 1.0,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
commands.spawn((
|
||||
Camera2d,
|
||||
Transform::from_xyz((SCREEN_WIDTH / 2) as f32, (SCREEN_HEIGHT / 2) as f32, 1.0),
|
||||
));
|
||||
}
|
||||
|
||||
fn debug_mouse(mouse: Res<Mouse>) {
|
||||
|
|
103
src/player.rs
103
src/player.rs
|
@ -1,19 +1,11 @@
|
|||
use std::f32::consts::PI;
|
||||
|
||||
use bevy::{
|
||||
input::gamepad::{GamepadConnection, GamepadEvent},
|
||||
prelude::*,
|
||||
render::view::VisibilityPlugin,
|
||||
};
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{
|
||||
common::{
|
||||
animation::{AnimationBundle, AnimationIndices, AnimationPlugin, AnimationTimer},
|
||||
velocity::Velocity,
|
||||
},
|
||||
gamepad::GamepadOne,
|
||||
level::{Collider, UnitBundle},
|
||||
GameState, SCREEN_HEIGHT, SCREEN_WIDTH, START_POSITION,
|
||||
common::{animation::SpriteAnimation, velocity::Velocity},
|
||||
level::Unit,
|
||||
GameState, START_POSITION,
|
||||
};
|
||||
|
||||
pub struct PlayerPlugin;
|
||||
|
@ -29,6 +21,7 @@ impl Plugin for PlayerPlugin {
|
|||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(Unit, SpriteAnimation)]
|
||||
pub struct Player;
|
||||
|
||||
fn setup(
|
||||
|
@ -37,52 +30,39 @@ fn setup(
|
|||
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
|
||||
) {
|
||||
let layout = TextureAtlasLayout::from_grid(UVec2::splat(135), 2, 1, None, None);
|
||||
let texture_atlas_layouts = texture_atlas_layouts.add(layout);
|
||||
let layout_handle = texture_atlas_layouts.add(layout);
|
||||
|
||||
commands.spawn((
|
||||
Player,
|
||||
Collider,
|
||||
UnitBundle {
|
||||
sprite: SpriteBundle {
|
||||
transform: Transform {
|
||||
Transform {
|
||||
translation: START_POSITION,
|
||||
scale: Vec2::new(0.5, 0.5).extend(1.0),
|
||||
..Default::default()
|
||||
},
|
||||
visibility: Visibility::Hidden,
|
||||
texture: asset_server.load("player.png"),
|
||||
..Default::default()
|
||||
},
|
||||
animator: AnimationBundle {
|
||||
atlas: TextureAtlas {
|
||||
layout: texture_atlas_layouts,
|
||||
Visibility::Hidden,
|
||||
Sprite {
|
||||
image: asset_server.load("player.png"),
|
||||
texture_atlas: Some(TextureAtlas {
|
||||
layout: layout_handle,
|
||||
index: 0,
|
||||
},
|
||||
timer: AnimationTimer(Timer::from_seconds(0.3, TimerMode::Repeating)),
|
||||
indices: AnimationIndices {
|
||||
first_index: 0,
|
||||
last_index: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
SpriteAnimation::new(1, Timer::from_seconds(0.3, TimerMode::Repeating)),
|
||||
));
|
||||
}
|
||||
|
||||
fn move_player(
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
axes: Res<Axis<GamepadAxis>>,
|
||||
gamepads: Res<ButtonInput<GamepadButton>>,
|
||||
gamepad1: Option<Res<GamepadOne>>,
|
||||
gamepads: Query<&Gamepad>,
|
||||
mut query: Query<(&mut Transform, &mut Velocity), With<Player>>,
|
||||
window: Query<&Window>,
|
||||
) {
|
||||
let (mut transform, mut velocity) = query.single_mut();
|
||||
let gamepad = gamepads.single();
|
||||
velocity.0 = Vec2::ZERO;
|
||||
|
||||
if let Some(gamepad) = gamepad1.as_deref() {
|
||||
handle_gamepad_movement(&axes, gamepad, &gamepads, &mut velocity);
|
||||
};
|
||||
handle_gamepad_movement(gamepad, &mut velocity);
|
||||
|
||||
if keys.pressed(KeyCode::ArrowRight) {
|
||||
velocity.x += 1.0;
|
||||
|
@ -109,59 +89,26 @@ fn move_player(
|
|||
transform.translation = transform.translation.clamp(Vec3::ZERO, screen_size);
|
||||
}
|
||||
|
||||
fn handle_gamepad_movement(
|
||||
axes: &Axis<GamepadAxis>,
|
||||
gamepad: &GamepadOne,
|
||||
gamepads: &Res<ButtonInput<GamepadButton>>,
|
||||
velocity: &mut Velocity,
|
||||
) {
|
||||
let axis_lx = GamepadAxis {
|
||||
gamepad: gamepad.0,
|
||||
axis_type: GamepadAxisType::LeftStickX,
|
||||
};
|
||||
let axis_ly = GamepadAxis {
|
||||
gamepad: gamepad.0,
|
||||
axis_type: GamepadAxisType::LeftStickY,
|
||||
};
|
||||
fn handle_gamepad_movement(gamepad: &Gamepad, velocity: &mut Velocity) {
|
||||
let axis_lx = gamepad.get(GamepadAxis::LeftStickX).unwrap_or_default();
|
||||
let axis_ly = gamepad.get(GamepadAxis::LeftStickY).unwrap_or_default();
|
||||
|
||||
if let (Some(x), Some(y)) = (axes.get(axis_lx), axes.get(axis_ly)) {
|
||||
let left_stick = Vec2::new(x, y);
|
||||
let left_stick = Vec2::new(axis_lx, axis_ly);
|
||||
if left_stick.length() > 0.25 {
|
||||
*velocity = Velocity(left_stick);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let up_btn = GamepadButton {
|
||||
gamepad: gamepad.0,
|
||||
button_type: GamepadButtonType::DPadUp,
|
||||
};
|
||||
|
||||
let down_btn = GamepadButton {
|
||||
gamepad: gamepad.0,
|
||||
button_type: GamepadButtonType::DPadDown,
|
||||
};
|
||||
|
||||
let left_btn = GamepadButton {
|
||||
gamepad: gamepad.0,
|
||||
button_type: GamepadButtonType::DPadLeft,
|
||||
};
|
||||
|
||||
let right_btn = GamepadButton {
|
||||
gamepad: gamepad.0,
|
||||
button_type: GamepadButtonType::DPadRight,
|
||||
};
|
||||
|
||||
if gamepads.pressed(right_btn) {
|
||||
if gamepad.pressed(GamepadButton::DPadRight) {
|
||||
velocity.x += 1.0;
|
||||
}
|
||||
if gamepads.pressed(left_btn) {
|
||||
if gamepad.pressed(GamepadButton::DPadLeft) {
|
||||
velocity.x -= 1.0;
|
||||
}
|
||||
if gamepads.pressed(up_btn) {
|
||||
if gamepad.pressed(GamepadButton::DPadUp) {
|
||||
velocity.y += 1.0;
|
||||
}
|
||||
if gamepads.pressed(down_btn) {
|
||||
if gamepad.pressed(GamepadButton::DPadDown) {
|
||||
velocity.y -= 1.0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,6 @@ fn score_tick(
|
|||
timer.tick(time.delta());
|
||||
if timer.just_finished() {
|
||||
score.0 += 1;
|
||||
score_text.sections[0].value = format!("{}", score.0);
|
||||
score_text.0 = format!("{}", score.0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue