Skip to content

Commit

Permalink
Expose EllipseColliderShape and RegularPolygonColliderShape (#596)
Browse files Browse the repository at this point in the history
# Objective

Fixes #595.

Currently, `EllipseWrapper` and `RegularPolygonWrapper` are not public, so you cannot access their information at runtime for colliders.

## Solution

Make them public, and rename them to `EllipseColliderShape` and `RegularPolygonColliderShape` for clarity.
  • Loading branch information
Jondolf authored Dec 14, 2024
1 parent 5cd89f1 commit b47c30c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 28 deletions.
14 changes: 7 additions & 7 deletions src/collision/collider/parry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod primitives2d;
mod primitives3d;

#[cfg(feature = "2d")]
pub(crate) use primitives2d::{EllipseWrapper, RegularPolygonWrapper};
pub use primitives2d::{EllipseColliderShape, RegularPolygonColliderShape};

impl<T: IntoCollider<Collider>> From<T> for Collider {
fn from(value: T) -> Self {
Expand Down Expand Up @@ -717,7 +717,7 @@ impl Collider {
/// Creates a collider with an ellipse shape defined by a half-width and half-height.
#[cfg(feature = "2d")]
pub fn ellipse(half_width: Scalar, half_height: Scalar) -> Self {
SharedShape::new(EllipseWrapper(Ellipse::new(
SharedShape::new(EllipseColliderShape(Ellipse::new(
half_width as f32,
half_height as f32,
)))
Expand Down Expand Up @@ -1317,7 +1317,7 @@ fn scale_shape(
Ok(SharedShape::ball(b.radius * scale.x.abs()))
} else {
// A 2D circle becomes an ellipse when scaled non-uniformly.
Ok(SharedShape::new(EllipseWrapper(Ellipse {
Ok(SharedShape::new(EllipseColliderShape(Ellipse {
half_size: Vec2::splat(b.radius as f32) * scale.f32().abs(),
})))
}
Expand Down Expand Up @@ -1467,14 +1467,14 @@ fn scale_shape(
TypedShape::Custom(_shape) => {
#[cfg(feature = "2d")]
{
if let Some(ellipse) = _shape.as_shape::<EllipseWrapper>() {
return Ok(SharedShape::new(EllipseWrapper(Ellipse {
if let Some(ellipse) = _shape.as_shape::<EllipseColliderShape>() {
return Ok(SharedShape::new(EllipseColliderShape(Ellipse {
half_size: ellipse.half_size * scale.f32().abs(),
})));
}
if let Some(polygon) = _shape.as_shape::<RegularPolygonWrapper>() {
if let Some(polygon) = _shape.as_shape::<RegularPolygonColliderShape>() {
if scale.x == scale.y {
return Ok(SharedShape::new(RegularPolygonWrapper(
return Ok(SharedShape::new(RegularPolygonColliderShape(
RegularPolygon::new(
polygon.circumradius() * scale.x.abs() as f32,
polygon.sides,
Expand Down
44 changes: 26 additions & 18 deletions src/collision/collider/parry/primitives2d.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{math, AdjustPrecision, Scalar, Vector, FRAC_PI_2, PI, TAU};

use super::{AsF32, Collider, IntoCollider};
use bevy::prelude::Deref;
use bevy::prelude::{Deref, DerefMut};
use bevy_math::{bounding::Bounded2d, prelude::*};
use nalgebra::{Point2, UnitVector2, Vector2};
use parry::{
Expand All @@ -25,14 +25,18 @@ impl IntoCollider<Collider> for Circle {

impl IntoCollider<Collider> for Ellipse {
fn collider(&self) -> Collider {
Collider::from(SharedShape::new(EllipseWrapper(*self)))
Collider::from(SharedShape::new(EllipseColliderShape(*self)))
}
}

#[derive(Clone, Copy, Debug, Deref)]
pub(crate) struct EllipseWrapper(pub(crate) Ellipse);
/// An ellipse shape that can be stored in a [`SharedShape`] for an ellipse [`Collider`].
///
/// This wrapper is required to allow implementing the necessary traits from [`parry`]
/// for Bevy's [`Ellipse`] type.
#[derive(Clone, Copy, Debug, Deref, DerefMut)]
pub struct EllipseColliderShape(pub Ellipse);

impl SupportMap for EllipseWrapper {
impl SupportMap for EllipseColliderShape {
#[inline]
fn local_support_point(&self, direction: &Vector2<Scalar>) -> Point2<Scalar> {
let [a, b] = self.half_size.adjust_precision().to_array();
Expand All @@ -41,7 +45,7 @@ impl SupportMap for EllipseWrapper {
}
}

impl Shape for EllipseWrapper {
impl Shape for EllipseColliderShape {
fn clone_dyn(&self) -> Box<dyn Shape> {
Box::new(*self)
}
Expand All @@ -52,7 +56,7 @@ impl Shape for EllipseWrapper {
_num_subdivisions: u32,
) -> Option<Box<dyn parry::shape::Shape>> {
let half_size = Vector::from(*scale).f32() * self.half_size;
Some(Box::new(EllipseWrapper(Ellipse::new(
Some(Box::new(EllipseColliderShape(Ellipse::new(
half_size.x,
half_size.y,
))))
Expand Down Expand Up @@ -131,7 +135,7 @@ impl Shape for EllipseWrapper {
}
}

impl RayCast for EllipseWrapper {
impl RayCast for EllipseColliderShape {
fn cast_local_ray_and_get_normal(
&self,
ray: &parry::query::Ray,
Expand All @@ -148,7 +152,7 @@ impl RayCast for EllipseWrapper {
}
}

impl PointQuery for EllipseWrapper {
impl PointQuery for EllipseColliderShape {
fn project_local_point(
&self,
pt: &parry::math::Point<Scalar>,
Expand Down Expand Up @@ -239,14 +243,18 @@ impl IntoCollider<Collider> for BoxedPolygon {

impl IntoCollider<Collider> for RegularPolygon {
fn collider(&self) -> Collider {
Collider::from(SharedShape::new(RegularPolygonWrapper(*self)))
Collider::from(SharedShape::new(RegularPolygonColliderShape(*self)))
}
}

#[derive(Clone, Copy, Debug, Deref)]
pub(crate) struct RegularPolygonWrapper(pub(crate) RegularPolygon);
/// A regular polygon shape that can be stored in a [`SharedShape`] for a regular polygon [`Collider`].
///
/// This wrapper is required to allow implementing the necessary traits from [`parry`]
/// for Bevy's [`RegularPolygon`] type.
#[derive(Clone, Copy, Debug, Deref, DerefMut)]
pub struct RegularPolygonColliderShape(pub RegularPolygon);

impl SupportMap for RegularPolygonWrapper {
impl SupportMap for RegularPolygonColliderShape {
#[inline]
fn local_support_point(&self, direction: &Vector2<Scalar>) -> Point2<Scalar> {
// TODO: For polygons with a small number of sides, maybe just iterating
Expand All @@ -273,7 +281,7 @@ impl SupportMap for RegularPolygonWrapper {
}
}

impl PolygonalFeatureMap for RegularPolygonWrapper {
impl PolygonalFeatureMap for RegularPolygonColliderShape {
#[inline]
fn local_support_feature(
&self,
Expand Down Expand Up @@ -315,7 +323,7 @@ impl PolygonalFeatureMap for RegularPolygonWrapper {
}
}

impl Shape for RegularPolygonWrapper {
impl Shape for RegularPolygonColliderShape {
fn clone_dyn(&self) -> Box<dyn Shape> {
Box::new(*self)
}
Expand All @@ -326,7 +334,7 @@ impl Shape for RegularPolygonWrapper {
_num_subdivisions: u32,
) -> Option<Box<dyn parry::shape::Shape>> {
let circumradius = Vector::from(*scale).f32() * self.circumradius();
Some(Box::new(RegularPolygonWrapper(RegularPolygon::new(
Some(Box::new(RegularPolygonColliderShape(RegularPolygon::new(
circumradius.length(),
self.sides,
))))
Expand Down Expand Up @@ -437,7 +445,7 @@ impl Shape for RegularPolygonWrapper {
}
}

impl RayCast for RegularPolygonWrapper {
impl RayCast for RegularPolygonColliderShape {
fn cast_local_ray_and_get_normal(
&self,
ray: &parry::query::Ray,
Expand All @@ -454,7 +462,7 @@ impl RayCast for RegularPolygonWrapper {
}
}

impl PointQuery for RegularPolygonWrapper {
impl PointQuery for RegularPolygonColliderShape {
fn project_local_point(
&self,
pt: &parry::math::Point<Scalar>,
Expand Down
9 changes: 6 additions & 3 deletions src/debug_render/gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,17 @@ impl PhysicsGizmoExt for Gizmos<'_, '_, PhysicsGizmos> {
TypedShape::Custom(_id) => {
#[cfg(feature = "2d")]
{
if let Some(ellipse) = collider.shape_scaled().as_shape::<EllipseWrapper>() {
if let Some(ellipse) =
collider.shape_scaled().as_shape::<EllipseColliderShape>()
{
let isometry = Isometry2d::new(
position.f32(),
Rot2::from_sin_cos(rotation.sin as f32, rotation.cos as f32),
);
self.primitive_2d(&ellipse.0, isometry, color);
} else if let Some(polygon) =
collider.shape_scaled().as_shape::<RegularPolygonWrapper>()
} else if let Some(polygon) = collider
.shape_scaled()
.as_shape::<RegularPolygonColliderShape>()
{
let isometry = Isometry2d::new(
position.f32(),
Expand Down

0 comments on commit b47c30c

Please sign in to comment.