Skip to content

Commit bdf266c

Browse files
committed
try velocity based sim
1 parent a2dfc8d commit bdf266c

5 files changed

Lines changed: 210 additions & 53 deletions

File tree

src/bench.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@ fn bench_simulate(bencher: &mut Bencher) {
3232
let mut i = 0;
3333
let mut world_rand = WorldRand::default();
3434
bencher.iter(|| {
35-
world[MatrixIndex::new(0, 0)].as_mut().unwrap().simulate(
36-
voxel_world[MatrixIndex::new(0, 0)].as_mut().unwrap(),
37-
&mut world_rand,
38-
i,
39-
);
35+
world.simulate_chunk(&mut voxel_world, MatrixIndex::new(0, 0), &mut world_rand, i);
4036
i = i.wrapping_add(1);
4137
})
4238
}

src/shapes/line.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,51 @@
1+
use crate::cell::CellVelocity;
2+
use crate::world_data::FullIndex;
3+
#[derive(Debug, Clone, Default)]
4+
pub struct LineFullIter {
5+
pub line: LineIter,
6+
}
7+
impl Iterator for LineFullIter {
8+
type Item = (StepCase, FullIndex);
9+
fn next(&mut self) -> Option<Self::Item> {
10+
self.line
11+
.next()
12+
.map(|(case, x2, y2)| (case, (x2, y2).into()))
13+
}
14+
}
15+
impl LineFullIter {
16+
#[inline]
17+
#[allow(clippy::needless_pass_by_value)]
18+
pub fn back(&mut self, case: StepCase) {
19+
self.line.back(case);
20+
}
21+
#[inline]
22+
#[must_use]
23+
pub fn new(i0: FullIndex, i1: FullIndex) -> Self {
24+
let (x0, y0) = i0.to_u16();
25+
let (x1, y1) = i1.to_u16();
26+
Self {
27+
line: LineIter::new(x0, y0, x1, y1),
28+
}
29+
}
30+
#[inline]
31+
#[must_use]
32+
pub fn new_vel(i0: FullIndex, vel: CellVelocity) -> Self {
33+
let (x0, y0) = i0.to_u16();
34+
let x1 = if vel.x > 0 {
35+
x0 + vel.x.strict_cast::<u16>()
36+
} else {
37+
x0 - vel.x.unsigned_abs().strict_cast::<u16>()
38+
};
39+
let y1 = if vel.y > 0 {
40+
y0 + vel.y.strict_cast::<u16>()
41+
} else {
42+
y0 - vel.y.unsigned_abs().strict_cast::<u16>()
43+
};
44+
Self {
45+
line: LineIter::new(x0, y0, x1, y1),
46+
}
47+
}
48+
}
149
#[derive(Debug, Clone)]
250
pub struct LineIter {
351
pub x0: u16,

src/world/cell.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::cells::CELLS;
2+
use crate::simulate_world::Direction;
23
use std::{mem, ptr};
34
pub type CellId = u16;
45
#[derive(Debug)]
@@ -88,12 +89,33 @@ pub struct Cell {
8889
pub last_changed: u8,
8990
pub velocity: CellVelocity,
9091
pub friction: CellFriction,
92+
pub gravity_part: u8,
9193
}
92-
#[derive(Clone, Default, Debug)]
94+
#[derive(Clone, Copy, Default, Debug)]
9395
pub struct CellVelocity {
9496
pub x: i8,
9597
pub y: i8,
9698
}
99+
impl CellVelocity {
100+
#[must_use]
101+
pub fn is_zero(self) -> bool {
102+
self.x == 0 && self.y == 0
103+
}
104+
#[must_use]
105+
pub fn to_dir(self, direction: Direction) -> Self {
106+
let Self { x, y } = self;
107+
match direction {
108+
Direction::UpLeft => Self { x: y, y: -y },
109+
Direction::Up => Self { x, y: -y },
110+
Direction::UpRight => Self { x: -y, y: -y },
111+
Direction::Left => Self { x: -y, y: x },
112+
Direction::Right => Self { x: y, y: x },
113+
Direction::DownLeft => Self { x: y, y },
114+
Direction::Down => Self { x, y },
115+
Direction::DownRight => Self { x: -y, y },
116+
}
117+
}
118+
}
97119
#[derive(Clone, Default, Debug)]
98120
pub struct CellFriction {
99121
pub x: u8,
@@ -108,6 +130,7 @@ impl Cell {
108130
last_changed: 0,
109131
velocity: CellVelocity::default(),
110132
friction: CellFriction::default(),
133+
gravity_part: 0,
111134
}
112135
}
113136
pub fn friction(&mut self, x: u8, y: u8) {
@@ -122,12 +145,29 @@ impl Cell {
122145
}
123146
}
124147
}
125-
run(&mut self.velocity.x, &mut self.friction.x, x);
126-
run(&mut self.velocity.y, &mut self.friction.y, y);
148+
if self.velocity.x != 0 {
149+
run(&mut self.velocity.x, &mut self.friction.x, x);
150+
}
151+
if self.velocity.y != 0 {
152+
run(&mut self.velocity.y, &mut self.friction.y, y);
153+
}
127154
}
128-
pub fn gravity(&mut self) {
129-
if self.velocity.y > -8 {
130-
self.velocity.y -= 1;
155+
pub fn gravity(&mut self, val: u8) {
156+
if self.velocity.y > -4 {
157+
let (n, over) = self.gravity_part.overflowing_add(val);
158+
self.gravity_part = n;
159+
if over {
160+
self.velocity.y -= 1;
161+
}
162+
}
163+
}
164+
pub fn reverse_gravity(&mut self, val: u8) {
165+
if self.velocity.y < 4 {
166+
let (n, over) = self.gravity_part.overflowing_add(val);
167+
self.gravity_part = n;
168+
if over {
169+
self.velocity.y += 1;
170+
}
131171
}
132172
}
133173
#[must_use]

src/world/simulate_world.rs

Lines changed: 104 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::cell::CellType;
2+
use crate::line::LineFullIter;
23
use crate::matrix::MatrixIndex;
34
use crate::world_data::{FullIndex, VoxelWorld, World, WorldModified};
5+
use crate::{CHUNK_HEIGHT_LAST, CHUNK_WIDTH_LAST};
46
use bevy::diagnostic::FrameCount;
57
use bevy::prelude::{Local, Res, ResMut};
68
use rand::distr::{Bernoulli, Uniform};
@@ -47,6 +49,17 @@ impl WorldRand {
4749
self.rng.sample(self.gas)
4850
}
4951
}
52+
#[derive(Clone, Copy, Debug)]
53+
pub enum Direction {
54+
UpLeft,
55+
Up,
56+
UpRight,
57+
Left,
58+
Right,
59+
DownLeft,
60+
Down,
61+
DownRight,
62+
}
5063
impl World {
5164
pub fn simulate(&mut self, voxel_world: &mut VoxelWorld, frame: u8) {
5265
#[cfg(not(feature = "wasm"))]
@@ -93,12 +106,24 @@ impl World {
93106
rand: &mut WorldRand,
94107
frame: u8,
95108
) {
96-
for i in 0..=65535 {
97-
let index = FullIndex {
98-
chunk_index,
99-
cell_index: MatrixIndex::from(i),
100-
};
101-
self.simulate_cell(voxel_world, index, rand, frame);
109+
for y in 0..=CHUNK_HEIGHT_LAST {
110+
if y.is_multiple_of(2) ^ frame.is_multiple_of(2) {
111+
for x in (0..=CHUNK_WIDTH_LAST).rev() {
112+
let index = FullIndex {
113+
chunk_index,
114+
cell_index: MatrixIndex { x, y },
115+
};
116+
self.simulate_cell(voxel_world, index, rand, frame);
117+
}
118+
} else {
119+
for x in 0..=CHUNK_WIDTH_LAST {
120+
let index = FullIndex {
121+
chunk_index,
122+
cell_index: MatrixIndex { x, y },
123+
};
124+
self.simulate_cell(voxel_world, index, rand, frame);
125+
}
126+
}
102127
}
103128
}
104129
pub fn simulate_cell(
@@ -117,50 +142,53 @@ impl World {
117142
cell.last_changed = frame;
118143
match cell.cell_type() {
119144
CellType::Liquid => {
145+
cell.gravity(64);
146+
if cell.velocity.is_zero() {
147+
return;
148+
}
120149
let check = if rand.half() {
121150
[
122-
index - (0, 1),
123-
index - (0, 1) + (1, 0),
124-
index - (0, 1) - (1, 0),
125-
index + (1, 0),
126-
index - (1, 0),
151+
Direction::Down,
152+
Direction::DownLeft,
153+
Direction::DownRight,
154+
Direction::Left,
155+
Direction::Right,
127156
]
128157
} else {
129158
[
130-
index - (0, 1),
131-
index - (0, 1) - (1, 0),
132-
index - (0, 1) + (1, 0),
133-
index - (1, 0),
134-
index + (1, 0),
159+
Direction::Down,
160+
Direction::DownRight,
161+
Direction::DownLeft,
162+
Direction::Right,
163+
Direction::Left,
135164
]
136165
};
137166
self.swap_from_list(voxel_world, index, &check);
138167
}
139168
CellType::Granular => {
169+
cell.gravity(64);
170+
if cell.velocity.is_zero() {
171+
return;
172+
}
140173
let check = if rand.half() {
141-
[
142-
index - (0, 1),
143-
index - (0, 1) + (1, 0),
144-
index - (0, 1) - (1, 0),
145-
]
174+
[Direction::Down, Direction::DownLeft, Direction::DownRight]
146175
} else {
147-
[
148-
index - (0, 1),
149-
index - (0, 1) - (1, 0),
150-
index - (0, 1) + (1, 0),
151-
]
176+
[Direction::Down, Direction::DownRight, Direction::DownLeft]
152177
};
153178
self.swap_from_list(voxel_world, index, &check);
154179
}
155180
CellType::Gas => {
181+
cell.gravity(64);
182+
if cell.velocity.is_zero() {
183+
return;
184+
}
156185
let check = [match rand.gas() {
157-
0 => index + (0, 1) - (1, 0),
158-
1 => index + (0, 1),
159-
2 => index + (1, 1),
160-
3 => index - (1, 0),
161-
4 => index,
162-
5 => index + (1, 0),
163-
_ => unreachable!(),
186+
0 => Direction::UpLeft,
187+
1 => Direction::Up,
188+
2 => Direction::UpRight,
189+
3 => Direction::Left,
190+
4 => Direction::Right,
191+
_ => return,
164192
}];
165193
self.swap_from_list(voxel_world, index, &check);
166194
}
@@ -171,10 +199,10 @@ impl World {
171199
&mut self,
172200
voxel_world: &mut VoxelWorld,
173201
index: FullIndex,
174-
check: &[FullIndex],
202+
check: &[Direction],
175203
) {
176-
for swap_index in check.iter().copied() {
177-
if self.try_swap(voxel_world, index, swap_index) {
204+
for direction in check.iter().copied() {
205+
if self.try_swap(voxel_world, index, direction) {
178206
return;
179207
}
180208
}
@@ -183,13 +211,47 @@ impl World {
183211
&mut self,
184212
voxel_world: &mut VoxelWorld,
185213
index: FullIndex,
186-
swap_index: FullIndex,
214+
direction: Direction,
187215
) -> bool {
188-
if let Some(cell) = self.get(index)
189-
&& let Some(other) = self.get(swap_index)
190-
&& cell.can_move(other)
191-
{
192-
self.swap(voxel_world, index, swap_index);
216+
if let Some(cell) = self.get(index) {
217+
let vel = cell.velocity.to_dir(direction);
218+
let mut line = LineFullIter::new_vel(index, vel);
219+
line.next();
220+
let mut last = index;
221+
let mut n = 0;
222+
for (_, swap_index) in line {
223+
n += 1;
224+
if let Some(new) = self.get(swap_index) {
225+
if new.is_air() {
226+
last = swap_index;
227+
} else if cell.can_move(new) {
228+
if let Some(cell) = self.get_mut(index) {
229+
for _ in 0..n {
230+
cell.friction(16, 16);
231+
}
232+
}
233+
if last == index {
234+
self.swap(voxel_world, index, swap_index);
235+
} else {
236+
self.swap(voxel_world, swap_index, last);
237+
self.swap(voxel_world, index, swap_index);
238+
}
239+
return true;
240+
} else if last == index {
241+
return false;
242+
} else {
243+
break;
244+
}
245+
} else {
246+
return false;
247+
}
248+
}
249+
if let Some(cell) = self.get_mut(index) {
250+
for _ in 0..n {
251+
cell.friction(16, 16);
252+
}
253+
}
254+
self.swap(voxel_world, index, last);
193255
true
194256
} else {
195257
false

src/world/world_data.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ impl From<(u16, u16)> for FullIndex {
124124
}
125125
}
126126
}
127+
impl FullIndex {
128+
#[must_use]
129+
pub fn to_u16(self) -> (u16, u16) {
130+
(
131+
self.chunk_index.x.strict_cast::<u16>() * CHUNK_WIDTH.strict_cast::<u16>()
132+
+ self.cell_index.x.strict_cast::<u16>(),
133+
self.chunk_index.y.strict_cast::<u16>() * CHUNK_HEIGHT.strict_cast::<u16>()
134+
+ self.cell_index.y.strict_cast::<u16>(),
135+
)
136+
}
137+
}
127138
impl World {
128139
#[must_use]
129140
pub fn get(&self, index: FullIndex) -> Option<&Cell> {

0 commit comments

Comments
 (0)