From b0ef20ff8b3004d0a16646895ac68ff19a4e849d Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Wed, 7 Aug 2019 02:44:49 -0500 Subject: [PATCH] huge refactor --- levels/tutorial.json | 22 ++-- src/color.rs | 14 +++ src/data.rs | 8 +- src/enums.rs | 18 +++- src/game.rs | 2 +- src/level/block.rs | 63 +++++++++++ src/level/cell_map.rs | 72 +++++++++++++ src/{level.rs => level/mod.rs} | 190 ++++++++++++--------------------- src/level/player.rs | 23 ++++ src/main.rs | 1 + src/renderer.rs | 4 +- 11 files changed, 278 insertions(+), 139 deletions(-) create mode 100644 src/color.rs create mode 100644 src/level/block.rs create mode 100644 src/level/cell_map.rs rename src/{level.rs => level/mod.rs} (58%) create mode 100644 src/level/player.rs diff --git a/levels/tutorial.json b/levels/tutorial.json index 45035d0..ceb8ebd 100644 --- a/levels/tutorial.json +++ b/levels/tutorial.json @@ -17,8 +17,8 @@ "position": [1, 3], "color": [255, 10, 100], "segments": [ - [0, 0, 0, 0], - [1, 0, 4, 0], + [1, 3, 0, 0], + [2, 3, 4, 0], ], }, { @@ -27,8 +27,8 @@ "position": [2, 4], "color": [105, 210, 50], "segments": [ - [0, 0, 2, 0], - [0, 1, 0, 0], + [2, 4, 2, 0], + [2, 5, 0, 0], ], }, { @@ -37,8 +37,8 @@ "position": [0, 4], "color": [35, 150, 100], "segments": [ - [0, 0, 1, 1], - [0, 1, 0, 1], + [0, 4, 1, 1], + [0, 5, 0, 1], ], }, { @@ -47,8 +47,8 @@ "position": [0, 3], "color": [25, 120, 10], "segments": [ - [0, 0, 3, 1], - [1, 0, 0, 1], + [0, 3, 3, 1], + [1, 3, 0, 1], ], }, { @@ -57,7 +57,7 @@ "position": [0, 2], "color": [15, 15, 15], "segments": [ - [0, 0, 0, 0], + [0, 2, 0, 0], ], }, { @@ -66,8 +66,8 @@ "position": [2, 2], "color": [15, 15, 15], "segments": [ - [0, 0, 0, 1], + [2, 2, 0, 1], ], }, ] -} \ No newline at end of file +} diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 0000000..8d10f79 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,14 @@ +#[derive(Copy, Clone, Debug)] +pub struct Color(pub f32, pub f32, pub f32, pub f32); + +impl Color { + pub fn from_rgb_u32(r: u32, g: u32, b: u32) -> Self { + Color(r as f32 / 256.0, g as f32 / 256.0, b as f32 / 256.0, 1.0) + } +} + +impl From<(u32, u32, u32)> for Color { + fn from(tuple: (u32, u32, u32)) -> Self { + Color::from_rgb_u32(tuple.0, tuple.1, tuple.2) + } +} diff --git a/src/data.rs b/src/data.rs index 6d57f31..3b96c87 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,15 +1,15 @@ #[derive(Debug, Deserialize)] pub struct PlayerData { - pub position: [i32; 2], - pub color: [u32; 3], + pub position: (i32, i32), + pub color: (u32, u32, u32), } #[derive(Debug, Deserialize)] pub struct BlockData { pub movable: bool, pub orientation: u32, - pub position: [i32; 2], - pub color: [u32; 3], + pub position: (i32, i32), + pub color: (u32, u32, u32), pub segments: Vec<[i32; 4]>, } diff --git a/src/enums.rs b/src/enums.rs index 01ed491..204c1ab 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -1,6 +1,6 @@ use std::ops::Add; -#[derive(Eq, PartialEq, Hash, PartialOrd, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Copy, Clone)] pub enum Board { Left = 0, Right = 1, @@ -18,9 +18,10 @@ impl From for Board { #[derive(Copy, Clone)] pub enum Orientation { - Both = 0, + None = 0, Horizontal = 1, Vertical = 2, + Both = 3, } impl From for Orientation { @@ -62,7 +63,7 @@ impl Add for (i32, i32, Board) { } } -#[derive(Copy, Clone, PartialOrd, PartialEq)] +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] pub enum Shape { Full = 0, TopRight = 1, @@ -85,6 +86,17 @@ impl From for Shape { } impl Shape { + pub fn opposite(&self) -> Shape { + use Shape::*; + match self { + TopRight => BottomLeft, + BottomLeft => TopRight, + TopLeft => BottomRight, + BottomRight => TopLeft, + Full => Full, + } + } + pub fn is_opposite(&self, other: &Shape) -> bool { use Shape::*; match (self, other) { diff --git a/src/game.rs b/src/game.rs index 0970fb4..4548c1f 100644 --- a/src/game.rs +++ b/src/game.rs @@ -92,7 +92,7 @@ impl<'a> Game<'a> { macro_rules! shit { ($key:expr, $player:expr, $movement:expr) => { if self.is_pressed(&$key) { - let mut level = self.get_current_level_mut(); + let level = self.get_current_level_mut(); level.handle_movement($player, $movement); self.keymap.insert($key, false); } diff --git a/src/level/block.rs b/src/level/block.rs new file mode 100644 index 0000000..0af1968 --- /dev/null +++ b/src/level/block.rs @@ -0,0 +1,63 @@ +use crate::color::Color; +use crate::data::BlockData; +use crate::enums::Orientation; +use crate::level::Segment; + +pub trait Blockish { + fn get_color(&self) -> Color; + fn get_orientation(&self) -> Orientation; + + // TODO: don't alloc/clone here? + fn get_segments(&self) -> Vec; +} + +#[derive(Clone)] +pub struct Block { + movable: bool, + position: (i32, i32), + color: Color, + orientation: Orientation, + segments: Vec, +} + +impl Block { + pub fn from_data(index: usize, data: &BlockData) -> Self { + let movable = data.movable; + let position = (data.position.0, data.position.1); + let segments = data + .segments + .iter() + .map(|segment| { + let seg = Segment { + position: (segment[0], segment[1]), + shape: segment[2].into(), + board: segment[3].into(), + }; + seg + }) + .collect(); + let orientation = data.orientation.into(); + let color = Color::from_rgb_u32(data.color.0, data.color.1, data.color.2); + Block { + movable, + position, + color, + segments, + orientation, + } + } +} + +impl Blockish for Block { + fn get_color(&self) -> Color { + self.color + } + + fn get_orientation(&self) -> Orientation { + self.orientation + } + + fn get_segments(&self) -> Vec { + self.segments.clone() + } +} diff --git a/src/level/cell_map.rs b/src/level/cell_map.rs new file mode 100644 index 0000000..5779b01 --- /dev/null +++ b/src/level/cell_map.rs @@ -0,0 +1,72 @@ +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.rs b/src/level/mod.rs similarity index 58% rename from src/level.rs rename to src/level/mod.rs index 3bd389c..530804f 100644 --- a/src/level.rs +++ b/src/level/mod.rs @@ -1,9 +1,18 @@ +mod block; +mod cell_map; +mod player; + use std::collections::{HashMap, VecDeque}; +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<()>, @@ -13,22 +22,11 @@ pub struct Level { player2: Player, } -#[derive(Clone)] -pub struct Block { - movable: bool, +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Segment { position: (i32, i32), - color: (f32, f32, f32), - orientation: Orientation, - segments: Vec, -} - -#[derive(Copy, Clone, PartialOrd, PartialEq)] -pub struct Segment(i32, i32, Shape, Board); - -#[derive(Copy, Clone)] -pub struct Player { - pub position: [i32; 2], - pub color: [u32; 3], + shape: Shape, + board: Board, } impl Level { @@ -36,48 +34,48 @@ impl Level { let data: LevelData = json5::from_str(data.as_ref()).unwrap(); println!("{:?}", data); + let mut cell_map = CellMap::new(); + let blocks = data .blocks .iter() - .map(|block| { - let movable = block.movable; - let position = (block.position[0], block.position[1]); - let segments = block - .segments - .iter() - .map(|segment| { - Segment(segment[0], segment[1], segment[2].into(), segment[3].into()) - }) - .collect(); - let orientation = block.orientation.into(); - let color = ( - block.color[0] as f32 / 256.0, - block.color[1] as f32 / 256.0, - block.color[2] as f32 / 256.0, - ); - Block { - movable, - position, - color, - segments, - orientation, + .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 }) .collect(); let player1 = Player { position: data.player1.position, - color: data.player1.color, + color: data.player1.color.into(), }; let player2 = Player { position: data.player2.position, - color: data.player2.color, + 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: CellMap::new(), + cell_map, blocks, player1, player2, @@ -87,7 +85,7 @@ 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 mut player = if player1 { + let player = if player1 { &self.player1 } else { &self.player2 @@ -95,8 +93,8 @@ impl Level { // 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 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 { @@ -106,21 +104,25 @@ impl Level { }; if let Some(_) = result { - player.position[0] = x; - player.position[1] = y; + player.position.0 = x; + player.position.1 = y; true } else { false } } + pub fn try_move(&self) {} + // 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); - fn can_push(src: Segment, dst: Segment) -> bool { + struct PushMap(CellMap); + + fn can_push_segment(src: ASegment, dst: ASegment) -> bool { if src.3 != dst.3 { return false; } @@ -130,14 +132,14 @@ impl Level { let player = if player1 { ( - self.player1.position[0], - self.player1.position[1], + self.player1.position.0, + self.player1.position.1, Board::Left, ) } else { ( - self.player2.position[0], - self.player2.position[1], + self.player2.position.0, + self.player2.position.1, Board::Right, ) }; @@ -153,7 +155,9 @@ impl Level { } // check if we're sharing a triangle cell - if let CellContents::Double(a, b) = self.cell_map.get(player) {} + 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? @@ -204,14 +208,22 @@ impl Level { // render blocks for block in self.blocks.iter() { - for segment in block.segments.iter() { - let offset = match &segment.3 { + for segment in block.get_segments().iter() { + let offset = match &segment.board { Board::Left => left_off, Board::Right => right_off, }; - let coord = (segment.0 + block.position.0, segment.1 + block.position.1); - let location = (offset.0 + coord.0 * scale, offset.1 + coord.1 * scale); - renderer.render_segment(location, scale, block.color, block.orientation, segment.2); + let location = ( + offset.0 + segment.position.0 * scale, + offset.1 + segment.position.1 * scale, + ); + renderer.render_segment( + location, + scale, + block.get_color(), + block.get_orientation(), + segment.shape, + ); } } @@ -228,75 +240,15 @@ impl Level { offset: (i32, i32), ) { let location = ( - offset.0 + player.position[0] * scale + 4, - offset.1 + player.position[1] * scale + 4, + offset.0 + player.position.0 * scale + 4, + offset.1 + player.position.1 * scale + 4, ); renderer.render_segment( location, (scale - 8), - ( - player.color[0] as f32, - player.color[1] as f32, - player.color[2] as f32, - ), + player.color, Orientation::Both, Shape::Full, ); } } - -struct CellMap(HashMap<(i32, i32, Board), CellContents>); - -#[derive(Copy, Clone)] -enum CellContents { - Empty, - Player, - Single(Segment), - - // invariant: .0 < .1 - Double(Segment, 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(&mut self, loc: (i32, i32, Board), segment: &Segment) -> bool { - let contents = self.get(loc).clone(); - match contents { - CellContents::Empty => { - // just add it like normal - self.0.insert(loc, CellContents::Single(*segment)); - true - } - CellContents::Single(existing) => { - if existing.2.is_opposite(&segment.2) { - self.0.insert( - loc, - if *segment < existing { - CellContents::Double(*segment, existing) - } else { - CellContents::Double(existing, *segment) - }, - ); - true - } else { - false - } - } - CellContents::Player | CellContents::Double(_, _) => false, - } - } -} diff --git a/src/level/player.rs b/src/level/player.rs new file mode 100644 index 0000000..0558d60 --- /dev/null +++ b/src/level/player.rs @@ -0,0 +1,23 @@ +use crate::color::Color; +use crate::enums::Orientation; +use crate::level::{Blockish, Segment}; + +#[derive(Copy, Clone)] +pub struct Player { + pub position: (i32, i32), + pub color: Color, +} + +impl Blockish for Player { + fn get_color(&self) -> Color { + self.color + } + + fn get_orientation(&self) -> Orientation { + Orientation::None + } + + fn get_segments(&self) -> Vec { + vec![] + } +} diff --git a/src/main.rs b/src/main.rs index 18624fe..ff62b29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate nalgebra_glm as glm; #[macro_use] extern crate serde_derive; +mod color; mod data; mod enums; mod game; diff --git a/src/renderer.rs b/src/renderer.rs index 72c1646..bed81b7 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,6 +3,7 @@ use glium::index::{NoIndices, PrimitiveType}; use glium::{Display, Frame, Program, Surface, Texture2d, VertexBuffer}; use nalgebra::{Matrix4, Vector4}; +use crate::color::Color; use crate::enums::{Orientation, Shape}; use crate::game::Game; @@ -85,7 +86,7 @@ impl<'a, 'b> Renderer<'a, 'b> { &mut self, location: (i32, i32), scale: i32, - color: (f32, f32, f32), + color: Color, orientation: Orientation, shape: Shape, ) { @@ -199,6 +200,7 @@ impl<'a, 'b> Renderer<'a, 'b> { let rotate_texture = match orientation { Orientation::Both => false, + Orientation::None => false, Orientation::Vertical => true, Orientation::Horizontal => false, };