1- use std:: f32:: consts:: TAU ;
1+ use std:: { f32:: consts:: TAU , time :: Duration } ;
22
33use avian2d:: prelude:: * ;
44use bevy:: prelude:: * ;
@@ -12,7 +12,7 @@ pub fn game_plugin(app: &mut App) {
1212 . add_systems ( OnEnter ( GameState :: Game ) , display_level)
1313 . add_systems (
1414 Update ,
15- ( collision , tick_explosion ) . run_if ( in_state ( GameState :: Game ) ) ,
15+ ( tick_explosion , laser_range , has_won ) . run_if ( in_state ( GameState :: Game ) ) ,
1616 ) ;
1717}
1818
@@ -69,29 +69,6 @@ fn display_level(
6969 }
7070}
7171
72- fn collision (
73- collisions : Collisions ,
74- player : Query < ( & Transform , Entity ) , With < Player > > ,
75- mut commands : Commands ,
76- game_assets : Res < GameAssets > ,
77- ) -> Result {
78- let Ok ( ( transform, entity) ) = player. single ( ) else {
79- return Ok ( ( ) ) ;
80- } ;
81-
82- if collisions. collisions_with ( entity) . next ( ) . is_some ( ) {
83- commands. spawn ( (
84- Sprite :: from_image ( game_assets. explosion . clone ( ) ) ,
85- ( * transform) . with_scale ( Vec3 :: splat ( 0.2 ) ) ,
86- Explosion ( Timer :: from_seconds ( 1.0 , TimerMode :: Once ) ) ,
87- StateScoped ( GameState :: Game ) ,
88- ) ) ;
89- commands. entity ( entity) . despawn ( ) ;
90- }
91-
92- Ok ( ( ) )
93- }
94-
9572fn tick_explosion (
9673 mut commands : Commands ,
9774 mut explosions : Query < ( Entity , & mut Explosion , & Transform ) > ,
@@ -125,6 +102,7 @@ fn spawn_player(commands: &mut Commands, game_assets: &GameAssets, position: Vec
125102 negative : KeyCode :: KeyD ,
126103 } ) ;
127104 actions. bind :: < Thrust > ( ) . to ( KeyCode :: KeyW ) ;
105+ actions. bind :: < FireLaser > ( ) . to ( KeyCode :: Space ) ;
128106
129107 commands
130108 . spawn ( (
@@ -145,7 +123,9 @@ fn spawn_player(commands: &mut Commands, game_assets: &GameAssets, position: Vec
145123 ) )
146124 . observe ( rotate)
147125 . observe ( thrust)
148- . observe ( thrust_stop) ;
126+ . observe ( thrust_stop)
127+ . observe ( fire_laser)
128+ . observe ( asteroid_collision) ;
149129}
150130
151131#[ derive( InputContext ) ]
@@ -159,6 +139,10 @@ struct Rotate;
159139#[ input_action( output = bool ) ]
160140struct Thrust ;
161141
142+ #[ derive( Debug , InputAction ) ]
143+ #[ input_action( output = bool ) ]
144+ struct FireLaser ;
145+
162146fn rotate (
163147 trigger : Trigger < Fired < Rotate > > ,
164148 mut player : Query < & mut AngularVelocity > ,
@@ -192,11 +176,97 @@ fn thrust_stop(
192176 player : Query < & Children > ,
193177 mut visibility : Query < & mut Visibility > ,
194178) -> Result {
195- let children = player. get ( trigger. target ( ) ) ?;
179+ let Ok ( children) = player. get ( trigger. target ( ) ) else {
180+ return Ok ( ( ) ) ;
181+ } ;
196182
197183 visibility
198184 . get_mut ( children[ 0 ] ) ?
199185 . set_if_neq ( Visibility :: Hidden ) ;
200186
201187 Ok ( ( ) )
202188}
189+
190+ fn asteroid_collision (
191+ collision : Trigger < OnCollisionStart > ,
192+ is_asteroid : Query < ( ) , With < Asteroid > > ,
193+ player : Query < & Transform > ,
194+ mut commands : Commands ,
195+ game_assets : Res < GameAssets > ,
196+ ) -> Result {
197+ if is_asteroid. get ( collision. collider ) . is_ok ( ) {
198+ let transform = player. get ( collision. target ( ) ) ?;
199+ commands. spawn ( (
200+ Sprite :: from_image ( game_assets. explosion . clone ( ) ) ,
201+ ( * transform) . with_scale ( Vec3 :: splat ( 0.2 ) ) ,
202+ Explosion ( Timer :: from_seconds ( 1.0 , TimerMode :: Once ) ) ,
203+ StateScoped ( GameState :: Game ) ,
204+ ) ) ;
205+ commands. entity ( collision. target ( ) ) . despawn ( ) ;
206+ commands. entity ( collision. collider ) . despawn ( ) ;
207+ }
208+ Ok ( ( ) )
209+ }
210+
211+ #[ derive( Component ) ]
212+ struct Laser ( Timer ) ;
213+
214+ fn fire_laser (
215+ trigger : Trigger < Fired < FireLaser > > ,
216+ player : Query < & Transform > ,
217+ mut commands : Commands ,
218+ time : Res < Time > ,
219+ mut last_fired : Local < Duration > ,
220+ game_assets : Res < GameAssets > ,
221+ ) -> Result {
222+ let mut transform = * player. get ( trigger. target ( ) ) ?;
223+ transform. translation += transform. local_y ( ) * 40.0 ;
224+ transform. scale = Vec3 :: ONE / 2.0 ;
225+
226+ if time. elapsed ( ) > * last_fired + Duration :: from_secs_f32 ( 0.5 ) {
227+ commands
228+ . spawn ( (
229+ // Sprite::from_image(game_assets.laser.clone()),
230+ Sprite {
231+ image : game_assets. laser . clone ( ) ,
232+ color : Color :: srgb ( 5.0 , 1.0 , 1.0 ) ,
233+ ..default ( )
234+ } ,
235+ transform,
236+ RigidBody :: Dynamic ,
237+ Collider :: rectangle ( 4.0 , 15.0 ) ,
238+ LinearVelocity ( transform. local_y ( ) . xy ( ) * 1000.0 ) ,
239+ Laser ( Timer :: from_seconds ( 1.0 , TimerMode :: Once ) ) ,
240+ CollisionEventsEnabled ,
241+ StateScoped ( GameState :: Game ) ,
242+ ) )
243+ . observe ( laser_attack) ;
244+ * last_fired = time. elapsed ( ) ;
245+ }
246+ Ok ( ( ) )
247+ }
248+
249+ fn laser_range ( mut commands : Commands , mut lasers : Query < ( Entity , & mut Laser ) > , time : Res < Time > ) {
250+ for ( entity, mut laser) in & mut lasers {
251+ if laser. 0 . tick ( time. delta ( ) ) . just_finished ( ) {
252+ commands. entity ( entity) . despawn ( ) ;
253+ }
254+ }
255+ }
256+
257+ fn laser_attack (
258+ collision : Trigger < OnCollisionStart > ,
259+ is_asteroid : Query < ( ) , With < Asteroid > > ,
260+ mut commands : Commands ,
261+ ) {
262+ if is_asteroid. get ( collision. collider ) . is_ok ( ) {
263+ commands. entity ( collision. collider ) . despawn ( ) ;
264+ commands. entity ( collision. target ( ) ) . despawn ( ) ;
265+ }
266+ }
267+
268+ fn has_won ( asteroids : Query < ( ) , With < Asteroid > > , mut next_state : ResMut < NextState < GameState > > ) {
269+ if asteroids. is_empty ( ) {
270+ next_state. set ( GameState :: Won ) ;
271+ }
272+ }
0 commit comments