colliders

This commit is contained in:
2026-01-05 04:54:13 +00:00
parent 71a031c3f9
commit c58488c5fa
5 changed files with 336 additions and 14 deletions

View File

@@ -1,6 +1,7 @@
//! BoxCollider component wrapper
use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3};
use crate::types::unity_types::Collider;
use sparsey::Entity;
/// A BoxCollider component
@@ -9,28 +10,39 @@ use sparsey::Entity;
/// It defines a box-shaped volume that can be used for collision detection.
#[derive(Debug, Clone)]
pub struct BoxCollider {
size: Option<Vector3>,
center: Option<Vector3>,
size: Vector3,
center: Vector3,
collider: Collider,
}
impl BoxCollider {
/// Get the size of the box collider
pub fn size(&self) -> Option<&Vector3> {
self.size.as_ref()
pub fn size(&self) -> &Vector3 {
&self.size
}
/// Get the center offset of the box collider
pub fn center(&self) -> Option<&Vector3> {
self.center.as_ref()
pub fn center(&self) -> &Vector3 {
&self.center
}
/// Get the base collider component
pub fn collider(&self) -> &Collider {
&self.collider
}
/// Get mutable access to the base collider component
pub fn collider_mut(&mut self) -> &mut Collider {
&mut self.collider
}
/// Set the size of the box collider
pub fn set_size(&mut self, size: Option<Vector3>) {
pub fn set_size(&mut self, size: Vector3) {
self.size = size;
}
/// Set the center offset of the box collider
pub fn set_center(&mut self, center: Option<Vector3>) {
pub fn set_center(&mut self, center: Vector3) {
self.center = center;
}
}
@@ -39,17 +51,23 @@ impl UnityComponent for BoxCollider {
/// Parse a BoxCollider from YAML
///
/// Note: Caller is responsible for ensuring this is called on the correct document type.
fn parse(yaml: &serde_yaml::Mapping, _ctx: &ComponentContext) -> Option<Self> {
let size = yaml_helpers::get_vector3(yaml, "m_Size");
let center = yaml_helpers::get_vector3(yaml, "m_Center");
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
let size = yaml_helpers::get_vector3(yaml, "m_Size").unwrap_or_default();
let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default();
Some(Self { size, center })
// Parse the base collider component (layer masks)
let collider = Collider::parse(yaml, ctx)?;
Some(Self { size, center, collider })
}
}
impl crate::types::EcsInsertable for BoxCollider {
fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) {
world.insert(entity, (self,));
// Insert both the BoxCollider and the base Collider component
// This allows querying for either specific collider types or all colliders
let collider = self.collider.clone();
world.insert(entity, (self, collider));
}
}
@@ -61,6 +79,9 @@ inventory::submit! {
parse_and_insert: |yaml, ctx, world, entity| {
<BoxCollider as crate::types::EcsInsertable>::parse_and_insert(yaml, ctx, world, entity)
},
register: |builder| builder.register::<BoxCollider>(),
register: |builder| {
// Register both BoxCollider and the base Collider component
builder.register::<BoxCollider>().register::<Collider>()
},
}
}

View File

@@ -0,0 +1,117 @@
//! CapsuleCollider component wrapper
use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3};
use crate::types::unity_types::Collider;
use sparsey::Entity;
/// A CapsuleCollider component
///
/// CapsuleCollider is a basic collision primitive in the shape of a capsule.
/// It defines a capsule-shaped volume (cylinder with hemispherical ends) that can be used for collision detection.
#[derive(Debug, Clone)]
pub struct CapsuleCollider {
radius: f32,
height: f32,
center: Vector3,
direction: i32, // 0 = X-axis, 1 = Y-axis, 2 = Z-axis
collider: Collider,
}
impl CapsuleCollider {
/// Get the radius of the capsule collider
pub fn radius(&self) -> f32 {
self.radius
}
/// Get the height of the capsule collider
pub fn height(&self) -> f32 {
self.height
}
/// Get the center offset of the capsule collider
pub fn center(&self) -> &Vector3 {
&self.center
}
/// Get the direction axis of the capsule (0=X, 1=Y, 2=Z)
pub fn direction(&self) -> i32 {
self.direction
}
/// Get the base collider component
pub fn collider(&self) -> &Collider {
&self.collider
}
/// Get mutable access to the base collider component
pub fn collider_mut(&mut self) -> &mut Collider {
&mut self.collider
}
/// Set the radius of the capsule collider
pub fn set_radius(&mut self, radius: f32) {
self.radius = radius;
}
/// Set the height of the capsule collider
pub fn set_height(&mut self, height: f32) {
self.height = height;
}
/// Set the center offset of the capsule collider
pub fn set_center(&mut self, center: Vector3) {
self.center = center;
}
/// Set the direction axis (0=X, 1=Y, 2=Z)
pub fn set_direction(&mut self, direction: i32) {
self.direction = direction;
}
}
impl UnityComponent for CapsuleCollider {
/// Parse a CapsuleCollider from YAML
///
/// Note: Caller is responsible for ensuring this is called on the correct document type.
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
let radius = yaml_helpers::get_f64(yaml, "m_Radius").unwrap_or(0.0) as f32;
let height = yaml_helpers::get_f64(yaml, "m_Height").unwrap_or(0.0) as f32;
let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default();
let direction = yaml_helpers::get_i64(yaml, "m_Direction").unwrap_or(0) as i32;
// Parse the base collider component (layer masks)
let collider = Collider::parse(yaml, ctx)?;
Some(Self {
radius,
height,
center,
direction,
collider,
})
}
}
impl crate::types::EcsInsertable for CapsuleCollider {
fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) {
// Insert both the CapsuleCollider and the base Collider component
// This allows querying for either specific collider types or all colliders
let collider = self.collider.clone();
world.insert(entity, (self, collider));
}
}
// Register component with inventory
inventory::submit! {
crate::types::ComponentRegistration {
type_id: 136, // Unity type ID for CapsuleCollider
class_name: "CapsuleCollider",
parse_and_insert: |yaml, ctx, world, entity| {
<CapsuleCollider as crate::types::EcsInsertable>::parse_and_insert(yaml, ctx, world, entity)
},
register: |builder| {
// Register both CapsuleCollider and the base Collider component
builder.register::<CapsuleCollider>().register::<Collider>()
},
}
}

