3
3
4
4
#![ allow( clippy:: type_complexity) ]
5
5
6
- use bevy:: {
7
- math:: { vec2, vec3} ,
8
- prelude:: * ,
9
- render:: camera:: ScalingMode ,
10
- window,
11
- } ;
6
+ use bevy:: { math:: vec3, prelude:: * , render:: camera:: ScalingMode , window} ;
12
7
use bevy_ecs_tilemap:: prelude as ecs_tilemap;
13
8
use clap:: Parser ;
14
- use slicetools:: * ;
15
9
use std:: f32:: consts:: PI ;
16
10
17
11
mod assets;
18
12
mod dashboard;
19
13
mod editor;
20
14
mod mapping;
15
+ mod physics;
21
16
mod tilemap;
22
17
mod util;
23
18
24
- use util:: IteratorToArrayExt ;
25
-
26
19
#[ derive( Clone , Debug , Parser , Resource ) ]
27
20
#[ command( author, version, about, long_about = None ) ]
28
21
struct Preferences {
@@ -90,13 +83,13 @@ fn main() {
90
83
(
91
84
handle_keyboard,
92
85
handle_ai_players,
93
- apply_velocity
86
+ physics :: apply_velocity
94
87
. after ( handle_ai_players)
95
88
. after ( handle_keyboard) ,
96
- apply_friction. after ( apply_velocity) ,
97
- track_player. after ( apply_velocity) ,
98
- collision_detection
99
- . after ( apply_velocity)
89
+ physics :: apply_friction. after ( physics :: apply_velocity) ,
90
+ track_player. after ( physics :: apply_velocity) ,
91
+ physics :: collision_detection
92
+ . after ( physics :: apply_velocity)
100
93
. after ( handle_keyboard)
101
94
. after ( handle_ai_players) ,
102
95
) ,
@@ -116,27 +109,6 @@ struct Racer {
116
109
#[ derive( Component , Default , Debug ) ]
117
110
struct Track ;
118
111
119
- #[ derive( Component , Debug , Reflect ) ]
120
- struct Velocity ( Vec2 ) ;
121
-
122
- #[ derive( Component , Clone , Debug , Reflect ) ]
123
- struct Angle ( f32 ) ;
124
-
125
- impl Angle {
126
- fn normalize ( & mut self ) {
127
- while self . 0 > PI {
128
- self . 0 -= 2.0 * PI ;
129
- }
130
- while self . 0 < -PI {
131
- self . 0 += 2.0 * PI ;
132
- }
133
- }
134
-
135
- fn to_quat ( & self ) -> Quat {
136
- Quat :: from_rotation_z ( self . 0 - PI / 2.0 )
137
- }
138
- }
139
-
140
112
fn spawn_camera ( mut commands : Commands ) {
141
113
let mut camera = Camera2dBundle :: default ( ) ;
142
114
// Request a constant width projection. 24 is the width in world units.
@@ -171,8 +143,8 @@ fn spawn_player(
171
143
commands. spawn ( (
172
144
Player ,
173
145
Racer :: default ( ) ,
174
- Angle ( 0.0 ) ,
175
- Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
146
+ physics :: Angle ( 0.0 ) ,
147
+ physics :: Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
176
148
SpriteSheetBundle {
177
149
texture_atlas : texture_atlas. add ( atlas) ,
178
150
transform : Transform {
@@ -196,8 +168,8 @@ fn spawn_ai_players(
196
168
197
169
commands. spawn ( (
198
170
Racer :: default ( ) ,
199
- Angle ( PI / 12.0 ) ,
200
- Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
171
+ physics :: Angle ( PI / 12.0 ) ,
172
+ physics :: Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
201
173
SpriteSheetBundle {
202
174
texture_atlas : texture_atlas. add ( atlas) ,
203
175
transform : Transform {
@@ -214,8 +186,8 @@ fn spawn_ai_players(
214
186
let atlas = TextureAtlas :: from_grid ( handle, Vec2 :: new ( 70. , 121. ) , 1 , 1 , None , None ) ;
215
187
commands. spawn ( (
216
188
Racer :: default ( ) ,
217
- Angle ( PI / 12.0 ) ,
218
- Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
189
+ physics :: Angle ( PI / 12.0 ) ,
190
+ physics :: Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
219
191
SpriteSheetBundle {
220
192
texture_atlas : texture_atlas. add ( atlas) ,
221
193
transform : Transform {
@@ -232,8 +204,8 @@ fn spawn_ai_players(
232
204
let atlas = TextureAtlas :: from_grid ( handle, Vec2 :: new ( 70. , 121. ) , 1 , 1 , None , None ) ;
233
205
commands. spawn ( (
234
206
Racer :: default ( ) ,
235
- Angle ( PI / 12.0 ) ,
236
- Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
207
+ physics :: Angle ( PI / 12.0 ) ,
208
+ physics :: Velocity ( Vec2 :: new ( 0.0 , 20.0 ) ) ,
237
209
SpriteSheetBundle {
238
210
texture_atlas : texture_atlas. add ( atlas) ,
239
211
transform : Transform {
@@ -246,160 +218,10 @@ fn spawn_ai_players(
246
218
) ) ;
247
219
}
248
220
249
- fn apply_friction (
250
- mut query : Query < ( & mut Velocity , & mut Transform ) > ,
251
- time : Res < Time > ,
252
- guide : Option < Res < mapping:: GuidanceField > > ,
253
- ) {
254
- let delta = time. delta_seconds ( ) ;
255
- for ( mut v, t) in query. iter_mut ( ) {
256
- v. 0 *= 1.0 - ( delta * 1.2 ) ;
257
-
258
- if let Some ( guide) = & guide {
259
- let pos = Vec2 :: new ( t. translation . x , t. translation . y ) ;
260
- let pixel = guide. get ( & pos) ;
261
- if pixel < 140 {
262
- let factor = 1.2 + 1.2 * ( 1.0 - ( pixel as f32 / 140.0 ) ) ;
263
- v. 0 *= 1.0 - ( delta * factor) ;
264
- }
265
- }
266
- }
267
- }
268
-
269
- fn apply_velocity ( mut query : Query < ( & Velocity , & mut Transform ) > , time : Res < Time > ) {
270
- let delta = time. delta_seconds ( ) ;
271
- for ( v, mut t) in query. iter_mut ( ) {
272
- t. translation . x += delta * v. 0 . x ;
273
- t. translation . y += delta * v. 0 . y ;
274
- }
275
- }
276
-
277
- fn same_side ( p1 : Vec2 , p2 : Vec2 , line : ( Vec2 , Vec2 ) ) -> bool {
278
- let p1 = Vec3 :: from ( ( p1, 0.0 ) ) ;
279
- let p2 = Vec3 :: from ( ( p2, 0.0 ) ) ;
280
- let line = ( Vec3 :: from ( ( line. 0 , 0.0 ) ) , Vec3 :: from ( ( line. 1 , 0.0 ) ) ) ;
281
-
282
- let cp1 = ( line. 1 - line. 0 ) . cross ( p1 - line. 0 ) ;
283
- let cp2 = ( line. 1 - line. 0 ) . cross ( p2 - line. 0 ) ;
284
-
285
- cp1. dot ( cp2) >= 0.0
286
- }
287
-
288
- fn point_in_polygon ( pt : Vec2 , shape : & [ Vec2 ] ) -> bool {
289
- let n = shape. len ( ) ;
290
- shape
291
- . windows ( 3 )
292
- . chain ( std:: iter:: once (
293
- [ shape[ n - 2 ] , shape[ n - 1 ] , shape[ 0 ] ] . as_slice ( ) ,
294
- ) )
295
- . chain ( std:: iter:: once (
296
- [ shape[ n - 1 ] , shape[ 0 ] , shape[ 1 ] ] . as_slice ( ) ,
297
- ) )
298
- . all ( |x| same_side ( pt, x[ 0 ] , ( x[ 1 ] , x[ 2 ] ) ) )
299
- }
300
-
301
- struct CollisionBox {
302
- points : [ Vec2 ; 8 ] ,
303
- }
304
-
305
- impl CollisionBox {
306
- fn from_transform ( tf : & Transform , sz : & Vec2 ) -> Self {
307
- let w = sz. x * 0.5 ;
308
- let h = sz. y * 0.5 ;
309
-
310
- // c is used to round the corners of the box, choosing
311
- // 2.5 is a little arbitrary but it gives a good "feel"
312
- // for most artwork... and you could handle special cases
313
- // by creating the box by hand.
314
- let c = w. min ( h) / 2.5 ;
315
-
316
- Self {
317
- points : [
318
- vec2 ( c - w, h) ,
319
- vec2 ( w - c, h) ,
320
- vec2 ( w, h - c) ,
321
- vec2 ( w, c - h) ,
322
- vec2 ( w - c, -h) ,
323
- vec2 ( c - w, -h) ,
324
- vec2 ( -w, c - h) ,
325
- vec2 ( -w, h - c) ,
326
- ]
327
- . iter ( )
328
- . map ( |v2| {
329
- let v3 = Vec3 :: from ( ( * v2, 0.0 ) ) ;
330
- let pt = tf. transform_point ( v3) ;
331
- vec2 ( pt. x , pt. y )
332
- } )
333
- . to_array ( ) ,
334
- }
335
- }
336
-
337
- /// Test whether two rectangles are touching.
338
- fn is_touching ( & self , other : & CollisionBox ) -> bool {
339
- other
340
- . points
341
- . iter ( )
342
- . any ( |pt| point_in_polygon ( * pt, & self . points ) )
343
- || self
344
- . points
345
- . iter ( )
346
- . any ( |pt| point_in_polygon ( * pt, & other. points ) )
347
- }
348
-
349
- fn draw ( & self , gizmos : & mut Gizmos ) {
350
- for w in self . points . windows ( 2 ) {
351
- gizmos. line_2d ( w[ 0 ] , w[ 1 ] , Color :: BLUE ) ;
352
- }
353
- gizmos. line_2d ( self . points [ 7 ] , self . points [ 0 ] , Color :: BLUE ) ;
354
- }
355
- }
356
-
357
- fn collision_detection (
358
- mut query : Query < ( & mut Transform , & Handle < TextureAtlas > , & mut Velocity ) > ,
359
- texture_atlases : Res < Assets < TextureAtlas > > ,
360
- prefs : Res < Preferences > ,
361
- mut gizmos : Gizmos ,
362
- ) {
363
- let mut colliders = query. iter_mut ( ) . collect :: < Vec < _ > > ( ) ;
364
- let mut it = colliders. pairs_mut ( ) ;
365
- while let Some ( ( a, b) ) = it. next ( ) {
366
- let atx = match texture_atlases. get ( a. 1 ) {
367
- Some ( tx) => tx,
368
- None => continue ,
369
- } ;
370
- let btx = match texture_atlases. get ( b. 1 ) {
371
- Some ( tx) => tx,
372
- None => continue ,
373
- } ;
374
-
375
- let mut abox = CollisionBox :: from_transform ( & a. 0 , & atx. size ) ;
376
- let mut bbox = CollisionBox :: from_transform ( & b. 0 , & btx. size ) ;
377
- if prefs. debug_low ( ) {
378
- abox. draw ( & mut gizmos) ;
379
- bbox. draw ( & mut gizmos) ;
380
- }
381
-
382
- if abox. is_touching ( & bbox) {
383
- std:: mem:: swap ( & mut a. 2 . 0 , & mut b. 2 . 0 ) ;
384
-
385
- let a2 = vec2 ( a. 0 . translation . x , a. 0 . translation . y ) ;
386
- let b2 = vec2 ( b. 0 . translation . x , b. 0 . translation . y ) ;
387
- let nudge = Vec3 :: from ( ( ( b2 - a2) . normalize ( ) * 0.5 , 0.0 ) ) ;
388
- while abox. is_touching ( & bbox) {
389
- a. 0 . translation -= nudge;
390
- b. 0 . translation += nudge;
391
-
392
- abox = CollisionBox :: from_transform ( & a. 0 , & atx. size ) ;
393
- bbox = CollisionBox :: from_transform ( & b. 0 , & btx. size ) ;
394
- }
395
- }
396
- }
397
- }
398
-
399
221
fn handle_keyboard (
400
222
mut query : Query < (
401
- & mut Angle ,
402
- & mut Velocity ,
223
+ & mut physics :: Angle ,
224
+ & mut physics :: Velocity ,
403
225
& mut Transform ,
404
226
& mut Racer ,
405
227
With < Player > ,
@@ -436,8 +258,8 @@ fn handle_keyboard(
436
258
437
259
fn handle_ai_players (
438
260
mut query : Query < (
439
- & mut Angle ,
440
- & mut Velocity ,
261
+ & mut physics :: Angle ,
262
+ & mut physics :: Velocity ,
441
263
& mut Transform ,
442
264
& mut Racer ,
443
265
Without < Player > ,
@@ -508,7 +330,7 @@ fn handle_ai_players(
508
330
}
509
331
510
332
fn track_player (
511
- player : Query < ( & Transform , & Velocity , With < Player > ) > ,
333
+ player : Query < ( & Transform , & physics :: Velocity , With < Player > ) > ,
512
334
mut camera : Query < ( & mut Transform , With < Camera > , Without < Player > ) > ,
513
335
) {
514
336
let ( txp, _, _) = player. single ( ) ;
0 commit comments