From b47c30c5ef231e3ce27435b56604b638ba5f9f4e Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 14 Dec 2024 21:58:38 +0200 Subject: [PATCH] Expose `EllipseColliderShape` and `RegularPolygonColliderShape` (#596) # 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. --- src/collision/collider/parry/mod.rs | 14 +++---- src/collision/collider/parry/primitives2d.rs | 44 ++++++++++++-------- src/debug_render/gizmos.rs | 9 ++-- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/collision/collider/parry/mod.rs b/src/collision/collider/parry/mod.rs index 759e8db4..3a4a56ff 100644 --- a/src/collision/collider/parry/mod.rs +++ b/src/collision/collider/parry/mod.rs @@ -14,7 +14,7 @@ mod primitives2d; mod primitives3d; #[cfg(feature = "2d")] -pub(crate) use primitives2d::{EllipseWrapper, RegularPolygonWrapper}; +pub use primitives2d::{EllipseColliderShape, RegularPolygonColliderShape}; impl> From for Collider { fn from(value: T) -> Self { @@ -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, ))) @@ -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(), }))) } @@ -1467,14 +1467,14 @@ fn scale_shape( TypedShape::Custom(_shape) => { #[cfg(feature = "2d")] { - if let Some(ellipse) = _shape.as_shape::() { - return Ok(SharedShape::new(EllipseWrapper(Ellipse { + if let Some(ellipse) = _shape.as_shape::() { + return Ok(SharedShape::new(EllipseColliderShape(Ellipse { half_size: ellipse.half_size * scale.f32().abs(), }))); } - if let Some(polygon) = _shape.as_shape::() { + if let Some(polygon) = _shape.as_shape::() { 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, diff --git a/src/collision/collider/parry/primitives2d.rs b/src/collision/collider/parry/primitives2d.rs index 76aee10c..5324dd9b 100644 --- a/src/collision/collider/parry/primitives2d.rs +++ b/src/collision/collider/parry/primitives2d.rs @@ -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::{ @@ -25,14 +25,18 @@ impl IntoCollider for Circle { impl IntoCollider 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) -> Point2 { let [a, b] = self.half_size.adjust_precision().to_array(); @@ -41,7 +45,7 @@ impl SupportMap for EllipseWrapper { } } -impl Shape for EllipseWrapper { +impl Shape for EllipseColliderShape { fn clone_dyn(&self) -> Box { Box::new(*self) } @@ -52,7 +56,7 @@ impl Shape for EllipseWrapper { _num_subdivisions: u32, ) -> Option> { 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, )))) @@ -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, @@ -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, @@ -239,14 +243,18 @@ impl IntoCollider for BoxedPolygon { impl IntoCollider 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) -> Point2 { // TODO: For polygons with a small number of sides, maybe just iterating @@ -273,7 +281,7 @@ impl SupportMap for RegularPolygonWrapper { } } -impl PolygonalFeatureMap for RegularPolygonWrapper { +impl PolygonalFeatureMap for RegularPolygonColliderShape { #[inline] fn local_support_feature( &self, @@ -315,7 +323,7 @@ impl PolygonalFeatureMap for RegularPolygonWrapper { } } -impl Shape for RegularPolygonWrapper { +impl Shape for RegularPolygonColliderShape { fn clone_dyn(&self) -> Box { Box::new(*self) } @@ -326,7 +334,7 @@ impl Shape for RegularPolygonWrapper { _num_subdivisions: u32, ) -> Option> { let circumradius = Vector::from(*scale).f32() * self.circumradius(); - Some(Box::new(RegularPolygonWrapper(RegularPolygon::new( + Some(Box::new(RegularPolygonColliderShape(RegularPolygon::new( circumradius.length(), self.sides, )))) @@ -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, @@ -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, diff --git a/src/debug_render/gizmos.rs b/src/debug_render/gizmos.rs index 16dd9940..87914f3e 100644 --- a/src/debug_render/gizmos.rs +++ b/src/debug_render/gizmos.rs @@ -432,14 +432,17 @@ impl PhysicsGizmoExt for Gizmos<'_, '_, PhysicsGizmos> { TypedShape::Custom(_id) => { #[cfg(feature = "2d")] { - if let Some(ellipse) = collider.shape_scaled().as_shape::() { + if let Some(ellipse) = + collider.shape_scaled().as_shape::() + { 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::() + } else if let Some(polygon) = collider + .shape_scaled() + .as_shape::() { let isometry = Isometry2d::new( position.f32(),