sge 1.2.0

Simple game engine
Documentation
# Physics API

The physics API is based on [`rapier2d`](https://docs.rs/rapier2d/latest/rapier2d/).

Create a [`PhysicsWorld`](https://docs.rs/sge/latest/sge/prelude/physics/struct.PhysicsWorld.html) 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.

```rust
#[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.

```rust
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:

```rust
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.

```rust
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 center
- `Bounds::Capsule { half_height, radius }`: vertical capsule
- `Bounds::CapsuleX { half_width, radius }`: horizontal capsule
- `Bounds::Triangle(a, b, c)`: relative to the object's position
- `Bounds::ConvexHull(points)`: computed from a point cloud
- `Bounds::Polyline(points)`: a series of connected line segments, useful for terrain
- `Bounds::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.

```rust
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

```rust
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

```rust
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:

```rust
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](https://docs.rs/sge/latest/sge/prelude/physics/index.html)

See also: [`/examples/physics.rs`](https://github.com/LilyRL/sge/blob/master/examples/physics.rs)