View File

@@ -0,0 +1,87 @@
//! Collider component wrapper
use crate::types::{ComponentContext, UnityComponent};
use serde_yaml::{Mapping, Value};
use sparsey::Entity;
/// A Collider component
///
/// Collider is the base class for collision primitives.
/// Contains layer mask information for collision filtering.
#[derive(Debug, Clone)]
pub struct Collider {
/// Layer mask for which layers this collider can collide with
include_layers: u32,
/// Layer mask for which layers this collider should ignore
exclude_layers: u32,
}
impl Collider {
/// Get the include layers bitset
pub fn include_layers(&self) -> u32 {
self.include_layers
}
/// Get the exclude layers bitset
pub fn exclude_layers(&self) -> u32 {
self.exclude_layers
}
/// Set the include layers bitset
pub fn set_include_layers(&mut self, layers: u32) {
self.include_layers = layers;
}
/// Set the exclude layers bitset
pub fn set_exclude_layers(&mut self, layers: u32) {
self.exclude_layers = layers;
}
/// Check if the collider can interact with a specific layer (0-31)
pub fn can_collide_with_layer(&self, layer: u8) -> bool {
if layer >= 32 {
return false;
}
let layer_bit = 1u32 << layer;
(self.include_layers & layer_bit) != 0 && (self.exclude_layers & layer_bit) == 0
}
}
/// Helper function to parse Unity's layer bitset structure
///
/// Unity stores layer masks as:
/// ```yaml
/// m_IncludeLayers:
/// serializedVersion: 2
/// m_Bits: 0
/// ```
fn parse_layer_bitset(map: &Mapping, key: &str) -> Option<u32> {
let obj = map
.get(&Value::String(key.to_string()))
.and_then(|v| v.as_mapping())?;
obj.get(&Value::String("m_Bits".to_string()))
.and_then(|v| v.as_u64())
.map(|bits| bits as u32)
}
impl UnityComponent for Collider {
/// Parse a Collider from YAML
///
/// Note: Caller is responsible for ensuring this is called on the correct document type.
fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option<Self> {
let include_layers = parse_layer_bitset(yaml, "m_IncludeLayers").unwrap_or(0);
let exclude_layers = parse_layer_bitset(yaml, "m_ExcludeLayers").unwrap_or(0);
Some(Self {
include_layers,
exclude_layers,
})
}
}
impl crate::types::EcsInsertable for Collider {
fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) {
world.insert(entity, (self,));
}
}

