refactor, add simulation controls and board resetting
This commit is contained in:
parent
a9eefcd836
commit
880993762e
4 changed files with 193 additions and 83 deletions
185
src/main.rs
185
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<String, Texture2D> = 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<String, Texture2D>) {
|
||||
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<String, Texture2D>) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u8>) -> 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<String, Texture2D>,
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Vec<Tile>>,
|
||||
width: usize,
|
||||
|
@ -84,4 +87,23 @@ impl Board {
|
|||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&self,
|
||||
d: &mut RaylibDrawHandle,
|
||||
textures: &HashMap<String, Texture2D>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue