diff --git a/notes.md b/notes.md index 71403ab..29ee1c4 100644 --- a/notes.md +++ b/notes.md @@ -5,3 +5,28 @@ Right now, wire inputs are pushed to by a node, and then the outputs pull from t With Connections, the node can push to the wire input through the connection, and then the node pulls from the wire output through a connection as well. This makes it easy to iterate through all the connections at once. + +# New wires + +Add Hitbox component + +```rs +enum Hitbox { + Circle(f32), // for nodes/connections + Rect(Rect), // for wires + Compound(Vec), // for wires +} +``` + +Make all click stuff go thru hitboxes + +Remove Pos component from wires, instead + +```rs +pub struct Wire { + ... + bend_points: Vec, +} +``` + +Rework drawing wires diff --git a/src/main.rs b/src/main.rs index b157916..402ab40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use crate::nodes::Wire; use crate::resources::UiSignal; use macroquad::prelude::*; +use resources::CameraRes; use specs::prelude::*; mod components; @@ -67,6 +68,12 @@ async fn main() { world.insert(resources::Tick(0)); world.insert(resources::TickFrames(60)); + world.insert(resources::CameraRes::default()); + + let mut prev_mouse_pos = { + let (mx, my) = mouse_position(); + Vec2::new(mx, my) + }; let mut last_fps = [60i32; 256]; @@ -115,6 +122,13 @@ async fn main() { }); }); + { + let camera = world.fetch::().0; + world.insert(resources::MousePos( + camera.screen_to_world(mouse_position().into()), + )); + } + if is_mouse_button_pressed(MouseButton::Left) { ui::mouse_click::handle_mouse_click(&mut world); } @@ -123,6 +137,33 @@ async fn main() { ui::mouse_click::handle_mouse_right_click(&mut world); } + let new_mouse_pos = { + let (mx, my) = mouse_position(); + Vec2::new(mx, -my) + }; + + if is_mouse_button_down(MouseButton::Middle) { + world.fetch_mut::().0.offset += (new_mouse_pos - prev_mouse_pos) / 1000.0; + } + + { + let mp: Vec2 = mouse_position().into(); + let old_camera = world.fetch::().0; + let old_focus = old_camera.screen_to_world(mp); + + let mwheel = macroquad::input::mouse_wheel().1; + let zoom_fac = 1.0 + mwheel / 10.0; + world.fetch_mut::().0.zoom *= zoom_fac; + let new_camera = world.fetch::().0; + let new_focus = new_camera.screen_to_world(mp); + + let delta_focus = new_focus - old_focus; + world.fetch_mut::().0.offset += delta_focus * new_camera.zoom; + } + + macroquad::camera::set_camera(world.fetch::().0); + prev_mouse_pos = new_mouse_pos; + egui_macroquad::draw(); next_frame().await; diff --git a/src/resources.rs b/src/resources.rs index 3a5c556..b2377b5 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,4 +1,7 @@ +use macroquad::prelude::screen_height; +use macroquad::prelude::Vec2; use macroquad::texture::Texture2D; +use macroquad::{camera::Camera2D, prelude::screen_width}; use specs::Entity; use crate::components::nodes::NodeTy; @@ -72,3 +75,20 @@ impl Default for CurrentModeText { ) } } + +pub struct CameraRes(pub Camera2D); + +impl Default for CameraRes { + fn default() -> Self { + CameraRes(Camera2D { + rotation: 0.0, + zoom: Vec2::new(2.0 / screen_width(), 2.0 / screen_height()), + target: Vec2::new(0.0, 0.0), + offset: Vec2::new(0.0, 0.0), + render_target: None, + }) + } +} + +#[derive(Default)] +pub struct MousePos(pub Vec2); diff --git a/src/systems/draw_systems.rs b/src/systems/draw_systems.rs index b7ec6d3..56d7347 100644 --- a/src/systems/draw_systems.rs +++ b/src/systems/draw_systems.rs @@ -1,5 +1,4 @@ -use crate::Pos; -use crate::Wire; +use crate::components::round_to_snap; use crate::{components::nodes::NandNode, nodes::NotNode}; use crate::{components::nodes::NorNode, nodes::OnNode}; use crate::{components::nodes::XnorNode, nodes::XorNode}; @@ -13,7 +12,9 @@ use crate::{ components::{nodes::AndNode, Node}, resources::Textures, }; +use crate::{resources::CameraRes, Wire}; use crate::{resources::GridMode, Connected}; +use crate::{resources::MousePos, Pos}; use core::marker::PhantomData; use macroquad::prelude::*; use specs::prelude::*; @@ -241,11 +242,12 @@ where pub struct TempWireDrawSys; impl<'a> System<'a> for TempWireDrawSys { - type SystemData = (Read<'a, UIState>, ReadStorage<'a, Pos>); + type SystemData = (Read<'a, UIState>, ReadStorage<'a, Pos>, Read<'a, MousePos>); - fn run(&mut self, (ui_state, position_storage): Self::SystemData) { + fn run(&mut self, (ui_state, position_storage, mouse_pos): Self::SystemData) { use crate::components::round_to_snap as snap; let color = LIGHTGRAY; + let mouse_pos = mouse_pos.0; match *ui_state { UIState::AddingWire { connection_entity: e, @@ -258,7 +260,7 @@ impl<'a> System<'a> for TempWireDrawSys { draw_line( start_pos.x, start_pos.y, - snap(mouse_position().0), + snap(mouse_pos.x), start_pos.y, 5.0, color, @@ -269,8 +271,7 @@ impl<'a> System<'a> for TempWireDrawSys { y_pos: Some(y_pos), .. } => { - let (mx, my) = mouse_position(); - let pos = Pos::from_vec(Vec2::new(mx, my)).pos; + let pos = Pos::from_vec(mouse_pos).pos; draw_line(snap(x_pos), snap(y_pos), snap(x_pos), pos.y, 5.0, color); draw_line(snap(x_pos), pos.y, pos.x, pos.y, 5.0, color); @@ -282,13 +283,14 @@ impl<'a> System<'a> for TempWireDrawSys { pub struct DrawConnectionSys; impl<'a> System<'a> for DrawConnectionSys { - type SystemData = (ReadStorage<'a, Connection>, ReadStorage<'a, Pos>); + type SystemData = ( + ReadStorage<'a, Connection>, + ReadStorage<'a, Pos>, + Read<'a, MousePos>, + ); - fn run(&mut self, (connections, positions): Self::SystemData) { - let mouse_pos = { - let (mx, my) = mouse_position(); - Vec2::new(mx, my) - }; + fn run(&mut self, (connections, positions, mouse_pos): Self::SystemData) { + let mouse_pos = mouse_pos.0; let color = |pos: Vec2| { if (pos - mouse_pos).length() > 10.0 { @@ -306,11 +308,39 @@ impl<'a> System<'a> for DrawConnectionSys { pub struct DrawGridSys; impl<'a> System<'a> for DrawGridSys { - type SystemData = Read<'a, GridMode>; + type SystemData = (Read<'a, GridMode>, Read<'a, CameraRes>); - fn run(&mut self, grid_mode: Self::SystemData) { + // TODO: for some reason this only draws in the first quadrant, should be fixed later + fn run(&mut self, (grid_mode, camera_res): Self::SystemData) { use crate::components::SNAP; let s = 4; + let camera = camera_res.0; + + let (top, left) = { + let top_left = camera.screen_to_world((0.0, 0.0).into()); + (top_left.y, top_left.x) + }; + let top = top - top.ceil() % SNAP + SNAP; + let left = left - left.ceil() % SNAP - SNAP; + let sx = s - ((left.floor() / SNAP).abs() as usize % s); + + let (bottom, right) = { + let bottom_right = camera.screen_to_world((screen_width(), screen_height()).into()); + (bottom_right.y, bottom_right.x) + }; + let bottom = bottom - bottom.ceil() % SNAP - SNAP; + let right = right - right.ceil() % SNAP + SNAP; + + // idk why they're switched but they are + let (bottom, top) = (top, bottom); + let sy = s - ((top.floor() / SNAP).abs() as usize % s); + + let x_positions = (0..((right - left) / SNAP).ceil() as usize + s + 1) + .map(|i| (i, i % s == 0)) + .map(|(i, is_big)| (left + i as f32 * SNAP - sx as f32 * SNAP - SNAP, is_big)); + let y_positions = (0..((bottom - top) / SNAP).ceil() as usize + s + 1) + .map(|i| (i, i % s == 0)) + .map(|(i, is_big)| (top + i as f32 * SNAP - sy as f32 * SNAP, is_big)); match *grid_mode { GridMode::Lines => { @@ -318,27 +348,25 @@ impl<'a> System<'a> for DrawGridSys { let base_width = 0.5; let wider_width = 1.5; - (0..(screen_width() / SNAP).ceil() as usize) - .map(|i| (i, if i % s == 0 { wider_width } else { base_width })) - .map(|(i, width)| (i as f32 * SNAP, width)) - .for_each(|(x, width)| draw_line(x, 0.0, x, screen_height(), width, DARKGRAY)); + let thickness = |is_big| { + if is_big { + wider_width + } else { + base_width + } + }; - (0..(screen_height() / SNAP).ceil() as usize) - .map(|i| (i, if i % s == 0 { wider_width } else { base_width })) - .map(|(i, width)| (i as f32 * SNAP, width)) - .for_each(|(y, width)| draw_line(0.0, y, screen_width(), y, width, DARKGRAY)); + x_positions.for_each(|(x, is_big)| { + draw_line(x, top, x, bottom, thickness(is_big), DARKGRAY) + }); + y_positions.for_each(|(y, is_big)| { + draw_line(left, y, right, y, thickness(is_big), DARKGRAY) + }); } GridMode::Dots => { let base_rad = 1.5; let wider_rad = 3.0; - let x_positions = (0..(screen_width() / SNAP).ceil() as usize) - .map(|i| (i, i % s == 0)) - .map(|(i, is_big)| (i as f32 * SNAP, is_big)); - let y_positions = (0..(screen_height() / SNAP).ceil() as usize) - .map(|i| (i, i % s == 0)) - .map(|(i, is_big)| (i as f32 * SNAP, is_big)); - for (x, b1) in x_positions { for (y, b2) in y_positions.clone() { let rad = if b1 && b2 { wider_rad } else { base_rad }; @@ -352,13 +380,6 @@ impl<'a> System<'a> for DrawGridSys { let wider_thickness = 1.25; let wider_length = 15.0; - let x_positions = (0..(screen_width() / SNAP).ceil() as usize) - .map(|i| (i, i % s == 0)) - .map(|(i, is_big)| (i as f32 * SNAP, is_big)); - let y_positions = (0..(screen_height() / SNAP).ceil() as usize) - .map(|i| (i, i % s == 0)) - .map(|(i, is_big)| (i as f32 * SNAP, is_big)); - for (x, b1) in x_positions { for (y, b2) in y_positions.clone() { let (thickness, len) = if b1 && b2 { @@ -368,6 +389,7 @@ impl<'a> System<'a> for DrawGridSys { }; draw_line(x - len / 2.0, y, x + len / 2.0, y, thickness, DARKGRAY); + draw_line(x, y - len / 2.0, x, y + len / 2.0, thickness, DARKGRAY); } } diff --git a/src/systems/place_node_sys.rs b/src/systems/place_node_sys.rs index 57484d6..1741e28 100644 --- a/src/systems/place_node_sys.rs +++ b/src/systems/place_node_sys.rs @@ -1,8 +1,7 @@ use crate::components::{Connection, ConnectionTy, Node}; -use crate::Connected; use crate::Pos; +use crate::{resources::MousePos, Connected}; use core::marker::PhantomData; -use macroquad::prelude::*; use specs::prelude::*; use std::convert::TryInto; @@ -22,15 +21,15 @@ where WriteStorage<'a, Connected>, WriteStorage<'a, Pos>, WriteStorage<'a, Connection>, + Read<'a, MousePos>, Entities<'a>, ); fn run( &mut self, - (mut node_storage, mut position_storage, mut connections, entities): Self::SystemData, + (mut node_storage, mut position_storage, mut connections, mouse_pos, entities): Self::SystemData, ) { - let mp = mouse_position(); - let pos = Pos::from_vec(mp.into()); + let pos = Pos::from_vec(mouse_pos.0); let input_offsets = N::input_offsets(); let output_offsets = N::output_offsets(); diff --git a/src/systems/place_wire_sys.rs b/src/systems/place_wire_sys.rs index 8755809..290469d 100644 --- a/src/systems/place_wire_sys.rs +++ b/src/systems/place_wire_sys.rs @@ -1,8 +1,7 @@ -use crate::components::Pos; use crate::components::{Connection, ConnectionTy}; use crate::resources::UIState; use crate::Wire; -use macroquad::prelude::*; +use crate::{components::Pos, resources::MousePos}; use specs::prelude::*; pub struct WirePlaceSys; @@ -12,15 +11,15 @@ impl<'a> System<'a> for WirePlaceSys { WriteStorage<'a, Wire>, ReadStorage<'a, Pos>, Write<'a, UIState>, + Read<'a, MousePos>, Entities<'a>, ); fn run( &mut self, - (mut connections, mut wires, positions, mut ui_state, entities): Self::SystemData, + (mut connections, mut wires, positions, mut ui_state, mouse_pos, entities): Self::SystemData, ) { - let (mx, my) = mouse_position(); - let mp = Vec2::new(mx, my); + let mp = mouse_pos.0; match *ui_state { UIState::AddingWire { wire_entity, .. } => { diff --git a/src/systems/ui_systems.rs b/src/systems/ui_systems.rs index 7dc3c61..ef9303d 100644 --- a/src/systems/ui_systems.rs +++ b/src/systems/ui_systems.rs @@ -1,11 +1,9 @@ -use crate::nodes::SwitchNode; use crate::resources::UIState; use crate::Connected; use crate::Pos; +use crate::{nodes::SwitchNode, resources::MousePos}; use specs::prelude::*; -use macroquad::prelude::*; - use crate::resources::CurrentModeText; pub struct CurrentModeSys; @@ -46,14 +44,12 @@ pub struct SwitchClickSys; impl<'a> System<'a> for SwitchClickSys { type SystemData = ( WriteStorage<'a, Connected>, + Read<'a, MousePos>, ReadStorage<'a, Pos>, ); - fn run(&mut self, (mut switches, positions): Self::SystemData) { - let mouse_pos = { - let (mx, my) = mouse_position(); - Vec2::new(mx, my) - }; + fn run(&mut self, (mut switches, mouse_pos, positions): Self::SystemData) { + let mouse_pos = mouse_pos.0; let target_switch = (&mut switches, &positions) .join() diff --git a/src/ui/mouse_click.rs b/src/ui/mouse_click.rs index fdbbe14..d6e9dea 100644 --- a/src/ui/mouse_click.rs +++ b/src/ui/mouse_click.rs @@ -1,5 +1,6 @@ use crate::components::Connection; use crate::components::{round_to_snap, Pos}; +use crate::resources::MousePos; use crate::resources::UIState; use crate::systems::place_node_sys::PlaceNodeSys; use macroquad::prelude::*; @@ -48,11 +49,7 @@ pub fn handle_mouse_click(world: &mut World) { UIState::Deleting => { let positions = world.read_storage::(); let entities = world.entities(); - let mouse_pos = { - let (mx, my) = mouse_position(); - Vec2::new(mx, my) - }; - + let mouse_pos = world.fetch::().0; let connections = world.read_storage::(); let target = (&positions, &entities).join().find(|(pos, e)| { (connections.get(*e).is_none()) && (pos.pos - mouse_pos).length() < 35.0 @@ -82,18 +79,18 @@ pub fn handle_mouse_right_click(world: &mut World) { x_pos: None, y_pos: Some(y_pos), } => { - let (mx, _) = mouse_position(); + let mouse_pos = world.fetch::().0; world.insert(UIState::AddingWire { connection_entity, wire_entity, - x_pos: Some(mx), + x_pos: Some(mouse_pos.x), y_pos: Some(y_pos), }); world .write_storage::() .insert( wire_entity, - Pos::from_vec(Vec2::new(mx, round_to_snap(y_pos))), + Pos::from_vec(Vec2::new(mouse_pos.x, round_to_snap(y_pos))), ) .unwrap(); }