Skip to content

Commit

Permalink
organize code a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
sim82 committed May 7, 2022
1 parent 4b5e665 commit 21274ca
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 290 deletions.
60 changes: 60 additions & 0 deletions src/auto_collider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use bevy::{prelude::*, utils::HashMap};
use bevy_rapier3d::prelude::*;
use multimap::MultiMap;

#[derive(Default)]
pub struct MeshColliderGenerator {
colliders: HashMap<Handle<Mesh>, Collider>,
pending: MultiMap<Handle<Mesh>, Entity>,
}

#[derive(Component)]
#[component(storage = "SparseSet")]
pub struct AttachCollider;

pub fn attach_collider_system(
mut commands: Commands,
mut state: ResMut<MeshColliderGenerator>,
mut mesh_events: EventReader<AssetEvent<Mesh>>,
meshes: Res<Assets<Mesh>>,
query: Query<(Entity, &Handle<Mesh>), (Added<AttachCollider>, Without<Collider>)>,
) {
for (entity, mesh) in query.iter() {
state.pending.insert(mesh.clone(), entity);
}

for event in mesh_events.iter() {
if let AssetEvent::Created { handle } = event {
if let Some(v) = state.pending.remove(handle) {
let collider = match state.colliders.entry(handle.clone()) {
bevy::utils::hashbrown::hash_map::Entry::Occupied(e) => e.get().clone(),
bevy::utils::hashbrown::hash_map::Entry::Vacant(e) => {
if let Some(mesh) = meshes.get(handle) {
// TODO: calculate decomposition in background
// TODO2: meh think again, the hex tiles are already convex...
// let collider = Collider::bevy_mesh_convex_decomposition(mesh).unwrap();
let collider = Collider::bevy_mesh(mesh).unwrap();
info!("convex decomposition done.");
e.insert(collider).clone()
} else {
panic!("could not get mesh instance after Created event!?");
}
}
};

for entity in v.iter() {
commands.entity(*entity).insert(collider.clone());
}
}
}
}
}

pub struct AutoColliderPlugin;

impl Plugin for AutoColliderPlugin {
fn build(&self, app: &mut App) {
app.add_system(attach_collider_system)
.init_resource::<MeshColliderGenerator>();
}
}
235 changes: 235 additions & 0 deletions src/fx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
use rand::prelude::*;

#[derive(Component, Default)]
#[component(storage = "SparseSet")]
pub struct DoRotate {
pub progress: f32,
}

pub fn rotate_system(
mut commands: Commands,
time: Res<Time>,
mut query: Query<(Entity, &mut Transform, &mut DoRotate)>,
) {
for (entity, mut transform, mut rotate) in query.iter_mut() {
rotate.progress += time.delta_seconds() * std::f32::consts::PI;

let rotation = if rotate.progress >= std::f32::consts::PI {
commands.entity(entity).remove::<DoRotate>();
0.0
} else {
rotate.progress
};
transform.rotation = Quat::from_axis_angle(Vec3::Z, rotation);
info!("transform: {:?}", transform);
}
// for (entity, mut velocity, transform, mut rotate) in query.iter_mut() {
// info!("transform: {:?}", transform);
// if rotate.progress == 0.0 {
// velocity.angvel = Vec3::X;
// }
// rotate.progress += time.delta_seconds() * std::f32::consts::PI;

// if rotate.progress >= std::f32::consts::PI {
// commands.entity(entity).remove::<DoRotate>();
// *velocity = Velocity::zero();
// }
// }
}

#[derive(Component, Default, Clone)]
pub struct FadeOut {
until_start: f32,
left: f32,
start: f32,
start_color: Color,
}

impl FadeOut {
pub fn new(until_start: f32, fade_time: f32) -> Self {
FadeOut {
until_start,
left: fade_time,
start: fade_time,
..default()
}
}
}

