summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/animation.rs81
-rw-r--r--src/entity.rs101
-rw-r--r--src/lib.rs2
-rw-r--r--src/npc.rs92
-rw-r--r--src/player.rs225
-rw-r--r--src/state.rs19
6 files changed, 289 insertions, 231 deletions
diff --git a/src/animation.rs b/src/animation.rs
new file mode 100644
index 0000000..24932b2
--- /dev/null
+++ b/src/animation.rs
@@ -0,0 +1,81 @@
+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)]
+pub struct Animation {
+ pub animation: Vec<(usize, Rect)>,
+ pub animations: HashMap<Action, Vec<(usize, Rect)>>,
+ pub timer: Instant,
+ pub source: Rect,
+}
+
+impl Animation {
+ pub fn new(tileset: &Tileset) -> Animation {
+ let mut animations = HashMap::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)]);
+
+ let mut moving = tileset.get_tile_by_entity_keyframe("player-top", 1);
+ moving.h += tileset.get_tile_by_entity_keyframe("player-bottom", 1).h;
+
+ 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)]);
+
+ source = flip(source);
+ moving = flip(moving);
+
+ animations.insert(Action::IdleRight, vec![(1, source)]);
+
+ 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)]);
+
+ Animation {
+ animations,
+ source,
+ timer: Instant::now(),
+ animation: Vec::new(),
+ }
+ }
+
+ 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;
+ }
+}
+
+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)
+ }
+ } 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 flip(rect: Rect) -> Rect {
+ let mut r = rect;
+ r.x *= -1.0;
+ r.x -= rect.w;
+ r
+}
diff --git a/src/entity.rs b/src/entity.rs
index 1c0aa35..8086b77 100644
--- a/src/entity.rs
+++ b/src/entity.rs
@@ -1,91 +1,40 @@
-use ggez::graphics::{spritebatch::SpriteBatch, DrawParam, Rect};
-use ggez::nalgebra::{distance, Point2, Vector2};
-use std::time::Instant;
+use ggez::graphics::spritebatch::SpriteBatch;
+use ggez::nalgebra::Point2;
-use crate::constants;
-use crate::map::Map;
-use crate::math::random_nearby_point;
-use crate::tileset::Tileset;
+pub trait Operable {
+ fn update(&mut self);
+ fn draw(&self, spritebatch: &mut SpriteBatch);
+}
#[derive(Clone)]
pub struct Entity {
- behavior: Behavior,
- position: Point2<f32>,
- source: Rect,
- spawn: Point2<f32>,
+ pub position: Point2<f32>,
+ pub spawn: Point2<f32>,
+ pub action: Action,
+ pub map_dimensions: (f32, f32),
}
impl Entity {
- pub fn new(tileset: &Tileset, spawn: Point2<f32>) -> Entity {
- let mut source = tileset.get_tile_by_entity_keyframe("player-top", 0);
- source.h += tileset.get_tile_by_entity_keyframe("player-bottom", 0).h;
-
+ pub fn new(spawn: Point2<f32>, map_dimensions: (f32, f32)) -> Entity {
Entity {
spawn,
- source,
+ action: Action::IdleLeft,
position: spawn,
- behavior: Behavior::Wandering(None),
- }
- }
-
- pub fn update(&mut self) {
- match self.behavior {
- Behavior::Wandering(destination) => self.wandering(destination),
- Behavior::Waiting(time) => (),
- }
- }
-
- pub fn wandering(&mut self, destination: Option<Point2<f32>>) {
- match destination {
- Some(destination) => {
- if distance(&self.position, &destination) < constants::GOAL_DISTANCE {
- self.behavior = Behavior::Waiting(Instant::now())
- } else {
- if self.position.x < destination.x {
- self.position.x += constants::ENTITY_SPEED;
- } else {
- self.position.x -= constants::ENTITY_SPEED;
- }
- if self.position.y < destination.y {
- self.position.y += constants::ENTITY_SPEED;
- } else {
- self.position.y -= constants::ENTITY_SPEED;
- }
- }
- }
- None => {
- self.behavior = Behavior::Wandering(Some(random_nearby_point(
- self.spawn,
- constants::WANDER_DISTANCE,
- )))
- }
- }
- }
-
- pub fn waiting(&mut self) {}
-
- pub fn draw(&self, spritebatch: &mut SpriteBatch) {
- let draw_param = DrawParam::default()
- .src(self.source)
- .dest(self.position)
- .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE));
-
- spritebatch.add(draw_param);
- }
-
- pub fn build_entities(tileset: &Tileset, map: &Map) -> Vec<Entity> {
- let mut entities = Vec::new();
-
- for (_name, position) in map.get_spawns() {
- entities.push(Entity::new(tileset, position));
+ map_dimensions,
}
-
- entities
}
}
-#[derive(Clone)]
-enum Behavior {
- Waiting(Instant),
- Wandering(Option<Point2<f32>>),
+#[derive(Clone, Hash, Eq, PartialEq)]
+pub enum Action {
+ IdleLeft,
+ IdleRight,
+ MovingUp,
+ MovingDown,
+ MovingLeft,
+ MovingRight,
+ MovingUpLeft,
+ MovingUpRight,
+ MovingDownLeft,
+ MovingDownRight,
}
diff --git a/src/lib.rs b/src/lib.rs
index 835c82e..14c74d1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,9 +1,11 @@
+pub mod animation;
pub mod camera;
pub mod constants;
pub mod entity;
pub mod layer;
pub mod map;
pub mod math;
+pub mod npc;
pub mod player;
pub mod property;
pub mod state;
diff --git a/src/npc.rs b/src/npc.rs
new file mode 100644
index 0000000..96cb489
--- /dev/null
+++ b/src/npc.rs
@@ -0,0 +1,92 @@
+use ggez::graphics::{spritebatch::SpriteBatch, DrawParam};
+use ggez::nalgebra::{/*distance,*/ Point2, Vector2};
+//use std::time::Instant;
+
+use crate::animation::Animation;
+use crate::constants;
+use crate::entity::{Entity, Operable};
+use crate::map::Map;
+use crate::tileset::Tileset;
+
+#[derive(Clone)]
+pub struct NPC {
+ entity: Entity,
+ behavior: Behavior,
+ animation: Animation,
+}
+
+impl Operable for NPC {
+ fn draw(&self, spritebatch: &mut SpriteBatch) {
+ spritebatch.add(
+ DrawParam::default()
+ .src(self.animation.source)
+ .dest(self.entity.position)
+ .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE)),
+ );
+ }
+
+ fn update(&mut self) {
+ /*
+ match self.behavior {
+ Behavior::Wandering(destination) => self.wandering(destination),
+ Behavior::Waiting(time) => (),
+ }
+ */
+ self.animation.update(&self.entity.action);
+ }
+}
+
+impl NPC {
+ pub fn new(tileset: &Tileset, spawn: Point2<f32>, map_dimensions: (f32, f32)) -> NPC {
+ NPC {
+ entity: Entity::new(spawn, map_dimensions),
+ behavior: Behavior::Wandering(None),
+ animation: Animation::new(tileset),
+ }
+ }
+
+ /*fn wandering(&mut self, destination: Option<Point2<f32>>) {
+ match destination {
+ Some(destination) => {
+ if distance(&self.position, &destination) < constants::GOAL_DISTANCE {
+ self.behavior = Behavior::Waiting(Instant::now())
+ } else {
+ if self.position.x < destination.x {
+ self.position.x += constants::ENTITY_SPEED;
+ } else {
+ self.position.x -= constants::ENTITY_SPEED;
+ }
+ if self.position.y < destination.y {
+ self.position.y += constants::ENTITY_SPEED;
+ } else {
+ self.position.y -= constants::ENTITY_SPEED;
+ }
+ }
+ }
+ None => {
+ self.behavior = Behavior::Wandering(Some(random_nearby_point(
+ self.spawn,
+ constants::WANDER_DISTANCE,
+ )))
+ }
+ }
+ }*/
+
+ //fn waiting(&mut self) {}
+
+ pub fn build_npcs(tileset: &Tileset, map: &Map) -> Vec<NPC> {
+ let mut npcs = Vec::new();
+
+ for (_name, position) in map.get_spawns() {
+ npcs.push(NPC::new(tileset, position, map.get_dimensions()));
+ }
+
+ npcs
+ }
+}
+
+#[derive(Clone)]
+enum Behavior {
+ //Waiting(Instant),
+ Wandering(Option<Point2<f32>>),
+}
diff --git a/src/player.rs b/src/player.rs
index 6440587..ae43d80 100644
--- a/src/player.rs
+++ b/src/player.rs
@@ -1,206 +1,139 @@
use ggez::event::KeyCode;
-use ggez::graphics::{spritebatch::SpriteBatch, DrawParam, Rect};
+use ggez::graphics::{spritebatch::SpriteBatch, DrawParam};
use ggez::nalgebra::{Point2, Vector2};
-use std::collections::HashMap;
-use std::time::Instant;
+use crate::animation::Animation;
use crate::constants;
-use crate::math::{flip, next_source};
+use crate::entity::{Action, Entity, Operable};
use crate::tileset::Tileset;
pub struct Player {
- pub position: Point2<f32>,
- state: AnimationState,
- source: Rect,
- timer: Instant,
- animation: Vec<(usize, Rect)>,
- animations: HashMap<AnimationState, Vec<(usize, Rect)>>,
- map_height: f32,
- map_width: f32,
+ entity: Entity,
+ animation: Animation,
}
-impl Player {
- pub fn new(tileset: &Tileset, dimensions: (f32, f32)) -> Player {
- Player {
- position: Point2::new(0.0, 0.0),
- state: AnimationState::IdleLeft,
- source: Rect::zero(),
- timer: Instant::now(),
- animation: Vec::new(),
- animations: Player::build_animations(tileset),
- map_width: dimensions.0,
- map_height: dimensions.1,
- }
- }
-
- fn build_animations(tileset: &Tileset) -> HashMap<AnimationState, Vec<(usize, Rect)>> {
- let mut animations = HashMap::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(AnimationState::IdleLeft, vec![(1, source)]);
-
- let mut moving = tileset.get_tile_by_entity_keyframe("player-top", 1);
- moving.h += tileset.get_tile_by_entity_keyframe("player-bottom", 1).h;
-
- animations.insert(AnimationState::MovingLeft, vec![(100, source), (100, moving)]);
- animations.insert(
- AnimationState::MovingUpLeft,
- vec![(100, source), (100, moving)],
- );
- animations.insert(
- AnimationState::MovingDownLeft,
- vec![(100, source), (100, moving)],
- );
-
- source = flip(source);
- moving = flip(moving);
-
- animations.insert(AnimationState::IdleRight, vec![(1, source)]);
-
- animations.insert(AnimationState::MovingRight, vec![(100, source), (100, moving)]);
- animations.insert(
- AnimationState::MovingUpRight,
- vec![(100, source), (100, moving)],
+impl Operable for Player {
+ fn draw(&self, spritebatch: &mut SpriteBatch) {
+ spritebatch.add(
+ DrawParam::default()
+ .src(self.animation.source)
+ .dest(self.entity.position)
+ .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE)),
);
- animations.insert(
- AnimationState::MovingDownRight,
- vec![(100, source), (100, moving)],
- );
-
- animations
}
- pub fn draw(&self, spritebatch: &mut SpriteBatch) {
- let draw_param = DrawParam::default()
- .src(self.source)
- .dest(self.position)
- .scale(Vector2::new(constants::TILE_SCALE, constants::TILE_SCALE));
-
- spritebatch.add(draw_param);
+ fn update(&mut self) {
+ self.move_position();
+ self.animation.update(&self.entity.action);
}
+}
- pub fn update(&mut self) {
- self.move_position();
+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),
+ }
+ }
- self.animation = self
- .animations
- .get(&self.state)
- .cloned()
- .unwrap_or_default();
- let (source, timer) = next_source(self.source, &self.animation, self.timer);
- self.source = source;
- self.timer = timer;
+ pub fn get_position(&self) -> Point2<f32> {
+ self.entity.position
}
fn move_position(&mut self) {
- match self.state {
- AnimationState::MovingUp => self.position.y -= constants::PLAYER_SPEED,
- AnimationState::MovingUpLeft => {
- self.position.x -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
- self.position.y -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ match self.entity.action {
+ Action::MovingUp => self.entity.position.y -= constants::PLAYER_SPEED,
+ Action::MovingUpLeft => {
+ self.entity.position.x -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ self.entity.position.y -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
}
- AnimationState::MovingUpRight => {
- self.position.x += constants::PLAYER_SPEED / 2.0_f32.sqrt();
- self.position.y -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ Action::MovingUpRight => {
+ self.entity.position.x += constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ self.entity.position.y -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
}
- AnimationState::MovingLeft => self.position.x -= constants::PLAYER_SPEED,
- AnimationState::MovingDown => self.position.y += constants::PLAYER_SPEED,
- AnimationState::MovingDownLeft => {
- self.position.x -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
- self.position.y += constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ Action::MovingLeft => self.entity.position.x -= constants::PLAYER_SPEED,
+ Action::MovingDown => self.entity.position.y += constants::PLAYER_SPEED,
+ Action::MovingDownLeft => {
+ self.entity.position.x -= constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ self.entity.position.y += constants::PLAYER_SPEED / 2.0_f32.sqrt();
}
- AnimationState::MovingDownRight => {
- self.position.x += constants::PLAYER_SPEED / 2.0_f32.sqrt();
- self.position.y += constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ Action::MovingDownRight => {
+ self.entity.position.x += constants::PLAYER_SPEED / 2.0_f32.sqrt();
+ self.entity.position.y += constants::PLAYER_SPEED / 2.0_f32.sqrt();
}
- AnimationState::MovingRight => self.position.x += constants::PLAYER_SPEED,
- AnimationState::IdleLeft | AnimationState::IdleRight => (),
+ Action::MovingRight => self.entity.position.x += constants::PLAYER_SPEED,
+ Action::IdleLeft | Action::IdleRight => (),
}
let pixel_width = constants::TILE_WIDTH * constants::TILE_SCALE;
let pixel_height = constants::TILE_HEIGHT * constants::TILE_SCALE;
- if self.position.x < 0.0 {
- self.position.x = 0.0;
- } else if self.position.x + pixel_height > self.map_width {
- self.position.x = self.map_width - pixel_width;
+ if self.entity.position.x < 0.0 {
+ self.entity.position.x = 0.0;
+ } else if self.entity.position.x + pixel_height > self.entity.map_dimensions.0 {
+ self.entity.position.x = self.entity.map_dimensions.0 - pixel_width;
}
- if self.position.y < 0.0 {
- self.position.y = 0.0;
- } else if self.position.y + pixel_height > self.map_height {
- self.position.y = self.map_height - pixel_height;
+ if self.entity.position.y < 0.0 {
+ self.entity.position.y = 0.0;
+ } else if self.entity.position.y + pixel_height > self.entity.map_dimensions.1 {
+ self.entity.position.y = self.entity.map_dimensions.1 - pixel_height;
}
}
pub fn give_key_down(&mut self, keycode: KeyCode) {
- let original_state = self.state.clone();
+ let original_state = self.entity.action.clone();
- self.state = match keycode {
+ self.entity.action = match keycode {
KeyCode::W => match original_state {
- AnimationState::MovingLeft => AnimationState::MovingUpLeft,
- AnimationState::MovingRight => AnimationState::MovingUpRight,
- _ => AnimationState::MovingUp,
+ Action::MovingLeft => Action::MovingUpLeft,
+ Action::MovingRight => Action::MovingUpRight,
+ _ => Action::MovingUp,
},
KeyCode::A => match original_state {
- AnimationState::MovingUp => AnimationState::MovingUpLeft,
- AnimationState::MovingDown => AnimationState::MovingDownLeft,
- _ => AnimationState::MovingLeft,
+ Action::MovingUp => Action::MovingUpLeft,
+ Action::MovingDown => Action::MovingDownLeft,
+ _ => Action::MovingLeft,
},
KeyCode::S => match original_state {
- AnimationState::MovingLeft => AnimationState::MovingDownLeft,
- AnimationState::MovingRight => AnimationState::MovingDownRight,
- _ => AnimationState::MovingDown,
+ Action::MovingLeft => Action::MovingDownLeft,
+ Action::MovingRight => Action::MovingDownRight,
+ _ => Action::MovingDown,
},
KeyCode::D => match original_state {
- AnimationState::MovingUp => AnimationState::MovingUpRight,
- AnimationState::MovingDown => AnimationState::MovingDownRight,
- _ => AnimationState::MovingRight,
+ Action::MovingUp => Action::MovingUpRight,
+ Action::MovingDown => Action::MovingDownRight,
+ _ => Action::MovingRight,
},
_ => original_state,
}
}
pub fn give_key_up(&mut self, keycode: KeyCode) {
- let original_state = self.state.clone();
+ let original_state = self.entity.action.clone();
- self.state = match keycode {
+ self.entity.action = match keycode {
KeyCode::W => match original_state {
- AnimationState::MovingUpLeft => AnimationState::MovingLeft,
- AnimationState::MovingUpRight => AnimationState::MovingRight,
- _ => AnimationState::IdleLeft,
+ Action::MovingUpLeft => Action::MovingLeft,
+ Action::MovingUpRight => Action::MovingRight,
+ _ => Action::IdleLeft,
},
KeyCode::A => match original_state {
- AnimationState::MovingUpLeft => AnimationState::MovingUp,
- AnimationState::MovingDownLeft => AnimationState::MovingDown,
- _ => AnimationState::IdleLeft,
+ Action::MovingUpLeft => Action::MovingUp,
+ Action::MovingDownLeft => Action::MovingDown,
+ _ => Action::IdleLeft,
},
KeyCode::S => match original_state {
- AnimationState::MovingDownLeft => AnimationState::MovingLeft,
- AnimationState::MovingDownRight => AnimationState::MovingRight,
- _ => AnimationState::IdleRight,
+ Action::MovingDownLeft => Action::MovingLeft,
+ Action::MovingDownRight => Action::MovingRight,
+ _ => Action::IdleRight,
},
KeyCode::D => match original_state {
- AnimationState::MovingUpRight => AnimationState::MovingUp,
- AnimationState::MovingDownRight => AnimationState::MovingDown,
- _ => AnimationState::IdleRight,
+ Action::MovingUpRight => Action::MovingUp,
+ Action::MovingDownRight => Action::MovingDown,
+ _ => Action::IdleRight,
},
_ => original_state,
}
}
}
-
-#[derive(Clone, Hash, Eq, PartialEq)]
-enum AnimationState {
- IdleLeft,
- IdleRight,
- MovingUp,
- MovingDown,
- MovingLeft,
- MovingRight,
- MovingUpLeft,
- MovingUpRight,
- MovingDownLeft,
- MovingDownRight,
-}
diff --git a/src/state.rs b/src/state.rs
index a541a02..b705fd4 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -3,8 +3,9 @@ use ggez::graphics::{self, spritebatch::SpriteBatch, DrawParam, FilterMode, Imag
use ggez::{filesystem, Context, GameResult};
use crate::camera::Camera;
-use crate::entity::Entity;
+use crate::entity::Operable;
use crate::map::Map;
+use crate::npc::NPC;
use crate::player::Player;
use crate::tileset::Tileset;
@@ -13,7 +14,7 @@ pub struct State {
spritebatch: SpriteBatch,
camera: Camera,
player: Player,
- entities: Vec<Entity>,
+ npcs: Vec<NPC>,
}
impl State {
@@ -32,7 +33,7 @@ impl State {
spritebatch: SpriteBatch::new(image),
camera: Camera::new(context, map_dimensions),
player: Player::new(&tileset, map_dimensions),
- entities: Entity::build_entities(&tileset, &map),
+ npcs: NPC::build_npcs(&tileset, &map),
})
}
}
@@ -41,10 +42,11 @@ impl EventHandler for State {
fn update(&mut self, _context: &mut Context) -> GameResult {
self.map.update();
self.player.update();
- for entity in self.entities.iter_mut() {
- entity.update();
+ for npc in self.npcs.iter_mut() {
+ npc.update();
}
- self.camera.give_center(self.player.position);
+
+ self.camera.give_center(self.player.get_position());
Ok(())
}
@@ -53,9 +55,8 @@ impl EventHandler for State {
self.map.draw(&mut self.spritebatch);
self.player.draw(&mut self.spritebatch);
-
- for entity in &self.entities {
- entity.draw(&mut self.spritebatch);
+ for npc in self.npcs.iter_mut() {
+ npc.draw(&mut self.spritebatch);
}
graphics::draw(