huge refactor

This commit is contained in:
Michael Zhang 2019-08-07 02:44:49 -05:00
parent e9c8cdbf48
commit b0ef20ff8b
No known key found for this signature in database
GPG key ID: 5BAEFE5D04F0CE6C
11 changed files with 278 additions and 139 deletions

View file

@ -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],
],
},
]
}
}

14
src/color.rs Normal file
View file

@ -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)
}
}

View file

@ -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]>,
}

View file

@ -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<i32> for Board {
#[derive(Copy, Clone)]
pub enum Orientation {
Both = 0,
None = 0,
Horizontal = 1,
Vertical = 2,
Both = 3,
}
impl From<u32> for Orientation {
@ -62,7 +63,7 @@ impl Add<PushDir> 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<i32> 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) {

View file

@ -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);
}

63
src/level/block.rs Normal file
View file

@ -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<Segment>;
}
#[derive(Clone)]
pub struct Block {
movable: bool,
position: (i32, i32),
color: Color,
orientation: Orientation,
segments: Vec<Segment>,
}
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<Segment> {
self.segments.clone()
}
}

72
src/level/cell_map.rs Normal file
View file

@ -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,
}
}
}

View file

@ -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<Segment>,
}
#[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,
}
}
}

23
src/level/player.rs Normal file
View file

@ -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<Segment> {
vec![]
}
}

View file

@ -4,6 +4,7 @@ extern crate nalgebra_glm as glm;
#[macro_use]
extern crate serde_derive;
mod color;
mod data;
mod enums;
mod game;

View file

@ -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,
};