auto resize board when drawing out of bounds

This commit is contained in:
Crispy 2024-10-06 23:30:59 +02:00
parent f9b8dba019
commit db7a2b2418
5 changed files with 96 additions and 36 deletions

View file

@ -9,7 +9,7 @@ sim/speed control gui
(option) display input as numbers
scroll output
default i/o text modes specified per level
grow grid automatically while editing
properly center view
make marble movement not order-dependent (`>ooo <` does not behave symmetrically)
blueprints
scroll level list

View file

@ -186,6 +186,11 @@ impl Editor {
}
}
fn set_tile(&mut self, pos: Pos, tile: Tile) {
self.source_board.grow_to_include(pos);
self.source_board.set(pos, tile);
}
pub fn update(&mut self, rl: &RaylibHandle) {
if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
self.sim_state = SimState::Editing;
@ -515,13 +520,6 @@ impl Editor {
(1 << self.zoom) as f32,
Color::new(255, 180, 20, 255),
);
for n in 0..10 {
if d.is_key_pressed(unsafe {
std::mem::transmute(KeyboardKey::KEY_ZERO as u32 + n)
}) {
self.source_board.set(*pos, Tile::Digit(n as u8));
}
}
if d.is_key_pressed(KeyboardKey::KEY_LEFT) {
pos.x -= 1;
}
@ -534,6 +532,14 @@ impl Editor {
if d.is_key_pressed(KeyboardKey::KEY_DOWN) {
pos.y += 1;
}
let pos = *pos;
for n in 0..10 {
if d.is_key_pressed(unsafe {
std::mem::transmute(KeyboardKey::KEY_ZERO as u32 + n)
}) {
self.set_tile(pos, Tile::Digit(n as u8));
}
}
}
if mouse_pos.y < footer_top && mouse_pos.y > HEADER_HEIGHT as f32 {
let tile_pos = (mouse_pos - self.view_offset) / (16 << self.zoom) as f32;
@ -570,25 +576,25 @@ impl Editor {
if d.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT) {
match self.active_tool {
Tool::None => (),
Tool::SetTile(tile) => self.source_board.set(tile_pos.into(), tile),
Tool::Math => self.source_board.set(
Tool::SetTile(tile) => self.set_tile(tile_pos.into(), tile),
Tool::Math => self.set_tile(
tile_pos.into(),
Tile::Powerable(PTile::Math(self.tool_menu_math), false),
),
Tool::Gate => self.source_board.set(
Tool::Gate => self.set_tile(
tile_pos.into(),
Tile::Powerable(PTile::Gate(self.tool_menu_gate), false),
),
Tool::Wire => self.source_board.set(
Tool::Wire => self.set_tile(
tile_pos.into(),
Tile::Powerable(PTile::Wire(self.tool_menu_wire), false),
),
Tool::Arrow => self
.source_board
.set(tile_pos.into(), Tile::Arrow(self.tool_menu_arrow)),
Tool::Mirror => self
.source_board
.set(tile_pos.into(), Tile::Mirror(self.tool_menu_mirror)),
Tool::Arrow => {
self.set_tile(tile_pos.into(), Tile::Arrow(self.tool_menu_arrow))
}
Tool::Mirror => {
self.set_tile(tile_pos.into(), Tile::Mirror(self.tool_menu_mirror))
}
Tool::Digits(_pos) => {
self.active_tool = Tool::Digits(Some(tile_pos.into()));
if let Some(tile) = self.source_board.get_mut(tile_pos.into()) {

View file

@ -121,7 +121,7 @@ impl Machine {
continue;
};
let next_pos = dir.step(marble_pos);
if !self.board.in_bounds(next_pos) {
if !self.board.pos_in_bounds(next_pos) {
continue;
}
let mut new_tile = None;

View file

@ -41,6 +41,8 @@ pub struct Board {
rows: Vec<Vec<Tile>>,
width: usize,
height: usize,
offset_x: isize,
offset_y: isize,
}
impl Board {
@ -80,6 +82,8 @@ impl Board {
rows,
width,
height,
offset_x: 0,
offset_y: 0,
}
}
@ -88,6 +92,8 @@ impl Board {
width: rows[0].len(),
height: rows.len(),
rows,
offset_x: 0,
offset_y: 0,
}
}
@ -104,11 +110,24 @@ impl Board {
sum
}
pub fn in_bounds(&self, p: Pos) -> bool {
fn transform(&self, p: Pos) -> Pos {
Pos {
x: p.x + self.offset_x,
y: p.y + self.offset_y,
}
}
pub fn pos_in_bounds(&self, p: Pos) -> bool {
let p = self.transform(p);
self.in_bounds(p)
}
fn in_bounds(&self, p: Pos) -> bool {
p.x >= 0 && p.y >= 0 && p.x < self.width as isize && p.y < self.height as isize
}
pub fn get(&self, p: Pos) -> Option<Tile> {
let p = self.transform(p);
if self.in_bounds(p) {
Some(self.rows[p.y as usize][p.x as usize])
} else {
@ -117,6 +136,7 @@ impl Board {
}
pub fn get_or_blank(&self, p: Pos) -> Tile {
let p = self.transform(p);
if self.in_bounds(p) {
self.rows[p.y as usize][p.x as usize]
} else {
@ -125,6 +145,7 @@ impl Board {
}
pub fn get_mut(&mut self, p: Pos) -> Option<&mut Tile> {
let p = self.transform(p);
if self.in_bounds(p) {
Some(&mut self.rows[p.y as usize][p.x as usize])
} else {
@ -133,6 +154,7 @@ impl Board {
}
pub fn get_blank_mut(&mut self, p: Pos) -> Option<&mut Tile> {
let p = self.transform(p);
if self.in_bounds(p) {
let tile = &mut self.rows[p.y as usize][p.x as usize];
if tile == &Tile::Blank {
@ -143,11 +165,45 @@ impl Board {
}
pub fn set(&mut self, p: Pos, tile: Tile) {
let p = self.transform(p);
if self.in_bounds(p) {
self.rows[p.y as usize][p.x as usize] = tile;
}
}
pub fn grow_to_include(&mut self, p: Pos) {
let p = self.transform(p);
if p.x < 0 {
let len = p.x.abs() as usize;
for row in &mut self.rows {
let mut new_row = vec![Tile::Blank; len];
new_row.append(row);
*row = new_row;
}
self.offset_x += len as isize;
self.width += len;
} else if p.x as usize >= self.width {
let new_width = p.x as usize + 1;
for row in &mut self.rows {
row.resize(new_width, Tile::Blank);
}
self.width = new_width;
}
if p.y < 0 {
let len = p.y.abs() as usize;
let mut new_rows = vec![vec![Tile::Blank; self.width]; len];
new_rows.append(&mut self.rows);
self.rows = new_rows;
self.offset_y += len as isize;
self.height += len;
} else if p.y as usize > self.height {
let new_height = p.y as usize + 1;
self.rows.resize(new_height, vec![Tile::Blank; self.width]);
self.height = new_height;
}
}
pub fn width(&self) -> usize {
self.width
}
@ -160,9 +216,11 @@ impl Board {
let tile_size = 16 << zoom;
for x in 0..self.width {
for y in 0..self.height {
if let Some(tile) = self.get((x, y).into()) {
let px = x as i32 * tile_size + offset.x as i32 + tile_size / 2;
let py = y as i32 * tile_size + offset.y as i32 + tile_size / 2;
let tile = self.rows[y][x];
let px =
(x as i32 - self.offset_x as i32) * tile_size + offset.x as i32 + tile_size / 2;
let py =
(y as i32 - self.offset_y as i32) * tile_size + offset.y as i32 + tile_size / 2;
let texture = textures.get(&tile.texture());
d.draw_texture_ex(
texture,
@ -175,4 +233,3 @@ impl Board {
}
}
}
}

View file

@ -30,10 +30,7 @@ impl Solution {
solution_id: format!("solution_{number}"),
level_id: level.id().to_owned(),
name: format!("Unnamed {number}"),
board: level
.init_board()
.unwrap_or_else(|| " \n".repeat(20)), // todo remove when auto resizing is implemented
// score: Some(Score { cycles: 5, tiles: 88, area: 987 }),
board: level.init_board().unwrap_or(String::from(" ")),
score: None,
}
}