// Copyright (C) 2023 Nicholas Maltbie // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and // associated documentation files (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, publish, distribute, // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System.Collections.Generic; using System.Linq; using UnityEngine; namespace nickmaltbie.OpenKCC.Utils.ColliderCast { /// /// Collider cast for selecting between different primitive collider /// /// shapes. /// public class PrimitiveColliderCast : AbstractPrimitiveColliderCast { /// /// Selected collider configuration. /// [Tooltip("Collider type selected for casting.")] [SerializeField] public ColliderConfiguration config = new ColliderConfiguration(); /// /// Generated collider for this primitive collider cast. /// [HideInInspector] [SerializeField] private Collider generatedCollider; /// /// Create the collider for this primitive collider cast. /// public override void UpdateColliderParameters() { base.UpdateColliderParameters(); generatedCollider = config.AttachCollider(gameObject, true); base._collider = generatedCollider; if (config.type == ColliderType.Point) { SphereCollider sphere = gameObject.AddComponent(); sphere.radius = KCCUtils.Epsilon / 2; sphere.center = config.pointCenter; generatedCollider = sphere; } } /// public override Vector3 GetBottom(Vector3 position, Quaternion rotation) { switch (config.type) { case ColliderType.Box: (Vector3 boxCenter, Vector3 boxSize) = BoxColliderCast.GetParams(config.Center, config.Size, position, rotation); return boxCenter + rotation * Vector3.down * boxSize.y / 2; case ColliderType.Sphere: (Vector3 sphereCenter, float sphereRadius) = SphereColliderCast.GetParams(config.Center, config.Radius, position, rotation); return sphereCenter - sphereRadius * (rotation * transform.up); case ColliderType.Capsule: (_, Vector3 capsuleBottom, float capsuleRadius, _) = CapsuleColliderCast.GetParams(config.Center, config.Radius, config.Height, config.CapsuleDirection, position, rotation); return capsuleBottom + capsuleRadius * (rotation * Vector3.down); case ColliderType.Point: default: return position + rotation * config.Center; } } /// public override IEnumerable GetHits(Vector3 position, Quaternion rotation, Vector3 direction, float distance, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore, float skinWidth = 0.01f) { IEnumerable hits; switch (config.type) { case ColliderType.Box: (Vector3 boxCenter, Vector3 boxSize) = BoxColliderCast.GetParams(config.Center, config.Size, position, rotation, -skinWidth); hits = Physics.BoxCastAll(boxCenter, boxSize / 2, direction, rotation, distance + skinWidth, layerMask, queryTriggerInteraction); break; case ColliderType.Sphere: (Vector3 sphereCenter, float sphereRadius) = SphereColliderCast.GetParams(config.Center, config.Radius, position, rotation, -skinWidth); hits = Physics.SphereCastAll(sphereCenter, sphereRadius, direction, distance + skinWidth, layerMask, queryTriggerInteraction); break; case ColliderType.Capsule: (Vector3 capsuleTop, Vector3 capsuleBottom, float capsuleRadius, float capsuleHeight) = CapsuleColliderCast.GetParams(config.Center, config.Radius, config.Height, config.CapsuleDirection, position, rotation, -skinWidth); hits = Physics.CapsuleCastAll(capsuleTop, capsuleBottom, capsuleRadius, direction, distance + skinWidth, layerMask, queryTriggerInteraction); break; case ColliderType.Point: default: Vector3 origin = position + rotation * config.Center; hits = Physics.RaycastAll(origin, direction, distance, layerMask, queryTriggerInteraction); skinWidth = 0.0f; break; } return hits.Where(hit => hit.collider.transform != transform) .Select(hit => { hit.distance = Mathf.Max(hit.distance - skinWidth, 0); return hit; }); } /// public override IEnumerable GetOverlapping(Vector3 position, Quaternion rotation, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore, float skinWidth = 0.0f) { IEnumerable overlap; switch (config.type) { case ColliderType.Box: (Vector3 boxCenter, Vector3 boxSize) = BoxColliderCast.GetParams(config.Center, config.Size, position, rotation, -skinWidth); overlap = Physics.OverlapBox(boxCenter, boxSize / 2, rotation, layerMask, queryTriggerInteraction); break; case ColliderType.Sphere: (Vector3 sphereCenter, float sphereRadius) = SphereColliderCast.GetParams(config.Center, config.Radius, position, rotation, -skinWidth); overlap = Physics.OverlapSphere(sphereCenter, sphereRadius, layerMask, queryTriggerInteraction); break; case ColliderType.Capsule: (Vector3 capsuleTop, Vector3 capsuleBottom, float capsuleRadius, float capsuleHeight) = CapsuleColliderCast.GetParams(config.Center, config.Radius, config.Height, config.CapsuleDirection, position, rotation, -skinWidth); overlap = Physics.OverlapCapsule(capsuleTop, capsuleBottom, capsuleRadius, layerMask, queryTriggerInteraction); break; case ColliderType.Point: default: Vector3 origin = position + rotation * config.Center; overlap = Physics.OverlapSphere(origin, KCCUtils.Epsilon / 2, layerMask, queryTriggerInteraction); break; } return overlap.Where(collider => collider.transform != transform); } /// protected override Collider SetupColliderComponent() { UpdateColliderParameters(); return generatedCollider; } } }