Skip to content

Commit

Permalink
feat: Rigidbodies (#62)
Browse files Browse the repository at this point in the history
* Adds part of the rigidbody implementation
  • Loading branch information
Zac8668 authored Jan 27, 2024
1 parent 17853e6 commit c011d13
Show file tree
Hide file tree
Showing 11 changed files with 1,557 additions and 566 deletions.
1,591 changes: 1,073 additions & 518 deletions Cargo.lock

Large diffs are not rendered by default.

23 changes: 14 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ default-run = "astratomic"
[dependencies]
bevy = {version = "0.12", features =["file_watcher"]}
bevy-inspector-egui = "0.22"
rand = { version = "0.8.5", features = ["small_rng"] }
fastrand = "2.0.1"
async-channel = "2.1.0"
smallvec = "1.11.2"
itertools = "0.12.0"
rand = { version = "0.8", features = ["small_rng"] }
fastrand = "2.0"
async-channel = "2.1"
smallvec = "1.12"
itertools = "0.12"

serde = "1.0"
serde_derive = "1.0"
bincode = "1.3.3"
serde-big-array = "0.5.1"
ron = "0.8.1"
bevy-async-task = "1.3.1"
bincode = "1.3"
serde-big-array = "0.5"
ron = "0.8"
bevy-async-task = "1.3"

contour = "0.12"
bevy_rapier2d = { version = "0.23", features = [ "simd-stable", "debug-render-2d", "parallel" ] }
geo = "0.27"
rotsprite = "0.1"

egui = "0.24"
bevy_egui = "0.24"
Expand Down
Binary file added assets/tree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::Deserialize;

use crate::prelude::*;

#[derive(Clone, Copy, Default, PartialEq, Debug, Serialize, Deserialize)]
#[derive(Clone, Copy, Default, PartialEq, Debug, Serialize, Deserialize, Eq)]
pub struct Atom {
pub color: [u8; 4],
pub id: u8,
Expand Down
36 changes: 34 additions & 2 deletions src/chunk.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::render::render_resource::*;
use std::collections::HashSet;

use crate::prelude::*;
use crate::{prelude::*, rigidbody};

#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct Chunk {
Expand All @@ -10,13 +10,16 @@ pub struct Chunk {

#[serde(skip)]
pub texture: Handle<Image>,
#[serde(skip)]
pub entity: Option<Entity>,
}

impl Default for Chunk {
fn default() -> Self {
Self {
atoms: [Atom::default(); CHUNK_LEN],
texture: Handle::default(),
entity: None,
}
}
}
Expand Down Expand Up @@ -49,7 +52,11 @@ impl Chunk {
}
}

Chunk { atoms, texture }
Chunk {
atoms,
texture,
entity: None,
}
}

pub fn new_image() -> Image {
Expand Down Expand Up @@ -80,4 +87,29 @@ impl Chunk {

self.update_image_positions(image, &positions)
}

pub fn get_collider(&self, materials: &Materials) -> Option<Collider> {
rigidbody::get_collider(
&self.get_values(materials),
CHUNK_LENGHT as u32,
CHUNK_LENGHT as u32,
(0., 0.),
)
}

pub fn get_values(&self, materials: &Materials) -> Vec<f64> {
let mut values = vec![];

for row in self.atoms.chunks(CHUNK_LENGHT) {
for atom in row {
if materials[atom].is_solid() {
values.push(1.)
} else {
values.push(0.)
}
}
}

values
}
}
145 changes: 114 additions & 31 deletions src/chunk_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl DirtyRects {
}

#[derive(Component)]
pub struct ChunkTextures;
pub struct ChunksParent;

