spacetime_physics 0.1.0

Physics engine for SpacetimeDB
Documentation
use std::fmt::Display;

use parry3d::query::Ray;
use spacetimedb::ReducerContext;

use crate::{math::Vec3, Collider, RigidBodyData};

#[derive(Debug, Clone)]
pub struct RacyCastHit {
    pub distance: f32,
    pub position: Vec3,
    pub normal: Vec3,
    pub rigid_body_id: u64,
}

impl Display for RacyCastHit {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "RacyCastHit {{ distance: {}, position: {:?}, normal: {:?}, rigid_body_id: {} }}",
            self.distance, self.position, self.normal, self.rigid_body_id
        )
    }
}

pub fn raycast_all(
    ctx: &ReducerContext,
    world_id: u64,
    origin: Vec3,
    direction: Vec3,
    max_distance: f32,
    solid: bool,
) -> impl Iterator<Item = RacyCastHit> {
    let colliders = Collider::all(ctx, world_id);
    let bodies = RigidBodyData::collect(ctx, world_id, &colliders).into_iter();
    raycast_all_with_rigid_bodies(bodies, origin, direction, max_distance, solid)
}

pub fn raycast_all_with_rigid_bodies(
    entities: impl Iterator<Item = RigidBodyData>,
    origin: Vec3,
    direction: Vec3,
    max_distance: f32,
    solid: bool,
) -> impl Iterator<Item = RacyCastHit> {
    let ray = Ray::new(origin.into(), direction.into());

    entities.filter_map(move |body| {
        let isometry = (&body).into();

        body.shape()
            .cast_ray_and_get_normal(&isometry, &ray, max_distance, solid)
            .map(|intersection| RacyCastHit {
                distance: intersection.time_of_impact,
                position: ray.point_at(intersection.time_of_impact).into(),
                normal: intersection.normal.into(),
                rigid_body_id: body.id,
            })
    })
}