Skip to content

Commit

Permalink
Extracts collision and spatial plugins into its own modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
reu committed Jun 4, 2022
1 parent e7a7de5 commit e4a3033
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 76 deletions.
64 changes: 64 additions & 0 deletions src/collision.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::marker::PhantomData;

use bevy::prelude::*;

use crate::spatial::Spatial;

pub struct CollisionPlugin<Hittable, Hurtable> {
_phantom: PhantomData<(Hittable, Hurtable)>,
}

impl<Hittable: Component, Hurtable: Component> CollisionPlugin<Hittable, Hurtable> {
pub fn new() -> Self {
Self {
_phantom: PhantomData,
}
}
}

impl<Hittable: Component, Hurtable: Component> Plugin for CollisionPlugin<Hittable, Hurtable> {
fn build(&self, app: &mut App) {
app.add_event::<HitEvent<Hittable, Hurtable>>()
.add_system(collision_system::<Hittable, Hurtable>.label(CollisionSystemLabel));
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(SystemLabel)]
pub struct CollisionSystemLabel;

#[derive(Debug)]
pub struct HitEvent<A, B> {
entities: (Entity, Entity),
_phantom: PhantomData<(A, B)>,
}

impl<A, B> HitEvent<A, B> {
pub fn hittable(&self) -> Entity {
self.entities.0
}

pub fn hurtable(&self) -> Entity {
self.entities.1
}
}

#[derive(Debug, Component)]
pub struct Collidable;

fn collision_system<A: Component, B: Component>(
mut hits: EventWriter<HitEvent<A, B>>,
hittables: Query<(Entity, &Spatial), (With<Collidable>, With<A>)>,
hurtables: Query<(Entity, &Spatial), (With<Collidable>, With<B>)>,
) {
for (hittable_entity, hittable) in hittables.iter() {
for (hurtable_entity, hurtable) in hurtables.iter() {
if hittable.intersects(hurtable) {
hits.send(HitEvent {
entities: (hittable_entity, hurtable_entity),
_phantom: PhantomData,
});
}
}
}
}
94 changes: 18 additions & 76 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::type_complexity)]

use std::{f32::consts::PI, marker::PhantomData, ops::Range, time::Duration};
use std::{f32::consts::PI, ops::Range, time::Duration};

use bevy::{core::FixedTimestep, prelude::*, window::PresentMode};
use bevy_prototype_lyon::{
Expand All @@ -11,7 +11,12 @@ use bevy_prototype_lyon::{
},
shapes::Polygon,
};
use collision::{Collidable, CollisionPlugin, HitEvent, CollisionSystemLabel};
use rand::{prelude::SmallRng, Rng, SeedableRng};
use spatial::{Spatial, SpatialPlugin};

mod collision;
mod spatial;

const TIME_STEP: f32 = 1.0 / 120.0;

Expand All @@ -32,8 +37,9 @@ fn main() {
small: 10.0..20.0,
})
.add_event::<AsteroidSpawnEvent>()
.add_event::<HitEvent<Asteroid, Bullet>>()
.add_event::<HitEvent<Asteroid, Ship>>()
.add_plugin(SpatialPlugin)
.add_plugin(CollisionPlugin::<Bullet, Asteroid>::new())
.add_plugin(CollisionPlugin::<Asteroid, Ship>::new())
.add_startup_system(setup_system)
.add_system_set(
SystemSet::new()
Expand Down Expand Up @@ -67,10 +73,8 @@ fn main() {
.with_system(boundary_remove_system)
.with_system(boundary_wrap_system),
)
.add_system(collision_system)
.add_system(asteroid_hit_system.after(collision_system))
.add_system(ship_hit_system.after(collision_system))
.add_system(drawing_system.after("wrap"))
.add_system(asteroid_hit_system.after(CollisionSystemLabel))
.add_system(ship_hit_system.after(CollisionSystemLabel))
.run();
}

Expand All @@ -93,20 +97,6 @@ struct AsteroidSizes {
small: Range<f32>,
}

#[derive(Debug, Component, Default, Clone)]
struct Spatial {
position: Vec2,
rotation: f32,
radius: f32,
}

impl Spatial {
fn intersects(&self, other: &Spatial) -> bool {
let distance = (self.position - other.position).length();
distance < self.radius + other.radius
}
}

#[derive(Debug, Component, Default)]
struct Velocity(Vec2);

Expand Down Expand Up @@ -177,7 +167,7 @@ struct BoundaryWrap;
struct BoundaryRemoval;

#[derive(Debug, Component, Default)]
struct Ship {
pub struct Ship {
state: ShipState,
}

Expand Down Expand Up @@ -214,27 +204,18 @@ impl Default for ShipState {
}
}

#[derive(Debug, Component)]
struct Collidable;

#[derive(Debug, Component, Default)]
struct Bullet;
pub struct Bullet;

