Physics API
The physics API is based on rapier2d.
Create a PhysicsWorld with PhysicsWorld::new(). This returns a WorldRef that you call .update() on each frame to step the simulation.
Rapier2D uses positive y up, but SGE uses positive y down, so coordinates converted before being returned, so that the position in the world can be the same as the position onscreen. A conversion rate of 100 pixels per Rapier2D meter is used.
#[main("Physics")]
fn main() {
let mut world = PhysicsWorld::new();
loop {
world.update();
if should_quit() {
break;
}
next_frame().await;
}
}
Creating Objects
There are three types of physics objects:
- Dynamic: affected by gravity and forces, collides with everything.
- Fixed: immovable, used for walls, floors, and static geometry.
- Kinematic: moved manually (e.g. via
set_position), but participates in collision detection.
#![allow(unused)]
fn main() {
let dynamic_obj = world.create_dynamic(Bounds::Circle(20.0));
let wall = world.create_fixed(Bounds::Rect(Vec2::new(1000.0, 50.0)));
let platform = world.create_kinematic(Bounds::Rect(Vec2::new(200.0, 20.0)));
}
Each of these also has a _with variant that accepts a ColliderConfig for customizing physical material properties:
#![allow(unused)]
fn main() {
let bouncy = world.create_dynamic_with(
Bounds::Circle(15.0),
ColliderConfig::default()
.restitution(0.9)
.friction(0.1)
.density(2.0),
);
}
Objects can be removed with .remove().
Once created, objects can be manipulated using the methods on the ObjectRef struct.
#![allow(unused)]
fn main() {
let obj = world
.create_dynamic(Bounds::Circle(15.0))
.with_position(Vec2::new(200.0, 100.0))
.with_velocity(Vec2::new(150.0, 0.0))
.with_ccd(); // continuous collision detection
// Reading state
let pos = obj.get_position();
let vel = obj.get_velocity();
let rot = obj.get_rotation(); // all rotations are in radians
let mass = obj.get_mass();
obj.set_position(Vec2::new(300.0, 200.0));
obj.set_velocity(Vec2::new(0.0, -100.0));
obj.set_rotation(std::f32::consts::PI * 0.25);
obj.add_velocity(Vec2::new(50.0, 0.0));
obj.add_force(Vec2::new(0.0, -500.0));
obj.move_by(Vec2::new(5.0, 0.0));
obj.set_angvel(2.0); // rad/s
obj.add_angvel(0.5);
}
Bounds
Bounds describes the shape of a collider. The available variants are:
Bounds::Circle(radius)Bounds::Rect(Vec2): full size from centerBounds::Capsule { half_height, radius }: vertical capsuleBounds::CapsuleX { half_width, radius }: horizontal capsuleBounds::Triangle(a, b, c): relative to the object’s positionBounds::ConvexHull(points): computed from a point cloudBounds::Polyline(points): a series of connected line segments, useful for terrainBounds::Line { a, b }Bounds::Compound(children): multiple shapes combined, each with an offset
Sensors
Sensors are not physical objects, other objects will pass right through them, but they still check if something is colliding with them.
#![allow(unused)]
fn main() {
let sensor = world
.create_fixed_with(Bounds::Circle(80.0), ColliderConfig::default().sensor(true))
.with_position(Vec2::new(400.0, 300.0));
if sensor.is_colliding() {
// something is inside the sensor
}
}
Collisions
#![allow(unused)]
fn main() {
if obj.is_colliding() { ... }
if obj.is_colliding_with(other) { ... }
if let Some(points) = obj.check_collision_with(other) {
let normal = points.normal;
let depth = points.depth;
}
for info in obj.collisions() {
let other: ObjectRef = info.other;
let normal: Vec2 = info.points.normal;
match info.event {
CollisionType::Started => { /* wasn't colliding last frame, colliding now */ }
CollisionType::Ongoing => { /* colliding last frame, still colliding now */ }
CollisionType::Stopped => { /* was colliding last frame, not anymore */ }
}
}
}
World Settings
#![allow(unused)]
fn main() {
world.set_gravity(980.0); // in pixels/world units, so 9.8 will be very slow
let g = world.get_gravity();
}
Debug Visualization
You can draw outlines of all colliders and collision normals for debugging:
#![allow(unused)]
fn main() {
world.draw_colliders();
// or
world.draw_colliders_world();
}
Colliders are drawn in red, objects currently in collision are highlighted in yellow with arrows showing the collision normals.
See: physics module
See also: /examples/physics.rs