#[allow(clippy::collapsible_else_if)]
pub fn fade_out_system(
mut commands: Commands,
time: Res<Time>,
mut query: Query<
(
Entity,
&mut FadeOut,
&mut Transform,
&Handle<StandardMaterial>,
),
Without<PointLight>,
>,
mut query2: Query<(Entity, &mut FadeOut, &mut PointLight)>,

mut materials: ResMut<Assets<StandardMaterial>>,
) {
for (entity, mut fade_out, mut transform, material) in query.iter_mut() {
if fade_out.until_start > 0.0 {
fade_out.until_start -= time.delta_seconds();
} else {
if fade_out.left <= 0.0 {
info!("exploding: fadeout despawn mesh");
commands.entity(entity).despawn_recursive();
} else {
let v = fade_out.left / fade_out.start;
fade_out.left -= time.delta_seconds();

transform.scale = Vec3::splat(v);
// if let Some(material) = materials.get_mut(material) {
// material.emissive = fade_out.start_color * v;
// }
}
}
}
for (entity, mut fade_out, mut point_light) in query2.iter_mut() {
if fade_out.until_start > 0.0 {
fade_out.until_start -= time.delta_seconds();
} else {
if fade_out.left <= 0.0 {
info!("exploding: fadeout despawn light");
commands.entity(entity).despawn_recursive();
} else {
let v = fade_out.left / fade_out.start;
fade_out.left -= time.delta_seconds();

point_light.color = fade_out.start_color * v;
}
}
}
}

pub fn spawn_exploding_cube(
commands: &mut Commands,
pos: Vec3,
meshes: &mut Assets<Mesh>,
materials: &mut Assets<StandardMaterial>,
) {
let cube = meshes.add(shape::Cube { size: 0.03 }.into());
let mut rng = rand::thread_rng();
info!("exploding: spawn cubes. pos: {:?}", pos);
let cube_size = 4;
for z in 0..cube_size {
for y in 0..cube_size {
for x in 0..cube_size {
let cube_size = 0.025;
let x = x as f32 * cube_size;
let y = y as f32 * cube_size;
let z = z as f32 * cube_size;
let color = *crate::COLORS.choose(&mut rng).unwrap();
let material = materials.add(StandardMaterial {
base_color: Color::BLACK,
reflectance: 0.0,
emissive: color,
..default()
});

let velocity = Vec3::new(
rng.gen_range(-1.0..1.0) * 2.0,
rng.gen_range(2.0..3.0) * 0.5,
rng.gen_range(-1.0..1.0) * 2.0,
);

let fade_out = FadeOut {
until_start: 1.0,
left: 1.0,
start: 1.0,
start_color: color,
};

commands
.spawn_bundle(PbrBundle {
transform: Transform::from_translation(
pos + Vec3::new(x, y, z) + Vec3::Y * 0.1,
),
material,
mesh: cube.clone(),
..default()
})
// .insert(Collider::cuboid(
// cube_size / 2.0,
// cube_size / 2.0,
// cube_size / 2.0,
// ))
.insert(Collider::ball(cube_size / 2.0))
.insert(Restitution {
coefficient: 1.0,
..default()
})
.insert(RigidBody::Dynamic)
.insert(Velocity::linear(velocity))
.insert(fade_out.clone())
.with_children(|commands| {
commands
.spawn_bundle(PointLightBundle {
point_light: PointLight {
intensity: 5.0,
radius: cube_size / 2.0,
range: 0.7,
color,
..default()
},
..default()
})
.insert(fade_out);
});
}
}
}
}

#[derive(Component)]
#[component(storage = "SparseSet")]
pub struct PlayerExplosion {
pub time_left: f32,
}