#[derive(Debug, Component, Default)]
struct Explosion;

#[derive(Debug, Component, Default)]
struct Asteroid;
pub struct Asteroid;

#[derive(Debug, Deref)]
struct AsteroidSpawnEvent(Spatial);

#[derive(Debug)]
struct HitEvent<A, B> {
entities: (Entity, Entity),
_phantom: PhantomData<(A, B)>,
}

#[derive(Bundle)]
struct ExplosionBundle {
#[bundle]
Expand Down Expand Up @@ -266,13 +247,6 @@ impl Default for ExplosionBundle {
}
}

fn hit_event<A, B>(e1: Entity, e2: Entity) -> HitEvent<A, B> {
HitEvent {
entities: (e1, e2),
_phantom: PhantomData,
}
}

fn setup_system(mut commands: Commands) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn().insert(Ship::spawn(Duration::from_secs(0)));
Expand Down Expand Up @@ -351,30 +325,6 @@ fn weapon_system(
}
}

fn collision_system(
mut asteroid_hits: EventWriter<HitEvent<Asteroid, Bullet>>,
mut ship_hits: EventWriter<HitEvent<Asteroid, Ship>>,
ships: Query<(Entity, &Spatial), (With<Collidable>, With<Ship>)>,
asteroids: Query<(Entity, &Spatial), (With<Collidable>, With<Asteroid>)>,
bullets: Query<(Entity, &Spatial), (With<Collidable>, With<Bullet>)>,
) {
for (bullet_entity, bullet) in bullets.iter() {
for (asteroid_entity, asteroid) in asteroids.iter() {
if bullet.intersects(asteroid) {
asteroid_hits.send(hit_event(asteroid_entity, bullet_entity))
}
}
}

for (ship_entity, ship) in ships.iter() {
for (asteroid_entity, asteroid) in asteroids.iter() {
if ship.intersects(asteroid) {
ship_hits.send(hit_event(asteroid_entity, ship_entity));
}
}
}
}

fn ship_state_system(
time: Res<Time>,
mut commands: Commands,
Expand Down Expand Up @@ -649,22 +599,14 @@ fn explosion_system(mut query: Query<&mut Transform, With<Explosion>>) {
}
}

fn drawing_system(mut query: Query<(&mut Transform, &Spatial)>) {
for (mut transform, spatial) in query.iter_mut() {
transform.translation.x = spatial.position.x;
transform.translation.y = spatial.position.y;
transform.rotation = Quat::from_rotation_z(spatial.rotation);
}
}

fn ship_hit_system(
mut rng: Local<Random>,
mut ship_hits: EventReader<HitEvent<Asteroid, Ship>>,
mut commands: Commands,
query: Query<&Spatial, With<Ship>>,
) {
for hit in ship_hits.iter() {
let ship = hit.entities.1;
let ship = hit.hurtable();

if let Ok(spatial) = query.get(ship) {
for n in 0..12 * 6 {
Expand Down Expand Up @@ -698,14 +640,14 @@ fn ship_hit_system(
fn asteroid_hit_system(
asteroid_sizes: Res<AsteroidSizes>,
mut rng: Local<Random>,
mut asteroid_hits: EventReader<HitEvent<Asteroid, Bullet>>,
mut asteroid_hits: EventReader<HitEvent<Bullet, Asteroid>>,
mut asteroid_spawn: EventWriter<AsteroidSpawnEvent>,
mut commands: Commands,
query: Query<&Spatial, With<Asteroid>>,
) {
for hit in asteroid_hits.iter() {
let asteroid = hit.entities.0;
let bullet = hit.entities.1;
let asteroid = hit.hurtable();
let bullet = hit.hittable();

if let Ok(spatial) = query.get(asteroid) {
if asteroid_sizes.big.contains(&spatial.radius) {
Expand Down
34 changes: 34 additions & 0 deletions src/spatial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use bevy::prelude::*;

pub struct SpatialPlugin;

impl Plugin for SpatialPlugin {
fn build(&self, app: &mut App) {
app.add_system(spatial_system.label(SpatialSystemLabel));
}
}

#[derive(Debug, Component, Default, Clone)]
pub struct Spatial {
pub position: Vec2,
pub rotation: f32,
pub radius: f32,
}

impl Spatial {
pub fn intersects(&self, other: &Spatial) -> bool {
let distance = (self.position - other.position).length();
distance < self.radius + other.radius
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SystemLabel)]
pub struct SpatialSystemLabel;

fn spatial_system(mut query: Query<(&mut Transform, &Spatial)>) {
for (mut transform, spatial) in query.iter_mut() {
transform.translation.x = spatial.position.x;
transform.translation.y = spatial.position.y;
transform.rotation = Quat::from_rotation_z(spatial.rotation);
}
}

0 comments on commit e4a3033

Please sign in to comment.