use specs::world::WorldExt;
use specs::{Component, NullStorage, VecStorage};
pub type World = ncollide2d::world::CollisionWorld<f32, specs::Entity>;
/// Register all the components with the world.
pub fn register(world: &mut specs::World) {
world.register::<Position>();
world.register::<Velocity>();
world.register::<Sprite>();
world.register::<Background>();
world.register::<Foreground>();
world.register::<Decoration>();
world.register::<Controlled>();
world.register::<Collision>();
world.register::<Blocking>();
}
/// The `Position` component represents (in world coordinates) a thing
/// that has a position in the world, measured from the top-left of
/// the thing.
#[derive(Component, Debug, Clone)]
#[storage(VecStorage)]
pub struct Position {
pub x: f32,
pub y: f32,
}
impl Position {
/// Convert a `Position` to a screen point
pub fn to_point(&self) -> mint::Point2<f32> {
mint::Point2 {
x: self.x * 3.0,
y: self.y * 3.0,
}
}
pub fn to_grid(&self) -> (i32, i32) {
((self.x / 24.0) as i32, (self.y / 24.0) as i32)
}
pub fn moved(&self, vel: &Velocity) -> Position {
Position {
x: self.x + vel.dx,
y: self.y + vel.dy,
}
}
}
/// The `Velocity` componenent is present on any entity that moves
/// through the world, and represents its rate of change per
/// time-unit.
#[derive(Component, Debug)]
#[storage(VecStorage)]
pub struct Velocity {
pub dx: f32,
pub dy: f32,
}
/// The `Sprite` components represents the current display location of
/// a sprite in the spritesheet.
#[derive(Component, Debug)]
#[storage(VecStorage)]
pub struct Sprite {
pub u: u8,
pub v: u8,
}
impl Sprite {
/// Convert a `Sprite` into the rectangle that specifies the
/// sprite location on the spritesheet
pub fn to_rect(&self) -> ggez::graphics::Rect {
ggez::graphics::Rect {
x: (1.0 / 32.0) * self.u as f32,
y: (1.0 / 32.0) * self.v as f32,
w: 1.0 / 32.0,
h: 1.0 / 32.0,
}
}
}
/// A drawing-phase component: represents tiles that appear in the
/// background of everything.
#[derive(Component, Default, Debug)]
#[storage(NullStorage)]
pub struct Background;
/// A drawing-phase component: represents tiles which appear in the
/// foreground, possibly entities.
#[derive(Component, Default, Debug)]
#[storage(NullStorage)]
pub struct Foreground;
/// A drawing-phase component: represents tiles which appear on top of
/// everything else, such as the tops of trees or roofs of houses.
#[derive(Component, Default, Debug)]
#[storage(NullStorage)]
pub struct Decoration;
/// A component that represents entities which are controlled by the
/// keyboard.
#[derive(Component, Default, Debug)]
#[storage(NullStorage)]
pub struct Controlled;
/// A component that represents entities which can collide with other
/// things.
#[derive(Component, Debug)]
#[storage(VecStorage)]
pub struct Collision {
pub has_collision: bool,
}
/// A component which represents things which have a collision shape
/// in the world
#[derive(Component)]
#[storage(VecStorage)]
pub struct Blocking {
pub handle: ncollide2d::pipeline::CollisionObjectSlabHandle,
}
impl Blocking {
/// create a `Blocking` component for an entity given a specified shape
pub fn new_shape<S>(e: specs::Entity, w: &mut World, volume: S) -> Blocking
where
S: ncollide2d::shape::Shape<f32>,
{
let (handle, _) = w.add(
nalgebra::geometry::Isometry::identity(),
ncollide2d::shape::ShapeHandle::new(volume),
ncollide2d::pipeline::CollisionGroups::new(),
ncollide2d::pipeline::object::GeometricQueryType::Proximity(0.0),
e,
);
Blocking { handle }
}
/// create an 11pxx11px box for an entity
pub fn new_box(e: specs::Entity, w: &mut World) -> Blocking {
Blocking::new_shape(
e,
w,
ncollide2d::shape::Cuboid::new(nalgebra::Vector2::new(11.0, 11.0)),
)
}
/// create a 11px ball for an entity
pub fn new_ball(e: specs::Entity, w: &mut World) -> Blocking {
Blocking::new_shape(e, w, ncollide2d::shape::Ball::new(11.0))
}
}