Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fixed some atoms problems #32

Merged
merged 1 commit into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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