Skip to content

Commit 6e34487

Browse files
authoredJun 4, 2024
Merge pull request #3 from ArthurBugan/feat/add-debug-and-more-enemies
feat: add debug panel, reorder spritesheet and more assets
2 parents 89f0391 + 4e8e776 commit 6e34487

20 files changed

+1349
-720
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/target
22
/out
3+
.DS_Store

‎Cargo.lock

+1,135-587
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+18-11
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,25 @@ edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

8-
[dependencies]
9-
bevy = { version = "0.13.1", features = ["dynamic_linking"] }
10-
bevy_pancam = "0.11.0"
11-
kd-tree = "0.5.3"
12-
rand = "0.8.5"
13-
typenum = "1.17.0"
14-
15-
[workspace]
16-
resolver = "2"
17-
8+
# Enable a small amount of optimization in debug mode
189
[profile.dev]
1910
opt-level = 1
2011

2112
[profile.dev.package."*"]
22-
opt-level = 3
13+
opt-level = 3
14+
15+
[profile.release]
16+
lto = true
17+
opt-level = 3
18+
codegen-units = 1
19+
incremental = false
20+
debug = false
21+
22+
[dependencies]
23+
bevy = "0.13.*"
24+
bevy-inspector-egui = "0.24.*"
25+
iyes_perf_ui = "0.2.*"
26+
bevy_pancam = "0.11.0"
27+
kd-tree = "0.5.3"
28+
rand = "0.8.5"
29+
typenum = "1.17.0"

‎assets/monogram.ttf

100644100755
159 KB
Binary file not shown.

‎assets/textures/Pawn_Blue.png

-30.8 KB
Binary file not shown.

‎assets/textures/Pawn_Purple.png

-30.8 KB
Binary file not shown.

‎assets/textures/Pawn_Red.png

-30.8 KB
Binary file not shown.

‎assets/textures/Pawn_Yellow.png

-30.8 KB
Binary file not shown.

‎assets/textures/Torch_Blue.png

-56.7 KB
Binary file not shown.

‎assets/textures/all_textures.png

1.06 MB
Loading

‎src/animation.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ pub struct AnimationPlugin;
1313
#[derive(Component, Deref, DerefMut)]
1414
pub struct AnimationTimer(pub Timer);
1515

