summaryrefslogtreecommitdiff
path: root/src/sim/mod.rs
blob: c73a373070b7964616ce6ae002785eb6681bf89a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::{
    config::CHUNK_SIZE,
    sim::{cell::materials::MaterialId, cell_sim::world::World, rb_sim::RbSimManager},
};

pub mod cell;
pub mod cell_sim;
pub mod lib;
pub mod rb_sim;

pub fn write_rb_entity_to_world(
    world: &mut World,
    rb_sim_manager: &RbSimManager,
    rb_entity_id: u32,
    // make sure these cells will be simulated
    seqno: u64,
    // (entity_x, entity_y, cell_x, cell_y)
) -> Vec<(u8, u8, i32, i32)> {
    let mut cells_written: Vec<(u8, u8, i32, i32)> = Vec::new();
    if let Some(rb_entity) = rb_sim_manager.rb_entities.get(&rb_entity_id)
        && let Some((rb_x, rb_y, cos, sin)) = rb_sim_manager.get_rb_entity_transform(rb_entity_id)
    {
        let (half_size_x, half_size_y) =
            (rb_entity.width as f32 / 2.0, rb_entity.height as f32 / 2.0);
        // half-extent of the rotated grid's axis-aligned bounding box, plus a cell of margin
        let (radius_x, radius_y) = (
            half_size_x * (cos.abs() + sin.abs()) + 1.0,
            half_size_y * (cos.abs() + sin.abs()) + 1.0,
        );

        let world_xl = (rb_x - radius_x).floor() as i32;
        let world_xu = (rb_x + radius_x).ceil() as i32;
        let world_yl = (rb_y - radius_y).floor() as i32;
        let world_yu = (rb_y + radius_y).ceil() as i32;

        for world_x in world_xl..=world_xu {
            for world_y in world_yl..=world_yu {
                if let Some(cur_world_cell) = world.get_cell_from_game_position(world_x, world_y)
                    && cur_world_cell.material == MaterialId::Void
                {
                    // same as shader
                    let d = (world_x as f32 + 0.5 - rb_x, world_y as f32 + 0.5 - rb_y);
                    let q = (d.0.floor() + 0.5, d.1.floor() + 0.5);
                    let (lx, ly) = (
                        (q.0 * cos + q.1 * sin + half_size_x).floor() as i32,
                        (-q.0 * sin + q.1 * cos + half_size_y).floor() as i32,
                    );

                    if lx < 0 || ly < 0 || lx >= rb_entity.width || ly >= rb_entity.height {
                        continue;
                    }

                    let mut cell = rb_entity.get_cell_at_local_position(lx as u8, ly as u8);
                    if cell.material == MaterialId::Void {
                        continue;
                    }

                    cell.match_parity(seqno);

                    // TODO: OPTIMIZE!!
                    world.set_cell_from_game_position(world_x, world_y, cell, false);
                    cells_written.push((lx as u8, ly as u8, world_x, world_y));
                }
            }
        }
    }
    cells_written
}