Skip to content

Commit

Permalink
Fixed some atoms problems
Browse files Browse the repository at this point in the history
  • Loading branch information
Zac8668 committed Jan 5, 2024
1 parent 7e296b1 commit adcf29b
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 50 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
.vscode/
/assets/worlds/**
/assets/worlds/**
.cargo/config.toml
22 changes: 15 additions & 7 deletions src/actors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,30 @@ pub struct Actor {
}

//Called before simulations
pub fn add_actors(mut chunk_manager: ResMut<ChunkManager>, actors: Query<&Actor>) {
pub fn add_actors(
mut chunk_manager: ResMut<ChunkManager>,
actors: Query<&Actor>,
mut dirty_rects: ResMut<DirtyRects>,
) {
for actor in actors.iter() {
for x_off in 0..actor.width as i32 {
for y_off in 0..actor.height as i32 {
let pos = global_to_chunk(actor.pos + ivec2(x_off, y_off));
if let Some(atom) = chunk_manager.get_mut_atom(pos) {
if atom.state == State::Void {
*atom = Atom::object();
} else if atom.state == State::Liquid {
let rand_angle = fastrand::f32() - 0.5;
let vel = actor.vel * -4. * vec2(rand_angle.cos(), rand_angle.sin());
//Water splashes
atom.velocity = (
(vel.x).clamp(-126.0, 126.) as i8,
(vel.y).clamp(-126.0, 126.) as i8,
);
atom.automata_mode = false;
}
}
update_dirty_rects_3x3(&mut dirty_rects.current, pos);
}
}
}
Expand Down Expand Up @@ -137,9 +151,6 @@ pub fn move_x(chunk_manager: &mut ChunkManager, actor: &mut Actor, dir: i32) ->
if atom.state == State::Powder || atom.state == State::Solid {
actor.vel = Vec2::ZERO;
return false;
} else if atom.state == State::Liquid {
//Water splashes
atom.velocity = (0, -20)
}
} else {
actor.vel = Vec2::ZERO;
Expand Down Expand Up @@ -170,9 +181,6 @@ pub fn move_y(chunk_manager: &mut ChunkManager, actor: &mut Actor, dir: i32) ->
if atom.state == State::Powder || atom.state == State::Solid {
actor.vel = Vec2::ZERO;
return false;
} else if atom.state == State::Liquid {
//Water splashes
atom.velocity = (0, -20)
}
} else {
actor.vel = Vec2::ZERO;
Expand Down
19 changes: 14 additions & 5 deletions src/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Atom {
#[serde(skip)]
pub updated_at: u8,
#[serde(skip)]
pub fall_speed: u8,
pub automata_mode: bool,
// Used when thrown up, etc
#[serde(skip)]
pub velocity: (i8, i8),
Expand All @@ -25,7 +25,6 @@ impl Atom {
pub fn object() -> Self {
Atom {
state: State::Object,
color: [255, 255, 255, 255],
..Default::default()
}
}
Expand Down Expand Up @@ -134,7 +133,8 @@ pub fn update_liquid(chunks: &mut UpdateChunksType, pos: IVec2, dt: u8) -> HashS

if let Some(side) = side {
for _ in 0..5 {
if !swapable(chunks, cur_pos + IVec2::new(side, 0), &[], dt) {
let state = get_state(chunks, cur_pos);
if !swapable(chunks, cur_pos + IVec2::new(side, 0), &[], state, dt) {
break;
}

Expand Down Expand Up @@ -164,19 +164,28 @@ pub fn update_particle(chunks: &mut UpdateChunksType, pos: IVec2, dt: u8) -> Has
// Move
for pos in Line::new(cur_pos, vel) {
awakened.insert(cur_pos);
if swapable(chunks, pos, &[], dt) {
let state = get_state(chunks, cur_pos);
if swapable(chunks, pos, &[], state, dt) {
swap(chunks, cur_pos, pos, dt);
cur_pos = pos;
awakened.insert(cur_pos);
} else if get_state(chunks, pos) == State::Liquid
&& get_state(chunks, cur_pos) == State::Liquid
{
awakened.insert(pos);
set_vel(chunks, pos, vel * 4 / 5);
set_vel(chunks, cur_pos, vel / 5);
break;
} else {
if vel.abs().x > 4 && vel.abs().y > 4 {
set_vel(
chunks,
cur_pos,
(Vec2::from_angle(PI).rotate(vel.as_vec2()) * 0.5).as_ivec2(),
);
} else {
} else if !swapable(chunks, cur_pos + IVec2::Y, &[], state, dt) {
set_vel(chunks, cur_pos, IVec2::ZERO);
set_mode(chunks, cur_pos, true);
}
break;
}
Expand Down
48 changes: 29 additions & 19 deletions src/chunk_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl std::ops::IndexMut<ChunkPos> for ChunkManager {
}
}

#[derive(Component)]
#[derive(Resource, Default)]
pub struct DirtyRects {
/// The current chunk update dirty rects
pub current: HashMap<IVec2, URect>,
Expand Down Expand Up @@ -203,23 +203,16 @@ pub fn manager_setup(
ChunkTextures,
))
.push_children(&images_vec);

commands.spawn(DirtyRects {
current: HashMap::new(),
new: HashMap::new(),
render: HashMap::new(),
});
}

pub fn chunk_manager_update(
mut chunk_manager: ResMut<ChunkManager>,
mut dirty_rects: Query<&mut DirtyRects>,
mut dirty_rects_resource: ResMut<DirtyRects>,
) {
chunk_manager.dt = chunk_manager.dt.wrapping_add(1);
let dt = chunk_manager.dt;

// Get dirty rects
let mut dirty_rects_resource = dirty_rects.single_mut();
let DirtyRects {
current: dirty_rects,
new: new_dirty_rects,
Expand Down Expand Up @@ -256,7 +249,11 @@ pub fn chunk_manager_update(

// Loop through deferred tasks
while let Ok(update) = dirty_update_rects_recv.recv().await {
update_dirty_rects_3x3(new_dirty_rects, update.chunk_pos);
if update.awake_surrouding {
update_dirty_rects_3x3(new_dirty_rects, update.chunk_pos);
} else {
update_dirty_rects(new_dirty_rects, update.chunk_pos)
}
}
});

Expand Down Expand Up @@ -400,33 +397,46 @@ pub fn update_chunks(chunks: &mut UpdateChunksType, dt: u8, dirty_rect: &URect)

let mut awake_self = false;
let state;
let vel;
let automata_mode;
{
let atom = &mut chunks.group[local_pos];
state = atom.state;
vel = atom.velocity != (0, 0);

if atom.velocity == (0, 0) {
atom.automata_mode = true;
}
automata_mode = atom.automata_mode;
if automata_mode {
atom.velocity = (0, atom.velocity.1.abs());
}

if atom.f_idle < FRAMES_SLEEP && state != State::Void && state != State::Solid {
atom.f_idle += 1;
awake_self = true;
}
}

let mut awakened = if vel {
update_particle(chunks, pos, dt)
} else {
let mut awakened = if automata_mode {
match state {
State::Powder => update_powder(chunks, pos, dt),
State::Liquid => update_liquid(chunks, pos, dt),
_ => HashSet::new(),
}
} else {
update_particle(chunks, pos, dt)
};

let mut self_awakened = HashSet::new();
if awakened.contains(&pos) {
let atom = &mut chunks.group[local_pos];
atom.f_idle = 0;
} else if !automata_mode {
awakened.insert(pos);
let atom = &mut chunks.group[local_pos];
atom.f_idle = 0;
} else if awake_self {
awakened.insert(pos);
self_awakened.insert(pos);
}

for awoke in awakened {
Expand All @@ -437,6 +447,7 @@ pub fn update_chunks(chunks: &mut UpdateChunksType, dt: u8, dirty_rect: &URect)
.dirty_update_rect_send
.try_send(DeferredDirtyRectUpdate {
chunk_pos: ChunkPos::new(local.0.try_into().unwrap(), chunk),
awake_surrouding: !self_awakened.contains(&awoke),
})
.unwrap();
}
Expand Down Expand Up @@ -582,11 +593,9 @@ struct ExtractedTextureUpdate {

fn extract_chunk_texture_updates(
chunk_manager: Extract<Res<ChunkManager>>,
dirty_rects: Extract<Query<&DirtyRects>>,
dirty_rects: Extract<Res<DirtyRects>>,
mut extracted_updates: ResMut<ExtractedTextureUpdates>,
) {
let dirty_rects = dirty_rects.single();

for (chunk_pos, chunk) in chunk_manager.chunks.iter() {
if let Some(rect) = dirty_rects.render.get(chunk_pos) {
let id = chunk.texture.id();
Expand Down Expand Up @@ -651,7 +660,8 @@ impl Plugin for ChunkManagerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, manager_setup)
.add_systems(Update, (chunk_manager_update, update_manager_pos))
.init_resource::<ChunkManager>();
.init_resource::<ChunkManager>()
.init_resource::<DirtyRects>();

if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
render_app
Expand Down
4 changes: 2 additions & 2 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub const GRAVITY: u8 = 1;
pub const TERM_VEL: u8 = 10;
pub const FRAMES_SLEEP: u8 = 4;
//Has to be even
pub const LOAD_WIDTH: i32 = 32;
pub const LOAD_HEIGHT: i32 = 20;
pub const LOAD_WIDTH: i32 = 20;
pub const LOAD_HEIGHT: i32 = 12;

pub const _CAMERA_SPEED: f32 = 10.;
6 changes: 2 additions & 4 deletions src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn brush(
window: Query<&Window>,
camera_q: Query<(&Camera, &GlobalTransform)>,
mut chunk_manager: ResMut<ChunkManager>,
mut dirty_rects: Query<&mut DirtyRects>,
mut dirty_rects: ResMut<DirtyRects>,
prev_mpos: Query<&PreviousMousePos>,
input: (Res<Input<MouseButton>>, Res<Input<KeyCode>>),
) {
Expand Down Expand Up @@ -51,7 +51,6 @@ fn brush(
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor))
.map(|ray| ray.origin.truncate())
{
let mut dirty_rects = dirty_rects.single_mut();
world_position.y *= -1.;
let prev_mpos = prev_mpos.single().0.unwrap();

Expand Down Expand Up @@ -122,8 +121,7 @@ fn prev_mpos(

//Debug Render systems

pub fn render_dirty_rects(mut commands: Commands, dirty_rects: Query<&DirtyRects>) {
let dirty_rects = dirty_rects.single();
pub fn render_dirty_rects(mut commands: Commands, dirty_rects: Res<DirtyRects>) {
let (dirty_update, render_update) = (&dirty_rects.new, &dirty_rects.render);

let mut i = 0.;
Expand Down
32 changes: 24 additions & 8 deletions src/manager_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn swap(chunks: &mut UpdateChunksType, pos1: IVec2, pos2: IVec2, dt: u8) {
.dirty_render_rect_send
.try_send(DeferredDirtyRectUpdate {
chunk_pos: ChunkPos::new(pos.try_into().unwrap(), chunk),
..Default::default()
})
.unwrap();
}
Expand Down Expand Up @@ -92,12 +93,19 @@ pub fn chunk_to_global(pos: ChunkPos) -> IVec2 {

/// See if position is swapable, that means it sees if the position is a void
/// or if it's a swapable state and has been not updated
pub fn swapable(chunks: &UpdateChunksType, pos: IVec2, states: &[(State, f32)], dt: u8) -> bool {
pub fn swapable(
chunks: &UpdateChunksType,
pos: IVec2,
states: &[(State, f32)],
state: State,
dt: u8,
) -> bool {
if let Some(atom) = chunks.group.get_global(pos) {
atom.state == State::Void
|| (states.iter().any(|&(state, prob)| {
state == atom.state && rand::thread_rng().gen_range(0.0..1.0) < prob
}) && atom.updated_at != dt)
|| (atom.state == State::Object && state == State::Liquid)
} else {
false
}
Expand All @@ -112,8 +120,9 @@ pub fn down_neigh(
) -> [(bool, IVec2); 3] {
let mut neigh = [(false, IVec2::ZERO); 3];

let state = get_state(chunks, pos);
for (neigh, x) in neigh.iter_mut().zip([0, -1, 1]) {
neigh.0 = swapable(chunks, pos + IVec2::new(x, 1), states, dt);
neigh.0 = swapable(chunks, pos + IVec2::new(x, 1), states, state, dt);
neigh.1 = IVec2::new(x, 1);
}

Expand All @@ -133,8 +142,9 @@ pub fn side_neigh(
) -> [(bool, IVec2); 2] {
let mut neigh = [(false, IVec2::ZERO); 2];

let state = get_state(chunks, pos);
for (neigh, x) in neigh.iter_mut().zip([-1, 1]) {
neigh.0 = swapable(chunks, pos + IVec2::new(x, 0), states, dt);
neigh.0 = swapable(chunks, pos + IVec2::new(x, 0), states, state, dt);
neigh.1 = IVec2::new(x, 0);
}

Expand Down Expand Up @@ -165,19 +175,24 @@ pub fn set_vel(chunks: &mut UpdateChunksType, pos: IVec2, velocity: IVec2) {
}
}

/// Sets mode from a global pos
pub fn set_mode(chunks: &mut UpdateChunksType, pos: IVec2, mode: bool) {
chunks.group[pos].automata_mode = mode
}

/// Gets fall speed from a global pos
pub fn get_fspeed(chunks: &UpdateChunksType, pos: IVec2) -> u8 {
chunks.group[pos].fall_speed
chunks.group[pos].velocity.1.try_into().unwrap()
}

/// Gets state from a global pos
pub fn _get_state(chunks: &UpdateChunksType, pos: IVec2) -> State {
pub fn get_state(chunks: &UpdateChunksType, pos: IVec2) -> State {
chunks.group[pos].state
}

/// Sets fall speed from a global pos
pub fn set_fspeed(chunks: &mut UpdateChunksType, pos: IVec2, fall_speed: u8) {
chunks.group[pos].fall_speed = fall_speed
chunks.group[pos].velocity.1 = fall_speed as i8
}

/// Checks if atom is able to update this frame from a global pos
Expand Down Expand Up @@ -344,7 +359,7 @@ pub fn update_dirty_rects_3x3(dirty_rects: &mut HashMap<IVec2, URect>, pos: Chun
}
}

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ChunkPos {
pub atom: UVec2,
pub chunk: IVec2,
Expand All @@ -358,7 +373,8 @@ impl ChunkPos {

/// A deferred update message.
/// Indicates that an image or dirty rect should update.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct DeferredDirtyRectUpdate {
pub chunk_pos: ChunkPos,
pub awake_surrouding: bool,
}
Loading

0 comments on commit adcf29b

Please sign in to comment.