-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft PR for review : Add physics module to Nazara (physics engine: nphysics2d) #8
base: master
Are you sure you want to change the base?
Changes from all commits
51b28d3
1a79652
ccabc05
b18b36d
29406c2
5744441
fc89967
26b2d54
867ed86
8117388
8a4169d
900b2f4
91b425d
8cbc044
9c84a68
483427a
2dd8b62
eb94f28
c7f56ed
ae87b57
ccf2356
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,5 @@ members = [ | |
"nazara_core", | ||
"nazara_gfx", | ||
"nazara_net", | ||
"nazara_physics2d", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "nazara_physics2d" | ||
version = "0.1.0" | ||
authors = ["Faymoon"] | ||
edition = "2018" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
nphysics2d = "0.13.0" | ||
nalgebra = "0.19.0" | ||
ncollide2d = "0.21.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
extern crate nazara_physics2d; | ||
extern crate nalgebra; | ||
extern crate ncollide2d; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The goal is not to avoid the use of the lib ncollide and to go through Nazara2d? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nphysics2d requires ncollide2d |
||
|
||
use std::time::Instant; | ||
|
||
use nazara_physics2d::physworld::PhysWorld; | ||
use nazara_physics2d::rigidbody::RigidBodyBuilder; | ||
//use nazara_physics2d::rigidbody::RigidBody; | ||
use nazara_physics2d::collider::Collider; | ||
use nazara_physics2d::material::Material; | ||
|
||
use nalgebra::Vector2; | ||
use nalgebra::Point2; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing for nalgebra I think. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same nphysics2d requires nalgebra |
||
|
||
fn main() | ||
{ | ||
let mut world = PhysWorld::new(Vector2::y() * -9.81); | ||
|
||
let material = Material::new(0.1, 0.0, None); | ||
let collider = Collider::Circle{ radius: 4.0, offset: None }; | ||
let body = RigidBodyBuilder::new().mass(1.2) // simply set the mass of the body | ||
.collider(&collider, Some(&material)) // set a collider and optionally a material, material and collider are linked so they must be set together | ||
.build(&mut world); // simply build the rigidbody into the world | ||
|
||
let ground_collider = Collider::Box{ size: Vector2::new(20.0, 5.0), offset: Some(Point2::new(-10.0, -30.0)) }; // the offset is an internal translation, and it won't change the body's position, here (0, 0) | ||
let ground = RigidBodyBuilder::new().make_static() // make the body static, so it won't move and it won't need a mass | ||
.collider(&ground_collider, None) // set the collider and no material | ||
.build(&mut world); // mwork as the other body | ||
|
||
let mut instant = Instant::now(); // record the actual instant | ||
|
||
loop | ||
{ | ||
world.step((instant.elapsed().as_nanos() as f64) / 1_000_000_000.0); // tell the physical world to simulate the elapsed time since last step | ||
instant = Instant::now(); // record the instant | ||
|
||
println!("{:?}", body.get_position().unwrap()); // print the ball position | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use nalgebra::Vector2; | ||
use nalgebra::geometry::Point2; | ||
use nphysics2d::object::ColliderDesc; | ||
use nphysics2d::material::MaterialHandle; | ||
use ncollide2d::shape; | ||
|
||
use crate::material::Material; | ||
use crate::number::Number; | ||
|
||
pub enum Collider<T: Number> | ||
{ | ||
Box{ size: Vector2<T>, offset: Option<Point2<T>> }, | ||
Circle{ radius: T, offset: Option<Point2<T>> }, | ||
Capsule{ radius: T, half_height: T }, | ||
//Compound(colliders: Vec<Collider<T>> ), | ||
Segment{ first_point: Point2<T> , second_point: Point2<T> }, | ||
//Triangle(first_point: Point2<T>, second_point: Point2<T>, third_point: Point2<T>), because shape::Triangle doesn't impl shape trait for no reason | ||
} | ||
|
||
impl<T: Number> Collider<T> | ||
{ | ||
pub(crate) fn create_desc(&self, material: Option<&Material<T>>) -> ColliderDesc<T> | ||
{ | ||
let mut description = match self | ||
{ | ||
&Collider::Box{ size, offset } => | ||
{ | ||
let mut desc = ColliderDesc::new(shape::ShapeHandle::new(shape::Cuboid::new(size.unscale((2.0).into())))); // /2 because Cuboid expect half size | ||
if let Some(offset) = offset | ||
{ | ||
desc.set_translation(offset.coords); | ||
} | ||
desc | ||
} | ||
&Collider::Circle{ radius, offset } => | ||
{ | ||
let mut desc = ColliderDesc::new(shape::ShapeHandle::new(shape::Ball::new(radius))); | ||
if let Some(offset) = offset | ||
{ | ||
desc.set_translation(offset.coords); | ||
} | ||
desc | ||
}, | ||
&Collider::Capsule{ radius, half_height } => | ||
ColliderDesc::new(shape::ShapeHandle::new(shape::Capsule::new(half_height, radius))), | ||
//&Compound(colliders) => | ||
&Collider::Segment{ first_point, second_point } => | ||
ColliderDesc::new(shape::ShapeHandle::new(shape::Segment::new(first_point, second_point))), | ||
//&Triangle(first_point, second_point, third_point) => | ||
// ColliderDesc::new(shape::ShapeHandle::new(shape::Triangle::new(first_point, second_point, third_point))), | ||
}; | ||
if let Some(material) = material | ||
{ | ||
if let Some(density) = material.density | ||
{ | ||
description.set_density(density); | ||
} | ||
description.set_material(MaterialHandle::new(material.material)); | ||
} | ||
description | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
pub mod rigidbody; | ||
pub mod physworld; | ||
pub mod collider; | ||
pub mod material; | ||
pub mod number; | ||
|
||
extern crate nphysics2d; | ||
extern crate nalgebra; | ||
extern crate ncollide2d; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use nphysics2d::material::BasicMaterial; | ||
|
||
use crate::number::Number; | ||
|
||
pub struct Material<T: Number> | ||
{ | ||
pub(crate) material: BasicMaterial<T>, | ||
pub(crate) density: Option<T>, | ||
} | ||
|
||
impl<T: Number> Material<T> | ||
{ | ||
pub fn new(restitution: T, friction: T, density: Option<T>) -> Self | ||
{ | ||
Material | ||
{ | ||
material: BasicMaterial::new(restitution, friction), | ||
density, | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
use std::convert::From; | ||
|
||
use nalgebra::RealField; | ||
|
||
pub trait Number : From<f64> + RealField {} | ||
impl<T> Number for T where T: From<f64> + RealField {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use std::cell::RefCell; | ||
use std::rc::Rc; | ||
|
||
use nalgebra::Vector2; | ||
use nphysics2d::object::{DefaultBodySet, DefaultColliderSet}; | ||
use nphysics2d::force_generator::DefaultForceGeneratorSet; | ||
use nphysics2d::joint::DefaultJointConstraintSet; | ||
use nphysics2d::world::{DefaultMechanicalWorld, DefaultGeometricalWorld}; | ||
|
||
use crate::number::Number; | ||
|
||
pub struct PhysWorld<T: Number> | ||
{ | ||
mechanical_world: DefaultMechanicalWorld<T>, | ||
geometric_world: DefaultGeometricalWorld<T>, | ||
pub(crate) body_set: Rc<RefCell<DefaultBodySet<T>>>, | ||
pub(crate) collider_set: DefaultColliderSet<T>, | ||
joint_set: DefaultJointConstraintSet<T>, | ||
force_generator_set: DefaultForceGeneratorSet<T>, | ||
} | ||
|
||
impl<T: Number> PhysWorld<T> | ||
{ | ||
pub fn new(gravity: Vector2<T>) -> PhysWorld<T> | ||
{ | ||
PhysWorld | ||
{ | ||
mechanical_world: DefaultMechanicalWorld::new(gravity), | ||
geometric_world: DefaultGeometricalWorld::new(), | ||
body_set: Rc::new(RefCell::new(DefaultBodySet::new())), | ||
collider_set: DefaultColliderSet::new(), | ||
joint_set: DefaultJointConstraintSet::new(), | ||
force_generator_set: DefaultForceGeneratorSet::new(), | ||
} | ||
} | ||
|
||
pub fn step(&mut self, timestep: T) | ||
{ | ||
self.mechanical_world.set_timestep(timestep); | ||
self.mechanical_world.step(&mut self.geometric_world, &mut (*self.body_set.borrow_mut()), &mut self.collider_set, &mut self.joint_set, &mut self.force_generator_set); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
use std::cell::RefCell; | ||
use std::rc::{Rc, Weak}; | ||
|
||
use nalgebra::Vector2; | ||
use nphysics2d::object::{RigidBodyDesc, BodyStatus, DefaultBodyHandle, BodyPartHandle, DefaultBodySet}; | ||
|
||
use crate::physworld::PhysWorld; | ||
use crate::collider::Collider; | ||
use crate::material::Material; | ||
use crate::number::Number; | ||
|
||
pub enum RigidBodyStatus | ||
{ | ||
Static, | ||
Dynamic, | ||
} | ||
|
||
pub struct RigidBodyBuilder<'a, T: Number> | ||
{ | ||
desc: RigidBodyDesc<T>, | ||
collider: Option<&'a Collider<T>>, | ||
material: Option<&'a Material<T>>, | ||
} | ||
|
||
impl<'a, T: Number> RigidBodyBuilder<'a, T> | ||
{ | ||
pub fn new() -> Self | ||
{ | ||
RigidBodyBuilder | ||
{ | ||
desc: RigidBodyDesc::new(), | ||
collider: None, | ||
material: None, | ||
} | ||
} | ||
|
||
pub fn mass(mut self, mass: T) -> Self | ||
{ | ||
self.desc.set_mass(mass); | ||
self | ||
} | ||
|
||
pub fn make_static(mut self) -> Self | ||
{ | ||
self.desc.set_status(BodyStatus::Static); | ||
self | ||
} | ||
|
||
pub fn collider(mut self, col: &'a Collider<T>, mat: Option<&'a Material<T>>) -> Self | ||
{ | ||
self.collider = Some(col); | ||
self.material = mat; | ||
self | ||
} | ||
|
||
pub fn build(&self, world: &mut PhysWorld<T>) -> RigidBody<T> | ||
{ | ||
let handle = world.body_set.borrow_mut().insert(self.desc.build()); | ||
|
||
if let Some(c) = self.collider | ||
{ | ||
world.collider_set.insert(c.create_desc(self.material).build(BodyPartHandle(handle, 0))); | ||
} | ||
|
||
RigidBody | ||
{ | ||
body: handle, | ||
body_set: Rc::downgrade(&world.body_set), | ||
} | ||
} | ||
} | ||
|
||
pub struct RigidBody<T: Number> | ||
{ | ||
body: DefaultBodyHandle, | ||
body_set: Weak<RefCell<DefaultBodySet<T>>>, | ||
} | ||
|
||
impl<T: Number> RigidBody<T> | ||
{ | ||
pub fn get_position(&self) -> Option<Vector2<T>> | ||
{ | ||
Some(self.body_set.upgrade()?.borrow().rigid_body(self.body)?.position().translation.vector) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are minor versions very useful here? (thanks Lynix)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I juste left default cargo.toml