Commit 1a93587b authored by Luke Jones's avatar Luke Jones

Many changes. Check-in of work

parent b6fbf668
Pipeline #17130779 passed with stage
in 1 minute and 55 seconds
......@@ -108,4 +108,4 @@ Entities!(
[10, ARMOUR, armour, parts::Armour],
[11, INVENTORY, inventory, parts::Inventory],
[12, CIRCLE, circle, parts::Circle]
);
);
\ No newline at end of file
......@@ -4,6 +4,7 @@
// resolve contacts
use components::*;
use components::parts::*;
use components::systems::has_mask;
use std::f32;
use vec2d::Vec2d;
......@@ -18,17 +19,23 @@ use vec2d::Vec2d;
const DRAGCOEFICIENT: f32 = 0.05; // 0.05 feels balanced
const REAL_MAX: f32 = 1.0;
pub struct EntityRefs<'a> {
pub position: &'a mut Vec2d<f32>,
pub velocity: &'a mut Vec2d<f32>,
pub physics: &'a mut Physics,
}
/// The physics `Contact` resolver.
///
/// Works with an `Entities` object to get:
/// * Position
/// * Velocity
/// * Physics object
pub struct Contact {
pub struct Contact<'a> {
/// ID of the primary entity contact
pub first: u32,
pub first: EntityRefs<'a>,
/// ID of the secondary entity contact
pub second: u32,
pub second: Option<EntityRefs<'a>>,
pub first_move: Vec2d<f32>,
pub second_move: Vec2d<f32>,
pub restitution: f32,
......@@ -36,28 +43,25 @@ pub struct Contact {
pub penetration: f32,
}
impl Contact {
impl<'a> Contact<'a> {
/// The main contact resolution method
pub fn resolve(&mut self, entities: &mut Entities, dt: f32) {
self.resolve_velocity(entities, dt);
self.resolve_interpen(entities, dt);
pub fn resolve(&mut self, dt: f32) {
self.resolve_velocity(dt);
self.resolve_interpen(dt);
}
/// Called by `resolve_velocity`
pub fn calc_separating_v(&self, entities: &Entities, dt: f32) -> f32 {
if let Some(velocity) = entities.parts.velocity.get(&self.first) {
let mut relative_velocity = velocity.vel.clone();
if let Some(other_v) = entities.parts.velocity.get(&self.second) {
relative_velocity -= other_v.vel
};
return (relative_velocity * self.contact_norm).magnitude();
}
0.0
pub fn calc_separating_v(&self, dt: f32) -> f32 {
let mut relative_velocity = self.first.velocity.clone();
if let Some(ref other) = self.second {
relative_velocity -= *other.velocity;
};
return (relative_velocity * self.contact_norm).magnitude();
}
pub fn resolve_velocity(&self, entities: &mut Entities, dt: f32) {
pub fn resolve_velocity(&mut self, dt: f32) {
// velocity in direction of contact
let separating_v = self.calc_separating_v(entities, dt);
let separating_v = self.calc_separating_v(dt);
if separating_v > 0.0 {
return;
}
......@@ -66,10 +70,7 @@ impl Contact {
let delta_velocity = new_separating_v - separating_v;
// apply velocity to each entity in proportion to their mass
let total_inverse_mass = match self.get_total_inverse_mass(entities) {
Some(inverse) => inverse,
None => return,
};
let total_inverse_mass = self.get_total_inverse_mass();
if total_inverse_mass <= 0.0 {
return;
}
......@@ -79,55 +80,46 @@ impl Contact {
let impulse_per_imass = self.contact_norm * impulse;
// Now, apply impulses
if let Some(velocity) = entities.parts.velocity.get_mut(&self.first) {
let tmp = velocity.vel.clone(); // need to clone because of mut rules
// getting imass this way is safe since earlier block would have returned if missing
let imass = entities.parts.physics[&self.first].inv_mass;
velocity.vel = tmp + impulse_per_imass * imass;
}
if let Some(velocity) = entities.parts.velocity.get_mut(&self.second) {
let tmp = velocity.vel.clone();
let imass = entities.parts.physics[&self.first].inv_mass;
velocity.vel = tmp + impulse_per_imass * imass;
let tmp = self.first.velocity.clone(); // need to clone because of mut rules
let imass = self.first.physics.inv_mass; // copy type
*self.first.velocity = tmp + impulse_per_imass * imass;
if let Some(ref mut other) = self.second {
let tmp = other.velocity.clone();
let imass = self.first.physics.inv_mass;
*other.velocity = tmp + impulse_per_imass * imass;
}
}
pub fn get_total_inverse_mass(&self, entities: &Entities) -> Option<f32> {
if let Some(first) = entities.parts.physics.get(&self.first) {
if let Some(second) = entities.parts.physics.get(&self.second) {
return Some(first.inv_mass + second.inv_mass);
}
return Some(first.inv_mass);
pub fn get_total_inverse_mass(&mut self) -> f32 {
if let Some(ref mut other) = self.second {
return self.first.physics.inv_mass + other.physics.inv_mass;
}
None
return self.first.physics.inv_mass;
}
pub fn resolve_interpen(&mut self, entities: &mut Entities, dt: f32) {
pub fn resolve_interpen(&mut self, dt: f32) {
if self.penetration < 0.0 {
return;
}
let total_inverse_mass = match self.get_total_inverse_mass(entities) {
Some(inverse) => inverse,
None => return,
};
let total_inverse_mass = self.get_total_inverse_mass();
if total_inverse_mass <= 0.0 {
return;
}
let move_per_imass = self.contact_norm * (self.penetration / total_inverse_mass);
// Calc movement amounts
self.first_move = move_per_imass * entities.parts.physics[&self.first].inv_mass;
self.second_move = move_per_imass * -entities.parts.physics[&self.second].inv_mass;
self.first_move = move_per_imass * self.first.physics.inv_mass;
if let Some(ref other) = self.second {
self.second_move = move_per_imass * -other.physics.inv_mass;
};
// Apply penetration resolution to positions
if let Some(position) = entities.parts.position.get_mut(&self.first) {
position.pos += self.first_move;
};
if let Some(position) = entities.parts.position.get_mut(&self.second) {
position.pos += self.second_move;
*self.first.position += self.first_move;
if let Some(ref mut other) = self.second {
*other.position += self.second_move;
}
}
}
......@@ -238,7 +230,7 @@ pub fn resolve_contacts(contacts: &mut Vec<Contact>,
let mut max_index = num_contacts as usize;
let mut sep_vel;
for i in 0..num_contacts as usize {
sep_vel = contacts[i as usize].calc_separating_v(entities, dt);
sep_vel = contacts[i as usize].calc_separating_v(dt);
if sep_vel < max && (sep_vel < 0.0 || contacts[i].penetration > 0.0) {
max = sep_vel;
max_index = i;
......@@ -248,9 +240,8 @@ pub fn resolve_contacts(contacts: &mut Vec<Contact>,
break;
}
// resolve this contact
contacts[max_index as usize].resolve(&mut entities, dt);
contacts[max_index as usize].resolve(dt);
iterations_used += 1;
}
contacts.clear();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment