add more tiles to gui, with controls to rotate between variants in a group

This commit is contained in:
Crispy 2024-10-05 17:46:45 +02:00
parent 175d01cb03
commit bf82d1455f
3 changed files with 195 additions and 72 deletions

View file

@ -4,7 +4,12 @@ use std::{
ops::Rem,
};
use marble_engine::{board::Board, parse, tile::Tile, tile_to_char, Machine};
use marble_engine::{
board::Board,
parse,
tile::{Direction, GateType, MathOp, MirrorType, PTile, Tile},
tile_from_char, Machine,
};
use raylib::prelude::*;
mod marble_engine;
@ -21,6 +26,10 @@ struct Game {
output_as_text: bool,
input_as_text: bool,
active_tool: Tool,
tool_menu_math: MathOp,
tool_menu_gate: GateType,
tool_menu_arrow: Direction,
tool_menu_mirror: MirrorType,
input_text_selected: bool,
sim_speed: f32,
time_since_step: f32,
@ -30,8 +39,12 @@ struct Game {
enum Tool {
None,
SetTile(Tile),
// Erase,
// Select,
Math,
Gate,
Arrow,
Mirror,
Number,
// SelectArea,
}
#[derive(Debug, Clone, PartialEq)]
@ -65,6 +78,8 @@ fn main() {
.title("good window title")
.build();
rl.set_target_fps(60);
rl.set_window_min_size(640, 480);
rl.set_mouse_cursor(MouseCursor::MOUSE_CURSOR_CROSSHAIR);
rl.set_exit_key(None);
let mut textures: HashMap<String, Texture2D> = HashMap::new();
@ -97,6 +112,10 @@ impl Game {
input_text_selected: false,
sim_speed: 8.,
time_since_step: 0.,
tool_menu_math: MathOp::Add,
tool_menu_gate: GateType::Equal,
tool_menu_arrow: Direction::Right,
tool_menu_mirror: MirrorType::Forward,
}
}
@ -109,6 +128,44 @@ impl Game {
self.machine.set_board(self.source_board.clone());
}
fn rotate_tool(&mut self, shift: bool) {
match &self.active_tool {
Tool::Math => {
self.tool_menu_math = match self.tool_menu_math {
MathOp::Add => MathOp::Sub,
MathOp::Sub => MathOp::Mul,
MathOp::Mul => MathOp::Div,
MathOp::Div => MathOp::Rem,
MathOp::Rem => MathOp::Add,
}
}
Tool::Gate => {
self.tool_menu_gate = match self.tool_menu_gate {
GateType::LessThan => GateType::GreaterThan,
GateType::GreaterThan => GateType::Equal,
GateType::Equal => GateType::NotEqual,
GateType::NotEqual => GateType::LessThan,
}
}
Tool::Arrow => {
self.tool_menu_arrow = if shift {
self.tool_menu_arrow.left()
} else {
self.tool_menu_arrow.right()
}
}
Tool::Mirror => {
self.tool_menu_mirror = match self.tool_menu_mirror {
MirrorType::Forward => MirrorType::Back,
MirrorType::Back => MirrorType::Forward,
}
}
Tool::None => (),
Tool::SetTile(_) => (),
Tool::Number => (),
}
}
fn input(&mut self, rl: &RaylibHandle) {
if self.sim_state == SimState::Running {
self.time_since_step += rl.get_frame_time();
@ -237,32 +294,53 @@ impl Game {
border,
);
};
tool_button((0, -1), "eraser", Tool::SetTile(tile_to_char(' ')));
tool_button((0, -1), "eraser", Tool::SetTile(tile_from_char(' ')));
tool_button((1, -1), "", Tool::None);
tool_button((0, 0), "marble", Tool::SetTile(tile_to_char('o')));
tool_button((0, 1), "block", Tool::SetTile(tile_to_char('#')));
tool_button((0, 2), "bag_off", Tool::SetTile(tile_to_char('B')));
tool_button((0, 3), "trigger_off", Tool::SetTile(tile_to_char('*')));
tool_button((0, 4), "input_off", Tool::SetTile(tile_to_char('I')));
tool_button((0, 5), "output_off", Tool::SetTile(tile_to_char('P')));
tool_button((0, 6), "flipper_off", Tool::SetTile(tile_to_char('F')));
tool_button((0, 0), "marble", Tool::SetTile(tile_from_char('o')));
tool_button((0, 1), "block", Tool::SetTile(tile_from_char('#')));
tool_button((0, 2), "bag_off", Tool::SetTile(tile_from_char('B')));
tool_button((0, 3), "trigger_off", Tool::SetTile(tile_from_char('*')));
tool_button((0, 4), "input_off", Tool::SetTile(tile_from_char('I')));
tool_button((0, 5), "output_off", Tool::SetTile(tile_from_char('P')));
tool_button((0, 6), "flipper_off", Tool::SetTile(tile_from_char('F')));
tool_button(
(1, 0),
"wire_horizontal_off",
Tool::SetTile(tile_to_char('-')),
Tool::SetTile(tile_from_char('-')),
);
tool_button(
(1, 1),
"wire_vertical_off",
Tool::SetTile(tile_to_char('|')),
Tool::SetTile(tile_from_char('|')),
);
tool_button((1, 2), "wire_cross_off", Tool::SetTile(tile_to_char('+')));
tool_button((1, 3), "arrow_up", Tool::SetTile(tile_to_char('^')));
tool_button((1, 4), "arrow_down", Tool::SetTile(tile_to_char('v')));
tool_button((1, 5), "arrow_left", Tool::SetTile(tile_to_char('<')));
tool_button((1, 6), "arrow_right", Tool::SetTile(tile_to_char('>')));
tool_button((1, 2), "wire_cross_off", Tool::SetTile(tile_from_char('+')));
tool_button(
(1, 3),
&Tile::Arrow(self.tool_menu_arrow).texture(),
Tool::Arrow,
);
tool_button(
(1, 4),
&Tile::Mirror(self.tool_menu_mirror).texture(),
Tool::Mirror,
);
tool_button(
(1, 5),
&Tile::Powerable(PTile::Math(self.tool_menu_math), false).texture(),
Tool::Math,
);
tool_button(
(1, 6),
&Tile::Powerable(PTile::Gate(self.tool_menu_gate), false).texture(),
Tool::Gate,
);
let is_shift = d.is_key_down(KeyboardKey::KEY_LEFT_SHIFT);
if d.is_key_pressed(KeyboardKey::KEY_R) {
self.rotate_tool(is_shift);
}
let mouse_pos = d.get_mouse_position();
if self.sim_state == SimState::Editing && mouse_pos.y < footer_top {
@ -271,17 +349,53 @@ impl Game {
let tile_screen_pos = tile_pos * (16 << self.zoom) as f32 + self.view_offset;
if let Tool::SetTile(tile) = self.active_tool {
if self.active_tool != Tool::None {
let tex = match self.active_tool {
Tool::None => unreachable!(),
Tool::SetTile(t) => {
if t == Tile::Blank {
"selection".into()
} else {
t.texture()
}
}
Tool::Math => format!("{}_off",self.tool_menu_math.texture_name()),
Tool::Gate => format!("{}_off",self.tool_menu_gate.texture_name()),
Tool::Arrow => self.tool_menu_arrow.arrow_texture_name().into(),
Tool::Mirror => self.tool_menu_mirror.texture_name().into(),
Tool::Number => todo!(),
};
let tex = textures
.get(&tex)
.unwrap_or_else(|| textures.get("missing").unwrap());
d.draw_texture_ex(
textures.get("selection").unwrap(),
tex,
tile_screen_pos,
0.,
(1 << self.zoom) as f32,
Color::new(255, 255, 255, 150),
Color::new(255, 255, 255, 100),
);
}
if d.is_mouse_button_down(MouseButton::MOUSE_BUTTON_LEFT) {
self.source_board.set(tile_pos.into(), tile)
match self.active_tool {
Tool::None => (),
Tool::SetTile(tile) => self.source_board.set(tile_pos.into(), tile),
Tool::Math => self.source_board.set(
tile_pos.into(),
Tile::Powerable(PTile::Math(self.tool_menu_math), false),
),
Tool::Gate => self.source_board.set(
tile_pos.into(),
Tile::Powerable(PTile::Gate(self.tool_menu_gate), 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::Number => todo!(),
}
}
}

View file

@ -58,10 +58,6 @@ impl Machine {
&self.input
}
pub fn input_mut(&mut self) -> &mut Vec<u8> {
&mut self.input
}
pub fn set_input(&mut self, bytes: Vec<u8>) {
self.input_index = self.input_index.min(bytes.len());
self.input = bytes;
@ -327,7 +323,7 @@ pub fn parse(source: &str) -> Board {
width = width.max(line.len());
let mut tiles = Vec::new();
for char in line.chars() {
tiles.push(tile_to_char(char));
tiles.push(tile_from_char(char));
}
rows.push(tiles);
}
@ -338,7 +334,7 @@ pub fn parse(source: &str) -> Board {
Board::new(rows)
}
pub const fn tile_to_char(c: char) -> Tile {
pub const fn tile_from_char(c: char) -> Tile {
match c {
'o' => Tile::Marble {
value: 0,
@ -367,7 +363,7 @@ pub const fn tile_to_char(c: char) -> Tile {
'D' => Tile::Powerable(PTile::Math(MathOp::Div), false),
'R' => Tile::Powerable(PTile::Math(MathOp::Rem), false),
'B' => Tile::Powerable(PTile::Bag, false),
d @ '0'..='9' => Tile::Digit(d as u8),
d @ '0'..='9' => Tile::Digit(d as u8 - b'0'),
'#' => Tile::Block,
' ' => Tile::Blank,
_ => Tile::Blank,

View file

@ -85,50 +85,15 @@ impl Tile {
Tile::Blank => "transparent",
Tile::Block => "block",
Tile::Marble { value: _, dir: _ } => "marble",
Tile::Digit(n) => match n {
b'0' => "digit_0",
b'1' => "digit_1",
b'2' => "digit_2",
b'3' => "digit_3",
b'4' => "digit_4",
b'5' => "digit_5",
b'6' => "digit_6",
b'7' => "digit_7",
b'8' => "digit_8",
b'9' => "digit_9",
_ => unreachable!("invalid digit"),
},
Tile::Mirror(mirror) => match mirror {
MirrorType::Forward => "mirror_forward",
MirrorType::Back => "mirror_back",
},
Tile::Arrow(dir) => match dir {
Direction::Up => "arrow_up",
Direction::Down => "arrow_down",
Direction::Left => "arrow_left",
Direction::Right => "arrow_right",
},
Tile::Digit(n) => return format!("digit_{n}"),
Tile::Mirror(mirror) => mirror.texture_name(),
Tile::Arrow(dir) => dir.arrow_texture_name(),
Tile::Powerable(tile, state) => {
let root = match tile {
PTile::Trigger => "trigger",
PTile::Wire(wire) => match wire {
WireType::Vertical => "wire_vertical",
WireType::Horizontal => "wire_horizontal",
WireType::Cross => "wire_cross",
},
PTile::Gate(gate) => match gate {
GateType::LessThan => "lt",
GateType::GreaterThan => "gt",
GateType::Equal => "eq",
GateType::NotEqual => "neq",
},
PTile::Math(math_op) => match math_op {
MathOp::Add => "add",
MathOp::Sub => "sub",
MathOp::Mul => "mul",
MathOp::Div => "div",
MathOp::Rem => "rem",
},
PTile::Wire(wire) => wire.texture_name(),
PTile::Gate(gate) => gate.texture_name(),
PTile::Math(math_op) => math_op.texture_name(),
PTile::Bag => "bag",
PTile::Flipper => "flipper",
PTile::Input => "input",
@ -180,6 +145,15 @@ impl Direction {
}
pos
}
pub const fn arrow_texture_name(&self) -> &'static str {
match self {
Direction::Up => "arrow_up",
Direction::Down => "arrow_down",
Direction::Left => "arrow_left",
Direction::Right => "arrow_right",
}
}
}
impl WireType {
@ -190,6 +164,14 @@ impl WireType {
WireType::Cross => &Direction::ALL,
}
}
pub const fn texture_name(&self) -> &'static str {
match self {
WireType::Vertical => "wire_vertical",
WireType::Horizontal => "wire_horizontal",
WireType::Cross => "wire_cross",
}
}
}
impl MirrorType {
@ -209,4 +191,35 @@ impl MirrorType {
},
}
}
pub const fn texture_name(&self) -> &'static str {
match self {
MirrorType::Forward => "mirror_forward",
MirrorType::Back => "mirror_back",
}
}
}
impl MathOp {
pub const fn texture_name(&self) -> &'static str {
match self {
MathOp::Add => "add",
MathOp::Sub => "sub",
MathOp::Mul => "mul",
MathOp::Div => "div",
MathOp::Rem => "rem",
}
}
}
impl GateType {
pub const fn texture_name(&self) -> &'static str {
match self {
GateType::LessThan => "lt",
GateType::GreaterThan => "gt",
GateType::Equal => "eq",
GateType::NotEqual => "neq",
}
}
}