...
 
Commits (9)
[submodule "tiny_ecs"]
path = tiny_ecs
url = https://gitlab.com/ljcode/tiny_ecs.git
[submodule "vec2d"]
path = vec2d
url = https://gitlab.com/ljcode/vec2d.git
[submodule "cyclone-rs"]
path = cyclone-rs
url = https://gitlab.com/ljcode/cyclone-rs.git
max_width = 100
max_width =80
comment_width = 80
wrap_comments = false
......
[workspace]
members = ["./game", "./tiny_ecs"]
[profile.release]
lto = true
opt-level = 3
debuginfo = 0
panic = "abort"
[package]
name = "rust_game"
version = "0.1.1"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke Jones <luke.nukem.jones@gmail.com>"]
edition = "2018"
[dependencies]
rand = "*"
num-traits = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tiny_ecs = { path = "tiny_ecs" }
[dependencies.sdl2]
version = "0.32"
default-features = false
features = ["image"]
[[bin]]
name = "game"
path = "src/main.rs"
[features]
default = []
lag =[]
Subproject commit 1eba4546b3e159dfa9ffb182428a64a8fb3898db
[package]
name = "rs_game_framework"
version = "0.1.1"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke Jones <luke.nukem.jones@gmail.com>"]
edition = "2018"
[dependencies]
rand = "*"
num-traits = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tiny_ecs = { path = "../tiny_ecs" }
[dependencies.sdl2]
version = "0.32"
default-features = false
features = ["image"]
[[bin]]
name = "game"
path = "src/main.rs"
[features]
default = []
lag =[]
This diff is collapsed.
......@@ -12,14 +12,16 @@ use crate::vec2d::Vec2d;
/// Create a Player entity at the X,Y coords in the World
pub fn player(
world: &mut World, x: u32, y: u32, sprite_id: &str, sprite_sheets: &SpriteSheets,
world: &mut World, x: u32, y: u32, sprite_id: &str,
sprite_sheets: &SpriteSheets,
) -> u32 {
if let Ok(ent) = world.entities.get_free_slot() {
let pos = world.from_tile(x, y);
world.player = ent;
world
.entities
.add_part::<Position>(ent, Position::new(pos.x as f32, pos.y as f32, 0.0));
world.entities.add_part::<Position>(
ent,
Position::new(pos.x as f32, pos.y as f32, 0.0),
);
world
.entities
......@@ -27,9 +29,10 @@ pub fn player(
let tx = sprite_sheets.get_ref(sprite_id);
let rec = Rect::new(0, 0, tx.width(), tx.height());
world
.entities
.add_part::<AABB>(ent, AABB::new(pos.x, pos.y, tx.width(), tx.height()));
world.entities.add_part::<AABB>(
ent,
AABB::new(pos.x, pos.y, tx.width(), tx.height()),
);
world
.entities
......@@ -41,9 +44,10 @@ pub fn player(
let mut binds = Bindings::new();
binds.initialize();
world
.entities
.add_part::<InputTypes>(ent, InputTypes::Player(PlayerInput::new(binds)));
world.entities.add_part::<InputTypes>(
ent,
InputTypes::Player(PlayerInput::new(binds)),
);
world
.entities
......@@ -60,12 +64,15 @@ pub fn player(
/// Creates a background tile at X,Y in the World - requires a `sprite_id` and `Rect` for size,
/// the size of the sprite and rectangle don't need to match, the sprite will be drawn to the
/// size of the `Rect`.
pub fn background_tile(world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect) {
pub fn background_tile(
world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect,
) {
if let Ok(ent) = world.entities.get_free_slot() {
let pos = world.from_tile(x, y);
world
.entities
.add_part::<Position>(ent, Position::new(pos.x as f32, pos.y as f32, 0.0));
world.entities.add_part::<Position>(
ent,
Position::new(pos.x as f32, pos.y as f32, 0.0),
);
world
.entities
.add_part::<Sprite>(ent, Sprite::new(sprite_id, rec));
......@@ -80,15 +87,19 @@ pub fn background_tile(world: &mut World, x: u32, y: u32, sprite_id: &str, rec:
/// the size of the sprite and rectangle don't need to match, the sprite will be drawn to the
/// size of the `Rect` and the `Rect` will also function as a collider AABB. The tile can
/// have physics properties
pub fn level_tile(world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect) {
pub fn level_tile(
world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect,
) {
if let Ok(ent) = world.entities.get_free_slot() {
let pos = world.from_tile(x, y);
world
.entities
.add_part::<Position>(ent, Position::new(pos.x as f32, pos.y as f32, 0.0));
world
.entities
.add_part::<AABB>(ent, AABB::new(pos.x, pos.y, rec.width(), rec.height()));
world.entities.add_part::<Position>(
ent,
Position::new(pos.x as f32, pos.y as f32, 0.0),
);
world.entities.add_part::<AABB>(
ent,
AABB::new(pos.x, pos.y, rec.width(), rec.height()),
);
world
.entities
.add_part::<Sprite>(ent, Sprite::new(sprite_id, rec));
......@@ -109,15 +120,19 @@ pub fn level_tile(world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect)
/// Requires a `sprite_id` and `Rect` for size, the size of the sprite and rectangle don't need
/// to match, the sprite will be drawn to the size of the `Rect` and the `Rect` will also
/// function as a collider AABB
pub fn object_tile(world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect) {
pub fn object_tile(
world: &mut World, x: u32, y: u32, sprite_id: &str, rec: Rect,
) {
if let Ok(ent) = world.entities.get_free_slot() {
let pos = world.from_tile(x, y);
world
.entities
.add_part::<Position>(ent, Position::new(pos.x as f32, pos.y as f32, 0.0));
world
.entities
.add_part::<AABB>(ent, AABB::new(pos.x, pos.y, rec.width(), rec.height()));
world.entities.add_part::<Position>(
ent,
Position::new(pos.x as f32, pos.y as f32, 0.0),
);
world.entities.add_part::<AABB>(
ent,
AABB::new(pos.x, pos.y, rec.width(), rec.height()),
);
world
.entities
.add_part::<Sprite>(ent, Sprite::new(sprite_id, rec));
......
......@@ -73,7 +73,9 @@ impl Circle {
/// Basic Physics Component
#[derive(Clone)]
pub struct Physics {
pub acceleration: Vec2d<f32>,
pub position: Vec2d<f32>,
pub velocity: Vec2d<f32>,
pub rotation: Vec2d<f32>,
pub mass: f32,
pub inv_mass: f32,
pub force: Vec2d<f32>,
......@@ -81,13 +83,16 @@ pub struct Physics {
pub restitution: f32,
pub friction: f32,
pub force_accum: Vec2d<f32>,
pub acceleration: Vec2d<f32>,
pub damping: f32,
}
impl Physics {
pub fn new(mass: f32, restitution: f32, damping: f32) -> Physics {
let inv_mass = if mass == 0.0 { 0.0 } else { 1.0 / mass };
Physics {
acceleration: Vec2d::new(0.0, GRAVITY),
position: Vec2d::new(0.0, 0.0),
velocity: Vec2d::new(0.0, 0.0),
rotation: Vec2d::new(0.0, 0.0),
mass: mass,
inv_mass: inv_mass,
force: Vec2d::new(0.0, 0.0),
......@@ -95,6 +100,7 @@ impl Physics {
restitution: restitution,
friction: 0.5,
force_accum: Vec2d::new(0.0, 0.0),
acceleration: Vec2d::new(0.0, GRAVITY),
damping: damping,
}
}
......@@ -190,8 +196,8 @@ pub struct Animation {
}
impl Animation {
pub fn new(
x: i32, y: i32, w: u32, h: u32, speed: u32, per_anim: u32, columns: u32,
keys: HashMap<String, u32>, sprite_id: String,
x: i32, y: i32, w: u32, h: u32, speed: u32, per_anim: u32,
columns: u32, keys: HashMap<String, u32>, sprite_id: String,
) -> Animation {
Animation {
counter: 0,
......@@ -307,7 +313,8 @@ pub struct WeaponRanged {
}
impl WeaponRanged {
pub fn new(
n: String, r: u32, d: u32, s: u32, sp: u32, ma: u32, ca: u32, rs: u32, sc: u32,
n: String, r: u32, d: u32, s: u32, sp: u32, ma: u32, ca: u32, rs: u32,
sc: u32,
) -> WeaponRanged {
WeaponRanged {
name: n,
......
// update forces
// integrate entities
// generate collision contacts
// resolve contacts
use crate::components::*;
use std::f32;
use tiny_ecs::Entities;
/// Set in conjunction with `physics.damping` expectations
///
/// If `DRAGCOEFICIENT` is high then `physics.damping` will
/// have much less impact. If set low, then damping will play
/// a much larger role in the physics feel per `Physics` part.
/// In practice it can either be balancing between both or
/// one or the other.
const DRAGCOEFICIENT: f32 = 0.05; // 0.05 feels balanced
const REAL_MAX: f32 = 1.0;
/* Independent methods */
/// Adds forces to entity physics force accumulator
///
/// Each physics part stores the current force acting on it, gravity, and
/// accumulated impulse forces.
///
/// The book shows this as an object that forces against bodies can be
/// registered with. May follow that later.
pub fn update_forces(entity: u32, entities: &mut Entities, _dt: f32) {
if !entities.entity_contains::<parts::Velocity>(entity)
|| !entities.entity_contains::<parts::Physics>(entity)
{
return;
}
let mut pmap = entities
.borrow_mut::<parts::Physics>()
.expect("No Physics map");
let mut vmap = entities
.borrow_mut::<parts::Velocity>()
.expect("No VelocityVelocity map");
// would be best with match for safety but hopefully the mask catches bas things
if let Ok(vel) = vmap.get_part_mut(entity) {
let mut drag_force = vel.vel.clone();
if let Ok(physics) = pmap.get_part_mut(entity) {
if physics.inv_mass <= 0.0 {
return;
}
// Could use a "force registery" like in Ian Millington's book.
// Gravity
physics.force_accum += physics.gravity * physics.mass;
// Drag
if DRAGCOEFICIENT > 0.0 {
let mut drag_coeff = drag_force.magnitude();
drag_coeff = DRAGCOEFICIENT * drag_coeff
+ DRAGCOEFICIENT * drag_coeff * drag_coeff;
// calculate the final force to apply
drag_force = drag_force.normalise();
drag_force *= -drag_coeff;
physics.force_accum += drag_force;
}
};
};
}
/// Performs integration of movement
pub fn integrate(entity: u32, entities: &mut Entities, dt: f32) {
if !entities.entity_contains::<parts::Position>(entity)
|| !entities.entity_contains::<parts::Velocity>(entity)
|| !entities.entity_contains::<parts::Physics>(entity)
{
return;
}
let mut phymap = entities
.borrow_mut::<parts::Physics>()
.expect("No Physics map");
let mut posmap = entities
.borrow_mut::<parts::Position>()
.expect("No Position map");
let mut vmap = entities
.borrow_mut::<parts::Velocity>()
.expect("No Velocity map");
if phymap.get_part_ref(entity).expect("4").inv_mass <= 0.0 {
return;
}
let physics = phymap.get_part_ref(entity).expect("5");
let velocity = vmap.get_part_ref(entity).expect("6");
if let Ok(position) = posmap.get_part_mut(entity) {
// update linear position
position.pos += velocity.vel * dt;
//*position += *velocity * dt + physics.acceleration * dt * dt * 0.5;
};
if let Ok(velocity) = vmap.get_part_mut(entity) {
// work out forces
let mut acceleration = physics.acceleration.clone();
acceleration += physics.force_accum * physics.inv_mass;
// Update linear velocity
velocity.vel += acceleration * dt;
// damping required to avoid float errors
velocity.vel *= physics.damping.powf(dt);
};
// TODO: temporary, actual entitiy bounding update should be done
// elsewhere to not clutter this up
let position = posmap.get_part_ref(entity).expect("7");
let mut aabbmap =
entities.borrow_mut::<parts::AABB>().expect("No AABB map");
if let Ok(aabb) = aabbmap.get_part_mut(entity) {
aabb.rect.set_x(position.pos.x as i32);
aabb.rect.set_y(position.pos.y as i32);
}
if let Ok(physics) = phymap.get_part_mut(entity) {
physics.force_accum.x = 0.0;
physics.force_accum.y = 0.0;
// TODO: temporary
physics.acceleration.x = 0.0;
physics.acceleration.y = 0.0;
}
}
......@@ -5,35 +5,33 @@
#![allow(unused_variables)]
use crate::components::messages::*;
use crate::components::parts::*;
use crate::components::physics::{integrate, resolve_contacts, update_forces, Contact};
use crate::components::physics::{integrate, update_forces};
use crate::components::*;
use crate::manager::input::Input;
use std::collections::HashMap;
use std::f32;
// update forces
// update forces (generators)
// integrate entities
// generate collision contacts
// resolve contacts
pub fn run_physics(active_ents: Vec<u32>, entities: &mut Entities, dt: f32) {
pub fn run_physics(active_ents: &[u32], entities: &mut Entities, dt: f32) {
for entity in active_ents {
update_forces(entity, entities, dt);
update_forces(*entity, entities, dt);
integrate(*entity, entities, dt);
}
}
// TODO: Add integration?
pub fn move_non_colliders(eid: &u32, entities: &mut Entities, dt: f32) {
if entities.entity_contains::<Position>(*eid) && entities.entity_contains::<Velocity>(*eid) {
let velo_map = entities
.get_pmap_ref::<Velocity>()
.expect("Borrow failed")
.expect("No Sprite map");
let mut pos_map = entities
.get_pmap_mut::<Velocity>()
.expect("Borrow failed")
.expect("No Sprite map");
let vel = velo_map.get_part_ref::<Velocity>(*eid).unwrap().vel.clone();
if let Ok(pos) = pos_map.get_part_mut::<Position>(*eid) {
if entities.entity_contains::<Position>(*eid)
&& entities.entity_contains::<Velocity>(*eid)
{
let velo_map = entities.borrow::<Velocity>().expect("No Sprite map");
let mut pos_map =
entities.borrow_mut::<Position>().expect("No Sprite map");
let vel = velo_map.get_part_ref(*eid).unwrap().vel.clone();
if let Ok(pos) = pos_map.get_part_mut(*eid) {
pos.pos.x += vel.x;
pos.pos.y += vel.y;
}
......@@ -42,13 +40,13 @@ pub fn move_non_colliders(eid: &u32, entities: &mut Entities, dt: f32) {
/// Check for entities that have an `INPUT` and check if they had any input queued,
/// if so, add a message to the message queue keyed to that entity ID for processing
pub fn input_update(eid: u32, entities: &mut Entities, msg_bus: &mut MessageBus, _input: &Input) {
pub fn input_update(
eid: u32, entities: &mut Entities, msg_bus: &mut MessageBus, _input: &Input,
) {
if entities.entity_contains::<InputTypes>(eid) {
let mut input_map = entities
.get_pmap_mut::<InputTypes>()
.expect("Borrow failed")
.expect("No Sprite map");
if let Ok(input_type) = input_map.get_part_mut::<InputTypes>(eid) {
let mut input_map =
entities.borrow_mut::<InputTypes>().expect("No Sprite map");
if let Ok(input_type) = input_map.get_part_mut(eid) {
//let input_type = entities.parts.input.get_mut(&eid).unwrap();
// Is it PlayerInput?
match input_type {
......@@ -71,27 +69,26 @@ pub fn input_update(eid: u32, entities: &mut Entities, msg_bus: &mut MessageBus,
/// Pull player messages from message bus and act on them
///
pub fn player_update(eid: u32, entities: &mut Entities, msg_bus: &mut MessageBus) {
pub fn player_update(
eid: u32, entities: &mut Entities, msg_bus: &mut MessageBus,
) {
if entities.entity_contains::<Physics>(eid)
&& entities.entity_contains::<Player>(eid)
&& entities.entity_contains::<Velocity>(eid)
{
let mut pmap = entities
.get_pmap_mut::<parts::Physics>()
.expect("Mutable borrow failed")
.borrow_mut::<parts::Physics>()
.expect("No Physics map");
let mut vmap = entities
.get_pmap_mut::<parts::Velocity>()
.expect("Mutable borrow failed")
.borrow_mut::<parts::Velocity>()
.expect("No Velocity map");
let mut plmap = entities
.get_pmap_mut::<parts::Player>()
.expect("Mutable borrow failed")
.borrow_mut::<parts::Player>()
.expect("No Player map");
if let Ok(physics) = pmap.get_part_mut::<Physics>(eid) {
if let Ok(player) = plmap.get_part_mut::<Player>(eid) {
if let Ok(velocity) = vmap.get_part_mut::<Velocity>(eid) {
if let Ok(physics) = pmap.get_part_mut(eid) {
if let Ok(player) = plmap.get_part_mut(eid) {
if let Ok(velocity) = vmap.get_part_mut(eid) {
// if it has a message queue waiting, get it,
// match, and destructure it to perform the action
if let Some(messages) = msg_bus.drain(&eid) {
......@@ -140,4 +137,7 @@ pub fn animation_update(eid: u32, entities: &mut Entities, dt: f32) {}
/// Update all sprites
///
/// TODO: May or may not be used. Depends on if sprites are coming from a sheet and need a frame..
pub fn sprite_update(active: &[u32], amask: &[u32], dt: f32, s: &mut HashMap<u32, Sprite>) {}
pub fn sprite_update(
active: &[u32], amask: &[u32], dt: f32, s: &mut HashMap<u32, Sprite>,
) {
}
......@@ -89,24 +89,34 @@ impl<'surface> Game<'surface> {
self.input.update();
if self.input.get_key(&Scancode::Escape) {
if self.states.get_state_id().unwrap() == "_MENU" && !self.state_changing {
if self.states.get_state_id().unwrap() == "_MENU"
&& !self.state_changing
{
self.states.pop();
self.states.change(Box::new(Play::new()));
self.state_changing = true;
} else if self.states.get_state_id().unwrap() == "_PLAY" && !self.state_changing {
} else if self.states.get_state_id().unwrap() == "_PLAY"
&& !self.state_changing
{
self.states.push(Box::new(Pause::new()));
self.state_changing = true;
} else if self.states.get_state_id().unwrap() == "_PAUSE" && !self.state_changing {
} else if self.states.get_state_id().unwrap() == "_PAUSE"
&& !self.state_changing
{
self.states.pop();
self.state_changing = true;
}
} else if self.input.get_key(&Scancode::Return) {
if self.states.get_state_id().unwrap() == "_PAUSE" && !self.state_changing {
if self.states.get_state_id().unwrap() == "_PAUSE"
&& !self.state_changing
{
self.states.pop();
self.states.change(Box::new(Menu::new()));
self.state_changing = true;
}
} else if !self.input.get_key(&Scancode::Escape) && !self.input.get_key(&Scancode::Return) {
} else if !self.input.get_key(&Scancode::Escape)
&& !self.input.get_key(&Scancode::Return)
{
self.state_changing = false;
}
}
......
......@@ -43,10 +43,12 @@ impl Input {
for event in self.pump.poll_event() {
match event {
KeyDown { .. } => {
self.key_state = self.pump.keyboard_state().pressed_scancodes().collect()
self.key_state =
self.pump.keyboard_state().pressed_scancodes().collect()
}
KeyUp { .. } => {
self.key_state = self.pump.keyboard_state().pressed_scancodes().collect()
self.key_state =
self.pump.keyboard_state().pressed_scancodes().collect()
}
MouseButtonDown { mouse_btn, .. } => {
......
......@@ -46,7 +46,10 @@ impl Level {
for c in buffer.split(',') {
match c.to_string().parse::<i32>() {
Ok(n) => row.push(n),
Err(e) => println!("Failed to read level on {:?} : {:?}", c, e),
Err(e) => println!(
"Failed to read level on {:?} : {:?}",
c, e
),
}
}
level.push(row);
......@@ -65,7 +68,8 @@ impl Level {
/// Parse all `Level` objects in the sequence they are loaded
pub fn parse_levels(level_list: &str) -> Vec<Level> {
// parse the level_list line by line for Path data, then build level
let file = fs::File::open(Path::new(&level_list)).expect("Can't open level list");
let file =
fs::File::open(Path::new(&level_list)).expect("Can't open level list");
let mut reader = BufReader::new(file);
let mut level = String::new();
......@@ -92,7 +96,9 @@ pub struct TileSet {
height: u32,
}
impl TileSet {
pub fn new(_id: &str, tw: u32, th: u32, sp: u32, m: u32, col: u32, h: u32) -> TileSet {
pub fn new(
_id: &str, tw: u32, th: u32, sp: u32, m: u32, col: u32, h: u32,
) -> TileSet {
TileSet {
tile_width: tw,
tile_height: th,
......@@ -103,8 +109,10 @@ impl TileSet {
}
}
pub fn get_frame(&self, num: u32) -> Option<Rect> {
let x = (num % self.columns) * self.tile_width + (self.margin + self.spacing * num);
let y = (num / self.columns) * self.tile_height + (self.margin + self.spacing * num);
let x = (num % self.columns) * self.tile_width
+ (self.margin + self.spacing * num);
let y = (num / self.columns) * self.tile_height
+ (self.margin + self.spacing * num);
Some(Rect::new(
x as i32,
y as i32,
......
......@@ -79,7 +79,8 @@ impl<'a> World<'a> {
self.map_detail.tile_size.y = th;
self.map_detail.dimensions.x = col;
self.map_detail.dimensions.y = row;
self.surface = Surface::new(col * tw, row * th, PixelFormatEnum::RGB24).unwrap();
self.surface =
Surface::new(col * tw, row * th, PixelFormatEnum::RGB24).unwrap();
}
/// Find the tile position of a pixel location
......@@ -124,13 +125,9 @@ impl<'a> World<'a> {
// set viewport position
let mut aabb_map = self
.entities
.get_pmap_mut::<parts::AABB>()
.expect("Mutable borrow failed")
.borrow_mut::<parts::AABB>()
.expect("No player AABB");
let pr = aabb_map
.get_part_mut::<parts::AABB>(self.player)
.unwrap()
.rect;
let pr = aabb_map.get_part_mut(self.player).unwrap().rect;
let limit = 32;
let left_limit = self.viewport.rect.center().x() - limit;
let right_limit = self.viewport.rect.center().x() + limit;
......@@ -166,7 +163,8 @@ impl<'a> World<'a> {
if self.viewport.rect.top() < 0 {
self.viewport.rect.set_y(0)
} else if self.viewport.rect.bottom() > self.surface.height() as i32 {
} else if self.viewport.rect.bottom() > self.surface.height() as i32
{
let h = self.viewport.rect.height() as i32;
self.viewport.rect.set_y(self.surface.height() as i32 - h)
}
......@@ -187,10 +185,14 @@ impl<'a> World<'a> {
self.active_ents.clear();
for y in self.viewport.start_tile.y..self.viewport.end_tile.y {
for x in self.viewport.start_tile.x..self.viewport.end_tile.x {
if let Some(id) = self.map_detail.background.get(self.to_tile_num(x, y)) {
if let Some(id) =
self.map_detail.background.get(self.to_tile_num(x, y))
{
self.active_ents.push(id.clone());
}
if let Some(id) = self.map_detail.foreground.get(self.to_tile_num(x, y)) {
if let Some(id) =
self.map_detail.foreground.get(self.to_tile_num(x, y))
{
self.active_ents.push(id.clone());
}
//self.active_ents = self.tile_layer.clone();
......@@ -201,15 +203,11 @@ impl<'a> World<'a> {
{
let pos_map = self
.entities
.get_pmap_ref::<parts::Position>()
.expect("Borrow failed")
.borrow::<parts::Position>()
.expect("No player Position");
// Only update the entities within the viewport
for entity in &self.map_detail.objects {
let exy = pos_map
.get_part_ref::<parts::Position>(*entity)
.unwrap()
.pos;
let exy = pos_map.get_part_ref(*entity).unwrap().pos;
let exy = self.to_tile(exy.x as u32, exy.y as u32);
if exy.x >= self.viewport.start_tile.x
&& exy.x <= self.viewport.end_tile.x
......@@ -224,7 +222,12 @@ impl<'a> World<'a> {
// input - entities with input and velocity. Player specific, will have defined set of actions
// for example, and elevator input might check positions then switch velocity.
for eid in &self.active_ents {
systems::input_update(*eid, &mut self.entities, &mut self.msg_bus, _input);
systems::input_update(
*eid,
&mut self.entities,
&mut self.msg_bus,
_input,
);
systems::player_update(*eid, &mut self.entities, &mut self.msg_bus);
// collisions & physics against all other active entities
physics::update_forces(*eid, &mut self.entities, dt);
......@@ -239,22 +242,22 @@ impl<'a> World<'a> {
/// The final stage after a world update
///
/// Fetch all textures and positions, then draw what is visible.
pub fn render(&mut self, _dt: f32, sf: &mut Surface, sprite_sheets: &SpriteSheets) {
pub fn render(
&mut self, _dt: f32, sf: &mut Surface, sprite_sheets: &SpriteSheets,
) {
let sprite_map = self
.entities
.get_pmap_ref::<parts::Sprite>()
.expect("Borrow failed")
.borrow::<parts::Sprite>()
.expect("No Sprite map");
let pos_map = self
.entities
.get_pmap_ref::<parts::Position>()
.expect("Borrow failed")
.borrow::<parts::Position>()
.expect("No Position map");
for entity in &self.active_ents {
// TODO: render by layers
if let Ok(sprite) = sprite_map.get_part_ref::<parts::Sprite>(*entity) {
if let Ok(pos) = pos_map.get_part_ref::<parts::Position>(*entity) {
if let Ok(sprite) = sprite_map.get_part_ref(*entity) {
if let Ok(pos) = pos_map.get_part_ref(*entity) {
let pos = &pos.pos;
let sprite_id = &sprite.sid;
let frame = sprite.frame;
......@@ -269,24 +272,27 @@ impl<'a> World<'a> {
};
};
if let Ok(sprite) = sprite_map.get_part_ref::<parts::Sprite>(*entity) {
if let Ok(pos) = pos_map.get_part_ref::<parts::Position>(*entity) {
if let Some(anim_map) = self
.entities
.get_pmap_ref::<parts::Animation>()
.expect("Borrow failed")
if let Ok(sprite) = sprite_map.get_part_ref(*entity) {
if let Ok(pos) = pos_map.get_part_ref(*entity) {
if let Ok(anim_map) =
self.entities.borrow::<parts::Animation>()
{
if let Ok(anim) = anim_map.get_part_ref::<parts::Animation>(*entity) {
if let Ok(anim) = anim_map.get_part_ref(*entity) {
let pos = &pos.pos;
let sprite_id = &sprite.sid;
let frame = anim.frame;
let tx = &sprite_sheets.get_ref(&sprite_id);
// Only the xy from the dst_rect is used
let dst_rect = Rect::new(pos.x as i32, pos.y as i32, 1, 1);
let dst_rect =
Rect::new(pos.x as i32, pos.y as i32, 1, 1);
tx.blit(Some(frame), &mut self.surface, Some(dst_rect))
.expect("Entity failed to blit to surface");
tx.blit(
Some(frame),
&mut self.surface,
Some(dst_rect),
)
.expect("Entity failed to blit to surface");
// draw to surface - no source rect. dstrect is position
};
}
......
......@@ -132,7 +132,9 @@ impl States {
/// state in the background, you would change this method to update all states in the
/// queue.
///
pub fn update(&mut self, dt: f32, input: &Input, mut bindings: &mut Bindings) {
pub fn update(
&mut self, dt: f32, input: &Input, mut bindings: &mut Bindings,
) {
if let Some(st) = self.game_states.back_mut() {
st.update(dt, input, &mut bindings)
}
......
......@@ -61,24 +61,39 @@ impl<'a> Play<'a> {
let row = row as u32;
// TODO: Kill the repitition here
let rec = self.tile_sets[sheet]
.get_frame(num_bg as u32)
.expect("frame number was out of bounds of sprite sheet");
let rec =
self.tile_sets[sheet].get_frame(num_bg as u32).expect(
"frame number was out of bounds of sprite sheet",
);
match num_bg {
-1 => self.world.map_detail.background.push(9000),
_ => create::background_tile(&mut self.world, col, row, sheet, rec),
_ => create::background_tile(
&mut self.world,
col,
row,
sheet,
rec,
),
}
let rec = self.tile_sets[sheet]
.get_frame(num_fg as u32)
.expect("frame number was out of bounds of sprite sheet");
let rec =
self.tile_sets[sheet].get_frame(num_fg as u32).expect(
"frame number was out of bounds of sprite sheet",
);
match num_fg {
-1 => self.world.map_detail.foreground.push(9000),
_ => create::level_tile(&mut self.world, col, row, sheet, rec),
_ => create::level_tile(
&mut self.world,
col,
row,
sheet,
rec,
),
}
let rec = self.tile_sets[sheet]
.get_frame(num_obj as u32)
.expect("frame number was out of bounds of sprite sheet");
let rec =
self.tile_sets[sheet].get_frame(num_obj as u32).expect(
"frame number was out of bounds of sprite sheet",
);
create::object_tile(&mut self.world, col, row, sheet, rec);
}
}
......
......@@ -10,7 +10,9 @@ pub struct Vec2d<T> {
}
use std::convert::From;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use std::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
};
macro_rules! impl_vec_ops_for {
($($t:ty)*) => {$(
......
Subproject commit 16a1896bf7d79910bd3d5f04541c12372bbfbb12
Subproject commit bd78a1f79feae58c5b79e43c4bb194663a177754
Subproject commit 276c28ffb11de1486ee6c6c3f91c4a43a6675174