16+
#[derive(Component)]
17+
pub struct AnimationIndices {
18+
pub first: usize,
19+
pub last: usize,
20+
}
21+
1622
impl Plugin for AnimationPlugin {
1723
fn build(&self, app: &mut App) {
1824
app.add_systems(
@@ -47,14 +53,20 @@ fn animate_player(
4753
}
4854

4955
let (mut atlas, state, timer) = player_query.single_mut();
56+
5057
if timer.just_finished() {
51-
let base_sprite_index = match state {
52-
PlayerState::Idle => 0,
53-
PlayerState::Run => 32,
58+
let base_sprite_index: AnimationIndices = match state {
59+
PlayerState::Idle => AnimationIndices { first: 0, last: 5 },
60+
PlayerState::Run => AnimationIndices { first: 6, last: 11 },
5461
};
5562

56-
atlas.index = base_sprite_index + ((atlas.index + 1) * 2) % 10;
57-
info!("atlas.index: {}", atlas.index);
63+
if base_sprite_index.last <= atlas.index {
64+
atlas.index = base_sprite_index.first;
65+
} else if base_sprite_index.first > atlas.index {
66+
atlas.index = base_sprite_index.first;
67+
} else {
68+
atlas.index = atlas.index + 1
69+
}
5870
}
5971
}
6072

@@ -67,7 +79,13 @@ fn animate_enemy(
6779

6880
for (mut atlas, timer, enemy_type) in enemy_query.iter_mut() {
6981
if timer.just_finished() {
70-
atlas.index = enemy_type.get_base_sprite_index() + ((atlas.index + 1) * 2) % 10;
82+
if enemy_type.get_base_sprite_index().last <= atlas.index {
83+
atlas.index = enemy_type.get_base_sprite_index().first;
84+
} else if enemy_type.get_base_sprite_index().first > atlas.index {
85+
atlas.index = enemy_type.get_base_sprite_index().first;
86+
} else {
87+
atlas.index = atlas.index + 1
88+
}
7189
}
7290
}
7391
}

‎src/configs.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ pub const WW: f32 = 1200.0;
33
pub const WH: f32 = 900.0;
44

55
// Sprites
6-
pub const SPRITE_SHEET_PATH: &str = "textures/Pawn_Blue.png";
7-
pub const SPRITE_SCALE_FACTOR: f32 = 0.5;
6+
pub const SPRITE_SCALE_FACTOR: f32 = 1.5;
87
pub const TILE_W: usize = 64;
98
pub const TILE_H: usize = 64;
109
pub const SPRITE_SHEET_W: usize = 16;
1110
pub const SPRITE_SHEET_H: usize = 16;
1211

1312
// World
14-
pub const NUM_WORLD_DECORATIONS: usize = 500;
13+
pub const NUM_WORLD_DECORATIONS: usize = 200;
1514
pub const WORLD_W: f32 = 3000.0;
1615
pub const WORLD_H: f32 = 2500.0;
1716

@@ -20,7 +19,7 @@ pub const PLAYER_SPEED: f32 = 2.0;
2019
pub const PLAYER_HEALTH: f32 = 100.0;
2120

2221
// Enemy
23-
pub const MAX_NUM_ENEMIES: usize = 20;
22+
pub const MAX_NUM_ENEMIES: usize = 5;
2423
pub const ENEMY_DAMAGE: f32 = 1.0;
2524
pub const SPAWN_RATE_PER_SECOND: usize = 2;
2625
pub const ENEMY_HEALTH: f32 = 100.0;

‎src/debug.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use bevy::prelude::*;
2+
use bevy_inspector_egui::quick::WorldInspectorPlugin;
3+
use iyes_perf_ui::PerfUiCompleteBundle;
4+
use iyes_perf_ui::PerfUiPlugin;
5+
6+
use crate::state::GameState;
7+
8+
pub struct DebugPlugin;
9+
10+
impl Plugin for DebugPlugin {
11+
fn build(&self, app: &mut App) {
12+
#[cfg(debug_assertions)]
13+
app.add_systems(OnEnter(GameState::InGame), debug_show_perf_stats);
14+
15+
app.add_plugins(WorldInspectorPlugin::new())
16+
.add_plugins(PerfUiPlugin)
17+
.add_plugins(bevy::diagnostic::FrameTimeDiagnosticsPlugin)
18+
.add_plugins(bevy::diagnostic::EntityCountDiagnosticsPlugin)
19+
.add_plugins(bevy::diagnostic::SystemInformationDiagnosticsPlugin);
20+
}
21+
}
22+
23+
#[cfg(debug_assertions)]
24+
fn debug_show_perf_stats(mut commands: Commands) {
25+
commands.spawn(PerfUiCompleteBundle::default());
26+
}

‎src/enemy.rs

+80-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use animation::AnimationIndices;
12
use bevy::utils::Duration;
23
use std::f32::consts::PI;
34

@@ -20,9 +21,18 @@ pub struct Enemy {
2021

2122
#[derive(Component)]
2223
pub enum EnemyType {
23-
Green,
24-
Red,
25-
Skin,
24+
TorchBlue,
25+
TorchRed,
26+
TorchPurple,
27+
TorchYellow,
28+
BarrelBlue,
29+
BarrelRed,
30+
BarrelPurple,
31+
BarrelYellow,
32+
TntBlue,
33+
TntRed,
34+
TntPurple,
35+
TntYellow,
2636
}
2737

2838
impl Plugin for EnemyPlugin {
@@ -83,12 +93,13 @@ fn spawn_enemies(
8393
for _ in 0..enemy_spawn_count {
8494
let (x, y) = get_random_position_around(player_pos);
8595
let enemy_type = EnemyType::get_rand_enemy();
96+
8697
commands.spawn((
8798
SpriteSheetBundle {
8899
texture: handle.image.clone().unwrap(),
89100
atlas: TextureAtlas {
90101
layout: handle.layout.clone().unwrap(),
91-
index: enemy_type.get_base_sprite_index(),
102+
index: enemy_type.get_base_sprite_index().first,
92103
},
93104
transform: Transform::from_translation(vec3(x, y, 1.0))
94105
.with_scale(Vec3::splat(SPRITE_SCALE_FACTOR)),
@@ -127,19 +138,76 @@ impl Default for Enemy {
127138
impl EnemyType {
128139
fn get_rand_enemy() -> Self {
129140
let mut rng = rand::thread_rng();
130-
let rand_index = rng.gen_range(0..3);
141+
let rand_index = rng.gen_range(0..11);
142+
131143
return match rand_index {
132-
0 => Self::Green,
133-
1 => Self::Red,
134-
_ => Self::Skin,
144+
0 => Self::TorchBlue,
145+
1 => Self::TorchYellow,
146+
2 => Self::TorchPurple,
147+
3 => Self::TorchRed,
148+
4 => Self::BarrelBlue,
149+
5 => Self::BarrelRed,
150+
6 => Self::BarrelPurple,
151+
7 => Self::BarrelYellow,
152+
8 => Self::TntBlue,
153+
9 => Self::TntRed,
154+
10 => Self::TntPurple,
155+
11 => Self::TntYellow,
156+
_ => Self::TorchBlue,
135157
};
136158
}
137159

138-
pub fn get_base_sprite_index(&self) -> usize {
160+
pub fn get_base_sprite_index(&self) -> AnimationIndices {
139161
match self {
140-
EnemyType::Green => 200,
141-
EnemyType::Red => 300,
142-
EnemyType::Skin => 400,
162+
EnemyType::TorchBlue => AnimationIndices {
163+
first: 606,
164+
last: 611,
165+
},
166+
EnemyType::TorchYellow => AnimationIndices {
167+
first: 606,
168+
last: 611,
169+
},
170+
EnemyType::TorchPurple => AnimationIndices {
171+
first: 606,
172+
last: 611,
173+
},
174+
EnemyType::TorchRed => AnimationIndices {
175+
first: 606,
176+
last: 611,
177+
},
178+
179+
EnemyType::BarrelBlue => AnimationIndices {
180+
first: 606,
181+
last: 611,
182+
},
183+
EnemyType::BarrelRed => AnimationIndices {
184+
first: 606,
185+
last: 611,
186+
},
187+
EnemyType::BarrelPurple => AnimationIndices {
188+
first: 606,
189+
last: 611,
190+
},
191+
EnemyType::BarrelYellow => AnimationIndices {
192+
first: 606,
193+
last: 611,
194+
},
195+
EnemyType::TntBlue => AnimationIndices {
196+
first: 606,
197+
last: 611,
198+
},
199+
EnemyType::TntRed => AnimationIndices {
200+
first: 606,
201+
last: 611,
202+
},
203+
EnemyType::TntPurple => AnimationIndices {
204+
first: 606,
205+
last: 611,
206+
},
207+
EnemyType::TntYellow => AnimationIndices {
208+
first: 606,
209+
last: 611,
210+
},
143211
}
144212
}
145213
}

‎src/gui.rs

+1-78
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
21
use bevy::prelude::*;
32

43
use crate::enemy::Enemy;
@@ -15,91 +14,15 @@ struct MainMenuItem;
1514

1615
impl Plugin for GuiPlugin {
1716
fn build(&self, app: &mut App) {
18-
app.add_plugins(FrameTimeDiagnosticsPlugin)
19-
.add_systems(OnEnter(GameState::MainMenu), setup_main_menu)
17+
app.add_systems(OnEnter(GameState::MainMenu), setup_main_menu)
2018
.add_systems(OnExit(GameState::MainMenu), despawn_main_menu)
2119
.add_systems(
2220
Update,
2321
handle_main_menu_buttons.run_if(in_state(GameState::MainMenu)),
24-
)
25-
.add_systems(OnEnter(GameState::GameInit), spawn_debug_text)
26-
.add_systems(
27-
Update,
28-
update_debug_text.run_if(in_state(GameState::InGame)),
2922
);
3023
}
3124
}
3225

33-
fn spawn_debug_text(mut commands: Commands, asset_server: Res<AssetServer>) {
34-
commands
35-
.spawn((
36-
NodeBundle {
37-
style: Style {
38-
width: Val::Percent(100.0),
39-
height: Val::Percent(100.0),
40-
align_items: AlignItems::Start,
41-
justify_content: JustifyContent::Start,
42-
flex_direction: FlexDirection::Column,
43-
..default()
44-
},
45-
..default()
46-
},
47-
GameEntity,
48-
))
49-
.with_children(|parent| {
50-
parent
51-
.spawn(NodeBundle {
52-
style: Style {
53-
width: Val::Px(345.0),
54-
height: Val::Px(125.0),
55-
align_items: AlignItems::Center,
56-
flex_direction: FlexDirection::Column,
57-
justify_content: JustifyContent::Center,
58-
padding: UiRect::all(Val::Px(8.0)),
59-
margin: UiRect::px(10.0, 10.0, 10.0, 0.0),
60-
..default()
61-
},
62-
background_color: BackgroundColor::from(Color::BLACK.with_a(0.9)),
63-
..default()
64-
})
65-
.with_children(|parent| {
66-
parent.spawn((
67-
TextBundle::from_section(
68-
"Hello Bevy!",
69-
TextStyle {
70-
font: asset_server.load("monogram.ttf"),
71-
font_size: 40.0,
72-
color: Color::WHITE,
73-
..default()
74-
},
75-
),
76-
DebugText,
77-
));
78-
});
79-
});
80-
}
81-
82-
fn update_debug_text(
83-
mut query: Query<&mut Text, With<DebugText>>,
84-
diagnostics: Res<DiagnosticsStore>,
85-
enemy_query: Query<(), With<Enemy>>,
86-
player_query: Query<&Health, With<Player>>,
87-
) {
88-
if query.is_empty() || player_query.is_empty() || enemy_query.is_empty() {
89-
return;
90-
}
91-
92-
let num_enemies = enemy_query.iter().count();
93-
let player_health = player_query.single().0;
94-
let mut text = query.single_mut();
95-
if let Some(fps) = diagnostics.get(&FrameTimeDiagnosticsPlugin::FPS) {
96-
if let Some(value) = fps.smoothed() {
97-
text.sections[0].value =
98-
format!("Fps: {value:.2}\nEnemies: {num_enemies}\nHealth: {player_health}");
99-
}
100-
}
101-
}
102-
10326
fn setup_main_menu(mut commands: Commands) {
10427
commands
10528
.spawn(NodeBundle {

‎src/gun.rs

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ fn handle_gun_input(
9090
}
9191

9292
let (gun_transform, mut gun_timer) = gun_query.single_mut();
93+
9394
let gun_pos = gun_transform.translation.truncate();
9495
gun_timer.0.tick(time.delta());
9596

@@ -108,6 +109,7 @@ fn handle_gun_input(
108109
bullet_direction.y + rng.gen_range(-0.5..0.5),
109110
bullet_direction.z,
110111
);
112+
111113
commands.spawn((
112114
SpriteSheetBundle {
113115
texture: handle.image.clone().unwrap(),

‎src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod animation;
22
pub mod camera;
33
pub mod collision;
44
pub mod configs;
5+
pub mod debug;
56
pub mod enemy;
67
pub mod gui;
78
pub mod gun;

‎src/main.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
use bevy::prelude::*;
21
use bevy::window::close_on_esc;
2+
use bevy::{
3+
log::LogPlugin,
4+
prelude::*,
5+
window::{PresentMode, WindowMode},
6+
};
37

48
use coding_pet::animation::AnimationPlugin;
59
use coding_pet::camera::FollowCameraPlugin;
610
use coding_pet::collision::CollisionPlugin;
11+
use coding_pet::debug::DebugPlugin;
712
use coding_pet::enemy::EnemyPlugin;
813
use coding_pet::gui::GuiPlugin;
914
use coding_pet::gun::GunPlugin;
@@ -17,13 +22,24 @@ fn main() {
1722
.init_state::<GameState>()
1823
.add_plugins(
1924
DefaultPlugins
25+
.set(LogPlugin {
26+
filter: "info,wgpu_core=warn,wgpu_hal=warn,coding_pet=debug".into(),
27+
level: bevy::log::Level::DEBUG,
28+
..default()
29+
})
2030
.set(ImagePlugin::default_nearest())
2131
.set(WindowPlugin {
2232
primary_window: Some(Window {
23-
// mode: bevy::window::WindowMode::Fullscreen,
24-
resizable: true,
25-
focused: true,
26-
resolution: (WW, WH).into(),
33+
title: "Tiktok game + Bevy!".into(),
34+
name: Some("MyWindow".into()),
35+
resolution: (1920., 1080.).into(),
36+
present_mode: PresentMode::AutoVsync,
37+
mode: WindowMode::Windowed,
38+
enabled_buttons: bevy::window::EnabledButtons {
39+
maximize: false,
40+
..Default::default()
41+
},
42+
visible: true,
2743
..default()
2844
}),
2945
..default()
@@ -35,6 +51,7 @@ fn main() {
3551
.add_plugins(FollowCameraPlugin)
3652
.add_plugins(GuiPlugin)
3753
.add_plugins(GunPlugin)
54+
.add_plugins(DebugPlugin)
3855
.add_plugins(PlayerPlugin)
3956
.add_plugins(AnimationPlugin)
4057
.add_plugins(ResourcesPlugin)

‎src/resources.rs

+31-15
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@ use bevy::window::PrimaryWindow;
55
use crate::state::GameState;
66

77
pub struct ResourcesPlugin;
8-
use crate::*;
98

109
#[derive(Resource)]
1110
pub struct GlobalTextureAtlas {
1211
pub layout: Option<Handle<TextureAtlasLayout>>,
1312
pub image: Option<Handle<Image>>,
1413
}
1514

15+
impl Default for GlobalTextureAtlas {
16+
fn default() -> Self {
17+
Self {
18+
layout: None,
19+
image: None,
20+
}
21+
}
22+
}
23+
1624
#[derive(Resource)]
1725
pub struct CursorPosition(pub Option<Vec2>);
1826

@@ -53,6 +61,7 @@ fn check_textures(
5361
}
5462

5563
fn setup(
64+
mut commands: Commands,
5665
rpg_sprite_handles: Res<RpgSpriteFolder>,
5766
loaded_folders: Res<Assets<LoadedFolder>>,
5867
mut textures: ResMut<Assets<Image>>,
@@ -68,13 +77,27 @@ fn setup(
6877

6978
let atlas = textures.get(&linear_texture).unwrap();
7079

71-
info!("{} {}", atlas.width(), atlas.height());
80+
info!(
81+
"atlas width {:?}, atlas height {:?}",
82+
atlas.width(),
83+
atlas.height()
84+
);
7285

73-
// Separate the TextureAtlasLayout into a grid using from_grid
86+
/*
87+
commands.spawn(SpriteBundle {
88+
texture: linear_texture.clone(),
89+
transform: Transform {
90+
translation: Vec3::new(-250.0, -130.0, 0.0),
91+
scale: Vec3::splat(0.8),
92+
..default()
93+
},
94+
..default()
95+
});
96+
*/
7497
let grid_layout = TextureAtlasLayout::from_grid(
7598
Vec2::new(128.0, 128.0), // Tile size
76-
20, // Width of the texture atlas
77-
20, // Height of the texture atlas
99+
50, // Width of the texture atlas
100+
50, // Height of the texture atlas
78101
Some(Vec2::new(64.0, 64.0)), // Optional minimum size
79102
Some(Vec2::new(32.0, 32.0)), // Optional maximum size
80103
);
@@ -95,7 +118,7 @@ fn create_texture_atlas(
95118
// Build a texture atlas using the individual sprites
96119
let mut texture_atlas_builder = TextureAtlasBuilder::default()
97120
.padding(padding.unwrap_or_default())
98-
.max_size(Vec2::new(4000.0, 4000.0));
121+
.max_size(Vec2::new(8000.0, 10000.0));
99122

100123
for handle in folder.handles.iter() {
101124
let id = handle.id().typed_unchecked::<Image>();
@@ -107,11 +130,13 @@ fn create_texture_atlas(
107130
continue;
108131
};
109132

133+
info!("id {}, path {:?}", id, handle.path());
110134
texture_atlas_builder.add_texture(Some(id), texture);
111135
}
112136

113137
let (texture_atlas_layout, texture) = texture_atlas_builder.finish().unwrap();
114138

139+
info!("size {}", texture_atlas_layout.size);
115140
let texture = textures.add(texture);
116141

117142
(texture_atlas_layout, texture)
@@ -175,12 +200,3 @@ fn update_cursor_position(
175200
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor))
176201
.map(|ray| ray.origin.truncate());
177202
}
178-
179-
impl Default for GlobalTextureAtlas {
180-
fn default() -> Self {
181-
Self {
182-
layout: None,
183-
image: None,
184-
}
185-
}
186-
}

‎src/world.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ fn init_world(
5151
texture: handle.image.clone().unwrap(),
5252
atlas: TextureAtlas {
5353
layout: handle.layout.clone().unwrap(),
54-
index: 118,
54+
index: 0,
5555
},
5656
transform: Transform::from_scale(Vec3::splat(SPRITE_SCALE_FACTOR)),
5757
..default()
@@ -69,12 +69,15 @@ fn spawn_world_decorations(mut commands: Commands, handle: Res<GlobalTextureAtla
6969
for _ in 0..NUM_WORLD_DECORATIONS {
7070
let x = rng.gen_range(-WORLD_W..WORLD_W);
7171
let y = rng.gen_range(-WORLD_H..WORLD_H);
72+
73+
let index = rng.gen_range(1200..=1240);
74+
7275
commands.spawn((
7376
SpriteSheetBundle {
7477
texture: handle.image.clone().unwrap(),
7578
atlas: TextureAtlas {
7679
layout: handle.layout.clone().unwrap(),
77-
index: rng.gen_range(49..=53),
80+
index,
7881
},
7982
transform: Transform::from_translation(vec3(x, y, 0.0))
8083
.with_scale(Vec3::splat(SPRITE_SCALE_FACTOR)),

0 commit comments

Comments
 (0)
Please sign in to comment.