├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── README.md
├── assets
├── AlfaSlabOne-Regular.ttf
├── crossair_black.png
├── crossair_blackOutline.png
├── crossair_blue.png
├── crossair_blueOutline.png
├── crossair_red.png
├── crossair_redOutline.png
├── crossair_white.png
├── crossair_whiteOutline.png
├── gameover.ogg
├── gameover.wav
├── glass_panel.png
├── green_boxCheckmark.png
├── grey_box.png
├── menu_click.ogg
├── menu_click.wav
├── pattern_blueprint.png
├── roboto.ttf
├── spaceShooter2_spritesheet_2X.png
├── spaceShooter2_spritesheet_2X.xml
├── space_sheet.png
├── space_sheet.xml
├── uipackSpace_sheet.png
└── uipackSpace_sheet.xml
├── examples
├── kenney.rs
└── spritesheet_viewer.rs
├── readme
├── choose_ship.avif
├── menu.avif
└── particles-and-lives.avif
└── src
├── assets.rs
├── colors.rs
├── controls.rs
├── kenney_assets.rs
├── levels.rs
├── lib.rs
├── lives.rs
├── main.rs
├── meteors.rs
├── movement.rs
├── scores.rs
├── scoring
└── display.rs
├── settings.rs
├── ship.rs
├── ufo.rs
├── ui.rs
└── ui
├── button.rs
├── choose_ship.rs
└── pause.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "space-shooter"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | bevy = "0.13.1"
10 | rand = "0.8.5"
11 | bevy_asset_loader = { version = "0.20", features = ["2d"] }
12 | bevy_xpbd_2d = { version = "0.4.2", features = ["debug-plugin"] }
13 | roxmltree = "0.19.0"
14 | bevy_hanabi = { version = "0.10.0", default-features = false, features = [
15 | "2d",
16 | ] }
17 |
18 | [profile.dev.package."*"]
19 | opt-level = 3
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Asteroids in Bevy
2 |
3 | This is a work-in-progress implementation of Asteroids in Bevy. Some modifications are being made from the original game, such as using sprites instead of line art.
4 |
5 | 
6 |
7 | 
8 |
9 | 
10 |
--------------------------------------------------------------------------------
/assets/AlfaSlabOne-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/AlfaSlabOne-Regular.ttf
--------------------------------------------------------------------------------
/assets/crossair_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_black.png
--------------------------------------------------------------------------------
/assets/crossair_blackOutline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_blackOutline.png
--------------------------------------------------------------------------------
/assets/crossair_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_blue.png
--------------------------------------------------------------------------------
/assets/crossair_blueOutline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_blueOutline.png
--------------------------------------------------------------------------------
/assets/crossair_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_red.png
--------------------------------------------------------------------------------
/assets/crossair_redOutline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_redOutline.png
--------------------------------------------------------------------------------
/assets/crossair_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_white.png
--------------------------------------------------------------------------------
/assets/crossair_whiteOutline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/crossair_whiteOutline.png
--------------------------------------------------------------------------------
/assets/gameover.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/gameover.ogg
--------------------------------------------------------------------------------
/assets/gameover.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/gameover.wav
--------------------------------------------------------------------------------
/assets/glass_panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/glass_panel.png
--------------------------------------------------------------------------------
/assets/green_boxCheckmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/green_boxCheckmark.png
--------------------------------------------------------------------------------
/assets/grey_box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/grey_box.png
--------------------------------------------------------------------------------
/assets/menu_click.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/menu_click.ogg
--------------------------------------------------------------------------------
/assets/menu_click.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/menu_click.wav
--------------------------------------------------------------------------------
/assets/pattern_blueprint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/pattern_blueprint.png
--------------------------------------------------------------------------------
/assets/roboto.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/roboto.ttf
--------------------------------------------------------------------------------
/assets/spaceShooter2_spritesheet_2X.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/spaceShooter2_spritesheet_2X.png
--------------------------------------------------------------------------------
/assets/spaceShooter2_spritesheet_2X.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
--------------------------------------------------------------------------------
/assets/space_sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/space_sheet.png
--------------------------------------------------------------------------------
/assets/space_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
--------------------------------------------------------------------------------
/assets/uipackSpace_sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/assets/uipackSpace_sheet.png
--------------------------------------------------------------------------------
/assets/uipackSpace_sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/examples/kenney.rs:
--------------------------------------------------------------------------------
1 | use bevy::prelude::*;
2 |
3 | use space_shooter::kenney_assets::*;
4 |
5 | fn main() {
6 | App::new()
7 | .add_plugins((DefaultPlugins, KenneyAssetPlugin))
8 | .init_resource::()
9 | .insert_resource(Time::::from_seconds(0.25))
10 | .add_systems(Startup, setup)
11 | .add_systems(Update, print_on_load)
12 | .add_systems(FixedUpdate, update)
13 | .run();
14 | }
15 |
16 | #[derive(Resource, Default)]
17 | struct State {
18 | handle: Handle,
19 | }
20 |
21 | fn setup(
22 | mut state: ResMut,
23 | asset_server: Res,
24 | ) {
25 | // Recommended way to load an asset
26 | state.handle = asset_server
27 | .load("spaceShooter2_spritesheet_2X.xml");
28 |
29 | // File extensions are optional, but are
30 | // recommended for project management and
31 | // last-resort inference
32 | // state.other_handle =
33 | // asset_server.load("data/
34 | // asset_no_extension");
35 | }
36 |
37 | fn print_on_load(
38 | mut commands: Commands,
39 | state: ResMut,
40 | spritesheets: Res>,
41 | mut printed: Local,
42 | ) {
43 | let custom_asset = spritesheets.get(&state.handle);
44 |
45 | if *printed || custom_asset.is_none() {
46 | return;
47 | }
48 |
49 | let kenney_sheet = custom_asset.unwrap();
50 | info!("image {:?}", kenney_sheet.sheet);
51 | info!(
52 | "first texture: {:?}",
53 | kenney_sheet.textures.first()
54 | );
55 |
56 | commands.spawn(Camera2dBundle::default());
57 | commands.spawn((
58 | SpriteBundle {
59 | texture: kenney_sheet.sheet.clone(),
60 | ..default()
61 | },
62 | TextureAtlas {
63 | index: 60,
64 | layout: kenney_sheet
65 | .texture_atlas_layout
66 | .clone(),
67 | },
68 | ));
69 | // Once printed, we won't print again
70 | *printed = true;
71 | }
72 |
73 | fn update(
74 | mut atlas: Query<&mut TextureAtlas>,
75 | state: ResMut,
76 | spritesheets: Res>,
77 | ) {
78 | let custom_asset = spritesheets.get(&state.handle);
79 |
80 | for mut atlas in &mut atlas {
81 | let kenney_sheet = custom_asset.unwrap();
82 |
83 | if atlas.index + 1 == kenney_sheet.textures.len() {
84 | atlas.index = 0;
85 | } else {
86 | atlas.index += 1;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/examples/spritesheet_viewer.rs:
--------------------------------------------------------------------------------
1 | // TODO: bevy_asset_loader currently doesn't
2 | // support custom asset types.
3 |
4 | use bevy::prelude::*;
5 | use bevy_asset_loader::prelude::*;
6 | use space_shooter::kenney_assets::{
7 | KenneyAssetPlugin, KenneySpriteSheetAsset,
8 | };
9 |
10 | fn main() {
11 | App::new()
12 | .init_state::()
13 | .add_loading_state(
14 | LoadingState::new(MyStates::AssetLoading)
15 | .continue_to_state(MyStates::Next)
16 | .load_collection::(),
17 | )
18 | .add_plugins((DefaultPlugins, KenneyAssetPlugin))
19 | .add_systems(OnEnter(MyStates::Next), setup)
20 | .add_systems(
21 | Update,
22 | input.run_if(in_state(MyStates::Next)),
23 | )
24 | .run()
25 | }
26 |
27 | #[derive(
28 | Clone, Eq, PartialEq, Debug, Hash, Default, States,
29 | )]
30 | enum MyStates {
31 | #[default]
32 | AssetLoading,
33 | Next,
34 | }
35 |
36 | #[derive(AssetCollection, Resource)]
37 | pub struct ImageAssets {
38 | #[asset(path = "spaceShooter2_spritesheet_2X.xml")]
39 | pub space_sheet: Handle,
40 | }
41 |
42 | fn setup(
43 | mut commands: Commands,
44 | spritesheets: Res>,
45 | images: Res,
46 | ) {
47 | let kenney_sheet =
48 | spritesheets.get(&images.space_sheet).unwrap();
49 | commands.spawn(Camera2dBundle::default());
50 | commands.spawn((
51 | SpriteBundle {
52 | texture: kenney_sheet.sheet.clone(),
53 | ..default()
54 | },
55 | TextureAtlas {
56 | index: 0,
57 | layout: kenney_sheet
58 | .texture_atlas_layout
59 | .clone(),
60 | },
61 | ));
62 | }
63 | fn input(
64 | input: Res>,
65 | spritesheets: Res>,
66 | images: Res,
67 | mut atlas: Query<&mut TextureAtlas>,
68 | ) {
69 | let kenney_sheet =
70 | spritesheets.get(&images.space_sheet).unwrap();
71 | let mut atlas = atlas.single_mut();
72 |
73 | if input.just_pressed(KeyCode::Space) {
74 | atlas.index += 1;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/readme/choose_ship.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/readme/choose_ship.avif
--------------------------------------------------------------------------------
/readme/menu.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/readme/menu.avif
--------------------------------------------------------------------------------
/readme/particles-and-lives.avif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rust-adventure/asteroids/3ae4b64a5c7b2ffd5cb9f280796271188a86ffdd/readme/particles-and-lives.avif
--------------------------------------------------------------------------------
/src/assets.rs:
--------------------------------------------------------------------------------
1 | use bevy::prelude::*;
2 | use bevy_asset_loader::prelude::*;
3 |
4 | use crate::{
5 | kenney_assets::{
6 | KenneyAssetPlugin, KenneySpriteSheetAsset,
7 | },
8 | GameState,
9 | };
10 |
11 | pub struct AssetsPlugin;
12 |
13 | impl Plugin for AssetsPlugin {
14 | fn build(&self, app: &mut App) {
15 | app.add_plugins(KenneyAssetPlugin)
16 | .add_loading_state(
17 | LoadingState::new(GameState::AssetLoading)
18 | .continue_to_state(GameState::Menu)
19 | .load_collection::()
20 | .load_collection::()
21 | .load_collection::(),
22 | );
23 | }
24 | }
25 |
26 | #[derive(AssetCollection, Resource)]
27 | pub struct FontAssets {
28 | #[asset(path = "AlfaSlabOne-Regular.ttf")]
29 | pub alfa_slab_one_regular: Handle,
30 | #[asset(path = "roboto.ttf")]
31 | pub roboto: Handle,
32 | }
33 |
34 | #[derive(AssetCollection, Resource)]
35 | pub struct AudioAssets {
36 | #[asset(path = "menu_click.ogg")]
37 | pub menu_click: Handle,
38 | }
39 |
40 | #[derive(AssetCollection, Resource)]
41 | pub struct ImageAssets {
42 | #[asset(path = "grey_box.png")]
43 | pub box_unchecked: Handle,
44 | #[asset(path = "green_boxCheckmark.png")]
45 | pub box_checked: Handle,
46 | #[asset(path = "glass_panel.png")]
47 | pub panel_glass: Handle,
48 | #[asset(path = "pattern_blueprint.png")]
49 | pub pattern_blueprint: Handle,
50 | #[asset(path = "space_sheet.xml")]
51 | pub space_sheet: Handle,
52 | }
53 |
--------------------------------------------------------------------------------
/src/colors.rs:
--------------------------------------------------------------------------------
1 | use bevy::prelude::Color;
2 |
3 | pub const TEXT: Color = Color::BLACK;
4 |
--------------------------------------------------------------------------------
/src/controls.rs:
--------------------------------------------------------------------------------
1 | use crate::{
2 | assets::ImageAssets,
3 | kenney_assets::KenneySpriteSheetAsset,
4 | ship::{PlayerEngineFire, PlayerShipType},
5 | ui::pause::Pausable,
6 | GameState, Player,
7 | };
8 | use bevy::prelude::*;
9 | use bevy_xpbd_2d::prelude::*;
10 | use std::time::Duration;
11 |
12 | pub struct ControlsPlugin;
13 |
14 | impl Plugin for ControlsPlugin {
15 | fn build(&self, app: &mut App) {
16 | app.init_resource::().add_systems(
17 | Update,
18 | (
19 | player_movement_system
20 | .run_if(in_state(GameState::Playing)),
21 | weapon_system
22 | .run_if(in_state(GameState::Playing)),
23 | engine_fire
24 | .run_if(in_state(GameState::Playing)),
25 | laser_movement,
26 | )
27 | .run_if(resource_equals(
28 | Pausable::NotPaused,
29 | )),
30 | );
31 | }
32 | }
33 |
34 | #[derive(Component)]
35 | pub struct Laser{
36 | /// movement factor is ship's movement speed at time of firing
37 | pub movement_factor: Vec2,
38 | /// speed is laser's inherent movement speed
39 | pub speed: f32,
40 | }
41 |
42 | #[derive(Resource, Default, Deref, DerefMut)]
43 | pub struct MovementFactor(pub Vec2);
44 |
45 | fn laser_movement(
46 | mut lasers: Query<(&mut Transform, &Laser)>,
47 | time: Res