Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/assets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ mod gamemap;

pub use atlas::{Atlas, Frame};
pub use gamemap::{GameMap, Object, Tile};

#[cfg(test)]
pub use gamemap::{Behaviour, BehaviourType, Mob};
137 changes: 137 additions & 0 deletions src/world/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,140 @@ pub fn make_step(curr_state: &mut State, input_state: &InputSnapshot) {
mob.y += vec_move.1;
}
}

#[cfg(test)]
mod tests {
use super::State;
use crate::assets::GameMap;

use super::*;

#[test]
fn test_abs_vector_zero() {
assert_eq!(abs_vector((0.0, 0.0)), 0.0);
}

#[test]
fn test_abs_vector_nonzero() {
let len = abs_vector((3.0, 4.0));
assert!((len - 5.0).abs() < 1e-5);
}

#[test]
fn test_normalize_vector_basic() {
let n = normalize_vector((3.0, 4.0));
assert!(((n.0 * n.0 + n.1 * n.1).sqrt() - 1.0).abs() < 1e-5);
}

#[test]
fn test_normalize_vector_small_vector_returns_zero() {
let n = normalize_vector((0.01, 0.01));
assert_eq!(n, (0.0, 0.0));
}

fn make_test_state() -> State {
let game_map = GameMap::load("input.json").expect("failed to load game map for tests");

let mut state = State::new(&game_map);

state.player.x = 0.0;
state.player.y = 0.0;
state.player.x_speed = 0.0;
state.player.y_speed = 0.0;

if state.mobs.is_empty() {
state.mobs.push(crate::world::Unit {
x: 100.0,
y: 0.0,
x_speed: -0.5,
y_speed: 0.0,
..Default::default()
});
}

state
}

#[test]
fn test_player_moves_right() {
let mut state = make_test_state();

let input = crate::input::InputSnapshot {
up: false,
down: false,
left: false,
right: true,
escape: false,
};

make_step(&mut state, &input);

assert!((state.player.x - 0.75).abs() < 1e-5);
assert!((state.player.y - 0.0).abs() < 1e-5);
}

#[test]
fn test_player_moves_up_left_diagonal() {
let mut state = make_test_state();

let input = crate::input::InputSnapshot {
up: true,
down: false,
left: true,
right: false,
escape: false,
};

make_step(&mut state, &input);

let dx = state.player.x;
let dy = state.player.y;
let len = (dx * dx + dy * dy).sqrt();
assert!((len - 0.75).abs() < 1e-5);
assert!(dx < 0.0 && dy < 0.0);
}

#[test]
fn test_mob_moves_toward_player() {
let mut state = make_test_state();
state.mobs[0].x = 50.0;
state.mobs[0].y = 0.0;
state.mobs[0].x_speed = -0.5;
state.mobs[0].y_speed = 0.0;

let input = crate::input::InputSnapshot {
up: false,
down: false,
left: false,
right: false,
escape: false,
};

make_step(&mut state, &input);

assert!(state.mobs[0].x < 50.0);
assert!(state.mobs[0].y.abs() < 1e-3);
}

#[test]
fn test_collision_pushes_mob_back() {
let mut state = make_test_state();

state.mobs[0].x = 2.0;
state.mobs[0].y = 0.0;

let input = crate::input::InputSnapshot {
up: false,
down: false,
left: false,
right: false,
escape: false,
};

make_step(&mut state, &input);

let vec_from = (state.mobs[0].x - state.player.x, state.mobs[0].y - state.player.y);
let dist = (vec_from.0 * vec_from.0 + vec_from.1 * vec_from.1).sqrt();
assert!((dist - 10.0).abs() < 1e-3);
}
}
106 changes: 106 additions & 0 deletions src/world/initiator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,109 @@ pub fn get_visible_objects(cur_state: &State, camera: &Camera) -> Vec<Unit> {

units.into_iter().filter(|mob| camera.is_visible(mob.x, mob.y)).collect()
}

#[cfg(test)]
mod visible_objects_tests {
use super::*;

#[derive(Clone)]
struct DummyUnit {
x: f32,
y: f32,
x_speed: f32,
y_speed: f32,
}

#[derive(Clone)]
struct DummyState {
player: DummyUnit,
mobs: Vec<DummyUnit>,
}

impl DummyState {
fn to_real_state(&self) -> State {
State {
player: Unit {
x: self.player.x,
y: self.player.y,
x_speed: self.player.x_speed,
y_speed: self.player.y_speed,
},
mobs: self
.mobs
.iter()
.map(|m| Unit { x: m.x, y: m.y, x_speed: m.x_speed, y_speed: m.y_speed })
.collect(),
}
}
}

#[test]
fn test_get_visible_objects_player_included() {
let dummy_state = DummyState {
player: DummyUnit { x: 0.0, y: 0.0, x_speed: 0.0, y_speed: 0.0 },
mobs: vec![],
};
let state = dummy_state.to_real_state();

let camera = Camera::new(0.0, 0.0, 800, 600);
let visible = get_visible_objects(&state, &camera);

assert_eq!(visible.len(), 1);
assert_eq!(visible[0].x, state.player.x);
assert_eq!(visible[0].y, state.player.y);
}

#[test]
fn test_get_visible_objects_mobs_visible() {
let dummy_state = DummyState {
player: DummyUnit { x: 0.0, y: 0.0, x_speed: 0.0, y_speed: 0.0 },
mobs: vec![
DummyUnit { x: 10.0, y: 10.0, x_speed: 0.0, y_speed: 0.0 },
DummyUnit { x: 1000.0, y: 1000.0, x_speed: 0.0, y_speed: 0.0 },
],
};
let state = dummy_state.to_real_state();
let camera = Camera::new(0.0, 0.0, 50, 50);

let visible = get_visible_objects(&state, &camera);
assert_eq!(visible.len(), 2);
assert_eq!(visible[1].x, 10.0);
assert_eq!(visible[1].y, 10.0);
}

#[test]
fn test_get_visible_objects_mobs_outside_not_included() {
let dummy_state = DummyState {
player: DummyUnit { x: 0.0, y: 0.0, x_speed: 0.0, y_speed: 0.0 },
mobs: vec![DummyUnit { x: 100.0, y: 100.0, x_speed: 0.0, y_speed: 0.0 }],
};
let state = dummy_state.to_real_state();
let camera = Camera::new(0.0, 0.0, 50, 50);

let visible = get_visible_objects(&state, &camera);
assert_eq!(visible.len(), 1);
assert_eq!(visible[0].x, state.player.x);
}

#[test]
fn test_get_visible_objects_multiple_mobs() {
let dummy_state = DummyState {
player: DummyUnit { x: 0.0, y: 0.0, x_speed: 0.0, y_speed: 0.0 },
mobs: vec![
DummyUnit { x: 5.0, y: 5.0, x_speed: 0.0, y_speed: 0.0 },
DummyUnit { x: 20.0, y: 20.0, x_speed: 0.0, y_speed: 0.0 },
DummyUnit { x: 100.0, y: 100.0, x_speed: 0.0, y_speed: 0.0 },
],
};
let state = dummy_state.to_real_state();
let camera = Camera::new(0.0, 0.0, 50, 50);

let visible = get_visible_objects(&state, &camera);
assert_eq!(visible.len(), 3);
let positions: Vec<_> = visible.iter().map(|u| (u.x, u.y)).collect();
assert!(positions.contains(&(0.0, 0.0)));
assert!(positions.contains(&(5.0, 5.0)));
assert!(positions.contains(&(20.0, 20.0)));
}
}
Loading