View File

@@ -1,14 +1,19 @@
//! Unity-specific types (GameObjects, Transforms, PrefabInstances)
pub mod box_collider;
pub mod capsule_collider;
pub mod collider;
pub mod game_object;
pub mod mesh_filter;
pub mod mesh_renderer;
pub mod prefab_instance;
pub mod renderer;
pub mod sphere_collider;
pub mod transform;
pub use box_collider::BoxCollider;
pub use capsule_collider::CapsuleCollider;
pub use collider::Collider;
pub use game_object::GameObject;
pub use mesh_filter::MeshFilter;
pub use mesh_renderer::MeshRenderer;
@@ -16,4 +21,5 @@ pub use prefab_instance::{
PrefabInstance, PrefabInstanceComponent, PrefabModification, PrefabResolver,
};
pub use renderer::Renderer;
pub use sphere_collider::SphereCollider;
pub use transform::{RectTransform, Transform};

View File

@@ -0,0 +1,91 @@
//! SphereCollider component wrapper
use crate::types::{yaml_helpers, ComponentContext, UnityComponent, Vector3};
use crate::types::unity_types::Collider;
use sparsey::Entity;
/// A SphereCollider component
///
/// SphereCollider is a basic collision primitive in the shape of a sphere.
/// It defines a sphere-shaped volume that can be used for collision detection.
#[derive(Debug, Clone)]
pub struct SphereCollider {
radius: f32,
center: Vector3,
collider: Collider,
}
impl SphereCollider {
/// Get the radius of the sphere collider
pub fn radius(&self) -> f32 {
self.radius
}
/// Get the center offset of the sphere collider
pub fn center(&self) -> &Vector3 {
&self.center
}
/// Get the base collider component
pub fn collider(&self) -> &Collider {
&self.collider
}
/// Get mutable access to the base collider component
pub fn collider_mut(&mut self) -> &mut Collider {
&mut self.collider
}
/// Set the radius of the sphere collider
pub fn set_radius(&mut self, radius: f32) {
self.radius = radius;
}
/// Set the center offset of the sphere collider
pub fn set_center(&mut self, center: Vector3) {
self.center = center;
}
}
impl UnityComponent for SphereCollider {
/// Parse a SphereCollider from YAML
///
/// Note: Caller is responsible for ensuring this is called on the correct document type.
fn parse(yaml: &serde_yaml::Mapping, ctx: &ComponentContext) -> Option<Self> {
let radius = yaml_helpers::get_f64(yaml, "m_Radius").unwrap_or(0.0) as f32;
let center = yaml_helpers::get_vector3(yaml, "m_Center").unwrap_or_default();
// Parse the base collider component (layer masks)
let collider = Collider::parse(yaml, ctx)?;
Some(Self {
radius,
center,
collider,
})
}
}
impl crate::types::EcsInsertable for SphereCollider {
fn insert_into_world(self, world: &mut sparsey::World, entity: Entity) {
// Insert both the SphereCollider and the base Collider component
// This allows querying for either specific collider types or all colliders
let collider = self.collider.clone();
world.insert(entity, (self, collider));
}
}
// Register component with inventory
inventory::submit! {
crate::types::ComponentRegistration {
type_id: 135, // Unity type ID for SphereCollider
class_name: "SphereCollider",
parse_and_insert: |yaml, ctx, world, entity| {
<SphereCollider as crate::types::EcsInsertable>::parse_and_insert(yaml, ctx, world, entity)
},
register: |builder| {
// Register both SphereCollider and the base Collider component
builder.register::<SphereCollider>().register::<Collider>()
},
}
}