use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::Arc;
use crate::core::world_core::WorldCore;
use crate::error::{ApiError, ApiResult};
use crate::types::{BodyId, MassData, Vec2};
use crate::world::World;
use boxdd_sys::ffi;
use std::ffi::{CStr, CString};
use std::os::raw::c_void;
pub struct OwnedBody {
id: BodyId,
core: Arc<crate::core::world_core::WorldCore>,
destroy_on_drop: bool,
_not_send: PhantomData<Rc<()>>,
}
impl OwnedBody {
pub(crate) fn new(core: Arc<crate::core::world_core::WorldCore>, id: BodyId) -> Self {
core.owned_bodies
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self {
id,
core,
destroy_on_drop: true,
_not_send: PhantomData,
}
}
pub fn id(&self) -> BodyId {
self.id
}
pub fn world_id(&self) -> ffi::b2WorldId {
self.assert_valid();
unsafe { ffi::b2Body_GetWorld(self.id) }
}
pub fn try_world_id(&self) -> ApiResult<ffi::b2WorldId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetWorld(self.id) })
}
pub fn is_valid(&self) -> bool {
crate::core::callback_state::assert_not_in_callback();
unsafe { ffi::b2Body_IsValid(self.id) }
}
pub fn try_is_valid(&self) -> ApiResult<bool> {
crate::core::callback_state::check_not_in_callback()?;
Ok(unsafe { ffi::b2Body_IsValid(self.id) })
}
#[inline]
fn assert_valid(&self) {
crate::core::debug_checks::assert_body_valid(self.id);
}
#[inline]
fn check_valid(&self) -> ApiResult<()> {
crate::core::debug_checks::check_body_valid(self.id)
}
pub fn position(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetPosition(self.id) })
}
pub fn try_position(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe { ffi::b2Body_GetPosition(self.id) }))
}
pub fn linear_velocity(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetLinearVelocity(self.id) })
}
pub fn try_linear_velocity(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLinearVelocity(self.id)
}))
}
pub fn angular_velocity(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetAngularVelocity(self.id) }
}
pub fn try_angular_velocity(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetAngularVelocity(self.id) })
}
pub fn transform(&self) -> ffi::b2Transform {
self.assert_valid();
unsafe { ffi::b2Body_GetTransform(self.id) }
}
pub fn try_transform(&self) -> ApiResult<ffi::b2Transform> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetTransform(self.id) })
}
pub fn transform_ex(&self) -> crate::Transform {
crate::Transform::from(self.transform())
}
pub fn local_point<V: Into<Vec2>>(&self, world_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = world_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalPoint(self.id, p) })
}
pub fn try_local_point<V: Into<Vec2>>(&self, world_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = world_point.into().into();
Ok(Vec2::from(unsafe { ffi::b2Body_GetLocalPoint(self.id, p) }))
}
pub fn world_point<V: Into<Vec2>>(&self, local_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = local_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldPoint(self.id, p) })
}
pub fn try_world_point<V: Into<Vec2>>(&self, local_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = local_point.into().into();
Ok(Vec2::from(unsafe { ffi::b2Body_GetWorldPoint(self.id, p) }))
}
pub fn local_vector<V: Into<Vec2>>(&self, world_vector: V) -> Vec2 {
self.assert_valid();
let v: ffi::b2Vec2 = world_vector.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalVector(self.id, v) })
}
pub fn try_local_vector<V: Into<Vec2>>(&self, world_vector: V) -> ApiResult<Vec2> {
self.check_valid()?;
let v: ffi::b2Vec2 = world_vector.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalVector(self.id, v)
}))
}
pub fn world_vector<V: Into<Vec2>>(&self, local_vector: V) -> Vec2 {
self.assert_valid();
let v: ffi::b2Vec2 = local_vector.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldVector(self.id, v) })
}
pub fn try_world_vector<V: Into<Vec2>>(&self, local_vector: V) -> ApiResult<Vec2> {
self.check_valid()?;
let v: ffi::b2Vec2 = local_vector.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldVector(self.id, v)
}))
}
pub fn local_point_velocity<V: Into<Vec2>>(&self, local_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = local_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalPointVelocity(self.id, p) })
}
pub fn try_local_point_velocity<V: Into<Vec2>>(&self, local_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = local_point.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalPointVelocity(self.id, p)
}))
}
pub fn world_point_velocity<V: Into<Vec2>>(&self, world_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = world_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldPointVelocity(self.id, p) })
}
pub fn try_world_point_velocity<V: Into<Vec2>>(&self, world_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = world_point.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldPointVelocity(self.id, p)
}))
}
pub fn set_position_and_rotation<V: Into<Vec2>>(&mut self, p: V, angle_radians: f32) {
self.assert_valid();
let (s, c) = angle_radians.sin_cos();
let rot = ffi::b2Rot { c, s };
let pos: ffi::b2Vec2 = p.into().into();
unsafe { ffi::b2Body_SetTransform(self.id, pos, rot) };
}
pub fn try_set_position_and_rotation<V: Into<Vec2>>(
&mut self,
p: V,
angle_radians: f32,
) -> ApiResult<()> {
self.check_valid()?;
let (s, c) = angle_radians.sin_cos();
let rot = ffi::b2Rot { c, s };
let pos: ffi::b2Vec2 = p.into().into();
unsafe { ffi::b2Body_SetTransform(self.id, pos, rot) };
Ok(())
}
pub fn set_linear_velocity<V: Into<Vec2>>(&mut self, v: V) {
self.assert_valid();
let vel: ffi::b2Vec2 = v.into().into();
unsafe { ffi::b2Body_SetLinearVelocity(self.id, vel) }
}
pub fn try_set_linear_velocity<V: Into<Vec2>>(&mut self, v: V) -> ApiResult<()> {
self.check_valid()?;
let vel: ffi::b2Vec2 = v.into().into();
unsafe { ffi::b2Body_SetLinearVelocity(self.id, vel) }
Ok(())
}
pub fn set_angular_velocity(&mut self, w: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetAngularVelocity(self.id, w) }
}
pub fn try_set_angular_velocity(&mut self, w: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAngularVelocity(self.id, w) }
Ok(())
}
pub fn set_target_transform(&mut self, target: crate::Transform, time_step: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetTargetTransform(self.id, target.into(), time_step, wake) };
}
pub fn try_set_target_transform(
&mut self,
target: crate::Transform,
time_step: f32,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetTargetTransform(self.id, target.into(), time_step, wake) };
Ok(())
}
pub fn apply_force_to_center<V: Into<Vec2>>(&mut self, force: V, wake: bool) {
self.assert_valid();
let f: ffi::b2Vec2 = force.into().into();
unsafe { ffi::b2Body_ApplyForceToCenter(self.id, f, wake) };
}
pub fn try_apply_force_to_center<V: Into<Vec2>>(
&mut self,
force: V,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let f: ffi::b2Vec2 = force.into().into();
unsafe { ffi::b2Body_ApplyForceToCenter(self.id, f, wake) };
Ok(())
}
pub fn apply_force<F: Into<Vec2>, P: Into<Vec2>>(&mut self, force: F, point: P, wake: bool) {
self.assert_valid();
let f: ffi::b2Vec2 = force.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyForce(self.id, f, p, wake) };
}
pub fn try_apply_force<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
force: F,
point: P,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let f: ffi::b2Vec2 = force.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyForce(self.id, f, p, wake) };
Ok(())
}
pub fn apply_torque(&mut self, torque: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyTorque(self.id, torque, wake) }
}
pub fn try_apply_torque(&mut self, torque: f32, wake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyTorque(self.id, torque, wake) }
Ok(())
}
pub fn clear_forces(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_ClearForces(self.id) };
}
pub fn try_clear_forces(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ClearForces(self.id) };
Ok(())
}
pub fn apply_linear_impulse_to_center<V: Into<Vec2>>(&mut self, impulse: V, wake: bool) {
self.assert_valid();
let i: ffi::b2Vec2 = impulse.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulseToCenter(self.id, i, wake) };
}
pub fn try_apply_linear_impulse_to_center<V: Into<Vec2>>(
&mut self,
impulse: V,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let i: ffi::b2Vec2 = impulse.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulseToCenter(self.id, i, wake) };
Ok(())
}
pub fn apply_linear_impulse<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
impulse: F,
point: P,
wake: bool,
) {
self.assert_valid();
let i: ffi::b2Vec2 = impulse.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulse(self.id, i, p, wake) };
}
pub fn apply_angular_impulse(&mut self, impulse: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyAngularImpulse(self.id, impulse, wake) }
}
pub fn try_apply_linear_impulse<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
impulse: F,
point: P,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let i: ffi::b2Vec2 = impulse.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulse(self.id, i, p, wake) };
Ok(())
}
pub fn try_apply_angular_impulse(&mut self, impulse: f32, wake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyAngularImpulse(self.id, impulse, wake) }
Ok(())
}
pub fn mass(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetMass(self.id) }
}
pub fn try_mass(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetMass(self.id) })
}
pub fn rotational_inertia(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetRotationalInertia(self.id) }
}
pub fn try_rotational_inertia(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetRotationalInertia(self.id) })
}
pub fn local_center_of_mass(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetLocalCenterOfMass(self.id) })
}
pub fn try_local_center_of_mass(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalCenterOfMass(self.id)
}))
}
pub fn world_center_of_mass(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetWorldCenterOfMass(self.id) })
}
pub fn try_world_center_of_mass(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldCenterOfMass(self.id)
}))
}
pub fn mass_data(&self) -> MassData {
self.assert_valid();
unsafe { ffi::b2Body_GetMassData(self.id) }
}
pub fn try_mass_data(&self) -> ApiResult<MassData> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetMassData(self.id) })
}
pub fn set_mass_data(&mut self, mass_data: MassData) {
self.assert_valid();
unsafe { ffi::b2Body_SetMassData(self.id, mass_data) };
}
pub fn try_set_mass_data(&mut self, mass_data: MassData) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetMassData(self.id, mass_data) };
Ok(())
}
pub fn apply_mass_from_shapes(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyMassFromShapes(self.id) };
}
pub fn try_apply_mass_from_shapes(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyMassFromShapes(self.id) };
Ok(())
}
pub fn body_type(&self) -> BodyType {
self.assert_valid();
BodyType::from(unsafe { ffi::b2Body_GetType(self.id) })
}
pub fn try_body_type(&self) -> ApiResult<BodyType> {
self.check_valid()?;
Ok(BodyType::from(unsafe { ffi::b2Body_GetType(self.id) }))
}
pub fn set_body_type(&mut self, t: BodyType) {
self.assert_valid();
unsafe { ffi::b2Body_SetType(self.id, t.into()) }
}
pub fn try_set_body_type(&mut self, t: BodyType) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetType(self.id, t.into()) }
Ok(())
}
pub fn gravity_scale(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetGravityScale(self.id) }
}
pub fn try_gravity_scale(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetGravityScale(self.id) })
}
pub fn set_gravity_scale(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetGravityScale(self.id, v) }
}
pub fn try_set_gravity_scale(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetGravityScale(self.id, v) }
Ok(())
}
pub fn linear_damping(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetLinearDamping(self.id) }
}
pub fn try_linear_damping(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetLinearDamping(self.id) })
}
pub fn set_linear_damping(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetLinearDamping(self.id, v) }
}
pub fn try_set_linear_damping(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetLinearDamping(self.id, v) }
Ok(())
}
pub fn angular_damping(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetAngularDamping(self.id) }
}
pub fn try_angular_damping(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetAngularDamping(self.id) })
}
pub fn set_angular_damping(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetAngularDamping(self.id, v) }
}
pub fn try_set_angular_damping(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAngularDamping(self.id, v) }
Ok(())
}
pub fn is_awake(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsAwake(self.id) }
}
pub fn try_is_awake(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsAwake(self.id) })
}
pub fn set_awake(&mut self, awake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetAwake(self.id, awake) }
}
pub fn try_set_awake(&mut self, awake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAwake(self.id, awake) }
Ok(())
}
pub fn is_enabled(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsEnabled(self.id) }
}
pub fn try_is_enabled(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsEnabled(self.id) })
}
pub fn enable(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_Enable(self.id) }
}
pub fn try_enable(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_Enable(self.id) }
Ok(())
}
pub fn disable(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_Disable(self.id) }
}
pub fn try_disable(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_Disable(self.id) }
Ok(())
}
pub fn is_bullet(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsBullet(self.id) }
}
pub fn try_is_bullet(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsBullet(self.id) })
}
pub fn set_bullet(&mut self, flag: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetBullet(self.id, flag) }
}
pub fn try_set_bullet(&mut self, flag: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetBullet(self.id, flag) }
Ok(())
}
pub fn set_name(&mut self, name: &str) {
self.assert_valid();
let cs = CString::new(name).expect("body name contains an interior NUL byte");
unsafe { ffi::b2Body_SetName(self.id, cs.as_ptr()) }
}
pub fn try_set_name(&mut self, name: &str) -> ApiResult<()> {
self.check_valid()?;
let cs = CString::new(name).map_err(|_| ApiError::NulByteInString)?;
unsafe { ffi::b2Body_SetName(self.id, cs.as_ptr()) }
Ok(())
}
pub fn name(&self) -> Option<String> {
self.assert_valid();
let ptr = unsafe { ffi::b2Body_GetName(self.id) };
if ptr.is_null() {
None
} else {
Some(
unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
)
}
}
pub fn try_name(&self) -> ApiResult<Option<String>> {
self.check_valid()?;
let ptr = unsafe { ffi::b2Body_GetName(self.id) };
if ptr.is_null() {
Ok(None)
} else {
Ok(Some(
unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
))
}
}
pub fn contact_data(&self) -> Vec<ffi::b2ContactData> {
self.assert_valid();
let cap = unsafe { ffi::b2Body_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Vec::new();
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Body_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
vec
}
pub fn try_contact_data(&self) -> ApiResult<Vec<ffi::b2ContactData>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Body_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Ok(Vec::new());
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Body_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
Ok(vec)
}
pub fn as_id(&self) -> BodyId {
self.id
}
pub unsafe fn set_user_data_ptr(&mut self, p: *mut c_void) {
self.assert_valid();
let _ = self.core.clear_body_user_data(self.id);
unsafe { ffi::b2Body_SetUserData(self.id, p) }
}
pub unsafe fn try_set_user_data_ptr(&mut self, p: *mut c_void) -> ApiResult<()> {
self.check_valid()?;
let _ = self.core.clear_body_user_data(self.id);
unsafe { ffi::b2Body_SetUserData(self.id, p) }
Ok(())
}
pub fn user_data_ptr(&self) -> *mut c_void {
self.assert_valid();
unsafe { ffi::b2Body_GetUserData(self.id) }
}
pub fn try_user_data_ptr(&self) -> ApiResult<*mut c_void> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetUserData(self.id) })
}
pub fn set_user_data<T: 'static>(&mut self, value: T) {
self.assert_valid();
let p = self.core.set_body_user_data(self.id, value);
unsafe { ffi::b2Body_SetUserData(self.id, p) };
}
pub fn try_set_user_data<T: 'static>(&mut self, value: T) -> ApiResult<()> {
self.check_valid()?;
let p = self.core.set_body_user_data(self.id, value);
unsafe { ffi::b2Body_SetUserData(self.id, p) };
Ok(())
}
pub fn clear_user_data(&mut self) -> bool {
self.assert_valid();
let had = self.core.clear_body_user_data(self.id);
if had {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
had
}
pub fn try_clear_user_data(&mut self) -> ApiResult<bool> {
self.check_valid()?;
let had = self.core.clear_body_user_data(self.id);
if had {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(had)
}
pub fn with_user_data<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_body_user_data(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data<T: 'static, R>(
&self,
f: impl FnOnce(&T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_body_user_data(self.id, f)
}
pub fn with_user_data_mut<T: 'static, R>(&mut self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_body_user_data_mut(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data_mut<T: 'static, R>(
&mut self,
f: impl FnOnce(&mut T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_body_user_data_mut(self.id, f)
}
pub fn take_user_data<T: 'static>(&mut self) -> Option<T> {
self.assert_valid();
let v = self
.core
.take_body_user_data::<T>(self.id)
.expect("user data type mismatch");
if v.is_some() {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
v
}
pub fn try_take_user_data<T: 'static>(&mut self) -> ApiResult<Option<T>> {
self.check_valid()?;
let v = self.core.take_body_user_data::<T>(self.id)?;
if v.is_some() {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(v)
}
pub fn into_id(mut self) -> BodyId {
self.destroy_on_drop = false;
self.id
}
pub fn destroy(mut self) {
if self.destroy_on_drop && unsafe { ffi::b2Body_IsValid(self.id) } {
if crate::core::callback_state::in_callback() || self.core.events_buffers_are_borrowed()
{
self.core
.defer_destroy(crate::core::world_core::DeferredDestroy::Body(self.id));
} else {
#[cfg(feature = "serialize")]
self.core.cleanup_before_destroy_body(self.id);
unsafe { ffi::b2DestroyBody(self.id) };
let _ = self.core.clear_body_user_data(self.id);
}
}
self.destroy_on_drop = false;
}
}
impl Drop for OwnedBody {
fn drop(&mut self) {
let _ = self.core.id;
let prev = self
.core
.owned_bodies
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
debug_assert!(prev > 0, "owned body counter underflow");
if self.destroy_on_drop && unsafe { ffi::b2Body_IsValid(self.id) } {
if crate::core::callback_state::in_callback() || self.core.events_buffers_are_borrowed()
{
self.core
.defer_destroy(crate::core::world_core::DeferredDestroy::Body(self.id));
} else {
#[cfg(feature = "serialize")]
self.core.cleanup_before_destroy_body(self.id);
unsafe { ffi::b2DestroyBody(self.id) };
let _ = self.core.clear_body_user_data(self.id);
}
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BodyType {
Static,
Kinematic,
Dynamic,
}
impl From<BodyType> for ffi::b2BodyType {
fn from(t: BodyType) -> Self {
match t {
BodyType::Static => ffi::b2BodyType_b2_staticBody,
BodyType::Kinematic => ffi::b2BodyType_b2_kinematicBody,
BodyType::Dynamic => ffi::b2BodyType_b2_dynamicBody,
}
}
}
impl From<ffi::b2BodyType> for BodyType {
fn from(t: ffi::b2BodyType) -> Self {
match t {
x if x == ffi::b2BodyType_b2_staticBody => BodyType::Static,
x if x == ffi::b2BodyType_b2_kinematicBody => BodyType::Kinematic,
_ => BodyType::Dynamic,
}
}
}
#[derive(Clone, Debug)]
pub struct BodyDef(pub(crate) ffi::b2BodyDef);
impl Default for BodyDef {
fn default() -> Self {
let def = unsafe { ffi::b2DefaultBodyDef() };
Self(def)
}
}
#[doc(alias = "body_builder")]
#[doc(alias = "bodybuilder")]
#[derive(Clone, Debug)]
pub struct BodyBuilder {
def: BodyDef,
}
impl BodyBuilder {
pub fn new() -> Self {
Self {
def: BodyDef::default(),
}
}
pub fn body_type(mut self, t: BodyType) -> Self {
self.def.0.type_ = t.into();
self
}
pub fn position<V: Into<Vec2>>(mut self, p: V) -> Self {
self.def.0.position = ffi::b2Vec2::from(p.into());
self
}
pub fn angle(mut self, radians: f32) -> Self {
let (s, c) = radians.sin_cos();
self.def.0.rotation = ffi::b2Rot { c, s };
self
}
pub fn linear_velocity<V: Into<Vec2>>(mut self, v: V) -> Self {
self.def.0.linearVelocity = ffi::b2Vec2::from(v.into());
self
}
pub fn angular_velocity(mut self, v: f32) -> Self {
self.def.0.angularVelocity = v;
self
}
pub fn linear_damping(mut self, v: f32) -> Self {
self.def.0.linearDamping = v;
self
}
pub fn angular_damping(mut self, v: f32) -> Self {
self.def.0.angularDamping = v;
self
}
pub fn gravity_scale(mut self, v: f32) -> Self {
self.def.0.gravityScale = v;
self
}
pub fn enable_sleep(mut self, flag: bool) -> Self {
self.def.0.enableSleep = flag;
self
}
pub fn awake(mut self, flag: bool) -> Self {
self.def.0.isAwake = flag;
self
}
pub fn bullet(mut self, flag: bool) -> Self {
self.def.0.isBullet = flag;
self
}
pub fn enabled(mut self, flag: bool) -> Self {
self.def.0.isEnabled = flag;
self
}
#[must_use]
pub fn build(self) -> BodyDef {
self.def
}
}
impl From<BodyDef> for BodyBuilder {
fn from(def: BodyDef) -> Self {
Self { def }
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for BodyDef {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(serde::Serialize)]
struct Repr {
body_type: super::body::BodyType,
position: crate::types::Vec2,
angle: f32,
linear_velocity: crate::types::Vec2,
angular_velocity: f32,
linear_damping: f32,
angular_damping: f32,
gravity_scale: f32,
enable_sleep: bool,
awake: bool,
bullet: bool,
enabled: bool,
}
let angle = self.0.rotation.s.atan2(self.0.rotation.c);
let r = Repr {
body_type: match self.0.type_ {
x if x == ffi::b2BodyType_b2_staticBody => BodyType::Static,
x if x == ffi::b2BodyType_b2_kinematicBody => BodyType::Kinematic,
_ => BodyType::Dynamic,
},
position: crate::types::Vec2::from(self.0.position),
angle,
linear_velocity: crate::types::Vec2::from(self.0.linearVelocity),
angular_velocity: self.0.angularVelocity,
linear_damping: self.0.linearDamping,
angular_damping: self.0.angularDamping,
gravity_scale: self.0.gravityScale,
enable_sleep: self.0.enableSleep,
awake: self.0.isAwake,
bullet: self.0.isBullet,
enabled: self.0.isEnabled,
};
r.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for BodyDef {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct Repr {
body_type: super::body::BodyType,
position: crate::types::Vec2,
angle: f32,
linear_velocity: crate::types::Vec2,
angular_velocity: f32,
linear_damping: f32,
angular_damping: f32,
gravity_scale: f32,
enable_sleep: bool,
awake: bool,
bullet: bool,
enabled: bool,
}
let r = Repr::deserialize(deserializer)?;
let b = BodyBuilder::new()
.body_type(r.body_type)
.position(r.position)
.angle(r.angle)
.linear_velocity(r.linear_velocity)
.angular_velocity(r.angular_velocity)
.linear_damping(r.linear_damping)
.angular_damping(r.angular_damping)
.gravity_scale(r.gravity_scale)
.enable_sleep(r.enable_sleep)
.awake(r.awake)
.bullet(r.bullet)
.enabled(r.enabled);
Ok(b.build())
}
}
impl Default for BodyBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct Body<'w> {
pub(crate) id: BodyId,
pub(crate) core: Arc<WorldCore>,
_world: PhantomData<&'w World>,
}
impl<'w> Body<'w> {
pub(crate) fn new(core: Arc<WorldCore>, id: BodyId) -> Self {
Self {
id,
core,
_world: PhantomData,
}
}
#[inline]
fn assert_valid(&self) {
crate::core::debug_checks::assert_body_valid(self.id);
}
#[inline]
fn check_valid(&self) -> ApiResult<()> {
crate::core::debug_checks::check_body_valid(self.id)
}
pub fn id(&self) -> BodyId {
self.id
}
pub fn world_id(&self) -> ffi::b2WorldId {
self.assert_valid();
unsafe { ffi::b2Body_GetWorld(self.id) }
}
pub fn try_world_id(&self) -> ApiResult<ffi::b2WorldId> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetWorld(self.id) })
}
pub fn is_valid(&self) -> bool {
crate::core::callback_state::assert_not_in_callback();
unsafe { ffi::b2Body_IsValid(self.id) }
}
pub fn try_is_valid(&self) -> ApiResult<bool> {
crate::core::callback_state::check_not_in_callback()?;
Ok(unsafe { ffi::b2Body_IsValid(self.id) })
}
pub fn position(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetPosition(self.id) })
}
pub fn try_position(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe { ffi::b2Body_GetPosition(self.id) }))
}
pub fn linear_velocity(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetLinearVelocity(self.id) })
}
pub fn try_linear_velocity(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLinearVelocity(self.id)
}))
}
pub fn angular_velocity(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetAngularVelocity(self.id) }
}
pub fn try_angular_velocity(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetAngularVelocity(self.id) })
}
pub fn transform(&self) -> ffi::b2Transform {
self.assert_valid();
unsafe { ffi::b2Body_GetTransform(self.id) }
}
pub fn try_transform(&self) -> ApiResult<ffi::b2Transform> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetTransform(self.id) })
}
pub fn transform_ex(&self) -> crate::Transform {
crate::Transform::from(self.transform())
}
pub fn local_point<V: Into<Vec2>>(&self, world_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = world_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalPoint(self.id, p) })
}
pub fn try_local_point<V: Into<Vec2>>(&self, world_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = world_point.into().into();
Ok(Vec2::from(unsafe { ffi::b2Body_GetLocalPoint(self.id, p) }))
}
pub fn world_point<V: Into<Vec2>>(&self, local_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = local_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldPoint(self.id, p) })
}
pub fn try_world_point<V: Into<Vec2>>(&self, local_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = local_point.into().into();
Ok(Vec2::from(unsafe { ffi::b2Body_GetWorldPoint(self.id, p) }))
}
pub fn local_vector<V: Into<Vec2>>(&self, world_vector: V) -> Vec2 {
self.assert_valid();
let v: ffi::b2Vec2 = world_vector.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalVector(self.id, v) })
}
pub fn try_local_vector<V: Into<Vec2>>(&self, world_vector: V) -> ApiResult<Vec2> {
self.check_valid()?;
let v: ffi::b2Vec2 = world_vector.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalVector(self.id, v)
}))
}
pub fn world_vector<V: Into<Vec2>>(&self, local_vector: V) -> Vec2 {
self.assert_valid();
let v: ffi::b2Vec2 = local_vector.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldVector(self.id, v) })
}
pub fn try_world_vector<V: Into<Vec2>>(&self, local_vector: V) -> ApiResult<Vec2> {
self.check_valid()?;
let v: ffi::b2Vec2 = local_vector.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldVector(self.id, v)
}))
}
pub fn local_point_velocity<V: Into<Vec2>>(&self, local_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = local_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetLocalPointVelocity(self.id, p) })
}
pub fn try_local_point_velocity<V: Into<Vec2>>(&self, local_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = local_point.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalPointVelocity(self.id, p)
}))
}
pub fn world_point_velocity<V: Into<Vec2>>(&self, world_point: V) -> Vec2 {
self.assert_valid();
let p: ffi::b2Vec2 = world_point.into().into();
Vec2::from(unsafe { ffi::b2Body_GetWorldPointVelocity(self.id, p) })
}
pub fn try_world_point_velocity<V: Into<Vec2>>(&self, world_point: V) -> ApiResult<Vec2> {
self.check_valid()?;
let p: ffi::b2Vec2 = world_point.into().into();
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldPointVelocity(self.id, p)
}))
}
pub fn set_position_and_rotation<V: Into<Vec2>>(&mut self, p: V, angle_radians: f32) {
self.assert_valid();
let (s, c) = angle_radians.sin_cos();
let rot = ffi::b2Rot { c, s };
let pos: ffi::b2Vec2 = p.into().into();
unsafe { ffi::b2Body_SetTransform(self.id, pos, rot) };
}
pub fn set_linear_velocity<V: Into<Vec2>>(&mut self, v: V) {
self.assert_valid();
let vel: ffi::b2Vec2 = v.into().into();
unsafe { ffi::b2Body_SetLinearVelocity(self.id, vel) }
}
pub fn try_set_linear_velocity<V: Into<Vec2>>(&mut self, v: V) -> ApiResult<()> {
self.check_valid()?;
let vel: ffi::b2Vec2 = v.into().into();
unsafe { ffi::b2Body_SetLinearVelocity(self.id, vel) }
Ok(())
}
pub fn set_angular_velocity(&mut self, w: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetAngularVelocity(self.id, w) }
}
pub fn try_set_angular_velocity(&mut self, w: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAngularVelocity(self.id, w) }
Ok(())
}
pub fn set_target_transform(&mut self, target: crate::Transform, time_step: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetTargetTransform(self.id, target.into(), time_step, wake) };
}
pub fn try_set_target_transform(
&mut self,
target: crate::Transform,
time_step: f32,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetTargetTransform(self.id, target.into(), time_step, wake) };
Ok(())
}
pub fn contact_data(&self) -> Vec<ffi::b2ContactData> {
self.assert_valid();
let cap = unsafe { ffi::b2Body_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Vec::new();
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Body_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
vec
}
pub fn try_contact_data(&self) -> ApiResult<Vec<ffi::b2ContactData>> {
self.check_valid()?;
let cap = unsafe { ffi::b2Body_GetContactCapacity(self.id) }.max(0) as usize;
if cap == 0 {
return Ok(Vec::new());
}
let mut vec: Vec<ffi::b2ContactData> = Vec::with_capacity(cap);
let wrote = unsafe { ffi::b2Body_GetContactData(self.id, vec.as_mut_ptr(), cap as i32) }
.max(0) as usize;
unsafe { vec.set_len(wrote.min(cap)) };
Ok(vec)
}
pub fn apply_force<F: Into<Vec2>, P: Into<Vec2>>(&mut self, force: F, point: P, wake: bool) {
self.assert_valid();
let f: ffi::b2Vec2 = force.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyForce(self.id, f, p, wake) };
}
pub fn try_apply_force<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
force: F,
point: P,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let f: ffi::b2Vec2 = force.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyForce(self.id, f, p, wake) };
Ok(())
}
pub fn apply_force_to_center<V: Into<Vec2>>(&mut self, force: V, wake: bool) {
self.assert_valid();
let f: ffi::b2Vec2 = force.into().into();
unsafe { ffi::b2Body_ApplyForceToCenter(self.id, f, wake) };
}
pub fn try_apply_force_to_center<V: Into<Vec2>>(
&mut self,
force: V,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let f: ffi::b2Vec2 = force.into().into();
unsafe { ffi::b2Body_ApplyForceToCenter(self.id, f, wake) };
Ok(())
}
pub fn apply_torque(&mut self, torque: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyTorque(self.id, torque, wake) }
}
pub fn try_apply_torque(&mut self, torque: f32, wake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyTorque(self.id, torque, wake) }
Ok(())
}
pub fn clear_forces(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_ClearForces(self.id) };
}
pub fn try_clear_forces(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ClearForces(self.id) };
Ok(())
}
pub fn apply_linear_impulse<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
impulse: F,
point: P,
wake: bool,
) {
self.assert_valid();
let i: ffi::b2Vec2 = impulse.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulse(self.id, i, p, wake) };
}
pub fn try_apply_linear_impulse<F: Into<Vec2>, P: Into<Vec2>>(
&mut self,
impulse: F,
point: P,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let i: ffi::b2Vec2 = impulse.into().into();
let p: ffi::b2Vec2 = point.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulse(self.id, i, p, wake) };
Ok(())
}
pub fn apply_linear_impulse_to_center<V: Into<Vec2>>(&mut self, impulse: V, wake: bool) {
self.assert_valid();
let i: ffi::b2Vec2 = impulse.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulseToCenter(self.id, i, wake) };
}
pub fn try_apply_linear_impulse_to_center<V: Into<Vec2>>(
&mut self,
impulse: V,
wake: bool,
) -> ApiResult<()> {
self.check_valid()?;
let i: ffi::b2Vec2 = impulse.into().into();
unsafe { ffi::b2Body_ApplyLinearImpulseToCenter(self.id, i, wake) };
Ok(())
}
pub fn apply_angular_impulse(&mut self, impulse: f32, wake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyAngularImpulse(self.id, impulse, wake) }
}
pub fn try_apply_angular_impulse(&mut self, impulse: f32, wake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyAngularImpulse(self.id, impulse, wake) }
Ok(())
}
pub fn mass(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetMass(self.id) }
}
pub fn try_mass(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetMass(self.id) })
}
pub fn rotational_inertia(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetRotationalInertia(self.id) }
}
pub fn try_rotational_inertia(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetRotationalInertia(self.id) })
}
pub fn local_center_of_mass(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetLocalCenterOfMass(self.id) })
}
pub fn try_local_center_of_mass(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetLocalCenterOfMass(self.id)
}))
}
pub fn world_center_of_mass(&self) -> Vec2 {
self.assert_valid();
Vec2::from(unsafe { ffi::b2Body_GetWorldCenterOfMass(self.id) })
}
pub fn try_world_center_of_mass(&self) -> ApiResult<Vec2> {
self.check_valid()?;
Ok(Vec2::from(unsafe {
ffi::b2Body_GetWorldCenterOfMass(self.id)
}))
}
pub fn mass_data(&self) -> MassData {
self.assert_valid();
unsafe { ffi::b2Body_GetMassData(self.id) }
}
pub fn try_mass_data(&self) -> ApiResult<MassData> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetMassData(self.id) })
}
pub fn set_mass_data(&mut self, mass_data: MassData) {
self.assert_valid();
unsafe { ffi::b2Body_SetMassData(self.id, mass_data) };
}
pub fn try_set_mass_data(&mut self, mass_data: MassData) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetMassData(self.id, mass_data) };
Ok(())
}
pub fn apply_mass_from_shapes(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_ApplyMassFromShapes(self.id) };
}
pub fn try_apply_mass_from_shapes(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_ApplyMassFromShapes(self.id) };
Ok(())
}
pub fn body_type(&self) -> BodyType {
self.assert_valid();
BodyType::from(unsafe { ffi::b2Body_GetType(self.id) })
}
pub fn try_body_type(&self) -> ApiResult<BodyType> {
self.check_valid()?;
Ok(BodyType::from(unsafe { ffi::b2Body_GetType(self.id) }))
}
pub fn set_body_type(&mut self, t: BodyType) {
self.assert_valid();
unsafe { ffi::b2Body_SetType(self.id, t.into()) }
}
pub fn try_set_body_type(&mut self, t: BodyType) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetType(self.id, t.into()) }
Ok(())
}
pub fn gravity_scale(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetGravityScale(self.id) }
}
pub fn try_gravity_scale(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetGravityScale(self.id) })
}
pub fn set_gravity_scale(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetGravityScale(self.id, v) }
}
pub fn try_set_gravity_scale(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetGravityScale(self.id, v) }
Ok(())
}
pub fn linear_damping(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetLinearDamping(self.id) }
}
pub fn try_linear_damping(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetLinearDamping(self.id) })
}
pub fn set_linear_damping(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetLinearDamping(self.id, v) }
}
pub fn try_set_linear_damping(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetLinearDamping(self.id, v) }
Ok(())
}
pub fn angular_damping(&self) -> f32 {
self.assert_valid();
unsafe { ffi::b2Body_GetAngularDamping(self.id) }
}
pub fn try_angular_damping(&self) -> ApiResult<f32> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetAngularDamping(self.id) })
}
pub fn set_angular_damping(&mut self, v: f32) {
self.assert_valid();
unsafe { ffi::b2Body_SetAngularDamping(self.id, v) }
}
pub fn try_set_angular_damping(&mut self, v: f32) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAngularDamping(self.id, v) }
Ok(())
}
pub fn is_awake(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsAwake(self.id) }
}
pub fn set_awake(&mut self, awake: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetAwake(self.id, awake) }
}
pub fn try_is_awake(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsAwake(self.id) })
}
pub fn try_set_awake(&mut self, awake: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetAwake(self.id, awake) }
Ok(())
}
pub fn is_enabled(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsEnabled(self.id) }
}
pub fn enable(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_Enable(self.id) }
}
pub fn disable(&mut self) {
self.assert_valid();
unsafe { ffi::b2Body_Disable(self.id) }
}
pub fn try_is_enabled(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsEnabled(self.id) })
}
pub fn try_enable(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_Enable(self.id) }
Ok(())
}
pub fn try_disable(&mut self) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_Disable(self.id) }
Ok(())
}
pub fn is_bullet(&self) -> bool {
self.assert_valid();
unsafe { ffi::b2Body_IsBullet(self.id) }
}
pub fn set_bullet(&mut self, flag: bool) {
self.assert_valid();
unsafe { ffi::b2Body_SetBullet(self.id, flag) }
}
pub fn try_is_bullet(&self) -> ApiResult<bool> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_IsBullet(self.id) })
}
pub fn try_set_bullet(&mut self, flag: bool) -> ApiResult<()> {
self.check_valid()?;
unsafe { ffi::b2Body_SetBullet(self.id, flag) }
Ok(())
}
pub fn set_name(&mut self, name: &str) {
self.assert_valid();
let cs = CString::new(name).expect("body name contains an interior NUL byte");
unsafe { ffi::b2Body_SetName(self.id, cs.as_ptr()) }
}
pub fn try_set_name(&mut self, name: &str) -> ApiResult<()> {
self.check_valid()?;
let cs = CString::new(name).map_err(|_| ApiError::NulByteInString)?;
unsafe { ffi::b2Body_SetName(self.id, cs.as_ptr()) }
Ok(())
}
pub fn name(&self) -> Option<String> {
self.assert_valid();
let ptr = unsafe { ffi::b2Body_GetName(self.id) };
if ptr.is_null() {
None
} else {
Some(
unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
)
}
}
pub fn try_name(&self) -> ApiResult<Option<String>> {
self.check_valid()?;
let ptr = unsafe { ffi::b2Body_GetName(self.id) };
if ptr.is_null() {
Ok(None)
} else {
Ok(Some(
unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
))
}
}
pub unsafe fn set_user_data_ptr(&mut self, p: *mut c_void) {
self.assert_valid();
let _ = self.core.clear_body_user_data(self.id);
unsafe { ffi::b2Body_SetUserData(self.id, p) }
}
pub unsafe fn try_set_user_data_ptr(&mut self, p: *mut c_void) -> ApiResult<()> {
self.check_valid()?;
let _ = self.core.clear_body_user_data(self.id);
unsafe { ffi::b2Body_SetUserData(self.id, p) }
Ok(())
}
pub fn user_data_ptr(&self) -> *mut c_void {
self.assert_valid();
unsafe { ffi::b2Body_GetUserData(self.id) }
}
pub fn try_user_data_ptr(&self) -> ApiResult<*mut c_void> {
self.check_valid()?;
Ok(unsafe { ffi::b2Body_GetUserData(self.id) })
}
pub fn set_user_data<T: 'static>(&mut self, value: T) {
self.assert_valid();
let p = self.core.set_body_user_data(self.id, value);
unsafe { ffi::b2Body_SetUserData(self.id, p) };
}
pub fn try_set_user_data<T: 'static>(&mut self, value: T) -> ApiResult<()> {
self.check_valid()?;
let p = self.core.set_body_user_data(self.id, value);
unsafe { ffi::b2Body_SetUserData(self.id, p) };
Ok(())
}
pub fn clear_user_data(&mut self) -> bool {
self.assert_valid();
let had = self.core.clear_body_user_data(self.id);
if had {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
had
}
pub fn try_clear_user_data(&mut self) -> ApiResult<bool> {
self.check_valid()?;
let had = self.core.clear_body_user_data(self.id);
if had {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(had)
}
pub fn with_user_data<T: 'static, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_body_user_data(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data<T: 'static, R>(
&self,
f: impl FnOnce(&T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_body_user_data(self.id, f)
}
pub fn with_user_data_mut<T: 'static, R>(&mut self, f: impl FnOnce(&mut T) -> R) -> Option<R> {
self.assert_valid();
self.core
.try_with_body_user_data_mut(self.id, f)
.expect("user data type mismatch")
}
pub fn try_with_user_data_mut<T: 'static, R>(
&mut self,
f: impl FnOnce(&mut T) -> R,
) -> ApiResult<Option<R>> {
self.check_valid()?;
self.core.try_with_body_user_data_mut(self.id, f)
}
pub fn take_user_data<T: 'static>(&mut self) -> Option<T> {
self.assert_valid();
let v = self
.core
.take_body_user_data::<T>(self.id)
.expect("user data type mismatch");
if v.is_some() {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
v
}
pub fn try_take_user_data<T: 'static>(&mut self) -> ApiResult<Option<T>> {
self.check_valid()?;
let v = self.core.take_body_user_data::<T>(self.id)?;
if v.is_some() {
unsafe { ffi::b2Body_SetUserData(self.id, core::ptr::null_mut()) };
}
Ok(v)
}
pub fn as_id(&self) -> BodyId {
self.id
}
}