pub fn manager_setup(
mut commands: Commands,
Expand Down Expand Up @@ -203,18 +203,98 @@ pub fn manager_setup(

commands
.spawn((
Name::new("Chunks textures"),
Name::new("Chunks"),
VisibilityBundle::default(),
TransformBundle::from_transform(Transform::from_translation(vec3(
0.,
0.,
AUTOMATA_LAYER,
))),
ChunkTextures,
ChunksParent,
))
.push_children(&images_vec);
}

pub fn add_colliders(
mut commands: Commands,
chunk_manager: Res<ChunkManager>,
chunks: Query<(Entity, &ChunkComponent)>,
rigidbodies: Query<(&Transform, &Rigidbody)>,
materials: (Res<Assets<Materials>>, Res<MaterialsHandle>),
) {
let materials = materials.0.get(materials.1 .0.clone()).unwrap();

let mut rects = vec![];

for (transform, rigidbody) in &rigidbodies {
let l = std::f32::consts::SQRT_2 * (rigidbody.width as f32).max(rigidbody.height as f32);

let angle = std::f32::consts::FRAC_PI_4 + std::f32::consts::PI;
let mut top_left = transform.translation.xy();
top_left.y *= -1.;
top_left += vec2(angle.cos(), angle.sin()) * l / 2.;

let angle = std::f32::consts::FRAC_PI_4;
let mut down_right = transform.translation.xy();
down_right.y *= -1.;
down_right += vec2(angle.cos(), angle.sin()) * l / 2.;

/*{
//Some debug visualization
let mut top_left = top_left;
top_left.y *= -1.;
gizmos.circle_2d(top_left, 10., Color::RED);
let mut down_right = down_right;
down_right.y *= -1.;
gizmos.circle_2d(down_right, 10., Color::BLACK);
}*/

top_left /= CHUNK_LENGHT as f32;
down_right /= CHUNK_LENGHT as f32;

const LOADING_OFF: i32 = 2;
let bounds_rect = IRect::new(
top_left.x as i32 - LOADING_OFF,
top_left.y as i32 - LOADING_OFF,
down_right.x as i32 + LOADING_OFF,
down_right.y as i32 + LOADING_OFF,
);

rects.push(bounds_rect);
}

if !rects.is_empty() {
'chunks: for (ent, pos) in &chunks {
for (i, rect) in rects.iter().enumerate() {
//If on bounds continue by breaking this loop
if rect.contains(pos.0) {
break;
} else if i == rects.len() - 1 {
//If none contains, remove collider and go to next chunk
//Remove collider
if let Some(mut entity) = commands.get_entity(ent) {
entity.remove::<Collider>();
entity.remove::<bevy_rapier2d::prelude::RigidBody>();
}
continue 'chunks;
}
}

if let Some(chunk) = chunk_manager.chunks.get(&pos.0) {
let collider = chunk.get_collider(materials);

if let Some(collider) = collider {
commands
.entity(ent)
.insert(collider)
.insert(bevy_rapier2d::prelude::RigidBody::Fixed);
}
}
}
}
}

