private void AddMapping(Hull hull, Collider col, HullPainterChild painterChild) { HullMapping newMapping = new HullMapping() { sourceHull = hull, generatedCollider = col, targetChild = painterChild }; this.hullMapping.Add(newMapping); }
private void RecreateChildCollider <T>(HullMapping mapping) where T : Collider { if (mapping.sourceHull == null || !mapping.sourceHull.isChildCollider) { return; } T col = AddComponent <T>(mapping.targetChild.gameObject); mapping.generatedCollider = col; }
private void RecreateChildCollider(HullMapping mapping) { if (mapping == null || mapping.sourceHull == null || !mapping.sourceHull.isChildCollider) { return; } if (mapping.sourceHull.type == HullType.Box) { RecreateChildCollider <BoxCollider>(mapping); } else if (mapping.sourceHull.type == HullType.Sphere) { RecreateChildCollider <SphereCollider>(mapping); } else if (mapping.sourceHull.type == HullType.ConvexHull) { RecreateChildCollider <MeshCollider>(mapping); } else if (mapping.sourceHull.type == HullType.Face) { RecreateChildCollider <MeshCollider>(mapping); } }
private void CreateHullMapping() { if (hullMapping == null) { // hullMapping = new Dictionary<Hull, Collider>(); hullMapping = new List <HullMapping>(); } // Remove any invalid entries from the hull mapping // null entries are garbage and can be dropped // null source hull means the hull has been deleted and this mapping is no longer relevant // missing *both* generated collider *and* target child means there's no data to point at, so might as well remove it and regen from scratch for (int i = hullMapping.Count - 1; i >= 0; i--) { HullMapping mapping = hullMapping[i]; if (mapping == null || mapping.sourceHull == null || (mapping.generatedCollider == null && mapping.targetChild == null)) { hullMapping.RemoveAt(i); } } // Check to see if any existing mappings need updating (hull.type doesn't match Collider type, or child type no longer matches) foreach (Hull hull in paintingData.hulls) { if (IsMapped(hull)) { // We already have a mapping for this, but is it still of the correct type? Collider value = FindExistingCollider(hullMapping, hull); bool isHullOk = (hull.type == HullType.ConvexHull && value is MeshCollider); bool isBoxOk = (hull.type == HullType.Box && value is BoxCollider); bool isSphereOk = (hull.type == HullType.Sphere && value is SphereCollider); bool isFaceOk = (hull.type == HullType.Face && value is MeshCollider); bool isColliderTypeOk = (isHullOk || isBoxOk || isSphereOk || isFaceOk); bool isChildTypeOk = value == null || ((hull.isChildCollider) == (value.transform.parent == this.transform)); if (isColliderTypeOk && isChildTypeOk) { // All good } else { // Mismatch - hull.type doesn't match collider type // Delete the collider and remove the mapping // This hull will then be orphaned, and a new collider added back in accordingly DestroyImmediateWithUndo(value); RemoveMapping(hull); } } } // Connect orphans // // Find hulls without a Collider // Find Colliders without hulls // Try and map the two together // First find orphans - hull, colliders or childs that aren't already mapped List <Hull> orphanedHulls = new List <Hull>(); List <Collider> orphanedColliders = new List <Collider>(); List <HullPainterChild> orphanedChilds = new List <HullPainterChild>(); foreach (Hull h in paintingData.hulls) { if (!IsMapped(h)) { orphanedHulls.Add(h); } } foreach (Collider c in FindLocal <Collider>()) { if (!IsMapped(c)) { orphanedColliders.Add(c); } } foreach (HullPainterChild c in FindLocal <HullPainterChild>()) { if (!IsMapped(c)) { orphanedChilds.Add(c); } } // Try and connect orphaned hulls with orphaned colliders for (int i = orphanedHulls.Count - 1; i >= 0; i--) { Hull h = orphanedHulls[i]; for (int j = orphanedColliders.Count - 1; j >= 0; j--) { Collider c = orphanedColliders[j]; // Find the HullPainterChild adjacent to the collider (if a child collider) HullPainterChild child = null; if (c.transform.parent == this.transform) { child = c.gameObject.GetComponent <HullPainterChild>(); } // todo needs better handling bool isMatchingChild = h.isChildCollider && c.transform.parent == this.transform; if (isMatchingChild) { BoxCollider boxCol = c as BoxCollider; SphereCollider sphereCol = c as SphereCollider; MeshCollider meshCol = c as MeshCollider; bool isMatchingBox = h.type == HullType.Box && c is BoxCollider && Approximately(h.collisionBox.center, boxCol.center) && Approximately(h.collisionBox.size, boxCol.size); bool isMatchingSphere = h.type == HullType.Sphere && c is SphereCollider && h.collisionSphere != null && Approximately(h.collisionSphere.center, sphereCol.center) && Approximately(h.collisionSphere.radius, sphereCol.radius); bool isMatchingConvexHull = h.type == HullType.ConvexHull && c is MeshCollider && meshCol.sharedMesh == h.collisionMesh; bool isMatchingFace = h.type == HullType.Face && c is MeshCollider && meshCol.sharedMesh == h.faceCollisionMesh; if (isMatchingBox || isMatchingSphere || isMatchingConvexHull || isMatchingFace) { // Found a pair, so add a mapping and remove the orphans AddMapping(h, c, child); // These are no longer orphaned, so remove them from these lists orphanedHulls.RemoveAt(i); orphanedColliders.RemoveAt(j); // Remove the no-longer orphaned child for (int k = 0; k < orphanedChilds.Count; k++) { if (orphanedChilds[k] == child) { orphanedChilds.RemoveAt(k); break; } } break; } } } } // We've tried to connect hulls to existing colliders, now try and connect hulls to existing HullPainterChilds // These will be child without a collider (as otherwise they'd have be picked up earlier) for (int i = orphanedHulls.Count - 1; i >= 0; i--) { Hull h = orphanedHulls[i]; if (!h.isChildCollider) { continue; } for (int j = orphanedChilds.Count - 1; j >= 0; j--) { HullPainterChild child = orphanedChilds[j]; HullMapping mapping = FindMapping(child); if (mapping != null && mapping.sourceHull != null) { // Found a match for hull-mapping-child // Ensure this still has a collider if (mapping.generatedCollider == null) { // Recreate the collider of the correct type with the existing hull-mapping-child RecreateChildCollider(mapping); } orphanedHulls.RemoveAt(i); orphanedChilds.RemoveAt(j); break; } } } // Create colliders for any hull mapping children without colliders foreach (HullMapping mapping in hullMapping) { if (mapping.targetChild != null && mapping.generatedCollider == null) { RecreateChildCollider(mapping); } } // Create child components for child colliders without them foreach (HullMapping mapping in hullMapping) { if (mapping.targetChild == null && mapping.generatedCollider != null && mapping.generatedCollider.transform.parent == this.transform) { // Mapping has a child collider but no HullPainterChild // Recreate the child component HullPainterChild newChild = AddComponent <HullPainterChild>(mapping.generatedCollider.gameObject); newChild.parent = this; mapping.targetChild = newChild; } } // Create colliders for any left over hulls foreach (Hull h in orphanedHulls) { if (h.type == HullType.Box) { CreateCollider <BoxCollider>(h); } else if (h.type == HullType.Sphere) { CreateCollider <SphereCollider>(h); } else if (h.type == HullType.ConvexHull) { CreateCollider <MeshCollider>(h); } else if (h.type == HullType.Face) { CreateCollider <MeshCollider>(h); } } // Delete any left over colliders // TODO: This probably isn't properly undo-aware foreach (Collider c in orphanedColliders) { if (c.gameObject == this.gameObject) { DestroyImmediateWithUndo(c); } else { // Child collider - delete collider, HullPainterChild (if any) and GameObject (if empty) GameObject go = c.gameObject; DestroyImmediateWithUndo(c); DestroyImmediateWithUndo(go.GetComponent <HullPainterChild>()); if (IsDeletable(go)) { DestroyImmediateWithUndo(go); } } } // Delete any left over hull painter childs // TODO: This probably isn't undo-aware foreach (HullPainterChild child in orphanedChilds) { if (child == null) { continue; } // Delete child, collider (if any) and GameObject (if empty) GameObject go = child.gameObject; DestroyImmediateWithUndo(child); DestroyImmediateWithUndo(go.GetComponent <Collider>()); if (IsDeletable(go)) { DestroyImmediateWithUndo(go); } } // Sanity check - all hull mappings should have a collider of the right type now // foreach (HullMapping mapping in hullMapping) // { // if (mapping.generatedCollider == null) // Debug.LogWarning("Null collider for hull: " + mapping.sourceHull.name); // } }