diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/animation.rs | 144 | ||||
-rw-r--r-- | src/npc.rs | 10 | ||||
-rw-r--r-- | src/player.rs | 10 | ||||
-rw-r--r-- | src/tileset.rs | 29 |
4 files changed, 118 insertions, 75 deletions
diff --git a/src/animation.rs b/src/animation.rs index 24932b2..bc7e493 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -1,81 +1,117 @@ use ggez::graphics::Rect; use std::collections::HashMap; -use std::f32::consts::PI; use std::time::Instant; use crate::entity::Action; use crate::tileset::Tileset; -#[derive(Clone)] +#[derive(Clone, PartialEq)] +pub struct Frame { + pub source: Rect, + pub delay: Option<usize>, + pub rotation: f32, +} + +impl Frame { + pub fn new(source: Rect, delay: Option<usize>, rotation: f32) -> Frame { + Frame { + source, + delay, + rotation, + } + } +} + +#[derive(Clone, PartialEq)] pub struct Animation { - pub animation: Vec<(usize, Rect)>, - pub animations: HashMap<Action, Vec<(usize, Rect)>>, + pub frames: Vec<Frame>, pub timer: Instant, - pub source: Rect, + pub current: Frame, } impl Animation { - pub fn new(tileset: &Tileset) -> Animation { - let mut animations = HashMap::new(); + pub fn new() -> Animation { + Animation { + current: Frame::new(Rect::zero(), None, 0.0), + timer: Instant::now(), + frames: Vec::new(), + } + } - let mut source = tileset.get_tile_by_entity_keyframe("player-top", 0); - source.h += tileset.get_tile_by_entity_keyframe("player-bottom", 0).h; - animations.insert(Action::IdleLeft, vec![(1, source)]); + pub fn give_frames(&mut self, frames: Vec<Frame>) { + self.frames = frames; + } - let mut moving = tileset.get_tile_by_entity_keyframe("player-top", 1); - moving.h += tileset.get_tile_by_entity_keyframe("player-bottom", 1).h; + 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 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() { + self.current = self.frames[0].clone(); + } + } +} - animations.insert(Action::MovingLeft, vec![(100, source), (100, moving)]); - animations.insert(Action::MovingUpLeft, vec![(100, source), (100, moving)]); - animations.insert(Action::MovingDownLeft, vec![(100, source), (100, moving)]); +#[derive(Clone)] +pub struct Animations { + pub available: HashMap<Action, Animation>, + pub current: Animation, +} - source = flip(source); - moving = flip(moving); +impl Animations { + pub fn new(tileset: &Tileset) -> Animations { + let mut available = HashMap::new(); - animations.insert(Action::IdleRight, vec![(1, source)]); + 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; - animations.insert(Action::MovingRight, vec![(100, source), (100, moving)]); - animations.insert(Action::MovingUpRight, vec![(100, source), (100, moving)]); - animations.insert(Action::MovingDownRight, vec![(100, source), (100, moving)]); + let mut animation = Animation::new(); + animation.give_frames(vec![idle.clone()]); + available.insert(Action::IdleLeft, animation.clone()); - Animation { - animations, - source, - timer: Instant::now(), - animation: Vec::new(), - } - } + 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; - pub fn update(&mut self, action: &Action) { - self.animation = self.animations.get(&action).cloned().unwrap_or_default(); - let (source, timer) = next_source(self.source, &self.animation, self.timer); - self.source = source; - self.timer = timer; - } -} + animation.give_frames(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())]); + available.insert(Action::IdleRight, animation.clone()); -pub fn next_source(source: Rect, animation: &[(usize, Rect)], timer: Instant) -> (Rect, Instant) { - if let Some(mut i) = animation.iter().position(|a| a.1 == source) { - if timer.elapsed().as_millis() > animation[i].0 as u128 { - i = if i == animation.len() - 1 { 0 } else { i + 1 }; - (animation[i].1, Instant::now()) - } else { - (source, timer) + animation.give_frames(vec![flip(idle.clone()), flip(moving.clone())]); + available.insert(Action::MovingRight, animation.clone()); + available.insert(Action::MovingUpRight, animation.clone()); + available.insert(Action::MovingDownRight, animation.clone()); + + Animations { + available, + current: Animation::new(), } - } else if !animation.is_empty() { - (animation[0].1, timer) - } else { - (source, timer) } -} -pub fn convert_angle_to_rad(angle: f32) -> f32 { - angle * (PI / 180.0) + pub fn update(&mut self, action: &Action) { + let animation = self.available.get(&action).cloned().unwrap(); + self.current.give_frames(animation.frames); + self.current.update(); + } } -pub fn flip(rect: Rect) -> Rect { - let mut r = rect; - r.x *= -1.0; - r.x -= rect.w; - r +pub fn flip(frame: Frame) -> Frame { + let mut f = frame.clone(); + f.source.x *= -1.0; + f.source.x -= frame.source.w; + f } @@ -2,7 +2,7 @@ use ggez::graphics::{spritebatch::SpriteBatch, DrawParam}; use ggez::nalgebra::{/*distance,*/ Point2, Vector2}; //use std::time::Instant; -use crate::animation::Animation; +use crate::animation::Animations; use crate::constants; use crate::entity::{Entity, Operable}; use crate::map::Map; @@ -12,14 +12,14 @@ use crate::tileset::Tileset; pub struct NPC { entity: Entity, behavior: Behavior, - animation: Animation, + animations: Animations, } impl Operable for NPC { fn draw(&self, spritebatch: &mut SpriteBatch) { spritebatch.add( DrawParam::default() - .src(self.animation.source) + .src(self.animations.current.current.source) .dest(self.entity.position) .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE)), ); @@ -32,7 +32,7 @@ impl Operable for NPC { Behavior::Waiting(time) => (), } */ - self.animation.update(&self.entity.action); + self.animations.update(&self.entity.action); } } @@ -41,7 +41,7 @@ impl NPC { NPC { entity: Entity::new(spawn, map_dimensions), behavior: Behavior::Wandering(None), - animation: Animation::new(tileset), + animations: Animations::new(tileset), } } diff --git a/src/player.rs b/src/player.rs index ae43d80..2941934 100644 --- a/src/player.rs +++ b/src/player.rs @@ -2,21 +2,21 @@ use ggez::event::KeyCode; use ggez::graphics::{spritebatch::SpriteBatch, DrawParam}; use ggez::nalgebra::{Point2, Vector2}; -use crate::animation::Animation; +use crate::animation::Animations; use crate::constants; use crate::entity::{Action, Entity, Operable}; use crate::tileset::Tileset; pub struct Player { entity: Entity, - animation: Animation, + animations: Animations, } impl Operable for Player { fn draw(&self, spritebatch: &mut SpriteBatch) { spritebatch.add( DrawParam::default() - .src(self.animation.source) + .src(self.animations.current.current.source) .dest(self.entity.position) .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE)), ); @@ -24,7 +24,7 @@ impl Operable for Player { fn update(&mut self) { self.move_position(); - self.animation.update(&self.entity.action); + self.animations.update(&self.entity.action); } } @@ -32,7 +32,7 @@ impl Player { pub fn new(tileset: &Tileset, dimensions: (f32, f32)) -> Player { Player { entity: Entity::new(Point2::new(0.0, 0.0), dimensions), - animation: Animation::new(tileset), + animations: Animations::new(tileset), } } diff --git a/src/tileset.rs b/src/tileset.rs index 0595186..975398d 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -2,6 +2,7 @@ use ggez::filesystem::File; use ggez::graphics::Rect; use std::collections::HashMap; +use crate::animation::Frame; use crate::constants; use crate::property::Property; use crate::xmlelements::XMLElements; @@ -96,17 +97,23 @@ impl Tileset { } } - pub fn get_tile_by_entity_keyframe(&self, entity: &str, keyframe: usize) -> Rect { - *self - .tiles - .get( - &self - .properties - .iter() - .find(|p| p.entity == Some(entity.to_string()) && Some(keyframe) == p.keyframe) - .unwrap() - .tile_id, - ) + pub fn get_frame_by_entity_keyframe(&self, entity: &str, keyframe: usize) -> Frame { + let tile_id = &self + .properties + .iter() + .find(|p| p.entity == Some(entity.to_string()) && Some(keyframe) == p.keyframe) + .unwrap() + .tile_id; + + let delay = self + .properties + .iter() + .find(|p| p.tile_id == *tile_id && p.delay.is_some()) .unwrap() + .delay; + + let source = self.tiles.get(tile_id).unwrap(); + + Frame::new(*source, delay, 0.0) } } |