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
pub mod kinematic;
pub mod collision;
pub mod rigid_body;

pub mod prelude {
	pub use crate::kinematic::*;
	pub use crate::collision::*;
	pub use crate::PhysicsPlugin;
	pub use crate::GravityEffect;
	pub use crate::DebugPlugin;
	pub use crate::Gravity;
}

use bevy::{prelude::*, math::vec2};

#[derive(Default)]
pub enum GravityEffect {
	#[default]
	None,
	Velocity,
	Acceleration,
}

#[derive(Default)]
pub struct PhysicsPlugin {
	pub gravity_effect: GravityEffect,
}

impl Plugin for PhysicsPlugin {
	fn build(&self, app: &mut App) {
		let mut post_update = SystemSet::new().with_system(kinematic::update_transform);
		post_update = match self.gravity_effect {
			GravityEffect::None         => post_update,
			GravityEffect::Velocity     => post_update.with_system(gravity_velocity    .before(kinematic::update_transform)),
			GravityEffect::Acceleration => post_update.with_system(gravity_acceleration.before(kinematic::update_transform))
		};

		app
			.add_event::<collision::CollisionEvent>()
			.add_system_to_stage(CoreStage::PreUpdate, collision::collision_event)
			.add_system_set_to_stage(
				CoreStage::PostUpdate,
				post_update
			);
	}
}

#[derive(Deref, DerefMut)]
pub struct Gravity(pub Vec2);

fn gravity_acceleration(
	gravity: Option<Res<Gravity>>,
	mut query: Query<&mut kinematic::Acceleration>,
) {
	if let Some(g) = gravity {
		for mut acceleration in query.iter_mut() {
			acceleration.linear += **g;
		}
	}
}

fn gravity_velocity(
	gravity: Option<Res<Gravity>>,
	mut query: Query<&mut kinematic::Velocity>
) {
	if let Some(g) = gravity {
		for mut velocity in query.iter_mut() {
			velocity.linear += **g;
		}
	}
}

// Debug Plugin

use bevy_prototype_lyon::prelude::*;
use collision::*;

pub struct DebugPlugin;
impl Plugin for DebugPlugin {
	fn build(&self, app: &mut App) {
	    app.add_plugin(ShapePlugin)
			.add_system(spawn_debug_shape)
			.add_system(collider_debug_transform_sync);
	}
}

#[derive(Component)] struct ColliderDebugParent(Entity);
#[derive(Component)] struct ColliderDebugChild(Entity);

fn spawn_debug_shape(
	mut commands: Commands,
	query: Query<(Entity, &ColliderShape), Added<ColliderShape>>
) {
	for (parent, collider_shape) in query.iter() {
		let mut builder = GeometryBuilder::new();
		match *collider_shape {
			ColliderShape::AABB(w, h) => {
				builder = builder.add(&shapes::Rectangle {
					extents: vec2(w*2.0, h*2.0),
					..default()
				});
			},
			ColliderShape::Circle(r) => {
				builder = builder.add(&shapes::Circle {
					radius: r,
					..default()
				});
			},
			_ => unreachable!()
		}

		let child = commands.spawn_bundle(builder.build(
			DrawMode::Stroke(StrokeMode::color(Color::GREEN)),
			default()
		)).insert(ColliderDebugParent(parent)).id();
	
		commands.entity(parent).insert(ColliderDebugChild(child));
	}
}

fn collider_debug_transform_sync(
	mut commands: Commands,
	mut child_query: Query<(Entity, &mut Transform, &ColliderDebugParent)>,
	parent_query: Query<(&Transform, &ColliderShape) , (With<ColliderDebugChild>, Without<ColliderDebugParent>)>,
) {
	for (child, mut child_transform, ColliderDebugParent(parent)) in child_query.iter_mut() {
		if let Ok((parent_transform, collider_shape)) = parent_query.get(*parent) {
			match collider_shape {
				ColliderShape::AABB(_, _) => child_transform.translation = parent_transform.translation,
				_ => *child_transform = *parent_transform
			}
			
		} else {
			commands.entity(child).despawn();
		}
	}
}