// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub struct RigidBodyHandle {
id : Int
generation : Int
}
///|
fn RigidBodyHandle::RigidBodyHandle(
id : Int,
generation : Int,
) -> RigidBodyHandle {
{ id, generation }
}
///|
pub fn RigidBodyHandle::equals(
self : RigidBodyHandle,
other : RigidBodyHandle,
) -> Bool {
self.id == other.id && self.generation == other.generation
}
///|
pub fn RigidBodyHandle::from_raw_parts(
id : Int,
generation : Int,
) -> RigidBodyHandle {
RigidBodyHandle(id, generation)
}
///|
pub fn RigidBodyHandle::into_raw_parts(self : RigidBodyHandle) -> (Int, Int) {
(self.id, self.generation)
}
///|
pub fn RigidBodyHandle::invalid() -> RigidBodyHandle {
RigidBodyHandle(-1, -1)
}
///|
pub struct RigidBodyIds {
mut active_island_id : Int
mut active_set_id : Int
mut active_set_timestamp : Int
}
///|
pub fn RigidBodyIds::default() -> RigidBodyIds {
{ active_island_id: -1, active_set_id: -1, active_set_timestamp: 0 }
}
///|
const RIGID_BODY_CHANGES_IN_MODIFIED_SET : Int = 1 << 0
///|
const RIGID_BODY_CHANGES_POSITION : Int = 1 << 1
///|
const RIGID_BODY_CHANGES_SLEEP : Int = 1 << 2
///|
const RIGID_BODY_CHANGES_COLLIDERS : Int = 1 << 3
///|
const RIGID_BODY_CHANGES_TYPE : Int = 1 << 4
///|
const RIGID_BODY_CHANGES_DOMINANCE : Int = 1 << 5
///|
const RIGID_BODY_CHANGES_LOCAL_MASS_PROPERTIES : Int = 1 << 6
///|
const RIGID_BODY_CHANGES_ENABLED_OR_DISABLED : Int = 1 << 7
///|
const RIGID_BODY_CHANGES_ALL : Int = RIGID_BODY_CHANGES_IN_MODIFIED_SET |
RIGID_BODY_CHANGES_POSITION |
RIGID_BODY_CHANGES_SLEEP |
RIGID_BODY_CHANGES_COLLIDERS |
RIGID_BODY_CHANGES_TYPE |
RIGID_BODY_CHANGES_DOMINANCE |
RIGID_BODY_CHANGES_LOCAL_MASS_PROPERTIES |
RIGID_BODY_CHANGES_ENABLED_OR_DISABLED
///|
pub struct RigidBodyChanges {
bits : Int
}
///|
pub fn RigidBodyChanges::all() -> RigidBodyChanges {
{ bits: RIGID_BODY_CHANGES_ALL }
}
///|
pub fn RigidBodyChanges::empty() -> RigidBodyChanges {
{ bits: 0 }
}
///|
pub fn RigidBodyChanges::insert(
self : RigidBodyChanges,
flag : Int,
) -> RigidBodyChanges {
{ bits: self.bits | flag }
}
///|
pub fn RigidBodyChanges::contains(self : RigidBodyChanges, flag : Int) -> Bool {
(self.bits & flag) != 0
}
///|
pub fn RigidBodyChanges::remove(
self : RigidBodyChanges,
flag : Int,
) -> RigidBodyChanges {
{ bits: self.bits & Int::lnot(flag) }
}
///|
/// Flag value helpers used by the pub-parity audit mapping.
pub fn RigidBodyChanges::sleep_flag() -> Int {
RIGID_BODY_CHANGES_SLEEP
}
///|
pub fn RigidBodyChanges::sleep() -> Int {
RigidBodyChanges::sleep_flag()
}
///|
pub fn RigidBodyChanges::colliders_flag() -> Int {
RIGID_BODY_CHANGES_COLLIDERS
}
///|
pub fn RigidBodyChanges::colliders() -> Int {
RigidBodyChanges::colliders_flag()
}
///|
pub fn RigidBodyChanges::dominance_flag() -> Int {
RIGID_BODY_CHANGES_DOMINANCE
}
///|
pub fn RigidBodyChanges::dominance() -> Int {
RigidBodyChanges::dominance_flag()
}
///|
pub struct RigidBodyDominance {
mut group : Int
}
///|
pub fn RigidBodyDominance::RigidBodyDominance(
group : Int,
) -> RigidBodyDominance {
{ group, }
}
///|
pub fn RigidBodyDominance::default() -> RigidBodyDominance {
RigidBodyDominance(0)
}
///|
pub fn RigidBodyDominance::effective_group(
self : RigidBodyDominance,
body_type : RigidBodyType,
) -> Int {
if body_type.is_dynamic_or_kinematic() {
self.group
} else {
128
}
}
///|
pub fn RigidBodyType::is_fixed(self : RigidBodyType) -> Bool {
self is Fixed
}
///|
pub fn RigidBodyType::is_dynamic(self : RigidBodyType) -> Bool {
self is Dynamic
}
///|
pub fn RigidBodyType::is_kinematic(self : RigidBodyType) -> Bool {
self is KinematicPositionBased || self is KinematicVelocityBased
}
///|
pub fn RigidBodyType::is_dynamic_or_kinematic(self : RigidBodyType) -> Bool {
!self.is_fixed()
}
///|
/// Deprecated alias in Rapier (kept for pub parity).
pub type BodyStatus = RigidBodyType
///|
pub struct RigidBodyPosition {
mut position : @core.Isometry2
mut next_position : @core.Isometry2
}
///|
pub fn RigidBodyPosition::RigidBodyPosition(
position : @core.Isometry2,
next_position : @core.Isometry2,
) -> RigidBodyPosition {
{ position, next_position }
}
///|
pub fn RigidBodyPosition::interpolate_velocity(
self : RigidBodyPosition,
inv_dt : @core.Real,
local_com : @core.Vec2,
) -> RigidBodyVelocity {
let com = self.position.transform_point(local_com)
let shift = @core.Isometry2::from_translation(com)
let dpos = shift
.inverse()
.mul(self.next_position)
.mul(self.position.inverse())
.mul(shift)
let angular = dpos.rotation.angle()
let linear = dpos.translation
{
linvel: Vec2(linear.x * inv_dt, linear.y * inv_dt),
angvel: angular * inv_dt,
}
}
///|
pub fn RigidBodyPosition::integrate_forces_and_velocities(
self : RigidBodyPosition,
dt : @core.Real,
forces : RigidBodyForces,
vels : RigidBodyVelocity,
mprops : RigidBodyMassProps,
) -> @core.Isometry2 {
let new_vels = forces.integrate(dt, vels, mprops)
let local_com = mprops.local_mprops.center_of_mass
new_vels.integrate(dt, self.position, local_com)
}
///|
pub struct RigidBodyVelocity {
mut linvel : @core.Vec2
mut angvel : @core.Real
}
///|
pub fn RigidBodyVelocity::RigidBodyVelocity(
linvel : @core.Vec2,
angvel : @core.Real,
) -> RigidBodyVelocity {
{ linvel, angvel }
}
///|
pub fn RigidBodyVelocity::linvel(self : RigidBodyVelocity) -> @core.Vec2 {
self.linvel
}
///|
pub fn RigidBodyVelocity::angvel(self : RigidBodyVelocity) -> @core.Real {
self.angvel
}
///|
pub fn RigidBodyVelocity::integrate(
self : RigidBodyVelocity,
dt : @core.Real,
curr_pos : @core.Isometry2,
local_com : @core.Vec2,
) -> @core.Isometry2 {
let com = curr_pos.transform_point(local_com)
let shift = @core.Isometry2::from_translation(Vec2(-com.x, -com.y))
let rot = @core.Isometry2(
@core.Vec2::zero(),
@core.Rot2::from_angle(self.angvel * dt),
)
let translation = @core.Vec2(self.linvel.x * dt, self.linvel.y * dt)
let unshift = @core.Isometry2::from_translation(com.add(translation))
unshift.mul(rot).mul(shift).mul(curr_pos)
}
///|
pub fn RigidBodyVelocity::zero() -> RigidBodyVelocity {
{ linvel: @core.Vec2::zero(), angvel: 0.0F }
}
///|
pub fn RigidBodyVelocity::apply_damping(
self : RigidBodyVelocity,
dt : @core.Real,
damping : RigidBodyDamping,
) -> RigidBodyVelocity {
let lin_scale = 1.0F / (1.0F + dt * damping.linear_damping)
let ang_scale = 1.0F / (1.0F + dt * damping.angular_damping)
{
linvel: Vec2(self.linvel.x * lin_scale, self.linvel.y * lin_scale),
angvel: self.angvel * ang_scale,
}
}
///|
pub fn RigidBodyVelocity::as_slice(
self : RigidBodyVelocity,
) -> Array[@core.Real] {
[self.linvel.x, self.linvel.y, self.angvel]
}
///|
pub fn RigidBodyVelocity::as_mut_slice(
self : RigidBodyVelocity,
) -> Array[@core.Real] {
// MoonBit doesn't expose `&mut [T]` in the same way as Rust.
self.as_slice()
}
///|
pub fn RigidBodyVelocity::from_slice(
slice : Array[@core.Real],
) -> RigidBodyVelocity {
let x = if slice.length() > 0 { slice[0] } else { 0.0F }
let y = if slice.length() > 1 { slice[1] } else { 0.0F }
let w = if slice.length() > 2 { slice[2] } else { 0.0F }
RigidBodyVelocity(Vec2(x, y), w)
}
///|
pub fn RigidBodyVelocity::as_vector(self : RigidBodyVelocity) -> @core.Vec3 {
Vec3(self.linvel.x, self.linvel.y, self.angvel)
}
///|
pub fn RigidBodyVelocity::as_vector_mut(self : RigidBodyVelocity) -> @core.Vec3 {
// See `as_mut_slice` note.
self.as_vector()
}
///|
pub fn RigidBodyVelocity::is_zero(self : RigidBodyVelocity) -> Bool {
self.linvel.x == 0.0F && self.linvel.y == 0.0F && self.angvel == 0.0F
}
///|
pub fn RigidBodyVelocity::pseudo_kinetic_energy(
self : RigidBodyVelocity,
) -> @core.Real {
0.5F * (self.linvel.length_squared() + self.angvel * self.angvel)
}
///|
pub fn RigidBodyVelocity::velocity_at_point(
self : RigidBodyVelocity,
point : @core.Vec2,
world_com : @core.Vec2,
) -> @core.Vec2 {
let dpt = point.sub(world_com)
// Equivalent to `angvel.gcross(dpt)` in Rapier's 2D.
let w_cross = @core.Vec2(-self.angvel * dpt.y, self.angvel * dpt.x)
self.linvel.add(w_cross)
}
///|
pub fn RigidBodyVelocity::transformed(
self : RigidBodyVelocity,
rotation : @core.Rot2,
) -> RigidBodyVelocity {
let c = rotation.cos
let s = rotation.sin
let v = self.linvel
let lin = @core.Vec2(c * v.x - s * v.y, s * v.x + c * v.y)
{ linvel: lin, angvel: self.angvel }
}
///|
pub fn RigidBodyVelocity::kinetic_energy(
self : RigidBodyVelocity,
rb_mprops : RigidBodyMassProps,
) -> @core.Real {
// 0.5 * m * v^2 + 0.5 * I * w^2.
let inv_m = rb_mprops.local_mprops.inv_mass
let m = if inv_m == 0.0F { 0.0F } else { 1.0F / inv_m }
let mut energy = 0.5F * m * self.linvel.length_squared()
let inv_i = rb_mprops.effective_world_inv_inertia
if inv_i != 0.0F {
let i = 1.0F / inv_i
energy = energy + 0.5F * i * self.angvel * self.angvel
}
energy
}
///|
const DEFAULT_SLEEP_LINEAR_THRESHOLD : @core.Real = 0.4F
///|
const DEFAULT_SLEEP_ANGULAR_THRESHOLD : @core.Real = 0.5F
///|
const DEFAULT_TIME_UNTIL_SLEEP : @core.Real = 2.0F
///|
enum SleepRootState {
Unknown
TraversalPending
Traversed
}
///|
pub struct RigidBodyActivation {
mut normalized_linear_threshold : @core.Real
mut angular_threshold : @core.Real
mut time_until_sleep : @core.Real
mut time_since_can_sleep : @core.Real
mut sleeping : Bool
mut sleep_root_state : SleepRootState
}
///|
pub fn RigidBodyActivation::default() -> RigidBodyActivation {
RigidBodyActivation::active()
}
///|
pub fn RigidBodyActivation::default_normalized_linear_threshold() -> @core.Real {
DEFAULT_SLEEP_LINEAR_THRESHOLD
}
///|
pub fn RigidBodyActivation::default_angular_threshold() -> @core.Real {
DEFAULT_SLEEP_ANGULAR_THRESHOLD
}
///|
pub fn RigidBodyActivation::default_time_until_sleep() -> @core.Real {
DEFAULT_TIME_UNTIL_SLEEP
}
///|
pub fn RigidBodyActivation::active() -> RigidBodyActivation {
{
normalized_linear_threshold: RigidBodyActivation::default_normalized_linear_threshold(),
angular_threshold: RigidBodyActivation::default_angular_threshold(),
time_until_sleep: RigidBodyActivation::default_time_until_sleep(),
time_since_can_sleep: 0.0F,
sleeping: false,
sleep_root_state: Unknown,
}
}
///|
pub fn RigidBodyActivation::inactive() -> RigidBodyActivation {
{
normalized_linear_threshold: RigidBodyActivation::default_normalized_linear_threshold(),
angular_threshold: RigidBodyActivation::default_angular_threshold(),
time_until_sleep: RigidBodyActivation::default_time_until_sleep(),
time_since_can_sleep: RigidBodyActivation::default_time_until_sleep(),
sleeping: true,
sleep_root_state: Unknown,
}
}
///|
pub fn RigidBodyActivation::cannot_sleep() -> RigidBodyActivation {
let active = RigidBodyActivation::active()
active.normalized_linear_threshold = -1.0F
active.angular_threshold = -1.0F
active
}
///|
pub fn RigidBodyActivation::is_active(self : RigidBodyActivation) -> Bool {
!self.sleeping
}
///|
pub fn RigidBodyActivation::wake_up(
self : RigidBodyActivation,
strong : Bool,
) -> RigidBodyActivation {
self.sleeping = false
if !(self.sleep_root_state is TraversalPending) {
self.sleep_root_state = Unknown
}
if strong {
self.time_since_can_sleep = 0.0F
}
self
}
///|
pub fn RigidBodyActivation::sleep(
self : RigidBodyActivation,
) -> RigidBodyActivation {
self.sleeping = true
self.time_since_can_sleep = self.time_until_sleep
self
}
///|
pub fn RigidBodyActivation::is_eligible_for_sleep(
self : RigidBodyActivation,
) -> Bool {
self.time_since_can_sleep >= self.time_until_sleep
}
///|
pub fn RigidBodyActivation::update_energy(
self : RigidBodyActivation,
body_type : RigidBodyType,
length_unit : @core.Real,
sq_linvel : @core.Real,
sq_angvel : @core.Real,
dt : @core.Real,
) -> RigidBodyActivation {
if self.normalized_linear_threshold < 0.0F || self.angular_threshold < 0.0F {
self.time_since_can_sleep = 0.0F
return self
}
let can_sleep = match body_type {
Dynamic => {
let linear_threshold = self.normalized_linear_threshold * length_unit
sq_linvel < linear_threshold * linear_threshold &&
sq_angvel < self.angular_threshold * self.angular_threshold
}
KinematicPositionBased => sq_linvel == 0.0F && sq_angvel == 0.0F
KinematicVelocityBased => sq_linvel == 0.0F && sq_angvel == 0.0F
Fixed => true
}
if can_sleep {
self.time_since_can_sleep = self.time_since_can_sleep + dt
} else {
self.time_since_can_sleep = 0.0F
}
self
}
///|
pub struct RigidBodyDamping {
mut linear_damping : @core.Real
mut angular_damping : @core.Real
}
///|
pub fn RigidBodyDamping::default() -> RigidBodyDamping {
{ linear_damping: 0.0F, angular_damping: 0.0F }
}
///|
pub struct RigidBodyForces {
mut force : @core.Vec2
mut torque : @core.Real
mut gravity_scale : @core.Real
mut user_force : @core.Vec2
mut user_torque : @core.Real
}
///|
pub fn RigidBodyForces::default() -> RigidBodyForces {
{
force: @core.Vec2::zero(),
torque: 0.0F,
gravity_scale: 1.0F,
user_force: @core.Vec2::zero(),
user_torque: 0.0F,
}
}
///|
pub fn RigidBodyForces::integrate(
self : RigidBodyForces,
dt : @core.Real,
init_vels : RigidBodyVelocity,
mprops : RigidBodyMassProps,
) -> RigidBodyVelocity {
let linear_acc = @core.Vec2(
self.force.x * mprops.effective_inv_mass.x,
self.force.y * mprops.effective_inv_mass.y,
)
let angular_acc = mprops.effective_world_inv_inertia * self.torque
{
linvel: Vec2(
init_vels.linvel.x + linear_acc.x * dt,
init_vels.linvel.y + linear_acc.y * dt,
),
angvel: init_vels.angvel + angular_acc * dt,
}
}
///|
pub fn RigidBodyForces::compute_effective_force_and_torque(
self : RigidBodyForces,
gravity : @core.Vec2,
mass : @core.Vec2,
) -> RigidBodyForces {
self.force = Vec2(
self.user_force.x + gravity.x * mass.x * self.gravity_scale,
self.user_force.y + gravity.y * mass.y * self.gravity_scale,
)
self.torque = self.user_torque
self
}
///|
pub fn RigidBodyForces::apply_force_at_point(
self : RigidBodyForces,
rb_mprops : RigidBodyMassProps,
force : @core.Vec2,
point : @core.Vec2,
) -> RigidBodyForces {
self.user_force = self.user_force.add(force)
let delta = @core.Vec2(
point.x - rb_mprops.world_com.x,
point.y - rb_mprops.world_com.y,
)
self.user_torque = self.user_torque + delta.cross(force)
self
}
///|
const DEFAULT_CCD_THICKNESS : @core.Real = 1.0e30F
///|
pub struct RigidBodyCcd {
ccd_thickness : @core.Real
ccd_max_dist : @core.Real
ccd_active : Bool
mut ccd_enabled : Bool
mut soft_ccd_prediction : @core.Real
}
///|
pub fn RigidBodyCcd::default() -> RigidBodyCcd {
{
ccd_thickness: DEFAULT_CCD_THICKNESS,
ccd_max_dist: 0.0F,
ccd_active: false,
ccd_enabled: false,
soft_ccd_prediction: 0.0F,
}
}
///|
pub fn RigidBodyCcd::max_point_velocity(
self : RigidBodyCcd,
vels : RigidBodyVelocity,
) -> @core.Real {
vels.linvel.length() + @core.abs(vels.angvel) * self.ccd_max_dist
}
///|
pub fn RigidBodyCcd::is_moving_fast(
self : RigidBodyCcd,
dt : @core.Real,
vels : RigidBodyVelocity,
forces : RigidBodyForces?,
) -> Bool {
let threshold = self.ccd_thickness / 10.0F
if forces is Some(active_forces) {
let force_term = @core.Vec2(
active_forces.force.x * dt,
active_forces.force.y * dt,
)
let linvel = @core.Vec2(
vels.linvel.x + force_term.x,
vels.linvel.y + force_term.y,
)
let angular = vels.angvel + active_forces.torque * dt
let angular_part = @core.abs(angular) * self.ccd_max_dist
linvel.length() + angular_part > threshold
} else {
self.max_point_velocity(vels) * dt > threshold
}
}
///|
pub struct RigidBodyMassProps {
mut world_com : @core.Vec2
mut effective_inv_mass : @core.Vec2
mut effective_world_inv_inertia : @core.Real
// Mass-properties contributed by attached colliders only.
mut collider_local_mprops : @core.MassProperties
mut local_mprops : @core.MassProperties
// Additional user-provided mass-properties (Rapier's `additional_local_mprops` equivalent).
mut additional_local_mprops : @core.MassProperties
}
///|
pub fn RigidBodyMassProps::default() -> RigidBodyMassProps {
{
world_com: @core.Vec2::zero(),
effective_inv_mass: @core.Vec2::zero(),
effective_world_inv_inertia: 0.0F,
collider_local_mprops: MassProperties(0.0F, 0.0F, @core.Vec2::zero()),
local_mprops: MassProperties(0.0F, 0.0F, @core.Vec2::zero()),
additional_local_mprops: MassProperties(0.0F, 0.0F, @core.Vec2::zero()),
}
}
///|
pub fn RigidBodyMassProps::set_effective_inv_mass(
self : RigidBodyMassProps,
inv_mass : @core.Vec2,
) -> RigidBodyMassProps {
self.effective_inv_mass = inv_mass
self
}
///|
pub fn RigidBodyMassProps::set_effective_world_inv_inertia(
self : RigidBodyMassProps,
inv_inertia : @core.Real,
) -> RigidBodyMassProps {
self.effective_world_inv_inertia = inv_inertia
self
}
///|
pub fn RigidBodyMassProps::update_world_mass_properties(
self : RigidBodyMassProps,
body_type : RigidBodyType,
position : @core.Isometry2,
) -> RigidBodyMassProps {
self.world_com = position.transform_point(self.local_mprops.center_of_mass)
if body_type.is_dynamic() {
let inv_mass = self.local_mprops.inv_mass
self.effective_inv_mass = Vec2(inv_mass, inv_mass)
self.effective_world_inv_inertia = self.local_mprops.inv_inertia
} else {
self.effective_inv_mass = @core.Vec2::zero()
self.effective_world_inv_inertia = 0.0F
}
self
}
///|
pub fn RigidBodyMassProps::effective_mass(
self : RigidBodyMassProps,
) -> @core.Vec2 {
fn inv(x : @core.Real) -> @core.Real {
if x == 0.0F {
0.0F
} else {
1.0F / x
}
}
Vec2(inv(self.effective_inv_mass.x), inv(self.effective_inv_mass.y))
}
///|
pub fn RigidBodyMassProps::effective_angular_inertia(
self : RigidBodyMassProps,
) -> @core.Real {
if self.effective_world_inv_inertia == 0.0F {
0.0F
} else {
1.0F / self.effective_world_inv_inertia
}
}
///|
/// Placeholder for pub parity with Rapier.
///
/// This port currently recomputes mass-properties from colliders at a higher level.
pub fn RigidBodyMassProps::recompute_mass_properties_from_colliders(
self : RigidBodyMassProps,
) -> RigidBodyMassProps {
// Mirror Rapier semantics: start from attached colliders mass-properties then
// apply additional user-provided mass-properties.
self.local_mprops = self.collider_local_mprops.add(
self.additional_local_mprops,
)
self
}
///|
/// Rapier-style additional mass-properties.
pub enum RigidBodyAdditionalMassProps {
Mass(@core.Real)
MassProps(@core.MassProperties)
MassProperties(@core.MassProperties)
}
///|
pub fn RigidBodyAdditionalMassProps::mass(
mass : @core.Real,
) -> RigidBodyAdditionalMassProps {
Mass(mass)
}
///|
pub fn RigidBodyAdditionalMassProps::mass_props(
mass_props : @core.MassProperties,
) -> RigidBodyAdditionalMassProps {
MassProps(mass_props)
}
///|
pub fn RigidBodyAdditionalMassProps::mass_properties(
mass_properties : @core.MassProperties,
) -> RigidBodyAdditionalMassProps {
MassProperties(mass_properties)
}
///|
pub struct RigidBody {
mut ids : RigidBodyIds
mut user_data : @core.UserData128
position : RigidBodyPosition
mut body_type : RigidBodyType
mut locked_translations : Bool
mut locked_rotations : Bool
dominance : RigidBodyDominance
mut enabled : Bool
mut activation : RigidBodyActivation
mut damping : RigidBodyDamping
mut vels : RigidBodyVelocity
mut forces : RigidBodyForces
mut ccd : RigidBodyCcd
mut mass_props : RigidBodyMassProps
mut colliders : RigidBodyColliders
mut additional_mass : @core.Real
mut additional_solver_iterations : Int
mut changes : RigidBodyChanges
}
///|
pub fn RigidBody::set_body_type(
self : RigidBody,
body_type : RigidBodyType,
wake_up : Bool,
) -> RigidBody {
if body_type_to_int(self.body_type) != body_type_to_int(body_type) {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_TYPE)
self.body_type = body_type
self.mass_props = self.mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
if body_type is Fixed {
self.vels = RigidBodyVelocity::zero()
}
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::body_type(self : RigidBody) -> RigidBodyType {
self.body_type
}
///|
pub fn RigidBody::is_enabled(self : RigidBody) -> Bool {
self.enabled
}
///|
pub fn RigidBody::is_fixed(self : RigidBody) -> Bool {
self.body_type.is_fixed()
}
///|
pub fn RigidBody::is_dynamic(self : RigidBody) -> Bool {
self.body_type.is_dynamic()
}
///|
pub fn RigidBody::is_kinematic(self : RigidBody) -> Bool {
self.body_type.is_kinematic()
}
///|
pub fn RigidBody::is_dynamic_or_kinematic(self : RigidBody) -> Bool {
self.body_type.is_dynamic_or_kinematic()
}
///|
pub fn RigidBody::active_island_id(self : RigidBody) -> Int {
self.ids.active_island_id
}
///|
pub fn RigidBody::locked_translations(self : RigidBody) -> Bool {
self.locked_translations
}
///|
pub fn RigidBody::locked_rotations(self : RigidBody) -> Bool {
self.locked_rotations
}
///|
pub fn RigidBody::set_locked_translations(
self : RigidBody,
locked : Bool,
wake_up : Bool,
) -> RigidBody {
if self.locked_translations != locked {
self.locked_translations = locked
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_locked_rotations(
self : RigidBody,
locked : Bool,
wake_up : Bool,
) -> RigidBody {
if self.locked_rotations != locked {
self.locked_rotations = locked
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::lock_translations(self : RigidBody) -> RigidBody {
self.set_locked_translations(true, true)
}
///|
pub fn RigidBody::lock_rotations(self : RigidBody) -> RigidBody {
self.set_locked_rotations(true, true)
}
///|
pub fn RigidBody::dominance_group(self : RigidBody) -> Int {
self.dominance.group
}
///|
pub fn RigidBody::effective_dominance_group(self : RigidBody) -> Int {
self.dominance.effective_group(self.body_type)
}
///|
pub fn RigidBody::set_dominance_group(
self : RigidBody,
group : Int,
) -> RigidBody {
if self.dominance.group != group {
self.dominance.group = group
self.changes = self.changes.insert(RIGID_BODY_CHANGES_DOMINANCE)
}
self
}
///|
pub fn RigidBody::additional_solver_iterations(self : RigidBody) -> Int {
self.additional_solver_iterations
}
///|
pub fn RigidBody::additional_mass(self : RigidBody) -> @core.Real {
self.additional_mass
}
///|
pub fn RigidBody::colliders(self : RigidBody) -> Array[(Int, Int)] {
self.colliders.handles()
}
///|
pub fn RigidBody::attach_collider_raw(
self : RigidBody,
id : Int,
generation : Int,
) -> RigidBody {
let prev_len = self.colliders.len()
self.colliders = self.colliders.attach_collider_raw(id, generation)
if self.colliders.len() != prev_len {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_COLLIDERS)
}
self
}
///|
pub fn RigidBody::detach_collider_raw(
self : RigidBody,
id : Int,
generation : Int,
) -> RigidBody {
let prev_len = self.colliders.len()
self.colliders = self.colliders.detach_collider_raw(id, generation)
if self.colliders.len() != prev_len {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_COLLIDERS)
}
self
}
///|
pub fn RigidBody::set_additional_mass(
self : RigidBody,
mass : @core.Real,
wake_up : Bool,
) -> RigidBody {
let should_clear_additional_mprops = !mass_properties_equal(
self.mass_props.additional_local_mprops,
@core.MassProperties::default(),
)
if self.additional_mass != mass || should_clear_additional_mprops {
self.additional_mass = mass
// Setting scalar additional mass overrides any previously configured additional mass-properties.
self.mass_props.additional_local_mprops = @core.MassProperties::default()
self.mark_local_mass_properties_changed() |> ignore
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_additional_solver_iterations(
self : RigidBody,
additional_iterations : Int,
) -> RigidBody {
self.additional_solver_iterations = additional_iterations
self
}
///|
pub fn RigidBody::is_sleeping(self : RigidBody) -> Bool {
self.activation.sleeping
}
///|
pub fn RigidBody::activation(self : RigidBody) -> RigidBodyActivation {
self.activation
}
///|
pub fn RigidBody::damping(self : RigidBody) -> RigidBodyDamping {
self.damping
}
///|
pub fn RigidBody::linear_damping(self : RigidBody) -> @core.Real {
self.damping.linear_damping
}
///|
pub fn RigidBody::set_linear_damping(
self : RigidBody,
damping : @core.Real,
) -> RigidBody {
let state = self.damping
state.linear_damping = damping
self.damping = state
self
}
///|
pub fn RigidBody::angular_damping(self : RigidBody) -> @core.Real {
self.damping.angular_damping
}
///|
pub fn RigidBody::set_angular_damping(
self : RigidBody,
damping : @core.Real,
) -> RigidBody {
let state = self.damping
state.angular_damping = damping
self.damping = state
self
}
///|
pub fn RigidBody::vels(self : RigidBody) -> RigidBodyVelocity {
self.vels
}
///|
pub fn RigidBody::linvel(self : RigidBody) -> @core.Vec2 {
self.vels.linvel
}
///|
pub fn RigidBody::angvel(self : RigidBody) -> @core.Real {
self.vels.angvel
}
///|
pub fn RigidBody::set_kinematic_position_based_vels(
self : RigidBody,
vels : RigidBodyVelocity,
) -> RigidBody {
if self.body_type is KinematicPositionBased {
self.vels = vels
}
self
}
///|
pub fn RigidBody::set_vels(
self : RigidBody,
vels : RigidBodyVelocity,
wake_up : Bool,
) -> RigidBody {
let updated = self.set_linvel(vels.linvel, wake_up)
updated.set_angvel(vels.angvel, wake_up)
}
///|
pub fn RigidBody::set_linvel(
self : RigidBody,
linvel : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
if !vec2_equal(self.vels.linvel, linvel) {
if self.body_type is Dynamic || self.body_type is KinematicVelocityBased {
self.vels.linvel = linvel
if wake_up {
self.wake_up(true) |> ignore
}
}
}
self
}
///|
pub fn RigidBody::set_angvel(
self : RigidBody,
angvel : @core.Real,
wake_up : Bool,
) -> RigidBody {
if self.vels.angvel != angvel {
if self.body_type is Dynamic || self.body_type is KinematicVelocityBased {
self.vels.angvel = angvel
if wake_up {
self.wake_up(true) |> ignore
}
}
}
self
}
///|
pub fn RigidBody::apply_impulse(
self : RigidBody,
impulse : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
if self.body_type is Dynamic {
let inv_mass = self.mass_props.effective_inv_mass
self.vels.linvel = self.vels.linvel.add(
Vec2(impulse.x * inv_mass.x, impulse.y * inv_mass.y),
)
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::apply_torque_impulse(
self : RigidBody,
torque_impulse : @core.Real,
wake_up : Bool,
) -> RigidBody {
if self.body_type is Dynamic {
self.vels.angvel = self.vels.angvel +
torque_impulse * self.mass_props.effective_world_inv_inertia
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::apply_impulse_at_point(
self : RigidBody,
impulse : @core.Vec2,
point : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
if self.body_type is Dynamic {
let delta = @core.Vec2(
point.x - self.mass_props.world_com.x,
point.y - self.mass_props.world_com.y,
)
let torque_impulse = delta.cross(impulse)
self.apply_impulse(impulse, wake_up) |> ignore
self.apply_torque_impulse(torque_impulse, wake_up) |> ignore
}
self
}
///|
pub fn RigidBody::forces(self : RigidBody) -> RigidBodyForces {
self.forces
}
///|
/// Update the effective force/torque (gravity + accumulated user force/torque) stored on this body.
/// This matches Rapier's workflow where `RigidBodyForces.force/torque` are derived each step.
pub fn RigidBody::update_effective_force_and_torque(
self : RigidBody,
gravity : @core.Vec2,
) -> RigidBody {
let mass = self.mass_props.local_mprops.mass
let mass_v = @core.Vec2(mass, mass)
self.forces = self.forces.compute_effective_force_and_torque(gravity, mass_v)
if self.locked_translations {
self.forces.force = @core.Vec2::zero()
}
if self.locked_rotations {
self.forces.torque = 0.0F
}
self
}
///|
pub fn RigidBody::gravity_scale(self : RigidBody) -> @core.Real {
self.forces.gravity_scale
}
///|
pub fn RigidBody::set_gravity_scale(
self : RigidBody,
scale : @core.Real,
wake_up : Bool,
) -> RigidBody {
if self.forces.gravity_scale != scale {
if wake_up && self.activation.sleeping {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_SLEEP)
self.activation.sleeping = false
}
self.forces.gravity_scale = scale
}
self
}
///|
pub fn RigidBody::reset_forces(self : RigidBody, wake_up : Bool) -> RigidBody {
if !vec2_equal(self.forces.user_force, @core.Vec2::zero()) {
self.forces.user_force = @core.Vec2::zero()
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::reset_torques(self : RigidBody, wake_up : Bool) -> RigidBody {
if self.forces.user_torque != 0.0F {
self.forces.user_torque = 0.0F
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::add_force(
self : RigidBody,
force : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
if !vec2_equal(force, @core.Vec2::zero()) && self.body_type is Dynamic {
self.forces.user_force = self.forces.user_force.add(force)
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::add_torque(
self : RigidBody,
torque : @core.Real,
wake_up : Bool,
) -> RigidBody {
if torque != 0.0F && self.body_type is Dynamic {
self.forces.user_torque = self.forces.user_torque + torque
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::add_force_at_point(
self : RigidBody,
force : @core.Vec2,
point : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
if !vec2_equal(force, @core.Vec2::zero()) && self.body_type is Dynamic {
self.forces = self.forces.apply_force_at_point(
self.mass_props,
force,
point,
)
if wake_up {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::ccd(self : RigidBody) -> RigidBodyCcd {
self.ccd
}
///|
pub fn RigidBody::enable_ccd(self : RigidBody, enabled : Bool) -> RigidBody {
let ccd = self.ccd
ccd.ccd_enabled = enabled
self.ccd = ccd
self
}
///|
pub fn RigidBody::is_ccd_enabled(self : RigidBody) -> Bool {
self.ccd.ccd_enabled
}
///|
pub fn RigidBody::set_soft_ccd_prediction(
self : RigidBody,
prediction_distance : @core.Real,
) -> RigidBody {
let ccd = self.ccd
ccd.soft_ccd_prediction = prediction_distance
self.ccd = ccd
self
}
///|
pub fn RigidBody::set_ccd_properties(
self : RigidBody,
ccd_thickness : @core.Real,
ccd_max_dist : @core.Real,
) -> RigidBody {
let ccd = self.ccd
self.ccd = {
ccd_thickness,
ccd_max_dist,
ccd_active: ccd.ccd_active,
ccd_enabled: ccd.ccd_enabled,
soft_ccd_prediction: ccd.soft_ccd_prediction,
}
self
}
///|
pub fn RigidBody::soft_ccd_prediction(self : RigidBody) -> @core.Real {
self.ccd.soft_ccd_prediction
}
///|
pub fn RigidBody::is_ccd_active(self : RigidBody) -> Bool {
self.ccd.ccd_active
}
///|
pub fn RigidBody::set_ccd_active(self : RigidBody, active : Bool) -> RigidBody {
let ccd = self.ccd
self.ccd = {
ccd_thickness: ccd.ccd_thickness,
ccd_max_dist: ccd.ccd_max_dist,
ccd_active: active,
ccd_enabled: ccd.ccd_enabled,
soft_ccd_prediction: ccd.soft_ccd_prediction,
}
self
}
///|
pub fn RigidBody::mass_props(self : RigidBody) -> RigidBodyMassProps {
self.mass_props
}
///|
pub fn RigidBody::set_local_mass_properties(
self : RigidBody,
mprops : @core.MassProperties,
) -> RigidBody {
let mass_props = self.mass_props
mass_props.collider_local_mprops = mprops
mass_props.local_mprops = mprops
self.mass_props = mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
self
}
///|
pub fn RigidBody::mass(self : RigidBody) -> @core.Real {
self.mass_props.local_mprops.mass
}
///|
pub fn RigidBody::inv_mass(self : RigidBody) -> @core.Real {
self.mass_props.local_mprops.inv_mass
}
///|
pub fn RigidBody::inertia(self : RigidBody) -> @core.Real {
self.mass_props.local_mprops.inertia
}
///|
pub fn RigidBody::inv_inertia(self : RigidBody) -> @core.Real {
self.mass_props.local_mprops.inv_inertia
}
///|
pub fn RigidBody::center_of_mass(self : RigidBody) -> @core.Vec2 {
self.mass_props.local_mprops.center_of_mass
}
///|
pub fn RigidBody::world_com(self : RigidBody) -> @core.Vec2 {
self.mass_props.world_com
}
///|
pub fn RigidBody::wake_up(self : RigidBody, strong : Bool) -> RigidBody {
if self.activation.sleeping {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_SLEEP)
}
self.activation = self.activation.wake_up(strong)
self
}
///|
pub fn RigidBody::sleep(self : RigidBody) -> RigidBody {
self.activation = self.activation.sleep()
self.vels = RigidBodyVelocity::zero()
self
}
///|
fn RigidBody::reset_internal_references(self : RigidBody) -> RigidBody {
self.ids = RigidBodyIds::default()
self
}
///|
pub fn RigidBody::translation(self : RigidBody) -> @core.Vec2 {
self.position.position.translation
}
///|
pub fn RigidBody::rotation(self : RigidBody) -> @core.Rot2 {
self.position.position.rotation
}
///|
pub fn RigidBody::set_translation(
self : RigidBody,
translation : @core.Vec2,
wake_up : Bool,
) -> RigidBody {
let curr_rot = self.position.position.rotation
let next_rot = self.position.next_position.rotation
let same_curr = vec2_equal(self.position.position.translation, translation)
let same_next = vec2_equal(
self.position.next_position.translation,
translation,
)
if !same_curr || !same_next {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_POSITION)
self.position.position = Isometry2(translation, curr_rot)
self.position.next_position = Isometry2(translation, next_rot)
self.mass_props = self.mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_rotation(
self : RigidBody,
rotation : @core.Rot2,
wake_up : Bool,
) -> RigidBody {
let curr_translation = self.position.position.translation
let next_translation = self.position.next_position.translation
let same_curr = rot2_equal(self.position.position.rotation, rotation)
let same_next = rot2_equal(self.position.next_position.rotation, rotation)
if !same_curr || !same_next {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_POSITION)
self.position.position = Isometry2(curr_translation, rotation)
self.position.next_position = Isometry2(next_translation, rotation)
self.mass_props = self.mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_position(
self : RigidBody,
position : @core.Isometry2,
wake_up : Bool,
) -> RigidBody {
let same_curr = vec2_equal(
self.position.position.translation,
position.translation,
) &&
rot2_equal(self.position.position.rotation, position.rotation)
let same_next = vec2_equal(
self.position.next_position.translation,
position.translation,
) &&
rot2_equal(self.position.next_position.rotation, position.rotation)
if !same_curr || !same_next {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_POSITION)
self.position.position = position
self.position.next_position = position
self.mass_props = self.mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_enabled(self : RigidBody, enabled : Bool) -> RigidBody {
if enabled != self.enabled {
if enabled {
self.changes = RigidBodyChanges::all()
} else {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_ENABLED_OR_DISABLED)
}
self.enabled = enabled
}
self
}
///|
pub fn RigidBody::clear_changes(self : RigidBody) -> RigidBody {
self.changes = self.changes.remove(RIGID_BODY_CHANGES_ALL)
self
}
///|
pub fn RigidBody::mark_local_mass_properties_changed(
self : RigidBody,
) -> RigidBody {
self.changes = self.changes.insert(RIGID_BODY_CHANGES_LOCAL_MASS_PROPERTIES)
self
}
///|
pub fn RigidBody::position(self : RigidBody) -> @core.Isometry2 {
self.position.position
}
///|
pub fn RigidBody::next_position(self : RigidBody) -> @core.Isometry2 {
self.position.next_position
}
///|
pub fn RigidBody::set_next_position_internal(
self : RigidBody,
next_position : @core.Isometry2,
) -> RigidBody {
// Used by the pipeline to stage integration results (Rapier parity).
self.position.next_position = next_position
self
}
///|
pub fn RigidBody::set_next_kinematic_translation(
self : RigidBody,
translation : @core.Vec2,
) -> RigidBody {
if self.is_kinematic() {
let next_rot = self.position.next_position.rotation
self.position.next_position = Isometry2(translation, next_rot)
if !vec2_equal(self.position.position.translation, translation) {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_next_kinematic_rotation(
self : RigidBody,
rotation : @core.Rot2,
) -> RigidBody {
if self.is_kinematic() {
let next_translation = self.position.next_position.translation
self.position.next_position = Isometry2(next_translation, rotation)
if !rot2_equal(self.position.position.rotation, rotation) {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub fn RigidBody::set_next_kinematic_position(
self : RigidBody,
position : @core.Isometry2,
) -> RigidBody {
if self.is_kinematic() {
self.position.next_position = position
if !vec2_equal(self.position.position.translation, position.translation) ||
!rot2_equal(self.position.position.rotation, position.rotation) {
self.wake_up(true) |> ignore
}
}
self
}
///|
pub struct RigidBodyBuilder {
mut position : @core.Isometry2
mut linvel : @core.Vec2
mut angvel : @core.Real
mut gravity_scale : @core.Real
mut linear_damping : @core.Real
mut angular_damping : @core.Real
body_type : RigidBodyType
mut lock_translations : Bool
mut lock_rotations : Bool
mut additional_mass : @core.Real
mut additional_local_mprops : @core.MassProperties
mut additional_solver_iterations : Int
mut can_sleep : Bool
mut sleeping : Bool
mut enabled : Bool
mut ccd_enabled : Bool
mut soft_ccd_prediction : @core.Real
mut dominance_group : Int
mut user_data : @core.UserData128
}
///|
pub fn RigidBodyBuilder::RigidBodyBuilder(
body_type : RigidBodyType,
) -> RigidBodyBuilder {
{
position: @core.Isometry2::identity(),
linvel: @core.Vec2::zero(),
angvel: 0.0F,
gravity_scale: 1.0F,
linear_damping: 0.0F,
angular_damping: 0.0F,
body_type,
lock_translations: false,
lock_rotations: false,
additional_mass: 0.0F,
additional_local_mprops: @core.MassProperties::default(),
additional_solver_iterations: 0,
can_sleep: true,
sleeping: false,
enabled: true,
ccd_enabled: false,
soft_ccd_prediction: 0.0F,
dominance_group: 0,
user_data: @core.UserData128::zero(),
}
}
///|
pub fn RigidBodyBuilder::dynamic() -> RigidBodyBuilder {
RigidBodyBuilder(Dynamic)
}
///|
pub fn RigidBodyBuilder::fixed() -> RigidBodyBuilder {
RigidBodyBuilder(Fixed)
}
///|
pub fn RigidBodyBuilder::kinematic_position_based() -> RigidBodyBuilder {
RigidBodyBuilder(KinematicPositionBased)
}
///|
pub fn RigidBodyBuilder::kinematic_velocity_based() -> RigidBodyBuilder {
RigidBodyBuilder(KinematicVelocityBased)
}
///|
pub fn RigidBodyBuilder::translation(
self : RigidBodyBuilder,
translation : @core.Vec2,
) -> RigidBodyBuilder {
let rot = self.position.rotation
self.position = Isometry2(translation, rot)
self
}
///|
pub fn RigidBodyBuilder::position(
self : RigidBodyBuilder,
position : @core.Isometry2,
) -> RigidBodyBuilder {
self.position = position
self
}
///|
pub fn RigidBodyBuilder::rotation(
self : RigidBodyBuilder,
rotation : @core.Rot2,
) -> RigidBodyBuilder {
let translation = self.position.translation
self.position = Isometry2(translation, rotation)
self
}
///|
pub fn RigidBodyBuilder::linvel(
self : RigidBodyBuilder,
linvel : @core.Vec2,
) -> RigidBodyBuilder {
self.linvel = linvel
self
}
///|
pub fn RigidBodyBuilder::angvel(
self : RigidBodyBuilder,
angvel : @core.Real,
) -> RigidBodyBuilder {
self.angvel = angvel
self
}
///|
pub fn RigidBodyBuilder::lock_translations(
self : RigidBodyBuilder,
) -> RigidBodyBuilder {
self.lock_translations = true
self
}
///|
pub fn RigidBodyBuilder::lock_rotations(
self : RigidBodyBuilder,
) -> RigidBodyBuilder {
self.lock_rotations = true
self
}
///|
pub fn RigidBodyBuilder::gravity_scale(
self : RigidBodyBuilder,
scale : @core.Real,
) -> RigidBodyBuilder {
self.gravity_scale = scale
self
}
///|
pub fn RigidBodyBuilder::linear_damping(
self : RigidBodyBuilder,
damping : @core.Real,
) -> RigidBodyBuilder {
self.linear_damping = damping
self
}
///|
pub fn RigidBodyBuilder::angular_damping(
self : RigidBodyBuilder,
damping : @core.Real,
) -> RigidBodyBuilder {
self.angular_damping = damping
self
}
///|
pub fn RigidBodyBuilder::additional_mass(
self : RigidBodyBuilder,
mass : @core.Real,
) -> RigidBodyBuilder {
self.additional_mass = mass
self.additional_local_mprops = @core.MassProperties::default()
self
}
///|
pub fn RigidBodyBuilder::additional_solver_iterations(
self : RigidBodyBuilder,
additional_iterations : Int,
) -> RigidBodyBuilder {
self.additional_solver_iterations = additional_iterations
self
}
///|
pub fn RigidBodyBuilder::dominance_group(
self : RigidBodyBuilder,
group : Int,
) -> RigidBodyBuilder {
self.dominance_group = group
self
}
///|
pub fn RigidBodyBuilder::user_data(
self : RigidBodyBuilder,
data : Int,
) -> RigidBodyBuilder {
self.user_data = @core.UserData128::from_int_truncate(data)
self
}
///|
pub fn RigidBodyBuilder::user_data128(
self : RigidBodyBuilder,
data : @core.UserData128,
) -> RigidBodyBuilder {
self.user_data = data
self
}
///|
pub fn RigidBodyBuilder::can_sleep(
self : RigidBodyBuilder,
can_sleep : Bool,
) -> RigidBodyBuilder {
self.can_sleep = can_sleep
self
}
///|
pub fn RigidBodyBuilder::sleeping(
self : RigidBodyBuilder,
sleeping : Bool,
) -> RigidBodyBuilder {
self.sleeping = sleeping
self
}
///|
pub fn RigidBodyBuilder::enabled(
self : RigidBodyBuilder,
enabled : Bool,
) -> RigidBodyBuilder {
self.enabled = enabled
self
}
///|
pub fn RigidBodyBuilder::ccd_enabled(
self : RigidBodyBuilder,
enabled : Bool,
) -> RigidBodyBuilder {
self.ccd_enabled = enabled
self
}
///|
pub fn RigidBodyBuilder::soft_ccd_prediction(
self : RigidBodyBuilder,
prediction_distance : @core.Real,
) -> RigidBodyBuilder {
self.soft_ccd_prediction = prediction_distance
self
}
///|
/// Rapier leaf-name shims.
pub fn RigidBodyBuilder::new_static() -> RigidBodyBuilder {
RigidBodyBuilder::fixed()
}
///|
pub fn RigidBodyBuilder::new_kinematic_position_based() -> RigidBodyBuilder {
RigidBodyBuilder::kinematic_position_based()
}
///|
pub fn RigidBodyBuilder::new_kinematic_velocity_based() -> RigidBodyBuilder {
RigidBodyBuilder::kinematic_velocity_based()
}
///|
pub fn RigidBodyBuilder::pose(
self : RigidBodyBuilder,
pose : @core.Isometry2,
) -> RigidBodyBuilder {
self.position(pose)
}
///|
pub fn RigidBodyBuilder::enabled_translations(
self : RigidBodyBuilder,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
) -> RigidBodyBuilder {
allow_z |> ignore
self.lock_translations = !(allow_x && allow_y)
self
}
///|
pub fn RigidBodyBuilder::restrict_translations(
self : RigidBodyBuilder,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
) -> RigidBodyBuilder {
self.enabled_translations(allow_x, allow_y, allow_z)
}
///|
pub fn RigidBodyBuilder::restrict_rotations(
self : RigidBodyBuilder,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
) -> RigidBodyBuilder {
allow_x |> ignore
allow_y |> ignore
self.lock_rotations = !allow_z
self
}
///|
pub fn RigidBodyBuilder::additional_mass_properties(
self : RigidBodyBuilder,
props : RigidBodyAdditionalMassProps,
) -> RigidBodyBuilder {
match props {
Mass(m) => self.additional_mass(m)
MassProps(mprops) => {
self.additional_mass = 0.0F
self.additional_local_mprops = mprops
self
}
MassProperties(mprops) => {
self.additional_mass = 0.0F
self.additional_local_mprops = mprops
self
}
}
}
///|
pub fn RigidBodyBuilder::build(self : RigidBodyBuilder) -> RigidBody {
let pos = RigidBodyPosition(self.position, self.position)
let activation = if self.can_sleep {
RigidBodyActivation::active()
} else {
RigidBodyActivation::cannot_sleep()
}
let forces = RigidBodyForces::default()
forces.gravity_scale = self.gravity_scale
let mut rb = {
ids: RigidBodyIds::default(),
user_data: self.user_data,
position: pos,
body_type: self.body_type,
locked_translations: self.lock_translations,
locked_rotations: self.lock_rotations,
dominance: RigidBodyDominance(self.dominance_group),
enabled: self.enabled,
activation,
damping: {
linear_damping: self.linear_damping,
angular_damping: self.angular_damping,
},
vels: { linvel: self.linvel, angvel: self.angvel },
forces,
ccd: RigidBodyCcd::default(),
mass_props: RigidBodyMassProps::default(),
colliders: RigidBodyColliders(),
additional_mass: self.additional_mass,
additional_solver_iterations: self.additional_solver_iterations,
changes: RigidBodyChanges::all(),
}
rb.mass_props.additional_local_mprops = self.additional_local_mprops
rb.recompute_mass_properties_from_colliders() |> ignore
rb = rb.enable_ccd(self.ccd_enabled)
rb = rb.set_soft_ccd_prediction(self.soft_ccd_prediction)
if self.can_sleep && self.sleeping {
rb = rb.sleep()
}
rb
}
///|
pub struct RigidBodySet {
bodies : Array[RigidBody?]
generations : Array[Int]
free_list : Array[Int]
modified_bodies : Array[RigidBodyHandle]
pending_collider_position_updates : Array[(Int, Int, @core.Isometry2)]
}
///|
pub fn RigidBodySet::RigidBodySet() -> RigidBodySet {
{
bodies: [],
generations: [],
free_list: [],
modified_bodies: [],
pending_collider_position_updates: [],
}
}
///|
pub fn RigidBodySet::with_capacity(capacity : Int) -> RigidBodySet {
capacity |> ignore
RigidBodySet()
}
///|
pub fn RigidBodySet::len(self : RigidBodySet) -> Int {
let mut count = 0
for i in 0.. Bool {
self.len() == 0
}
///|
pub fn RigidBodySet::contains(
self : RigidBodySet,
handle : RigidBodyHandle,
) -> Bool {
self.get(handle) is Some(_)
}
///|
pub fn RigidBodySet::take_modified(
self : RigidBodySet,
) -> Array[RigidBodyHandle] {
let result : Array[RigidBodyHandle] = []
for i in 0..= 0 && handle.id < self.bodies.length() {
if self.generations[handle.id] == handle.generation {
if self.bodies[handle.id] is Some(body) {
body.changes = body.changes.remove(RIGID_BODY_CHANGES_IN_MODIFIED_SET)
}
}
}
}
self.modified_bodies.clear()
result
}
///|
fn RigidBodySet::push_modified_unchecked(
self : RigidBodySet,
handle : RigidBodyHandle,
body : RigidBody,
) -> Unit {
body.changes = body.changes.insert(RIGID_BODY_CHANGES_IN_MODIFIED_SET)
self.modified_bodies.push(handle)
}
///|
fn RigidBodySet::push_modified(
self : RigidBodySet,
handle : RigidBodyHandle,
body : RigidBody,
) -> Unit {
if !body.changes.contains(RIGID_BODY_CHANGES_IN_MODIFIED_SET) {
self.push_modified_unchecked(handle, body)
}
}
///|
pub fn RigidBodySet::insert(
self : RigidBodySet,
body : RigidBody,
) -> RigidBodyHandle {
let body = body.reset_internal_references()
body.changes = RigidBodyChanges::all()
if self.free_list.pop() is Some(index) {
self.bodies[index] = Some(body)
let generation = self.generations[index]
let handle = RigidBodyHandle(index, generation)
if self.bodies[index] is Some(body_ref) {
self.push_modified_unchecked(handle, body_ref)
}
handle
} else {
let index = self.bodies.length()
self.bodies.push(Some(body))
self.generations.push(0)
let handle = RigidBodyHandle(index, 0)
if self.bodies[index] is Some(body_ref) {
self.push_modified_unchecked(handle, body_ref)
}
handle
}
}
///|
pub fn RigidBodySet::get(
self : RigidBodySet,
handle : RigidBodyHandle,
) -> RigidBody? {
if handle.id < 0 || handle.id >= self.bodies.length() {
return None
}
if self.generations[handle.id] != handle.generation {
return None
}
self.bodies[handle.id]
}
///|
pub fn RigidBodySet::get_mut(
self : RigidBodySet,
handle : RigidBodyHandle,
) -> RigidBody? {
self.get_mut_internal_with_modification_tracking(handle)
}
///|
pub fn RigidBodySet::get_mut_internal(
self : RigidBodySet,
handle : RigidBodyHandle,
) -> RigidBody? {
if handle.id < 0 || handle.id >= self.bodies.length() {
return None
}
if self.generations[handle.id] != handle.generation {
return None
}
self.bodies[handle.id]
}
///|
pub fn RigidBodySet::get_mut_internal_with_modification_tracking(
self : RigidBodySet,
handle : RigidBodyHandle,
) -> RigidBody? {
if self.get_mut_internal(handle) is Some(body) {
self.push_modified(handle, body)
Some(body)
} else {
None
}
}
///|
pub fn RigidBodySet::get_unknown_gen(
self : RigidBodySet,
id : Int,
) -> (RigidBody, RigidBodyHandle)? {
if id < 0 || id >= self.bodies.length() {
return None
}
if self.bodies[id] is Some(body) {
let handle = RigidBodyHandle(id, self.generations[id])
Some((body, handle))
} else {
None
}
}
///|
pub fn RigidBodySet::get_unknown_gen_mut(
self : RigidBodySet,
id : Int,
) -> (RigidBody, RigidBodyHandle)? {
if id < 0 || id >= self.bodies.length() {
return None
}
if self.bodies[id] is Some(body) {
let handle = RigidBodyHandle(id, self.generations[id])
self.push_modified(handle, body)
Some((body, handle))
} else {
None
}
}
///|
pub fn RigidBodySet::get_pair_mut(
self : RigidBodySet,
handle1 : RigidBodyHandle,
handle2 : RigidBodyHandle,
) -> (RigidBody?, RigidBody?) {
if RigidBodyHandle::equals(handle1, handle2) {
(self.get_mut(handle1), None)
} else {
(self.get_mut(handle1), self.get_mut(handle2))
}
}
///|
pub fn RigidBodySet::iter(
self : RigidBodySet,
) -> Array[(RigidBodyHandle, RigidBody)] {
let result : Array[(RigidBodyHandle, RigidBody)] = []
for i in 0.. Array[(RigidBodyHandle, RigidBody)] {
self.modified_bodies.clear()
let result : Array[(RigidBodyHandle, RigidBody)] = []
for i in 0.. RigidBody? {
if handle.id < 0 || handle.id >= self.bodies.length() {
islands |> ignore
colliders |> ignore
impulse_joints |> ignore
multibody_joints |> ignore
remove_attached_colliders |> ignore
return None
}
if self.generations[handle.id] != handle.generation {
islands |> ignore
colliders |> ignore
impulse_joints |> ignore
multibody_joints |> ignore
remove_attached_colliders |> ignore
return None
}
if self.bodies[handle.id] is Some(body) {
let ids = body.ids
self.bodies[handle.id] = None
self.generations[handle.id] = self.generations[handle.id] + 1
self.free_list.push(handle.id)
islands.remove_body_with_ids(self, handle, ids)
colliders |> ignore
remove_attached_colliders |> ignore
impulse_joints.remove_joints_attached_to_rigid_body(handle) |> ignore
multibody_joints.remove_joints_attached_to_rigid_body(handle)
Some(body)
} else {
islands |> ignore
colliders |> ignore
impulse_joints |> ignore
multibody_joints |> ignore
remove_attached_colliders |> ignore
None
}
}
///|
fn body_type_to_int(body_type : RigidBodyType) -> Int {
match body_type {
Dynamic => 0
Fixed => 1
KinematicPositionBased => 2
KinematicVelocityBased => 3
}
}
///|
fn body_type_from_int(value : Int) -> RigidBodyType {
if value == 1 {
Fixed
} else if value == 2 {
KinematicPositionBased
} else if value == 3 {
KinematicVelocityBased
} else {
Dynamic
}
}
///|
fn split_values(text : String, sep : String) -> Array[String] {
let values : Array[String] = []
for part in text.split(sep[:]) {
let value = part.to_owned()
if value.length() > 0 {
values.push(value)
}
}
values
}
///|
fn parse_int_value(text : String) -> Int {
let result = try @string.parse_int(text[:], base=10) catch {
err => Err(err)
} noraise {
value => Ok(value)
}
if result is Ok(value) {
value
} else {
0
}
}
///|
fn parse_real_value(text : String) -> @core.Real {
let result = try @string.parse_double(text[:]) catch {
err => Err(err)
} noraise {
value => Ok(value)
}
if result is Ok(value) {
Float::from_double(value)
} else {
0.0F
}
}
///|
fn parse_u64_value(text : String) -> UInt64 {
let result = try @string.parse_uint64(text[:], base=10) catch {
err => Err(err)
} noraise {
value => Ok(value)
}
if result is Ok(value) {
value
} else {
UInt64::default()
}
}
///|
fn parse_bool_value(text : String) -> Bool {
text == "1"
}
///|
fn vec2_equal(left : @core.Vec2, right : @core.Vec2) -> Bool {
left.x == right.x && left.y == right.y
}
///|
fn rot2_equal(left : @core.Rot2, right : @core.Rot2) -> Bool {
left.sin == right.sin && left.cos == right.cos
}
///|
fn mass_properties_equal(
left : @core.MassProperties,
right : @core.MassProperties,
) -> Bool {
left.mass == right.mass &&
left.inv_mass == right.inv_mass &&
left.inertia == right.inertia &&
left.inv_inertia == right.inv_inertia &&
left.center_of_mass.x == right.center_of_mass.x &&
left.center_of_mass.y == right.center_of_mass.y
}
///|
pub fn RigidBodySet::serialize(self : RigidBodySet) -> String {
let sb = StringBuilder()
sb.write_string("len=")
sb.write_object(self.bodies.length())
sb.write_char(';')
sb.write_string("gens=")
for i in 0.. 0 {
sb.write_char(',')
}
sb.write_object(self.generations[i])
}
sb.write_char(';')
sb.write_string("free=")
for i in 0.. 0 {
sb.write_char(',')
}
sb.write_object(self.free_list[i])
}
sb.write_char(';')
sb.write_string("bodies=")
for i in 0.. 0 {
sb.write_char('|')
}
if self.bodies[i] is Some(body) {
let pos = body.position.position
let next_pos = body.position.next_position
sb.write_string("B,")
sb.write_object(body_type_to_int(body.body_type))
sb.write_char(',')
sb.write_object(pos.translation.x)
sb.write_char(',')
sb.write_object(pos.translation.y)
sb.write_char(',')
sb.write_object(pos.rotation.angle())
sb.write_char(',')
sb.write_object(next_pos.translation.x)
sb.write_char(',')
sb.write_object(next_pos.translation.y)
sb.write_char(',')
sb.write_object(next_pos.rotation.angle())
sb.write_char(',')
sb.write_object(if body.enabled { 1 } else { 0 })
sb.write_char(',')
sb.write_object(if body.activation.sleeping { 1 } else { 0 })
sb.write_char(',')
sb.write_object(body.activation.normalized_linear_threshold)
sb.write_char(',')
sb.write_object(body.activation.angular_threshold)
sb.write_char(',')
sb.write_object(body.activation.time_until_sleep)
sb.write_char(',')
sb.write_object(body.activation.time_since_can_sleep)
sb.write_char(',')
sb.write_object(body.additional_mass)
sb.write_char(',')
sb.write_object(body.additional_solver_iterations)
sb.write_char(',')
sb.write_object(body.dominance.group)
sb.write_char(',')
sb.write_object(if body.locked_translations { 1 } else { 0 })
sb.write_char(',')
sb.write_object(if body.locked_rotations { 1 } else { 0 })
sb.write_char(',')
sb.write_object(body.damping.linear_damping)
sb.write_char(',')
sb.write_object(body.damping.angular_damping)
sb.write_char(',')
sb.write_object(body.vels.linvel.x)
sb.write_char(',')
sb.write_object(body.vels.linvel.y)
sb.write_char(',')
sb.write_object(body.vels.angvel)
sb.write_char(',')
sb.write_object(body.forces.gravity_scale)
sb.write_char(',')
sb.write_object(body.forces.user_force.x)
sb.write_char(',')
sb.write_object(body.forces.user_force.y)
sb.write_char(',')
sb.write_object(body.forces.user_torque)
sb.write_char(',')
sb.write_object(body.ccd.ccd_thickness)
sb.write_char(',')
sb.write_object(body.ccd.ccd_max_dist)
sb.write_char(',')
sb.write_object(if body.ccd.ccd_enabled { 1 } else { 0 })
sb.write_char(',')
sb.write_object(body.ccd.soft_ccd_prediction)
sb.write_char(',')
sb.write_object(body.user_data.to_int_truncate())
sb.write_char(',')
sb.write_string(body.user_data.hi().to_string())
sb.write_char(',')
sb.write_string(body.user_data.lo().to_string())
} else {
sb.write_char('N')
}
}
sb.to_string()
}
///|
pub fn RigidBodySet::deserialize(data : String) -> RigidBodySet {
let mut len = 0
let generations : Array[Int] = []
let free_list : Array[Int] = []
let bodies : Array[RigidBody?] = []
for part in data.split(";"[:]) {
let value = part.to_owned()
if value.strip_prefix("len="[:]) is Some(raw_view) {
let raw = raw_view.to_owned()
len = parse_int_value(raw)
} else if value.strip_prefix("gens="[:]) is Some(raw_view) {
let raw = raw_view.to_owned()
let items = split_values(raw, ",")
for item in items {
generations.push(parse_int_value(item))
}
} else if value.strip_prefix("free="[:]) is Some(raw_view) {
let raw = raw_view.to_owned()
let items = split_values(raw, ",")
for item in items {
free_list.push(parse_int_value(item))
}
} else if value.strip_prefix("bodies="[:]) is Some(raw_view) {
let raw = raw_view.to_owned()
let entries = split_values(raw, "|")
for entry in entries {
if entry == "N" {
bodies.push(None)
} else if entry.strip_prefix("B,"[:]) is Some(entry_view) {
let fields = split_values(entry_view.to_owned(), ",")
let body_type = body_type_from_int(
if fields.length() > 0 {
parse_int_value(fields[0])
} else {
0
},
)
let tx = if fields.length() > 1 {
parse_real_value(fields[1])
} else {
0.0F
}
let ty = if fields.length() > 2 {
parse_real_value(fields[2])
} else {
0.0F
}
let rot = if fields.length() > 3 {
parse_real_value(fields[3])
} else {
0.0F
}
let ntx = if fields.length() > 4 {
parse_real_value(fields[4])
} else {
tx
}
let nty = if fields.length() > 5 {
parse_real_value(fields[5])
} else {
ty
}
let nrot = if fields.length() > 6 {
parse_real_value(fields[6])
} else {
rot
}
let enabled = if fields.length() > 7 {
parse_bool_value(fields[7])
} else {
true
}
let activation = if fields.length() > 12 {
let sleeping = if fields.length() > 8 {
parse_bool_value(fields[8])
} else {
false
}
let normalized_linear_threshold = if fields.length() > 9 {
parse_real_value(fields[9])
} else {
DEFAULT_SLEEP_LINEAR_THRESHOLD
}
let angular_threshold = if fields.length() > 10 {
parse_real_value(fields[10])
} else {
DEFAULT_SLEEP_ANGULAR_THRESHOLD
}
let time_until_sleep = if fields.length() > 11 {
parse_real_value(fields[11])
} else {
DEFAULT_TIME_UNTIL_SLEEP
}
let time_since_can_sleep = if fields.length() > 12 {
parse_real_value(fields[12])
} else {
0.0F
}
let activation = RigidBodyActivation::active()
activation.normalized_linear_threshold = normalized_linear_threshold
activation.angular_threshold = angular_threshold
activation.time_until_sleep = time_until_sleep
activation.time_since_can_sleep = time_since_can_sleep
activation.sleeping = sleeping
activation
} else {
let can_sleep = if fields.length() > 8 {
parse_bool_value(fields[8])
} else {
true
}
let sleeping = if fields.length() > 9 {
parse_bool_value(fields[9])
} else {
false
}
let activation = if can_sleep {
RigidBodyActivation::active()
} else {
RigidBodyActivation::cannot_sleep()
}
activation.sleeping = sleeping
if sleeping {
activation.time_since_can_sleep = activation.time_until_sleep
}
activation
}
let additional_mass_index = if fields.length() > 12 { 13 } else { 10 }
let additional_mass = if fields.length() > additional_mass_index {
parse_real_value(fields[additional_mass_index])
} else {
0.0F
}
let solver_index = if fields.length() > 12 { 14 } else { 11 }
let additional_solver_iterations = if fields.length() > solver_index {
parse_int_value(fields[solver_index])
} else {
0
}
let dominance_index = solver_index + 1
let dominance_group = if fields.length() > dominance_index {
parse_int_value(fields[dominance_index])
} else {
0
}
let extras_start = dominance_index + 1
let locked_translations = if fields.length() > extras_start {
parse_bool_value(fields[extras_start])
} else {
false
}
let locked_rotations = if fields.length() > extras_start + 1 {
parse_bool_value(fields[extras_start + 1])
} else {
false
}
let linear_damping = if fields.length() > extras_start + 2 {
parse_real_value(fields[extras_start + 2])
} else {
0.0F
}
let angular_damping = if fields.length() > extras_start + 3 {
parse_real_value(fields[extras_start + 3])
} else {
0.0F
}
let linvel_x = if fields.length() > extras_start + 4 {
parse_real_value(fields[extras_start + 4])
} else {
0.0F
}
let linvel_y = if fields.length() > extras_start + 5 {
parse_real_value(fields[extras_start + 5])
} else {
0.0F
}
let angvel = if fields.length() > extras_start + 6 {
parse_real_value(fields[extras_start + 6])
} else {
0.0F
}
let gravity_scale = if fields.length() > extras_start + 7 {
parse_real_value(fields[extras_start + 7])
} else {
1.0F
}
let user_force_x = if fields.length() > extras_start + 8 {
parse_real_value(fields[extras_start + 8])
} else {
0.0F
}
let user_force_y = if fields.length() > extras_start + 9 {
parse_real_value(fields[extras_start + 9])
} else {
0.0F
}
let user_torque = if fields.length() > extras_start + 10 {
parse_real_value(fields[extras_start + 10])
} else {
0.0F
}
let ccd_thickness = if fields.length() > extras_start + 11 {
parse_real_value(fields[extras_start + 11])
} else {
DEFAULT_CCD_THICKNESS
}
let ccd_max_dist = if fields.length() > extras_start + 12 {
parse_real_value(fields[extras_start + 12])
} else {
0.0F
}
let ccd_enabled = if fields.length() > extras_start + 13 {
parse_bool_value(fields[extras_start + 13])
} else {
false
}
let soft_ccd_prediction = if fields.length() > extras_start + 14 {
parse_real_value(fields[extras_start + 14])
} else {
0.0F
}
let user_data_int = if fields.length() > extras_start + 15 {
parse_int_value(fields[extras_start + 15])
} else {
0
}
let user_data = if fields.length() > extras_start + 17 {
let hi = parse_u64_value(fields[extras_start + 16])
let lo = parse_u64_value(fields[extras_start + 17])
@core.UserData128::from_parts(hi, lo)
} else {
@core.UserData128::from_int_truncate(user_data_int)
}
let position = @core.Isometry2(
Vec2(tx, ty),
@core.Rot2::from_angle(rot),
)
let next_position = @core.Isometry2(
Vec2(ntx, nty),
@core.Rot2::from_angle(nrot),
)
let rb_pos = RigidBodyPosition(position, next_position)
let body : RigidBody = {
ids: RigidBodyIds::default(),
user_data,
position: rb_pos,
body_type,
locked_translations,
locked_rotations,
dominance: RigidBodyDominance(dominance_group),
enabled,
activation,
damping: { linear_damping, angular_damping },
vels: RigidBodyVelocity(Vec2(linvel_x, linvel_y), angvel),
forces: {
force: @core.Vec2::zero(),
torque: 0.0F,
gravity_scale,
user_force: Vec2(user_force_x, user_force_y),
user_torque,
},
ccd: {
ccd_thickness,
ccd_max_dist,
ccd_active: false,
ccd_enabled,
soft_ccd_prediction,
},
mass_props: RigidBodyMassProps::default(),
colliders: RigidBodyColliders(),
additional_mass,
additional_solver_iterations,
changes: RigidBodyChanges::all(),
}
let body = body.recompute_mass_properties_from_colliders()
bodies.push(Some(body))
} else {
bodies.push(None)
}
}
}
}
while generations.length() < len {
generations.push(0)
}
while bodies.length() < len {
bodies.push(None)
}
let modified_bodies : Array[RigidBodyHandle] = []
for i in 0.. RigidBodyActivation {
self.activation
}
///|
pub fn RigidBody::effective_active_set_offset(self : RigidBody) -> Int {
self.ids.active_set_id
}
///|
pub fn RigidBody::user_data(self : RigidBody) -> Int {
self.user_data.to_int_truncate()
}
///|
pub fn RigidBody::user_data128(self : RigidBody) -> @core.UserData128 {
self.user_data
}
///|
pub fn RigidBody::set_user_data(self : RigidBody, data : Int) -> RigidBody {
self.user_data = @core.UserData128::from_int_truncate(data)
self
}
///|
pub fn RigidBody::set_user_data128(
self : RigidBody,
data : @core.UserData128,
) -> RigidBody {
self.user_data = data
self
}
///|
pub fn RigidBody::is_moving(self : RigidBody) -> Bool {
!self.vels.is_zero()
}
///|
pub fn RigidBody::is_translation_locked(self : RigidBody) -> Bool {
self.locked_translations
}
///|
pub fn RigidBody::is_rotation_locked(self : RigidBody) -> Bool {
self.locked_rotations
}
///|
pub fn RigidBody::local_center_of_mass(self : RigidBody) -> @core.Vec2 {
self.center_of_mass()
}
///|
pub fn RigidBody::velocity_at_point(
self : RigidBody,
point : @core.Vec2,
) -> @core.Vec2 {
self.vels.velocity_at_point(point, self.mass_props.world_com)
}
///|
pub fn RigidBody::kinetic_energy(self : RigidBody) -> @core.Real {
self.vels.kinetic_energy(self.mass_props)
}
///|
pub fn RigidBody::gravitational_potential_energy(
self : RigidBody,
dt : @core.Real,
gravity : @core.Vec2,
) -> @core.Real {
// Leap-frog style estimate, matching Rapier's intent.
let half_dt = dt / 2.0F
let lin_half = @core.Vec2(
self.vels.linvel.x * half_dt,
self.vels.linvel.y * half_dt,
)
let world_com = self.mass_props.world_com.sub(lin_half)
-self.mass() * self.forces.gravity_scale * gravity.dot(world_com)
}
///|
pub fn RigidBody::predict_position_using_velocity_and_forces(
self : RigidBody,
dt : @core.Real,
) -> @core.Isometry2 {
self.position.integrate_forces_and_velocities(
dt,
self.forces,
self.vels,
self.mass_props,
)
}
///|
pub fn RigidBody::predict_position_using_velocity(
self : RigidBody,
dt : @core.Real,
) -> @core.Isometry2 {
let local_com = self.mass_props.local_mprops.center_of_mass
self.vels.integrate(dt, self.position.position, local_com)
}
///|
pub fn RigidBody::set_additional_mass_properties(
self : RigidBody,
props : RigidBodyAdditionalMassProps,
wake_up : Bool,
) -> RigidBody {
match props {
Mass(m) => self.set_additional_mass(m, wake_up)
MassProps(mprops) => {
if self.additional_mass != 0.0F ||
!mass_properties_equal(self.mass_props.additional_local_mprops, mprops) {
self.additional_mass = 0.0F
self.mass_props.additional_local_mprops = mprops
self.mark_local_mass_properties_changed() |> ignore
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
MassProperties(mprops) => {
if self.additional_mass != 0.0F ||
!mass_properties_equal(self.mass_props.additional_local_mprops, mprops) {
self.additional_mass = 0.0F
self.mass_props.additional_local_mprops = mprops
self.mark_local_mass_properties_changed() |> ignore
if wake_up && self.is_dynamic_or_kinematic() {
self.wake_up(true) |> ignore
}
}
self
}
}
}
///|
pub fn RigidBody::set_enabled_translations(
self : RigidBody,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
wake_up : Bool,
) -> RigidBody {
allow_z |> ignore
// This 2D port locks translations as a whole.
self.set_locked_translations(!(allow_x && allow_y), wake_up)
}
///|
pub fn RigidBody::set_enabled_rotations(
self : RigidBody,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
wake_up : Bool,
) -> RigidBody {
allow_x |> ignore
allow_y |> ignore
// This 2D port only has a single angular dof.
self.set_locked_rotations(!allow_z, wake_up)
}
///|
pub fn RigidBody::restrict_translations(
self : RigidBody,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
wake_up : Bool,
) -> RigidBody {
self.set_enabled_translations(allow_x, allow_y, allow_z, wake_up)
}
///|
pub fn RigidBody::restrict_rotations(
self : RigidBody,
allow_x : Bool,
allow_y : Bool,
allow_z : Bool,
wake_up : Bool,
) -> RigidBody {
self.set_enabled_rotations(allow_x, allow_y, allow_z, wake_up)
}
///|
pub fn RigidBody::recompute_mass_properties_from_colliders(
self : RigidBody,
) -> RigidBody {
self.mass_props = self.mass_props.recompute_mass_properties_from_colliders()
if self.additional_mass != 0.0F {
self.mass_props.local_mprops = self.mass_props.local_mprops.set_mass(
self.mass_props.local_mprops.mass + self.additional_mass,
true,
)
}
self.mass_props = self.mass_props.update_world_mass_properties(
self.body_type,
self.position.position,
)
self
}
///|
/// Rapier 3D-only API, exposed as a no-op for pub parity on this 2D implementation.
pub fn RigidBody::enable_gyroscopic_forces(
self : RigidBody,
enabled : Bool,
) -> RigidBody {
enabled |> ignore
self
}
///|
/// Rapier 3D-only API, exposed as a no-op for pub parity on this 2D implementation.
pub fn RigidBody::angvel_with_gyroscopic_forces(
self : RigidBody,
dt : @core.Real,
) -> @core.Real {
dt |> ignore
self.angvel()
}