using Unity.Assertions; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; namespace Unity.Physics.Extensions { /// /// Utility functions acting on physics components. /// public static class PhysicsSamplesExtensions { #region CompoundCollider Utilities /// /// Given the root Collider of a hierarchy and a ColliderKey referencing a child in that hierarchy, /// this function returns the ColliderKey referencing the parent Collider. /// /// A at the root of a Collider hierarchy. /// A referencing a child Collider somewhere in the hierarchy below rootColliderPtr. /// A referencing the parent of the child Collider. Will be ColliderKey.Empty if the parameters where invalid. /// Whether the parent was successfully found in the hierarchy. public static unsafe bool TryGetParentColliderKey(Collider* rootColliderPtr, ColliderKey childColliderKey, out ColliderKey parentColliderKey) { var childColliderPtr = rootColliderPtr; var childColliderKeyNumBits = childColliderPtr->NumColliderKeyBits; // Start with an Empty collider key and push sub keys onto it as we traverse down the compound hierarchy. var parentColliderKeyPath = ColliderKeyPath.Empty; // On the way down, the childColliderKey pops of sub keys and pushes them onto the parentColliderKeyPath do { childColliderKey.PopSubKey(childColliderKeyNumBits, out var childIndex); switch (childColliderPtr->Type) { case ColliderType.Compound: // Get the next child down and loop again parentColliderKeyPath.PushChildKey(new ColliderKeyPath(new ColliderKey(childColliderKeyNumBits, childIndex), childColliderKeyNumBits)); childColliderPtr = ((CompoundCollider*)childColliderPtr)->Children[(int)childIndex].Collider; childColliderKeyNumBits = childColliderPtr->NumColliderKeyBits; break; case ColliderType.Mesh: case ColliderType.Terrain: // We've hit a Terrain or Mesh collider so there should only be PolygonColliders below this. // At this point the childColliderKey should be Empty and childIndex should be the index of the polygon. if (!childColliderKey.Equals(ColliderKey.Empty)) { // We've reached the bottom without popping all the child keys. // The given childColliderKey doesn't fit this hierarchy! parentColliderKey = ColliderKey.Empty; return false; } break; default: // We've hit a Convex collider, so rootColliderPtr must not have been // the root of a hierarchy in the first place and so there is no parent! parentColliderKey = ColliderKey.Empty; return false; } } while (!childColliderKey.Equals(ColliderKey.Empty) && !childColliderPtr->CollisionType.Equals(CollisionType.Convex)); parentColliderKey = parentColliderKeyPath.Key; // childColliderKey should be Empty at this point. // However, if it isn't then we reached a leaf without finding the child collider! return childColliderKey.Equals(ColliderKey.Empty); } /// /// Given the root Collider of a hierarchy and a ColliderKey referencing a child in that hierarchy, /// this function returns the ChildCollider requested. /// /// A at the root of a Collider hierarchy. /// A referencing a child Collider somewhere in the hierarchy below rootColliderPtr. /// A valid returned from the hierarchy, if found. /// Whether a specified ColliderKey was successfully found in the hierarchy. public static unsafe bool TryGetChildInHierarchy(Collider* rootColliderPtr, ColliderKey childColliderKey, out ChildCollider childCollider) { //public static unsafe bool GetLeafCollider(Collider* root, RigidTransform rootTransform, ColliderKey key, out ChildCollider leaf) childCollider = new ChildCollider(rootColliderPtr, RigidTransform.identity); while (!childColliderKey.Equals(ColliderKey.Empty)) { if (!childCollider.Collider->GetChild(ref childColliderKey, out ChildCollider child)) { break; } childCollider = new ChildCollider(childCollider, child); } return (childCollider.Collider != null); } /// /// Sets the Entity references in a CompoundCollider according to the provided collider key entity pairs. /// /// A . /// An array of and pairs. public static unsafe void RemapColliderEntityReferences( CompoundCollider* compoundColliderPtr, in NativeArray keyEntityPairs) => RemapCompoundColliderEntityReferences(compoundColliderPtr, keyEntityPairs, ColliderKey.Empty); internal static unsafe void RemapCompoundColliderEntityReferences( CompoundCollider* compoundColliderPtr, in NativeArray keyEntityPairs, in ColliderKey key) { for (int childIndex = 0; childIndex < compoundColliderPtr->Children.Length; childIndex++) { ref CompoundCollider.Child child = ref compoundColliderPtr->Children[childIndex]; var childKey = key; childKey.PushSubKey(compoundColliderPtr->NumColliderKeyBits, (uint)childIndex); for (int i = 0; i < keyEntityPairs.Length; i++) { if (childKey.Equals(keyEntityPairs[i].Key)) { child.Entity = keyEntityPairs[i].Entity; break; } } if (child.Collider->Type == ColliderType.Compound) { RemapCompoundColliderEntityReferences((CompoundCollider*)child.Collider, keyEntityPairs, childKey); } } } #endregion } }