diff --git a/src/animations.rs b/src/animations.rs index b3283df..3554550 100644 --- a/src/animations.rs +++ b/src/animations.rs @@ -1,9 +1,13 @@ use std::collections::HashMap; use std::time::Duration; -pub type BlockOffsets = HashMap; +pub type BlockOffsets = HashMap; + +// TODO: don't yeet around a HashMap all the time pub type AnimationFn = Box BlockOffsets>; +const ANIMATION_DURATION: f32 = 1.0 / 6.0; + #[derive(Default)] pub struct AnimationState { pub is_animating: bool, @@ -21,9 +25,27 @@ impl AnimationState { self.progress_function = Some(f); } - pub fn make_progress(&mut self, delta: Duration) {} + pub fn make_progress(&mut self, delta: Duration) { + let progress = self.progress + delta.as_millis() as f32 / 1000.0; + let block_offsets = if let Some(f) = &self.progress_function { + Some(f(self.block_offsets.clone(), progress)) + } else { + None + }; + if let Some(block_offsets) = block_offsets { + self.block_offsets = block_offsets; + self.progress = progress; + } + } pub fn is_done(&self) -> bool { self.progress > 1.0 } + + pub fn get_offset(&self, index: usize) -> (i32, i32) { + self.block_offsets + .get(&index) + .cloned() + .unwrap_or_else(|| (0, 0)) + } } diff --git a/src/game.rs b/src/game.rs index fbd6312..7ea3703 100644 --- a/src/game.rs +++ b/src/game.rs @@ -5,7 +5,7 @@ use glium::glutin::{ElementState, Event, VirtualKeyCode, WindowEvent}; use glium::{Display, Frame}; use crate::animations::AnimationState; -use crate::enums::PushDir; +use crate::enums::{Board, PushDir}; use crate::level::Level; use crate::renderer::Renderer; use crate::resources::Resources; @@ -95,10 +95,10 @@ impl<'a> Game<'a> { pub fn update(&mut self, delta: Duration) { macro_rules! shit { - ($key:expr, $player:expr, $movement:expr) => { + ($key:expr, $board:expr, $direction:expr) => { if self.is_pressed(&$key) { let level = self.get_current_level_mut(); - let result = level.handle_movement($player, $movement); + let result = level.try_move($board, $direction); self.keymap.insert($key, false); } }; @@ -112,15 +112,15 @@ impl<'a> Game<'a> { } else { } } else { - shit!(VirtualKeyCode::W, true, PushDir::Up); - shit!(VirtualKeyCode::A, true, PushDir::Left); - shit!(VirtualKeyCode::S, true, PushDir::Down); - shit!(VirtualKeyCode::D, true, PushDir::Right); + shit!(VirtualKeyCode::W, Board::Left, PushDir::Up); + shit!(VirtualKeyCode::A, Board::Left, PushDir::Left); + shit!(VirtualKeyCode::S, Board::Left, PushDir::Down); + shit!(VirtualKeyCode::D, Board::Left, PushDir::Right); - shit!(VirtualKeyCode::I, false, PushDir::Up); - shit!(VirtualKeyCode::J, false, PushDir::Left); - shit!(VirtualKeyCode::K, false, PushDir::Down); - shit!(VirtualKeyCode::L, false, PushDir::Right); + shit!(VirtualKeyCode::I, Board::Right, PushDir::Up); + 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 !self.animations.last_move_success { @@ -135,6 +135,6 @@ impl<'a> Game<'a> { pub fn render(&self, renderer: &mut Renderer) { let level = self.get_current_level(); - level.render(renderer, &self.animations.block_offsets); + level.render(renderer, &self.animations); } } diff --git a/src/level/block.rs b/src/level/block.rs index 67d7267..c2cb9e4 100644 --- a/src/level/block.rs +++ b/src/level/block.rs @@ -14,7 +14,7 @@ pub trait Blockish { #[derive(Clone)] pub struct Block { index: usize, - movable: bool, + pub movable: bool, position: (i32, i32), color: Color, orientation: Orientation, diff --git a/src/level/mod.rs b/src/level/mod.rs index c6a683a..7488719 100644 --- a/src/level/mod.rs +++ b/src/level/mod.rs @@ -4,7 +4,7 @@ mod player; use std::collections::{HashMap, VecDeque}; -use crate::animations::BlockOffsets; +use crate::animations::AnimationState; use crate::color::Color; use crate::data::LevelData; use crate::enums::{Board, Orientation, PushDir, Shape}; @@ -83,122 +83,146 @@ impl Level { } } - // player1: true -> player1, false -> player2 - // TODO: don't use a boolean here - pub fn handle_movement(&mut self, player1: bool, direction: PushDir) -> bool { - let player = if player1 { - &self.player1 - } else { - &self.player2 - }; + // pub fn handle_movement(&mut self, board: Board, direction: PushDir) -> bool { + // let player = match board { + // Board::Left => &self.player1, + // Board::Right => &self.player2 + // }; - // TODO: check out of bounds - let movement = direction.as_pair(); - let x = player.position.0 + movement.0; - let y = player.position.1 + movement.1; + // // TODO: check out of bounds + // let movement = direction.as_pair(); + // let x = player.position.0 + movement.0; + // let y = player.position.1 + movement.1; - let result = self.can_move(player1, direction).clone(); - let mut player = if player1 { - &mut self.player1 - } else { - &mut self.player2 - }; + // let result = self.can_move(player1, direction).clone(); + // let player = match board { + // Board::Left => &mut self.player1, + // Board::Right => &mut self.player2 + // }; - if let Some(_) = result { - player.position.0 = x; - player.position.1 = y; - true - } else { - false - } + // if let Some(_) = result { + // player.position.0 = x; + // player.position.1 = y; + // true + // } else { + // false + // } + // } + + pub fn try_move(&self, board: Board, direction: PushDir) { + let result = self.player_can_move(board, direction); + println!("result: {:?}", result); } - pub fn try_move(&self) {} + fn player_can_move(&self, board: Board, direction: PushDir) {} - fn block_can_move(&self, block: impl Blockish) { - for segment in block.get_segments() {} - } + fn block_can_move(&self, index: usize, direction: PushDir) -> Option<()> { + let block = match self.blocks.get(index) { + Some(block) => block, + None => return None, + }; - fn segment_can_move(&self, block: Block, segment: Segment, direction: PushDir) -> Option<()> { - let triple = (segment.position.0, segment.position.1, segment.board); - let target = triple + direction; - - // is the target in the map? - if target.0 < 0 - || target.0 >= self.dimensions.0 as i32 - || target.1 < 0 - || target.1 >= self.dimensions.1 as i32 - { + // is the block even movable? + if !block.movable { return None; } - // check if we're sharing a triangle cell - if let CellContents::Double((ind1, block1), (ind2, block2)) = self.cell_map.get(triple) { - // figure out which one is the other block - - // check that we're pushing in the direction of the other block - + for segment in block.get_segments() { + let result = self.segment_can_move(Some(index), segment, direction); } - Some(()) } - // TODO: don't use a boolean here - pub fn can_move(&self, player1: bool, direction: PushDir) -> Option<()> { - // an absolute segment (as opposed to relative to a block) - #[derive(Copy, Clone, PartialOrd, PartialEq)] - struct ASegment(i32, i32, Shape, Board); - - struct PushMap(CellMap); - - fn can_push_segment(src: ASegment, dst: ASegment) -> bool { - if src.3 != dst.3 { - return false; - } - - true - } - - let player = if player1 { - ( - self.player1.position.0, - self.player1.position.1, - Board::Left, - ) - } else { - ( - self.player2.position.0, - self.player2.position.1, - Board::Right, - ) - }; - - // check to make sure that the player isn't trying to go out of bounds - let target = player + direction; - if target.0 < 0 - || target.0 >= self.dimensions.0 as i32 - || target.1 < 0 - || target.1 >= self.dimensions.1 as i32 - { - return None; - } - - // check if we're sharing a triangle cell - if let CellContents::Double(a, b) = self.cell_map.get(player) { - // get the shape of the other block - } - - // 08/06 pickup - // need to determine whether or not segment should hold a reference back to block or not? - // either way, segment in the cellmap should hold block information - // maybe cellmap should just carry a block index? seems hacky - // using refs to manage the whole thing is messy and probably doesn't work - // ??? - + fn segment_can_move( + &self, + block_index: Option, + segment: Segment, + direction: PushDir, + ) -> Option<()> { + let segment_loc = (segment.position.0, segment.position.1, segment.board); + let target = segment_loc + direction; Some(()) } - pub fn render(&self, renderer: &mut Renderer, block_offsets: &BlockOffsets) { + // fn segment_can_move(&self, block: Block, segment: Segment, direction: PushDir) -> Option<()> { + // let triple = (segment.position.0, segment.position.1, segment.board); + // let target = triple + direction; + + // // is the target in the map? + // if target.0 < 0 + // || target.0 >= self.dimensions.0 as i32 + // || target.1 < 0 + // || target.1 >= self.dimensions.1 as i32 + // { + // return None; + // } + + // // check if we're sharing a triangle cell + // if let CellContents::Double((ind1, block1), (ind2, block2)) = self.cell_map.get(triple) { + // // figure out which one is the other block + + // // check that we're pushing in the direction of the other block + + // } + + // Some(()) + // } + + // pub fn can_move(&self, board: Board, direction: PushDir) -> Option<()> { + // // an absolute segment (as opposed to relative to a block) + // #[derive(Copy, Clone, PartialOrd, PartialEq)] + // struct ASegment(i32, i32, Shape, Board); + + // struct PushMap(CellMap); + + // fn can_push_segment(src: ASegment, dst: ASegment) -> bool { + // if src.3 != dst.3 { + // return false; + // } + + // true + // } + + // let player = if player1 { + // ( + // self.player1.position.0, + // self.player1.position.1, + // Board::Left, + // ) + // } else { + // ( + // self.player2.position.0, + // self.player2.position.1, + // Board::Right, + // ) + // }; + + // // check to make sure that the player isn't trying to go out of bounds + // let target = player + direction; + // if target.0 < 0 + // || target.0 >= self.dimensions.0 as i32 + // || target.1 < 0 + // || target.1 >= self.dimensions.1 as i32 + // { + // return None; + // } + + // // check if we're sharing a triangle cell + // if let CellContents::Double(a, b) = self.cell_map.get(player) { + // // get the shape of the other block + // } + + // // 08/06 pickup + // // need to determine whether or not segment should hold a reference back to block or not? + // // either way, segment in the cellmap should hold block information + // // maybe cellmap should just carry a block index? seems hacky + // // using refs to manage the whole thing is messy and probably doesn't work + // // ??? + + // Some(()) + // } + + pub fn render(&self, renderer: &mut Renderer, animations: &AnimationState) { // board positioning calculations let playfield_ratio = (2 * self.dimensions.0 + 6) as f32 / (self.dimensions.1 + 4) as f32; let screen_ratio = renderer.window.0 / renderer.window.1; @@ -216,7 +240,7 @@ impl Level { (scale, xoff, 0) }; - self.render_boards(renderer, scale, (xoff, yoff), block_offsets); + self.render_boards(renderer, scale, (xoff, yoff), animations); } fn render_boards( @@ -224,7 +248,7 @@ impl Level { renderer: &mut Renderer, scale: i32, offset: (i32, i32), - block_offsets: &BlockOffsets, + animations: &AnimationState, ) { let left_off = (offset.0 + 2 * scale, offset.1 + 2 * scale); let right_off = ( @@ -242,16 +266,19 @@ impl Level { } // render blocks - for block in self.blocks.iter() { + for (i, block) in self.blocks.iter().enumerate() { for segment in block.get_segments().iter() { let offset = match &segment.board { Board::Left => left_off, Board::Right => right_off, }; - let location = ( + let mut location = ( offset.0 + segment.position.0 * scale, offset.1 + segment.position.1 * scale, ); + let animation_offset = animations.get_offset(i); + location.0 += animation_offset.0; + location.1 += animation_offset.1; renderer.render_segment( location, scale,