diff --git a/src/animations.rs b/src/animations.rs index ae21778..dd682df 100644 --- a/src/animations.rs +++ b/src/animations.rs @@ -34,6 +34,7 @@ impl AnimationState { } pub fn begin_move_transition(&mut self, result: MoveResult) { + println!("result: {:?}", result); self.last_move_result = Some(result); self.is_animating = true; self.progress = 0.0; @@ -45,12 +46,10 @@ impl AnimationState { for (entity, direction) in change_set { // TODO: implement ease-out? let pair = direction.as_pair(); + // cap progress at 1.0, we don't want blocks going past where they're supposed to + let progress = progress.min(1.0); let offset = (pair.0 as f32 * progress, pair.1 as f32 * progress); - println!( - "|| entity: {:?}, direction: {:?} => {:?}", - entity, direction, offset - ); - offsets.insert(entity.clone(), offset); + offsets.insert(entity, offset); } } // vibrate all blocking pieces @@ -66,12 +65,6 @@ impl AnimationState { self.progress_function = Some(Box::new(func)); } - pub fn begin_transition(&mut self, f: AnimationFn) { - self.is_animating = true; - self.progress = 0.0; - self.progress_function = Some(f); - } - pub fn make_progress(&mut self, delta: Duration) { let progress = self.progress + (delta.as_millis() as f32 / ANIMATION_DURATION) / 1000.0; @@ -97,10 +90,6 @@ impl AnimationState { } } - pub fn is_done(&self) -> bool { - self.progress > 1.0 - } - pub fn get_block_offset(&self, index: usize) -> (f32, f32) { self.block_offsets .get(&Entity::Block(index)) diff --git a/src/enums.rs b/src/enums.rs index 3bcf347..38dd1f3 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -44,7 +44,7 @@ pub enum PushDir { } impl PushDir { - pub fn as_pair(&self) -> (i32, i32) { + pub fn as_pair(self) -> (i32, i32) { match self { PushDir::Up => (0, -1), PushDir::Down => (0, 1), @@ -90,25 +90,20 @@ impl From for Shape { } impl Shape { - pub fn opposite(&self) -> Shape { + pub fn get_opposite(self) -> Option { use Shape::*; match self { - TopRight => BottomLeft, - BottomLeft => TopRight, - TopLeft => BottomRight, - BottomRight => TopLeft, - Full => Full, + TopRight => Some(BottomLeft), + BottomLeft => Some(TopRight), + TopLeft => Some(BottomRight), + BottomRight => Some(TopLeft), + Full => None, } } - pub fn is_opposite(&self, other: &Shape) -> bool { - use Shape::*; - match (self, other) { - (TopRight, BottomLeft) - | (BottomLeft, TopRight) - | (TopLeft, BottomRight) - | (BottomRight, TopLeft) => true, - _ => false, - } + pub fn is_opposite(self, other: Shape) -> bool { + self.get_opposite() + .map(|shape| shape == other) + .unwrap_or_else(|| false) } } diff --git a/src/game.rs b/src/game.rs index 6c9586c..3a22ee2 100644 --- a/src/game.rs +++ b/src/game.rs @@ -19,8 +19,6 @@ const SEGMENT_IMAGE: &[u8] = include_bytes!("../textures/segment.png"); const LEVEL_TUTORIAL: &str = include_str!("../levels/tutorial.json"); -const ANIMATION_SPEED: f32 = 6.0; - pub struct Game<'a> { pub resources: Resources, pub display: &'a Display, @@ -55,8 +53,8 @@ impl<'a> Game<'a> { } pub fn handle_event(&mut self, event: Event) { - match event { - Event::WindowEvent { event, .. } => match event { + if let Event::WindowEvent { event, .. } = event { + match event { WindowEvent::Resized(size) => self.resources.window_dimensions = size.into(), WindowEvent::KeyboardInput { input, .. } => { if let Some(code) = &input.virtual_keycode { @@ -68,8 +66,7 @@ impl<'a> Game<'a> { } } _ => (), - }, - _ => (), + } } } @@ -78,15 +75,15 @@ impl<'a> Game<'a> { } pub fn get_current_level(&self) -> &Level { - self.levels.iter().nth(self.current_level).unwrap() + self.levels.get(self.current_level).unwrap() } pub fn get_current_level_mut(&mut self) -> &mut Level { - self.levels.iter_mut().nth(self.current_level).unwrap() + self.levels.get_mut(self.current_level).unwrap() } - pub fn is_pressed(&self, code: &VirtualKeyCode) -> bool { - if let Some(true) = self.keymap.get(code) { + pub fn is_pressed(&self, code: VirtualKeyCode) -> bool { + if let Some(true) = self.keymap.get(&code) { true } else { false @@ -96,7 +93,7 @@ impl<'a> Game<'a> { pub fn update(&mut self, delta: Duration) { macro_rules! shit { ($key:expr, $board:expr, $direction:expr) => { - if self.is_pressed(&$key) { + if self.is_pressed($key) { println!("pushed: {:?}", $key); let level = self.get_current_level_mut(); let result = level.try_move($board, $direction); @@ -107,7 +104,7 @@ impl<'a> Game<'a> { } if self.animations.is_animating { - println!("animating. {:?}", self.animations.progress); + // println!("animating. {:?}", self.animations.progress); self.animations.make_progress(delta); // we just finished! @@ -134,9 +131,6 @@ impl<'a> Game<'a> { shit!(VirtualKeyCode::J, Board::Right, PushDir::Left); shit!(VirtualKeyCode::K, Board::Right, PushDir::Down); shit!(VirtualKeyCode::L, Board::Right, PushDir::Right); - - // failed a move - if let Some(Err(fail_set)) = &self.animations.last_move_result {} } } diff --git a/src/level/block.rs b/src/level/block.rs index 1e1122d..adb22ed 100644 --- a/src/level/block.rs +++ b/src/level/block.rs @@ -26,13 +26,10 @@ impl Block { let segments = data .segments .iter() - .map(|segment| { - let seg = Segment { - position: (segment[0], segment[1]), - shape: segment[2].into(), - board: segment[3].into(), - }; - seg + .map(|segment| Segment { + position: (segment[0], segment[1]), + shape: segment[2].into(), + board: segment[3].into(), }) .collect(); let orientation = data.orientation.into(); diff --git a/src/level/cell_map.rs b/src/level/cell_map.rs deleted file mode 100644 index 5779b01..0000000 --- a/src/level/cell_map.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::collections::HashMap; - -use crate::enums::Board; -use crate::level::Segment; - -#[derive(Debug)] -pub struct CellMap(HashMap<(i32, i32, Board), CellContents>); - -#[derive(Copy, Clone, Debug)] -pub enum CellContents { - Empty, - Player, - Single((usize, Segment)), - - // invariant: .0 < .1 - Double((usize, Segment), (usize, Segment)), -} - -impl CellMap { - pub fn new() -> Self { - CellMap(HashMap::new()) - } - - pub fn get(&self, loc: (i32, i32, Board)) -> CellContents { - self.0 - .get(&loc) - .cloned() - .unwrap_or_else(|| CellContents::Empty) - } - - pub fn clear(&mut self, loc: (i32, i32, Board)) { - self.0.remove(&loc); - } - - pub fn add_player(&mut self, loc: (i32, i32, Board)) -> bool { - let contents = self.get(loc).clone(); - match contents { - CellContents::Empty => { - self.0.insert(loc, CellContents::Player); - true - } - _ => false, - } - } - - pub fn add(&mut self, loc: (i32, i32, Board), index: usize, segment: &Segment) -> bool { - let contents = self.get(loc).clone(); - match contents { - CellContents::Empty => { - // just add it like normal - self.0.insert(loc, CellContents::Single((index, *segment))); - true - } - CellContents::Single((index0, existing)) => { - if existing.shape.is_opposite(&segment.shape) { - self.0.insert( - loc, - if *segment < existing { - CellContents::Double((index, *segment), (index0, existing)) - } else { - CellContents::Double((index0, existing), (index, *segment)) - }, - ); - true - } else { - false - } - } - CellContents::Player | CellContents::Double(_, _) => false, - } - } -} diff --git a/src/level/macros.rs b/src/level/macros.rs index f45eb8c..a2dd090 100644 --- a/src/level/macros.rs +++ b/src/level/macros.rs @@ -8,16 +8,6 @@ macro_rules! set { } } -macro_rules! merge { - ($(item:expr)*) => { - { - let mut set = std::collections::HashSet::new(); - $(set.extend($item);)* - set - } - } -} - macro_rules! fail_set { ($change_set:expr) => { $change_set @@ -34,7 +24,7 @@ macro_rules! entity_fail { ($item:expr) => { match $item { Some(index) => set!(index), - None => set!(), + None => std::collections::HashSet::new(), } }; } diff --git a/src/level/mod.rs b/src/level/mod.rs index 52124e0..2091d5c 100644 --- a/src/level/mod.rs +++ b/src/level/mod.rs @@ -2,25 +2,21 @@ mod macros; mod block; -mod cell_map; mod player; use std::collections::{HashMap, HashSet, VecDeque}; use crate::animations::AnimationState; -use crate::color::Color; use crate::data::LevelData; use crate::enums::{Board, Orientation, PushDir, Shape}; use crate::renderer::Renderer; use self::block::{Block, Blockish}; -use self::cell_map::{CellContents, CellMap}; use self::player::Player; pub struct Level { dimensions: (u32, u32), move_stack: VecDeque<()>, - cell_map: CellMap, blocks: Vec, player1: Player, player2: Player, @@ -46,25 +42,13 @@ pub type FailSet = HashSet; impl Level { pub fn from_json(data: impl AsRef) -> Level { let data: LevelData = json5::from_str(data.as_ref()).unwrap(); - println!("{:?}", data); - - let mut cell_map = CellMap::new(); + println!("level data: {:?}", data); let blocks = data .blocks .iter() .enumerate() - .map(|(i, block)| { - let block = Block::from_data(i, block); - for segment in block.get_segments() { - cell_map.add( - (segment.position.0, segment.position.1, segment.board), - i, - &segment, - ); - } - block - }) + .map(|(i, block)| Block::from_data(i, block)) .collect(); let player1 = Player { @@ -75,21 +59,10 @@ impl Level { position: data.player2.position, color: data.player2.color.into(), }; - cell_map.add_player(( - data.player1.position.0, - data.player1.position.1, - Board::Left, - )); - cell_map.add_player(( - data.player2.position.0, - data.player2.position.1, - Board::Right, - )); Level { dimensions: (data.dimensions[0], data.dimensions[1]), move_stack: VecDeque::new(), - cell_map, blocks, player1, player2, @@ -152,7 +125,7 @@ impl Level { println!("block_can_move({:?}, {:?})", index, direction); let block = match self.blocks.get(index) { Some(block) => block, - None => return Err(set!()), + None => return Err(HashSet::new()), }; // is the block even movable? @@ -247,8 +220,7 @@ impl Level { ); // handle special pushes - // if-statement disguised as a loop - while let Some((other_block, other_shape)) = current_occupant { + if let Some((other_block, other_shape)) = current_occupant { // are both shapes triangles? let both_triangles = match (segment.shape, other_shape) { (Shape::Full, Shape::Full) => false, @@ -256,28 +228,28 @@ impl Level { // TODO: enumerate them to get rid of invalid states }; - // what directions could we be pushing the other block into? - let possible_directions = match segment.shape { - Shape::TopRight => [PushDir::Up, PushDir::Right], - Shape::TopLeft => [PushDir::Left, PushDir::Up], - Shape::BottomLeft => [PushDir::Down, PushDir::Left], - Shape::BottomRight => [PushDir::Right, PushDir::Down], - Shape::Full => unreachable!("already eliminated this possibility"), - }; + if both_triangles { + // what directions could we be pushing the other block into? + let possible_directions = match segment.shape { + Shape::TopRight => [PushDir::Up, PushDir::Right], + Shape::TopLeft => [PushDir::Left, PushDir::Up], + Shape::BottomLeft => [PushDir::Down, PushDir::Left], + Shape::BottomRight => [PushDir::Right, PushDir::Down], + Shape::Full => unreachable!("already eliminated this possibility"), + }; - // does the direction we're pushing appear in this list? - if !possible_directions.contains(&direction) { - break; + // does the direction we're pushing appear in this list? + if possible_directions.contains(&direction) { + // the other shape goes in the other direction + let other_direction = { + let mut set = possible_directions.iter().collect::>(); + set.remove(&direction); + *set.into_iter().next().unwrap() + }; + + return self.block_can_move(other_block, other_direction, change_set); + } } - - // the other shape goes in the other direction - let other_direction = { - let mut set = possible_directions.iter().collect::>(); - set.remove(&direction); - *set.into_iter().next().unwrap() - }; - - return self.block_can_move(other_block, other_direction, change_set); } // handle normal pushes @@ -288,18 +260,20 @@ impl Level { Err(fail_set!(change_set)) } Entity::Block(index) => { + if // if it's part of the same block it's ok to push - if block_index.is_some() && block_index.unwrap() == index { - Ok(change_set) - } + block_index.is_some() && block_index.unwrap() == index || // if the shapes are opposite, we can actually both fit into the same spot - else if segment.shape.is_opposite(&shape) { + segment.shape.is_opposite(shape) + { Ok(change_set) } // if the block is already in the change set, it can't move else if change_set.contains_key(&Entity::Block(index)) { Err(fail_set!(change_set)) - } else { + } + // if the next block can move then so can this one + else { self.block_can_move(index, direction, change_set) } } @@ -414,7 +388,7 @@ impl Level { location.1 += (animation_offset.1 * scale as f32) as i32; renderer.render_segment( location, - (scale - 8), + scale - 8, player.color, Orientation::Both, Shape::Full, diff --git a/src/main.rs b/src/main.rs index 5d3dcaf..ed6b640 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use std::time::Instant; use glium::glutin::dpi::PhysicalSize; use glium::glutin::{ContextBuilder, Event, EventsLoop, WindowBuilder, WindowEvent}; -use glium::{Display, Rect, Surface}; +use glium::{Display, Surface}; use crate::game::Game; diff --git a/src/resources.rs b/src/resources.rs index 1c66772..38460d8 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use glium::texture::RawImage2d; use glium::{Display, Program, ProgramCreationError, Texture2d}; -use image::{DynamicImage, GenericImageView, ImageBuffer, ImageError, Rgba}; +use image::{DynamicImage, GenericImageView, ImageError}; #[derive(Default)] pub struct Resources {