pub fn player_explosion_system(
mut commands: Commands,
time: Res<Time>,
mut query: Query<(Entity, &mut Transform, &mut PlayerExplosion)>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
let mut rng = rand::thread_rng();
for (entity, mut transform, mut explosion) in query.iter_mut() {
explosion.time_left -= time.delta_seconds();

if explosion.time_left <= 0.0 {
commands.entity(entity).despawn_recursive();
spawn_exploding_cube(
&mut commands,
transform.translation,
&mut meshes,
&mut materials,
);
} else {
let v = (1.0 - explosion.time_left).clamp(0.0, 1.0) * 0.3;
// let distr = rand::distributions::Bernoulli::new(1.0).unwrap();
// transform.scale = Vec3::splat(1.0 + rng.gen_range(-v..v));
transform.scale += Vec3::splat(rng.gen_range(-v..v));
transform.scale = transform.scale.clamp(Vec3::splat(0.2), Vec3::splat(1.4));
}
}
}

pub struct FxPlugin;

impl Plugin for FxPlugin {
fn build(&self, app: &mut App) {
app.add_system(rotate_system)
.add_system(player_explosion_system)
.add_system(fade_out_system);
}
}
77 changes: 19 additions & 58 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use bevy::{
use bevy_rapier3d::prelude::{Collider, RigidBody};
use multimap::MultiMap;

pub mod auto_collider;
pub mod fx;
pub mod hex;

pub mod shape {
use bevy::{
prelude::*,
Expand Down Expand Up @@ -85,7 +86,7 @@ pub mod shape {
}
}

pub const colors: [Color; 18] = [
pub const colorsx: [Color; 18] = [
Color::PINK,
Color::CRIMSON,
Color::AQUAMARINE,
Expand All @@ -106,59 +107,19 @@ pub const colors: [Color; 18] = [
Color::YELLOW_GREEN,
];

#[derive(Default)]
pub struct MeshColliderGenerator {
colliders: HashMap<Handle<Mesh>, Collider>,
pending: MultiMap<Handle<Mesh>, Entity>,
}

#[derive(Component)]
#[component(storage = "SparseSet")]
pub struct AttachCollider;

pub fn attach_collider_system(
mut commands: Commands,
mut state: ResMut<MeshColliderGenerator>,
mut mesh_events: EventReader<AssetEvent<Mesh>>,
meshes: Res<Assets<Mesh>>,
query: Query<(Entity, &Handle<Mesh>), (Added<AttachCollider>, Without<Collider>)>,
) {
for (entity, mesh) in query.iter() {
state.pending.insert(mesh.clone(), entity);
}

for event in mesh_events.iter() {
if let AssetEvent::Created { handle } = event {
if let Some(v) = state.pending.remove(handle) {
let collider = match state.colliders.entry(handle.clone()) {
bevy::utils::hashbrown::hash_map::Entry::Occupied(e) => e.get().clone(),
bevy::utils::hashbrown::hash_map::Entry::Vacant(e) => {
if let Some(mesh) = meshes.get(handle) {
// TODO: calculate decomposition in background
// TODO2: meh think again, the hex tiles are already convex...
// let collider = Collider::bevy_mesh_convex_decomposition(mesh).unwrap();
let collider = Collider::bevy_mesh(mesh).unwrap();
info!("convex decomposition done.");
e.insert(collider).clone()
} else {
panic!("could not get mesh instance after Created event!?");
}
}
};

for entity in v.iter() {
commands.entity(*entity).insert(collider.clone());
}
}
}
}
}

pub struct AutoColliderPlugin;

impl Plugin for AutoColliderPlugin {
fn build(&self, app: &mut App) {
app.add_system(attach_collider_system)
.init_resource::<MeshColliderGenerator>();
}
}
pub const L: f32 = 0.75;

pub const COLORS: [Color; 12] = [
Color::hsl(0.0, 1.0, L),
Color::hsl(30.0, 1.0, L),
Color::hsl(60.0, 1.0, L),
Color::hsl(90.0, 1.0, L),
Color::hsl(120.0, 1.0, L),
Color::hsl(150.0, 1.0, L),
Color::hsl(180.0, 1.0, L),
Color::hsl(210.0, 1.0, L),
Color::hsl(240.0, 1.0, L),
Color::hsl(270.0, 1.0, L),
Color::hsl(300.0, 1.0, L),
Color::hsl(330.0, 1.0, L),
];
Loading

0 comments on commit 21274ca

Please sign in to comment.