diff --git a/src/main.rs b/src/main.rs index 0cfabc4..a50f066 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,17 +4,40 @@ use std::{ ops::Rem, }; -use marble_engine::parse; +use marble_engine::{board::Board, parse, tile::Tile, Machine}; use raylib::prelude::*; mod marble_engine; mod util; use util::*; +#[derive(Debug)] +struct Game { + source_board: Board, + machine: Machine, + sim_state: SimState, + view_offset: Vector2, + zoom: i32, + output_as_text: bool, + input_as_text: bool, + active_tool: Tool, + input_text_selected: bool, + sim_speed: f32, + time_since_step: f32, +} + +#[derive(Debug)] +enum Tool { + None, + SetTile(Tile), + // Erase, + // Select, +} + #[derive(Debug, Clone, PartialEq)] -enum EditorState { +enum SimState { Editing, - Playing, + Running, Stepping, } @@ -24,16 +47,7 @@ fn main() { .title("good window title") .build(); rl.set_target_fps(60); - - let board = parse(&read_to_string("boards/adder.mbl").unwrap()); - let mut pos_offset = Vector2::zero(); - let mut machine = marble_engine::Machine::new(board, "Vec::new()".bytes().collect()); - let mut editor_state = EditorState::Editing; - let mut output_as_text = false; - let mut input_as_text = true; - let mut input_text_selected = false; - - let mut zoom = 1; + rl.set_exit_key(None); let mut textures: HashMap = HashMap::new(); for d in read_dir("assets/tiles").unwrap().flatten() { @@ -46,31 +60,107 @@ fn main() { textures.insert(name.to_string(), texture); } } + let mut game = Game::new_sandbox(); + let board = parse(&read_to_string("boards/adder.mbl").unwrap()); + game.load_board(board); while !rl.window_should_close() { - if rl.is_key_pressed(KeyboardKey::KEY_SPACE) || rl.is_key_down(KeyboardKey::KEY_ENTER) { - machine.step(); - } - if rl.get_mouse_wheel_move() > 0. && zoom < 3 { - zoom += 1; - } - if rl.get_mouse_wheel_move() < 0. && zoom > 0 { - zoom -= 1; - } - if rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_MIDDLE) { - pos_offset += rl.get_mouse_delta() - } - if rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_RIGHT) { - pos_offset = Vector2::zero(); - } - + game.input(&rl); let mut d = rl.begin_drawing(&thread); d.clear_background(Color::new(64, 64, 64, 255)); + game.gui(&mut d, &textures); + d.draw_fps(2, 2); + } +} - machine.draw(&mut d, &textures, pos_offset, zoom); +impl Game { + fn new_sandbox() -> Self { + Self { + source_board: Board::new_empty(1, 1), + machine: Machine::new_empty(1), + sim_state: SimState::Editing, + view_offset: Vector2::zero(), + zoom: 1, + active_tool: Tool::None, + output_as_text: false, + input_as_text: false, + input_text_selected: false, + sim_speed: 8., + time_since_step: 0., + } + } + + fn load_board(&mut self, board: Board) { + self.source_board = board; + } + + fn start_sim(&mut self) { + self.machine.reset(); + self.machine.set_board(self.source_board.clone()); + } + + fn input(&mut self, rl: &RaylibHandle) { + if self.sim_state == SimState::Running { + self.time_since_step += rl.get_frame_time(); + if self.time_since_step > 1. / self.sim_speed { + self.time_since_step = 0.; + self.machine.step(); + } + } + if rl.is_key_pressed(KeyboardKey::KEY_SPACE) { + match self.sim_state { + SimState::Editing => { + self.start_sim(); + self.machine.step(); + } + SimState::Running => (), + SimState::Stepping => self.machine.step(), + } + self.sim_state = SimState::Stepping; + } + if rl.is_key_pressed(KeyboardKey::KEY_ESCAPE) { + self.sim_state = SimState::Editing; + } + if rl.is_key_pressed(KeyboardKey::KEY_ENTER) { + match self.sim_state { + SimState::Editing => { + self.start_sim(); + self.sim_state = SimState::Running; + } + SimState::Running => self.sim_state = SimState::Editing, + SimState::Stepping => self.sim_state = SimState::Running, + } + } + + if rl.get_mouse_wheel_move() > 0. && self.zoom < 3 { + self.zoom += 1; + } + if rl.get_mouse_wheel_move() < 0. && self.zoom > 0 { + self.zoom -= 1; + } + if rl.is_mouse_button_down(MouseButton::MOUSE_BUTTON_MIDDLE) { + self.view_offset += rl.get_mouse_delta() + } + if rl.is_mouse_button_pressed(MouseButton::MOUSE_BUTTON_RIGHT) { + self.view_offset = Vector2::zero(); + } + } + + fn draw_board(&self, d: &mut RaylibDrawHandle, textures: &HashMap) { + if self.sim_state == SimState::Editing { + self.source_board + .draw(d, textures, self.view_offset, self.zoom); + } else { + self.machine + .board() + .draw(d, textures, self.view_offset, self.zoom); + self.machine.draw_marble_values(d, self.view_offset, self.zoom); + } + } + + fn gui(&mut self, d: &mut RaylibDrawHandle, textures: &HashMap) { + self.draw_board(d, textures); - // UI - // d.draw_rectangle(x, y, width, height, color); let height = d.get_screen_height(); let footer_height = 100; let footer_top = (height - footer_height) as f32; @@ -82,9 +172,9 @@ fn main() { Color::new(32, 32, 32, 255), ); - let tile_size = (16 << zoom) as f32; - let grid_spill_x = (pos_offset.x).rem(tile_size) - tile_size; - let grid_spill_y = (pos_offset.y).rem(tile_size) - tile_size; + let tile_size = (16 << 1) as f32; + let grid_spill_x = (self.view_offset.x).rem(tile_size) - tile_size; + let grid_spill_y = (self.view_offset.y).rem(tile_size) - tile_size; d.gui_grid( Rectangle::new( grid_spill_x, @@ -100,32 +190,23 @@ fn main() { d.gui_check_box( Rectangle::new(5., footer_top + 5., 25., 25.), Some(rstr!("output as text")), - &mut output_as_text, + &mut self.output_as_text, ); - let out_text = if output_as_text { - String::from_utf8_lossy(machine.output()).to_string() + let out_text = if self.output_as_text { + String::from_utf8_lossy(self.machine.output()).to_string() } else { - format!("{:?}", machine.output()) + format!("{:?}", self.machine.output()) }; d.draw_text(&out_text, 5, footer_top as i32 + 35, 20, Color::WHITE); - let mut input_text = String::from_utf8_lossy(machine.input()).to_string(); + let mut input_text = String::from_utf8_lossy(self.machine.input()).to_string(); if text_input( - &mut d, + d, Rectangle::new(350., footer_top + 60., 200., 25.), &mut input_text, - &mut input_text_selected, + &mut self.input_text_selected, ) { - machine.set_input(input_text.into_bytes()); + self.machine.set_input(input_text.into_bytes()); } - - if d.gui_button( - Rectangle::new(0., height as f32 - 40., 100.0, 30.0), - Some(rstr!("meow")), - ) { - println!("meow"); - } - - d.draw_fps(2, 2); } } diff --git a/src/marble_engine.rs b/src/marble_engine.rs index d96fd3b..05f7516 100644 --- a/src/marble_engine.rs +++ b/src/marble_engine.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use raylib::prelude::*; -mod board; -mod tile; +pub mod board; +pub mod tile; use board::{Board, Pos}; use tile::*; @@ -30,6 +30,28 @@ impl Machine { } } + pub fn reset(&mut self) { + self.steps = 0; + self.input_index = 0; + self.output.clear(); + } + + pub fn set_board(&mut self, board: Board) { + self.marbles.clear(); + for y in 0..board.height() { + for x in 0..board.width() { + if let Some(Tile::Marble { value: _, dir: _ }) = board.get((x, y).into()) { + self.marbles.push((x, y).into()); + } + } + } + self.board = board; + } + + pub fn board(&self) -> &Board { + &self.board + } + pub fn output(&self) -> &[u8] { &self.output } @@ -46,40 +68,22 @@ impl Machine { self.input = bytes; } - pub fn new(grid: Board, input: Vec) -> Self { - // let (grid, marbles) = parse(source); - let mut marbles = Vec::new(); - for y in 0..grid.height() { - for x in 0..grid.width() { - if let Some(Tile::Marble { value: _, dir: _ }) = grid.get((x, y).into()) { - marbles.push((x, y).into()); - } - } - } - Self { - board: grid, - marbles, - input, - input_index: 0, - output: Vec::new(), - steps: 0, - } - } - - pub fn draw( - &self, - d: &mut RaylibDrawHandle, - textures: &HashMap, - offset: Vector2, - zoom: i32, - ) { + pub fn draw_marble_values(&self, d: &mut RaylibDrawHandle, offset: Vector2, zoom: i32) { let tile_size = 16 << zoom; for x in 0..self.board.width() { for y in 0..self.board.height() { if let Some(tile) = self.board.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; - tile.draw(d, textures, px, py, tile_size, zoom); + if let Tile::Marble { value, dir } = tile{ + d.draw_text( + &format!("{value}"), + px - tile_size / 2 + 2, + py - tile_size / 2 + 2, + 20, + Color::MAGENTA, + ) + } } } } diff --git a/src/marble_engine/board.rs b/src/marble_engine/board.rs index d0a71f7..b1ca44e 100644 --- a/src/marble_engine/board.rs +++ b/src/marble_engine/board.rs @@ -1,3 +1,6 @@ +use std::collections::HashMap; + +use raylib::prelude::*; use super::tile::*; #[derive(Debug, Default, Clone, Copy, PartialEq)] @@ -15,7 +18,7 @@ impl From<(usize, usize)> for Pos { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Board { rows: Vec>, width: usize, @@ -84,4 +87,23 @@ impl Board { pub fn height(&self) -> usize { self.height } + + pub fn draw( + &self, + d: &mut RaylibDrawHandle, + textures: &HashMap, + offset: Vector2, + zoom: i32, + ){ + 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; + tile.draw(d, textures, px, py, tile_size, zoom); + } + } + } + } } diff --git a/src/util.rs b/src/util.rs index f88c438..4eb69e5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -29,6 +29,9 @@ pub fn text_input( } if *is_selected { + if d.is_key_pressed(KeyboardKey::KEY_ESCAPE) { + *is_selected = false; + } if d.is_key_pressed(KeyboardKey::KEY_BACKSPACE) { changed = true; text.pop();