pub fn chunk_manager_update(
mut chunk_manager: ResMut<ChunkManager>,
mut dirty_rects_resource: ResMut<DirtyRects>,
Expand Down Expand Up @@ -268,16 +348,6 @@ pub fn chunk_manager_update(

// Spawn a task on the deferred scope for handling deferred dirty render rects.
deferred_scope.spawn(async move {
//Update all rendering, used when debugging
/*
for x in 0..CHUNKS_WIDTH {
for y in 0..CHUNKS_HEIGHT {
render_dirty_rects
.insert(IVec2::new(x as i32, y as i32), URect::new(0, 0, 63, 63));
}
}
*/

// Loop through deferred tasks
while let Ok(update) = dirty_render_rects_recv.recv().await {
update_dirty_rects(render_dirty_rects, update.chunk_pos);
Expand Down Expand Up @@ -390,6 +460,9 @@ pub fn update_chunks(chunks: &mut UpdateChunksType, dt: u8, dirty_rect: &URect)
}
}

#[derive(Component)]
pub struct ChunkComponent(pub IVec2);

//Still needs to add the return entity to a parent
pub fn add_chunk(
commands: &mut Commands,
Expand All @@ -410,25 +483,31 @@ pub fn add_chunk(
//Update chunk image
let image = images.get_mut(&chunk.texture).unwrap();
chunk.update_all(image);
chunk_manager.chunks.insert(index, chunk);

//Spawn Image
commands
.spawn(SpriteBundle {
texture: texture_copy,
sprite: Sprite {
anchor: Anchor::TopLeft,
let entity = commands
.spawn((
SpriteBundle {
texture: texture_copy,
sprite: Sprite {
anchor: Anchor::TopLeft,
..Default::default()
},
transform: Transform::from_xyz(pos.x, pos.y, 0.),
..Default::default()
},
transform: Transform::from_xyz(pos.x, pos.y, 0.),
..Default::default()
})
.id()
ChunkComponent(index),
))
.id();
chunk.entity = Some(entity);

chunk_manager.chunks.insert(index, chunk);
entity
}

pub fn update_manager_pos(
mut commands: Commands,
chunk_textures: Query<Entity, With<ChunkTextures>>,
chunk_textures: Query<Entity, With<ChunksParent>>,
image_entities: Query<(&Parent, Entity, &Handle<Image>)>,
player: Query<&Actor, With<Player>>,
resources: (
Expand Down Expand Up @@ -510,16 +589,17 @@ pub fn update_manager_pos(
}

#[derive(Resource, Default, Deref, DerefMut)]
struct ExtractedTextureUpdates(Vec<ExtractedTextureUpdate>);
pub struct ExtractedTextureUpdates(pub Vec<ExtractedTextureUpdate>);

struct ExtractedTextureUpdate {
id: AssetId<Image>,
#[derive(Clone)]
pub struct ExtractedTextureUpdate {
pub id: AssetId<Image>,
// TODO: determine a good size for the data smallvec array.
// The size of the array determines how many bytes we can store before it overflows and has
// to make a heap allocation. 256 is enough to store an 8x8 pixel dirty rect.
data: SmallVec<[u8; 256]>,
origin: Origin3d,
size: Extent3d,
pub data: SmallVec<[u8; 256]>,
pub origin: Origin3d,
pub size: Extent3d,
}

fn extract_chunk_texture_updates(
Expand Down Expand Up @@ -598,7 +678,10 @@ impl Plugin for ChunkManagerPlugin {
FixedUpdate,
chunk_manager_update.run_if(in_state(GameState::Game)),
)
.add_systems(Update, update_manager_pos.run_if(in_state(GameState::Game)))
.add_systems(
Update,
(update_manager_pos, add_colliders).run_if(in_state(GameState::Game)),
)
.add_systems(
PreUpdate,
clear_render_rect.run_if(in_state(GameState::Game)),
Expand Down
1 change: 1 addition & 0 deletions src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ impl Plugin for DebugPlugin {
)
.add_systems(PreUpdate, delete_image.run_if(in_state(GameState::Game)))
.add_plugins(WorldInspectorPlugin::new())
.add_plugins(RapierDebugRenderPlugin::default())
//Frame on console
.add_plugins((LogDiagnosticsPlugin::default(), FrameTimeDiagnosticsPlugin))
.init_resource::<PreviousMousePos>();
Expand Down
12 changes: 10 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ mod menu;
mod particles;
mod player;
mod puffin_plugin;
mod rigidbody;
mod prelude {
pub use crate::GameState;
pub use crate::{
actors::*, animation::*, atom::*, camera::*, chunk::*, chunk_group::*, chunk_manager::*,
consts::*, debug::*, geom_tools::*, manager_api::*, materials::*, menu::*, particles::*,
player::*, puffin_plugin::*,
player::*, puffin_plugin::*, rigidbody::*,
};
pub use bevy::input::mouse::MouseScrollUnit;
pub use bevy::input::mouse::MouseWheel;
Expand All @@ -43,6 +44,9 @@ mod prelude {
pub use std::io::{BufReader, BufWriter};
pub use std::sync::{Arc, RwLock};

pub use bevy_rapier2d::prelude::*;
pub use contour::ContourBuilder;

pub use crate::materials::Material;
pub use bevy_egui::EguiContext;
}
Expand All @@ -65,12 +69,16 @@ fn main() {
ParticlesPlugin,
MaterialsPlugin,
CameraPlugin,
RigidbodyPlugin,
))
.add_plugins((
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(6.),
MenuPlugin,
))
.add_systems(Startup, setup);

if args.contains(&"-d".to_string()) || args.contains(&"--debug".to_string()) {
app.add_plugins(DebugPlugin);
app.add_plugins((DebugPlugin,));
}

if args.contains(&"-p".to_string()) || args.contains(&"--profiling".to_string()) {
Expand Down
7 changes: 5 additions & 2 deletions src/materials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@ impl AssetLoader for MaterialsLoader {
}
}

pub fn setup(mut materials_handle: ResMut<MaterialsHandle>, asset_server: Res<AssetServer>) {
pub fn materials_setup(
mut materials_handle: ResMut<MaterialsHandle>,
asset_server: Res<AssetServer>,
) {
materials_handle.0 = asset_server.load("atoms.ron");
}

Expand All @@ -128,6 +131,6 @@ impl Plugin for MaterialsPlugin {
app.init_asset::<Materials>()
.init_resource::<MaterialsHandle>()
.init_asset_loader::<MaterialsLoader>()
.add_systems(Startup, setup);
.add_systems(Startup, materials_setup);
}
}
Loading

0 comments on commit c011d13

Please sign in to comment.