Skip to content

Commit 2d83c35

Browse files
Factor the physics code into a seperate module
1 parent a7bc050 commit 2d83c35

File tree

3 files changed

+203
-200
lines changed

3 files changed

+203
-200
lines changed

src/dashboard.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#![allow(clippy::type_complexity)]
55

6-
use super::{Player, Velocity};
6+
use super::{physics, Player};
77
use bevy::prelude::*;
88

99
#[derive(Component, Debug)]
@@ -91,7 +91,7 @@ fn spawn_dashboard(mut commands: Commands, asset_server: Res<AssetServer>) {
9191
}
9292

9393
fn update_speedo(
94-
player: Query<(&Velocity, With<Player>)>,
94+
player: Query<(&physics::Velocity, With<Player>)>,
9595
mut speedo: Query<(&mut Transform, With<Speedometer>)>,
9696
) {
9797
let (vp, _) = player.single();

src/main.rs

Lines changed: 20 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,19 @@
33

44
#![allow(clippy::type_complexity)]
55

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};
127
use bevy_ecs_tilemap::prelude as ecs_tilemap;
138
use clap::Parser;
14-
use slicetools::*;
159
use std::f32::consts::PI;
1610

1711
mod assets;
1812
mod dashboard;
1913
mod editor;
2014
mod mapping;
15+
mod physics;
2116
mod tilemap;
2217
mod util;
2318

24-
use util::IteratorToArrayExt;
25-
2619
#[derive(Clone, Debug, Parser, Resource)]
2720
#[command(author, version, about, long_about = None)]
2821
struct Preferences {
@@ -90,13 +83,13 @@ fn main() {
9083
(
9184
handle_keyboard,
9285
handle_ai_players,
93-
apply_velocity
86+
physics::apply_velocity
9487
.after(handle_ai_players)
9588
.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)
10093
.after(handle_keyboard)
10194
.after(handle_ai_players),
10295
),
@@ -116,27 +109,6 @@ struct Racer {
116109
#[derive(Component, Default, Debug)]
117110
struct Track;
118111

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-
140112
fn spawn_camera(mut commands: Commands) {
141113
let mut camera = Camera2dBundle::default();
142114
// Request a constant width projection. 24 is the width in world units.
@@ -171,8 +143,8 @@ fn spawn_player(
171143
commands.spawn((
172144
Player,
173145
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)),
176148
SpriteSheetBundle {
177149
texture_atlas: texture_atlas.add(atlas),
178150
transform: Transform {
@@ -196,8 +168,8 @@ fn spawn_ai_players(
196168

197169
commands.spawn((
198170
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)),
201173
SpriteSheetBundle {
202174
texture_atlas: texture_atlas.add(atlas),
203175
transform: Transform {
@@ -214,8 +186,8 @@ fn spawn_ai_players(
214186
let atlas = TextureAtlas::from_grid(handle, Vec2::new(70., 121.), 1, 1, None, None);
215187
commands.spawn((
216188
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)),
219191
SpriteSheetBundle {
220192
texture_atlas: texture_atlas.add(atlas),
221193
transform: Transform {
@@ -232,8 +204,8 @@ fn spawn_ai_players(
232204
let atlas = TextureAtlas::from_grid(handle, Vec2::new(70., 121.), 1, 1, None, None);
233205
commands.spawn((
234206
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)),
237209
SpriteSheetBundle {
238210
texture_atlas: texture_atlas.add(atlas),
239211
transform: Transform {
@@ -246,160 +218,10 @@ fn spawn_ai_players(
246218
));
247219
}
248220

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-
399221
fn handle_keyboard(
400222
mut query: Query<(
401-
&mut Angle,
402-
&mut Velocity,
223+
&mut physics::Angle,
224+
&mut physics::Velocity,
403225
&mut Transform,
404226
&mut Racer,
405227
With<Player>,
@@ -436,8 +258,8 @@ fn handle_keyboard(
436258

437259
fn handle_ai_players(
438260
mut query: Query<(
439-
&mut Angle,
440-
&mut Velocity,
261+
&mut physics::Angle,
262+
&mut physics::Velocity,
441263
&mut Transform,
442264
&mut Racer,
443265
Without<Player>,
@@ -508,7 +330,7 @@ fn handle_ai_players(
508330
}
509331

510332
fn track_player(
511-
player: Query<(&Transform, &Velocity, With<Player>)>,
333+
player: Query<(&Transform, &physics::Velocity, With<Player>)>,
512334
mut camera: Query<(&mut Transform, With<Camera>, Without<Player>)>,
513335
) {
514336
let (txp, _, _) = player.single();

0 commit comments

Comments
 (0)