From bfdaef7850b6ac17bb88f1b314236fb5014aac8e Mon Sep 17 00:00:00 2001 From: tom barrett Date: Fri, 5 Jul 2019 08:59:22 -0500 Subject: now a cells struct whichs layers own, which takes from tileset tiles --- README.md | 2 + src/animations.rs | 89 +++++++--------------------- src/camera.rs | 29 +++++---- src/constants.rs | 8 +-- src/layer.rs | 24 ++++---- src/map.rs | 47 +++++++-------- src/property.rs | 21 +++++-- src/state.rs | 8 +-- src/tile.rs | 42 +++---------- src/tileset.rs | 174 +++++++++++++++++++++++++++++++++--------------------- 10 files changed, 212 insertions(+), 232 deletions(-) diff --git a/README.md b/README.md index f511a69..e074b21 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ * collision * fat binary (include-bytes!) * textbox (with dialog options) + * have tile use the animation struct * have the tileset have the translated ids within the hashmap * merge the Tile struct and the Frame struct? +* rename property to properties diff --git a/src/animations.rs b/src/animations.rs index e308f1d..5e5740a 100644 --- a/src/animations.rs +++ b/src/animations.rs @@ -1,72 +1,42 @@ -use ggez::graphics::{spritebatch::SpriteBatch, DrawParam, Rect}; +use ggez::graphics::{spritebatch::SpriteBatch, DrawParam}; use ggez::nalgebra::{Point2, Vector2}; use std::collections::HashMap; -use std::f32::consts::PI; use std::time::Instant; use crate::constants; use crate::entity::Action; -use crate::tileset::Tileset; - -#[derive(Debug, Clone, PartialEq)] -pub struct Frame { - pub source: Rect, - pub delay: Option, - pub rotation: f32, -} - -impl Frame { - pub fn new(source: Rect, delay: Option, rotation: f32) -> Frame { - Frame { - source, - delay, - rotation, - } - } -} - -impl Default for Frame { - fn default() -> Frame { - Frame::new(Rect::zero(), None, 0.0) - } -} +use crate::tileset::{Tile, Tileset}; #[derive(Debug, Clone, PartialEq)] pub struct Animation { - pub frames: Vec, + pub frames: Vec, pub timer: Instant, - pub current: Frame, -} - -impl Default for Animation { - fn default() -> Animation { - Animation::new(Frame::default()) - } + pub current: Tile, } impl Animation { - pub fn new(current: Frame) -> Animation { + pub fn new(frames: Vec) -> Animation { Animation { - current, + current: frames[0].clone(), timer: Instant::now(), - frames: Vec::new(), + frames, } } - pub fn give_frames(&mut self, frames: Vec) { + pub fn give_frames(&mut self, frames: Vec) { self.frames = frames; } pub fn update(&mut self) { if let Some(mut i) = self.frames.iter().position(|a| a == &self.current) { - if let Some(delay) = self.current.delay { + if let Some(delay) = self.current.property.delay { if self.timer.elapsed().as_millis() > delay as u128 { i = if i == self.frames.len() - 1 { 0 } else { i + 1 }; self.current = self.frames[i].clone(); self.timer = Instant::now(); } } - } else if !self.frames.is_empty() { + } else { self.current = self.frames[0].clone(); } } @@ -91,38 +61,34 @@ impl Animations { pub fn new(tileset: &Tileset) -> Animations { let mut available = HashMap::new(); - let mut idle = tileset.get_frame_by_entity_keyframe("player-top", 0); - idle.source.h += tileset - .get_frame_by_entity_keyframe("player-bottom", 0) - .source - .h; + let mut idle = tileset.get_tile_by_entity_keyframe("player-top", 0); + idle.source.h *= 2.0; - let mut animation = Animation::new(idle.clone()); - animation.give_frames(vec![idle.clone()]); + let animation = Animation::new(vec![idle.clone()]); available.insert(Action::IdleLeft, animation.clone()); - let mut moving = tileset.get_frame_by_entity_keyframe("player-top", 1); - moving.source.h += tileset - .get_frame_by_entity_keyframe("player-bottom", 1) - .source - .h; + let mut moving = tileset.get_tile_by_entity_keyframe("player-top", 1); + moving.source.h *= 2.0; - animation.give_frames(vec![idle.clone(), moving.clone()]); + let animation = Animation::new(vec![idle.clone(), moving.clone()]); available.insert(Action::MovingLeft, animation.clone()); available.insert(Action::MovingUpLeft, animation.clone()); available.insert(Action::MovingDownLeft, animation.clone()); - animation.give_frames(vec![flip(idle.clone())]); + idle.flip(); + moving.flip(); + + let animation = Animation::new(vec![idle.clone()]); available.insert(Action::IdleRight, animation.clone()); - animation.give_frames(vec![flip(idle.clone()), flip(moving.clone())]); + let animation = Animation::new(vec![idle.clone(), moving.clone()]); available.insert(Action::MovingRight, animation.clone()); available.insert(Action::MovingUpRight, animation.clone()); available.insert(Action::MovingDownRight, animation.clone()); Animations { available, - current: Animation::default(), + current: animation, } } @@ -137,14 +103,3 @@ impl Animations { self.current.draw(spritebatch, position) } } - -pub fn flip(frame: Frame) -> Frame { - let mut f = frame.clone(); - f.source.x *= -1.0; - f.source.x -= frame.source.w; - f -} - -pub fn convert_angle_to_rad(angle: f32) -> f32 { - angle * (PI / 180.0) -} diff --git a/src/camera.rs b/src/camera.rs index ed5a20a..07745e5 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -5,37 +5,36 @@ use crate::constants; pub struct Camera { pub draw: Point2, - window_height: f32, - window_width: f32, - map_height: f32, - map_width: f32, + window_dimensions: (f32, f32), + map_dimensions: (f32, f32), } impl Camera { - pub fn new(context: &mut Context, dimensions: (f32, f32)) -> Camera { + pub fn new(context: &mut Context, map_dimensions: (f32, f32)) -> Camera { Camera { draw: Point2::new(0.0, 0.0), - window_height: context.conf.window_mode.height, - window_width: context.conf.window_mode.width, - map_width: dimensions.0, - map_height: dimensions.1, + window_dimensions: ( + context.conf.window_mode.width, + context.conf.window_mode.height, + ), + map_dimensions, } } pub fn give_center(&mut self, center: Point2) { - self.draw.x = ((self.window_width / 2.0) - center.x) - (constants::TILE_WIDTH); - self.draw.y = ((self.window_height / 2.0) - center.y) - (constants::TILE_HEIGHT); + self.draw.x = ((self.window_dimensions.0 / 2.0) - center.x) - (constants::TILE_WIDTH); + self.draw.y = ((self.window_dimensions.1 / 2.0) - center.y) - (constants::TILE_HEIGHT); if self.draw.x > 0.0 { self.draw.x = 0.0; - } else if self.draw.x - self.window_width < -1.0 * self.map_width { - self.draw.x = -1.0 * (self.map_width - self.window_width); + } else if self.draw.x - self.window_dimensions.0 < -1.0 * self.map_dimensions.0 { + self.draw.x = -1.0 * (self.map_dimensions.0 - self.window_dimensions.0); } if self.draw.y > 0.0 { self.draw.y = 0.0; - } else if self.draw.y - self.window_height < -1.0 * self.map_height { - self.draw.y = -1.0 * (self.map_height - self.window_height); + } else if self.draw.y - self.window_dimensions.1 < -1.0 * self.map_dimensions.1 { + self.draw.y = -1.0 * (self.map_dimensions.1 - self.window_dimensions.1); } } } diff --git a/src/constants.rs b/src/constants.rs index 8767bb0..a1dd0eb 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -7,7 +7,7 @@ pub const ENTITY_SPEED: f32 = 2.5; pub const WANDER_DISTANCE: f32 = 150.0; pub const GOAL_DISTANCE: f32 = 6.0; -pub const FLIP_HORIZONTAL_FLAG: usize = 0x8000_0000; -pub const FLIP_VERTICAL_FLAG: usize = 0x4000_0000; -pub const FLIP_DIAGONAL_FLAG: usize = 0x2000_0000; -pub const ALL_FLIP_FLAGS: usize = FLIP_DIAGONAL_FLAG | FLIP_HORIZONTAL_FLAG | FLIP_VERTICAL_FLAG; +pub const FLIP_H: usize = 0x8000_0000; +pub const FLIP_V: usize = 0x4000_0000; +pub const FLIP_D: usize = 0x2000_0000; +pub const FLIP_A: usize = FLIP_D | FLIP_H | FLIP_V; diff --git a/src/layer.rs b/src/layer.rs index ef21059..2ae9dc2 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -1,41 +1,39 @@ use ggez::graphics::spritebatch::SpriteBatch; use crate::entity::Operable; -use crate::tile::Tile; +use crate::tile::Cell; use crate::tileset::Tileset; #[derive(Debug, Clone)] pub struct Layer { - pub tiles: Vec, - width: usize, - height: usize, + pub cells: Vec, + dimensions: (usize, usize), } impl Operable for Layer { fn update(&mut self) { - for tile in self.tiles.iter_mut() { - tile.update(); + for cell in self.cells.iter_mut() { + cell.update(); } } fn draw(&self, spritebatch: &mut SpriteBatch) { - for tile in self.tiles.iter() { - tile.draw(spritebatch); + for cell in self.cells.iter() { + cell.draw(spritebatch); } } } impl Layer { - pub fn new(text: &str, tileset: &Tileset, width: usize, height: usize) -> Layer { + pub fn new(text: &str, tileset: &Tileset, dimensions: (usize, usize)) -> Layer { Layer { - tiles: text + cells: text .replace("\n", "") .split(',') .enumerate() - .map(|(i, s)| Tile::new(s, i, tileset, width, height)) + .map(|(i, s)| Cell::new(s, i, tileset, dimensions)) .collect(), - width, - height, + dimensions, } } } diff --git a/src/map.rs b/src/map.rs index a3ddfb3..7042f58 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,18 +1,18 @@ use ggez::filesystem::File; use ggez::graphics::spritebatch::SpriteBatch; use ggez::nalgebra::Point2; +use std::collections::HashMap; use xml::reader::XmlEvent::Characters; use crate::constants; use crate::entity::Operable; use crate::layer::Layer; -use crate::tileset::Tileset; +use crate::tileset::{Tile, Tileset}; use crate::xmlelements::XMLElements; #[derive(Clone)] pub struct Map { - width: usize, - height: usize, + dimensions: (usize, usize), layers: Vec, spawns: Vec<(String, Point2)>, } @@ -35,23 +35,25 @@ impl Map { pub fn new(file: File, tileset: &Tileset) -> Map { let elements = XMLElements::new(file); - let width = elements - .get_element_attribute("map", "width") - .unwrap() - .parse() - .unwrap(); - let height = elements - .get_element_attribute("map", "height") - .unwrap() - .parse() - .unwrap(); + let dimensions = ( + elements + .get_element_attribute("map", "width") + .unwrap() + .parse() + .unwrap(), + elements + .get_element_attribute("map", "height") + .unwrap() + .parse() + .unwrap(), + ); let layers: Vec = elements .events .iter() .filter_map(|e| { if let Characters(text) = e { - Some(Layer::new(text, tileset, width, height)) + Some(Layer::new(text, tileset, dimensions)) } else { None } @@ -62,23 +64,22 @@ impl Map { Map { layers, - width, - height, + dimensions, spawns, } } fn get_spawn_points( layers: &[Layer], - spawn_tiles: Vec<(String, usize)>, + spawn_tiles: HashMap, ) -> Vec<(String, Point2)> { let mut spawn_points = Vec::new(); for layer in layers.iter() { - for tile in layer.tiles.iter() { - for spawn_tile in spawn_tiles.iter() { - if spawn_tile.1 == tile.id { - spawn_points.push((spawn_tile.0.clone(), tile.destination)); + for cell in layer.cells.iter() { + for (id, tile) in spawn_tiles.iter() { + if id == &cell.id { + spawn_points.push((tile.property.spawn.clone().unwrap(), cell.destination)); } } } @@ -93,8 +94,8 @@ impl Map { pub fn get_dimensions(&self) -> (f32, f32) { ( - (constants::TILE_WIDTH * constants::TILE_SCALE) * self.width as f32, - (constants::TILE_HEIGHT * constants::TILE_SCALE) * self.height as f32, + (constants::TILE_WIDTH * constants::TILE_SCALE) * self.dimensions.0 as f32, + (constants::TILE_HEIGHT * constants::TILE_SCALE) * self.dimensions.1 as f32, ) } } diff --git a/src/property.rs b/src/property.rs index fb4e912..b57d54c 100644 --- a/src/property.rs +++ b/src/property.rs @@ -2,10 +2,10 @@ use xml::reader::XmlEvent; use crate::xmlelements::XMLElements; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Property { - pub tile_id: usize, pub entity: Option, + pub rotation: f32, pub keyframe: Option, pub delay: Option, pub spawn: Option, @@ -13,7 +13,7 @@ pub struct Property { } impl Property { - pub fn new(tile_id: usize, property_elements: Vec) -> Property { + pub fn new(property_elements: Vec) -> Property { let entity = match XMLElements::get_attribute_value(&property_elements, "entity") { Ok(entity) => entity.parse().ok(), Err(_) => None, @@ -33,7 +33,7 @@ impl Property { }; Property { - tile_id, + rotation: 0.0, entity, keyframe, delay, @@ -42,3 +42,16 @@ impl Property { } } } + +impl Default for Property { + fn default() -> Property { + Property { + rotation: 0.0, + entity: None, + keyframe: None, + delay: None, + spawn: None, + visible: None, + } + } +} diff --git a/src/state.rs b/src/state.rs index b705fd4..db72d10 100644 --- a/src/state.rs +++ b/src/state.rs @@ -72,6 +72,10 @@ impl EventHandler for State { Ok(()) } + fn key_up_event(&mut self, _: &mut Context, keycode: KeyCode, _: KeyMods) { + self.player.give_key_up(keycode) + } + fn key_down_event( &mut self, context: &mut Context, @@ -86,8 +90,4 @@ impl EventHandler for State { } } } - - fn key_up_event(&mut self, _: &mut Context, keycode: KeyCode, _: KeyMods) { - self.player.give_key_up(keycode) - } } diff --git a/src/tile.rs b/src/tile.rs index b00f55e..13d095f 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -1,52 +1,33 @@ use ggez::graphics::spritebatch::SpriteBatch; use ggez::nalgebra::Point2; -use crate::animations::{convert_angle_to_rad, flip, Animation, Frame}; +use crate::animations::Animation; use crate::constants; use crate::entity::Operable; use crate::tileset::Tileset; #[derive(Debug, Clone)] -pub struct Tile { +pub struct Cell { pub id: usize, pub animation: Animation, pub destination: Point2, } -impl Operable for Tile { +impl Operable for Cell { fn update(&mut self) { self.animation.update(); } fn draw(&self, spritebatch: &mut SpriteBatch) { self.animation.draw(spritebatch, self.destination); - /* - DrawParam::default() - .src(self.animation.current.source) - .dest(self.destination) - .offset(Point2::new(0.5, 0.5)) - //.rotation(self.rotation) - .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE)), - ); - */ } } -impl Tile { - pub fn new(text: &str, i: usize, tileset: &Tileset, width: usize, height: usize) -> Tile { +impl Cell { + pub fn new(text: &str, i: usize, tileset: &Tileset, dimensions: (usize, usize)) -> Cell { let id = text.parse::().unwrap(); /* - let flip_d = (id & constants::FLIP_DIAGONAL_FLAG) == constants::FLIP_DIAGONAL_FLAG; - let flip_h = (id & constants::FLIP_HORIZONTAL_FLAG) == constants::FLIP_HORIZONTAL_FLAG; - let flip_v = (id & constants::FLIP_VERTICAL_FLAG) == constants::FLIP_VERTICAL_FLAG; - - let id = if flip_h | flip_v | flip_d { - id & !constants::ALL_FLIP_FLAGS - } else { - id - }; - let (source, rotation) = match (flip_d, flip_h, flip_v) { (true, true, true) => (flip(tileset.get(id)), convert_angle_to_rad(90.0)), (true, true, false) => (tileset.get(id), convert_angle_to_rad(90.0)), @@ -60,8 +41,8 @@ impl Tile { }; */ - let x = i as f32 % width as f32; - let y = (i as f32 / height as f32).floor(); + let x = i as f32 % dimensions.0 as f32; + let y = (i as f32 / dimensions.1 as f32).floor(); //let offset = (constants::TILE_WIDTH / 2.0) * constants::TILE_SCALE; let destination = Point2::new( @@ -69,14 +50,7 @@ impl Tile { constants::TILE_HEIGHT * constants::TILE_SCALE * y, //+ offset, ); - //let mut animation = Animation::new(Frame::new(source, None, rotation)); - /* - let frame = tileset.get_frame(id); - let mut animation = Animation::default(); - animation.give_frames(tileset.get_frames(id)); - */ - - Tile { + Cell { id, animation: tileset.get_animation(id), destination, diff --git a/src/tileset.rs b/src/tileset.rs index 70095b8..f576e08 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -1,15 +1,45 @@ use ggez::filesystem::File; use ggez::graphics::Rect; use std::collections::HashMap; +use std::f32::consts::PI; -use crate::animations::{Animation, Frame}; -use crate::constants; +use crate::animations::Animation; +use crate::constants::{self, FLIP_A, FLIP_D, FLIP_H, FLIP_V}; use crate::property::Property; use crate::xmlelements::XMLElements; +#[derive(Clone, Debug, PartialEq)] +pub struct Tile { + pub source: Rect, + pub property: Property, +} + +impl Tile { + pub fn new(source: Rect, property: Property) -> Tile { + Tile { source, property } + } + + pub fn flip(&mut self) { + self.source.x *= -1.0; + self.source.x -= self.source.w; + } +} + +fn flip(tile: Tile) -> Tile { + let mut t = tile.clone(); + t.source.x *= -1.0; + t.source.x -= t.source.w; + t +} + +impl Default for Tile { + fn default() -> Tile { + Tile::new(Rect::zero(), Property::default()) + } +} + pub struct Tileset { - tiles: HashMap, - properties: Vec, + tiles: HashMap, } impl Tileset { @@ -30,96 +60,104 @@ impl Tileset { let rows = height / (constants::TILE_HEIGHT as usize); let mut tiles = HashMap::new(); - tiles.insert(0, Frame::default()); + tiles.insert(0, Tile::default()); let w = 1.0 / columns as f32; let h = 1.0 / rows as f32; - let mut key = 1; + let mut id = 1; for r in 0..rows { for c in 0..columns { let x = c as f32 / columns as f32; let y = r as f32 / rows as f32; - tiles.insert(key, Frame::new(Rect::new(x, y, w, h), None, 0.0)); - key += 1; - } - } - - let mut properties = Vec::new(); - - for tile_element in elements.get_elements("tile") { - let tile_id = XMLElements::get_attribute(&tile_element, "id") - .unwrap() - .parse::() - .unwrap() - + 1; - - let property_elements = elements.get_children(&tile_element, "property"); - properties.push(Property::new(tile_id, property_elements)); + let tile_element = elements.get_elements("tile").into_iter().find(|e| { + XMLElements::get_attribute(e, "id") + .unwrap() + .parse::() + .unwrap() + + 1 + == id + }); + + let property = match tile_element { + Some(tile_element) => { + Property::new(elements.get_children(&tile_element, "property")) + } + None => Property::default(), + }; + + tiles.insert(id, Tile::new(Rect::new(x, y, w, h), property)); + id += 1; + } } - let invisible: Vec = properties - .iter() - .filter(|p| p.visible == Some(false)) - .map(|p| p.tile_id) - .collect(); - - for i in invisible { - *tiles.get_mut(&i).unwrap() = Frame::default(); + for (id, tile) in tiles.clone().into_iter() { + for i in 1..8 { + let (new_id, new_tile) = match i { + 1 => ((id | FLIP_H), tile.clone()), + 2 => ((id | FLIP_V), flip(tile.clone())), + 3 => ((id | FLIP_D), tile.clone()), + 4 => ((id | FLIP_D | FLIP_H), tile.clone()), + 5 => ((id | FLIP_D | FLIP_V), tile.clone()), + 6 => ((id | FLIP_H | FLIP_V), tile.clone()), + 7 => ((id | FLIP_A), tile.clone()), + _ => (0, Tile::default()), + }; + + if new_id != 0 { + tiles.insert(new_id, new_tile); + } + } } - for tile in &tiles {} - - Tileset { tiles, properties } + Tileset { tiles } } - pub fn get_spawn_tiles(&self) -> Vec<(String, usize)> { - self.properties + pub fn get_spawn_tiles(&self) -> HashMap { + self.tiles .clone() .into_iter() - .filter(|p| p.spawn.is_some()) - .map(|p| (p.spawn.unwrap(), p.tile_id)) + .filter(|(_, t)| t.property.spawn.is_some()) .collect() } - /* - pub fn get_frames(&self, tile_id: usize) -> Vec { - if let Some(property) = self.properties.iter().find(|p| p.tile_id == tile_id) { - self.properties - .clone() - .into_iter() - .filter(|p| p.entity == property.entity && p.entity.is_some()) - .map(|p| Frame::new(*self.tiles.get(&p.tile_id).unwrap(), p.delay, 0.0)) - .collect() - } else { - Vec::new() - } - } - */ - pub fn get_animation(&self, tile_id: usize) -> Animation { - Animation::default() - } - - pub fn get_frame_by_entity_keyframe(&self, entity: &str, keyframe: usize) -> Frame { - let tile_id = &self - .properties + let first_tile = self + .tiles .iter() - .find(|p| p.entity == Some(entity.to_string()) && Some(keyframe) == p.keyframe) + .find(|(id, _)| id == &&tile_id) .unwrap() - .tile_id; + .1 + .clone(); + + if first_tile.property.entity.is_some() { + Animation::new( + self.tiles + .values() + .cloned() + .filter(|t| t.property.entity == first_tile.property.entity) + .collect(), + ) + } else { + Animation::new(vec![first_tile]) + } + } - /* - let delay = self - .properties + pub fn get_tile_by_entity_keyframe(&self, entity: &str, keyframe: usize) -> Tile { + let tile_id = self + .tiles .iter() - .find(|p| p.tile_id == *tile_id && p.delay.is_some()) + .find(|(_, t)| { + t.property.entity == Some(entity.to_string()) + && Some(keyframe) == t.property.keyframe + }) .unwrap() - .delay; - - Frame::new(*source, delay, 0.0) - */ + .0; self.tiles.get(tile_id).unwrap().clone() } } + +pub fn convert_angle_to_rad(angle: f32) -> f32 { + angle * (PI / 180.0) +} -- cgit v1.2.3