Skip to content

Commit

Permalink
Documentation improvements, UI improvements, Performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
3DI70R committed Feb 7, 2020
1 parent c163a8e commit 9a93660
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 74 deletions.
7 changes: 4 additions & 3 deletions Assets/Scripts/Runtime/BoxCastSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Sensor which casts box<br/>
/// Behaves like a Physics.BoxCast, Physics.BoxCastNonAlloc, depending on your settings
/// <para>Sensor which casts box</para>
/// <para>Behaves like a Physics.BoxCast, Physics.BoxCastNonAlloc, depending on your settings</para>
/// </summary>
public class BoxCastSensor : CastSensor
{
/// <summary>
/// Half extents of box
/// <para>Half extents of box</para>
/// </summary>
[Tooltip("Half extents of box")]
public Vector3 halfExtents;

protected override int DoCast(Ray ray, RaycastHit[] hitArray)
Expand Down
6 changes: 5 additions & 1 deletion Assets/Scripts/Runtime/BoxOverlapSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Sensor which checks for colliders inside its volume, behaves like a Physics.OverlapBox
/// <para>Sensor which checks for colliders inside its volume, behaves like a Physics.OverlapBox</para>
/// </summary>
public class BoxOverlapSensor : OverlapSensor
{
/// <summary>
/// <para>Half extents of box</para>
/// </summary>
[Tooltip("Half extents of box")]
public Vector3 halfExtents;

protected override int DoOverlapCheck(Vector3 center, Collider[] colliders)
Expand Down
55 changes: 32 additions & 23 deletions Assets/Scripts/Runtime/CastSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,71 @@
namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Abstract class for any cast sensor<br/>
/// Cast sensor can detect objects at specified distance
/// <para>Abstract class for any cast sensor</para>
/// <para>Cast sensor can detect objects at specified distance</para>
/// </summary>
public abstract class CastSensor : PhysicsSensor
{
private static readonly RaycastHit[] emptyRays = new RaycastHit[0];
private static readonly RaycastHit[] emptyRayHits = new RaycastHit[0];

/// <summary>
/// Transform which overrides ray cast direction
/// Makes possible to cast rotated shapes
///
/// If null, uses sensor object for direction
/// <para>Transform which overrides ray cast direction. Makes possible to cast rotated shapes</para>
/// <para>If null, uses sensor object for direction</para>
/// </summary>
[Tooltip("Transform which overrides ray cast direction. Makes possible to cast rotated shapes\n" +
"If null, uses sensor object for direction")]
public Transform rayDirectionOverride;

/// <summary>
/// Maximum ray cast distance
/// <para>Maximum cast distance</para>
/// </summary>
[Tooltip("Maximum cast distance")]
public float maxDistance = Mathf.Infinity;

private RaycastHit[] rayHits = emptyRays;
private RaycastHit[] rayHits = emptyRayHits;
private bool outdatedColliders;

/// <summary>
/// Actual ray that will be fired on update
/// <para>Actual ray that will be fired on update</para>
/// </summary>
public Ray Ray
{
get
{
return new Ray(transform.position, CastDirection *
new Vector3(0, 0, transform.lossyScale.z > 0 ? 1 : -1));
new Vector3(0, 0, transform.lossyScale.z > 0 ? 1 : -1));
}
}

/// <summary>
/// Array with all hits that have been detected during sensor update<br/>
/// This array is cached, and guaranteed to be at least HitCount long
/// <para>Array with all hits that have been detected during sensor update</para>
/// <para>This array is cached, and guaranteed to be at least HitCount long</para>
/// </summary>
public RaycastHit[] RayHits
{
get { return rayHits; }
get
{
EnsureArrayCapacity(ref rayHits);
return rayHits;
}
}

/// <summary>
/// Returns first RayHit<br/>
/// Convenience method, when maxCount is 1
/// <para>Returns first RayHit</para>
/// <para>Convenience method when maxCount is 1</para>
/// </summary>
public RaycastHit RayHit
{
get { return HitCount > 0 ? RayHits[0] : default(RaycastHit); }
get
{
return HitCount > 0 ? RayHits[0] : default(RaycastHit);
}
}

/// <summary>
/// Returns closest RayHit<br/>
/// Since NonAlloc methods returns array with no order, it
/// <para>Returns closest RayHit</para>
/// <para>Since NonAlloc methods returns array with no order,
/// method finds most closest hit in result array</para>
/// </summary>
public RaycastHit ClosestRayHit
{
Expand Down Expand Up @@ -93,16 +102,16 @@ public RaycastHit ClosestRayHit
}

/// <summary>
/// Direction in which ray will be casted
/// Either rotation used by this object, or rotation from rayDirectionOverride
/// <para>Direction in which ray will be casted</para>
/// <para>Either rotation used by this object, or rotation from rayDirectionOverride</para>
/// </summary>
public Quaternion CastDirection
{
get { return rayDirectionOverride ? rayDirectionOverride.rotation : transform.rotation; }
}

/// <summary>
/// Actual distance of cast, with respect of object scale
/// <para>Actual distance of cast, with respect of object scale</para>
/// </summary>
public float CastDistance
{
Expand Down Expand Up @@ -158,7 +167,7 @@ private void UpdateCollidersArray()

#if UNITY_EDITOR

private RaycastHit[] gizmoRayHits = emptyRays;
private RaycastHit[] gizmoRayHits = emptyRayHits;

private void OnDrawGizmosSelected()
{
Expand Down
4 changes: 2 additions & 2 deletions Assets/Scripts/Runtime/OverlapSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Abstract class for any overlap sensor
/// Overlap sensor can detect objects at specified location
/// <para>Abstract class for any overlap sensor</para>
/// <para>Overlap sensor can detect objects at specified location</para>
/// </summary>
public abstract class OverlapSensor : PhysicsSensor
{
Expand Down
67 changes: 47 additions & 20 deletions Assets/Scripts/Runtime/PhysicsSensor.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
using UnityEngine;
using UnityEngine.Animations;

namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Base class for any physics sensor
/// Provides shared collider detection logic that can be obtainer from any sensor
/// <para>Base class for any physics sensor</para>
/// <para>Provides shared collider detection logic that can be obtained from any sensor</para>
/// </summary>
public abstract class PhysicsSensor : MonoBehaviour
{
private static readonly Collider[] emptyColliders = new Collider[0];

/// <summary>
/// If false, all arrays will be allocated on object creation. If true, all arrays will be allocated
/// on first access to them. Saves memory on sensors that can be unused during object lifetime.
/// Slightly saves memory, but makes allocation on first access to sensor
/// <para>If false, all arrays will be allocated on object creation.</para>
/// <para>If true, all arrays will be allocated on first access.</para>
/// </summary>
public bool lazyAllocation;
#if UNITY_2019_2_OR_NEWER
[NotKeyable]
#endif
[SerializeField]
[Tooltip("If false, all arrays will be allocated on object creation.\n" +
"If true, all arrays will be allocated on first access.")]
protected bool lazyAllocation;

/// <summary>
/// Maximum amount of detected hits
/// Every sensor uses no allocation per cast, and it is important to know maximum amount of
/// objects this sensor is able to detect, to preallocate array at creation
/// Changing this property at runtime recreates array, so try to not touch it without much need
/// <para>Maximum amount of detected hits</para>
/// <para>Every sensor uses no allocation per cast, and it is important to know maximum amount of
/// objects this sensor is able to detect, to preallocate array
/// Changing this property at runtime recreates array, so try to not touch if not necessary</para>
/// </summary>
[Tooltip("Maximum amount of detected hits\n" +
"Every sensor uses no allocation per cast, and it is important to know maximum amount of objects " +
"this sensor is able to detect, to preallocate array. " +
"Changing this property at runtime recreates array, so try to not touch if not necessary")]
public int maxResults = 1;

/// <summary>
/// Layer mask of cast
/// <para>Layer mask which sensor will use<para>
/// </summary>
[Tooltip("Layer mask which sensor will use")]
public LayerMask layerMask = Physics.DefaultRaycastLayers;

/// <summary>
/// Setting that specifies, if sensor should detect triggers too
/// <para>Should this sensor detect triggers</para>
/// </summary>
[Tooltip("Should this sensor detect triggers")]
public QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;

protected int hitCount;
Expand All @@ -42,14 +54,22 @@ public abstract class PhysicsSensor : MonoBehaviour

private bool isCustomPhysicsSceneSet;
private PhysicsScene customPhysicsScene;

/// <summary>
/// <para>Is lazy allocation enabled in inspector</para>
/// </summary>
public bool UsesLazyAllocation
{
get { return lazyAllocation; }
}

/// <summary>
/// Physics scene used for physics checks
/// Defaults to "Physics.defaultPhysicsScene"
/// <para>Physics scene used for physics checks
/// Defaults to "Physics.defaultPhysicsScene"</para>
///
/// When set to different scene, it is user responsibility to correctly
/// <para>When set to different scene, it is user responsibility to correctly
/// handle cases when PhysicsScene is destroyed, sensor will not switch to "Physics.defaultPhysicsScene"
/// automatically
/// automatically</para>
/// </summary>
public PhysicsScene PhysicsScene
{
Expand Down Expand Up @@ -85,15 +105,22 @@ public int HitCount
/// </summary>
public virtual Collider[] HitColliders
{
get { return hitColliders; }
get
{
EnsureArrayCapacity(ref hitColliders);
return hitColliders;
}
}

/// <summary>
/// First collider that was hit, if any
/// </summary>
public Collider HitCollider
{
get { return HitCount > 0 ? HitColliders[0] : null; }
get
{
return HitCount > 0 ? HitColliders[0] : null;
}
}

/// <summary>
Expand All @@ -103,8 +130,8 @@ public Collider HitCollider
public abstract int UpdateSensor();

/// <summary>
/// Ensures that specified array contains enough items to store at least maxResults count
/// Recreates array if not
/// <para>Ensures that specified array contains enough items to store at least maxResults count</para>
/// <para>If static allocation is not used, </para>
/// </summary>
protected void EnsureArrayCapacity<T>(ref T[] array)
{
Expand Down
43 changes: 31 additions & 12 deletions Assets/Scripts/Runtime/PhysicsSensorUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static void GetCapsulePoints(Vector3 origin, Quaternion rotation, float w
private static readonly List<Vector3> sharedVertices = new List<Vector3>(8192);
private static readonly List<int> sharedIndices = new List<int>(8192);
private static readonly List<int> sharedIndicesTemp = new List<int>(8192);
private static Mesh lastInspectedMesh;

public static void DrawCollisionPoints(Vector3 collisionPoint, RaycastHit hit)
{
Expand All @@ -84,13 +85,18 @@ public static void HighlightMeshVertices(RaycastHit hit)
if (meshCollider != null)
{
var mesh = meshCollider.sharedMesh;
mesh.GetVertices(sharedVertices);
sharedIndices.Clear();

for (var i = 0; i < mesh.subMeshCount; i++)
if (mesh != lastInspectedMesh)
{
mesh.GetTriangles(sharedIndicesTemp, i, true);
sharedIndices.AddRange(sharedIndicesTemp);
lastInspectedMesh = mesh;
mesh.GetVertices(sharedVertices);
sharedIndices.Clear();

for (var i = 0; i < mesh.subMeshCount; i++)
{
mesh.GetTriangles(sharedIndicesTemp, i, true);
sharedIndices.AddRange(sharedIndicesTemp);
}
}

var triangleStart = hit.triangleIndex * 3;
Expand Down Expand Up @@ -125,21 +131,34 @@ public static void DrawHitInfo(RaycastHit hit)
if (offset.z > 0)
{
Handles.BeginGUI();
offset.x = offset.x - 64;
offset.y = -offset.y + sceneCamera.pixelHeight + 16;
var rect = new Rect(offset.x - 64,-offset.y + sceneCamera.pixelHeight + 16,
140, 56);
var boundsRect = Rect.MinMaxRect(8, 8,
sceneCamera.pixelWidth - 8, sceneCamera.pixelHeight - 8);

#if UNITY_2019_3 // New GUI
if (rect.x < boundsRect.x) rect.x = boundsRect.x;
if (rect.y < boundsRect.y) rect.y = boundsRect.y;
if (rect.xMax > boundsRect.xMax) rect.x = boundsRect.xMax - rect.width;
if (rect.yMax > boundsRect.yMax) rect.y = boundsRect.yMax - rect.height;

#if UNITY_2019_3_OR_NEWER // New GUI
var textHeight = 22;
var textOffset = 6;
#else
var textHeight = 16;
var textOffset = 8;
#endif

GUI.Box(new Rect(offset.x, offset.y, 140, 56), GUIContent.none);
GUI.Label(new Rect(offset.x + 8, offset.y + textOffset, 132, textHeight), hit.collider.gameObject.name);
GUI.Label(new Rect(offset.x + 8, offset.y + textOffset + 12, 132, textHeight), "distance: " + hit.distance);
GUI.Label(new Rect(offset.x + 8, offset.y + textOffset + 24, 132, textHeight), "triangleIndex: " + hit.triangleIndex);
GUI.color = Color.black * 0.6f;
GUI.Box(new Rect(rect.x, rect.y, rect.width, rect.height),
GUIContent.none, EditorStyles.textField);
GUI.color = Color.white;
GUI.Label(new Rect(rect.x + 8, rect.y + textOffset, 132, textHeight),
hit.collider.gameObject.name, EditorStyles.whiteLabel);
GUI.Label(new Rect(rect.x + 8, rect.y + textOffset + 12, 132, textHeight),
"distance: " + hit.distance, EditorStyles.whiteLabel);
GUI.Label(new Rect(rect.x + 8, rect.y + textOffset + 24, 132, textHeight),
"triangleIndex: " + hit.triangleIndex, EditorStyles.whiteLabel);
Handles.EndGUI();
}
}
Expand Down
12 changes: 7 additions & 5 deletions Assets/Scripts/Runtime/SphereCastSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
namespace ThreeDISevenZeroR.SensorKit
{
/// <summary>
/// Sensor which casts ray, sphere or capsule.
/// Behaves like a Physics.Raycast, Physics.RaycastNonAlloc, Physics.SphereCast, Physics.SphereCastNonAlloc,
/// Physics.CapsuleCast, Physics.CapsuleCastNonAlloc, depending on your settings
/// <para>Sensor which casts ray, sphere or capsule.</para>
/// <para>Behaves like a Physics.Raycast, Physics.RaycastNonAlloc, Physics.SphereCast, Physics.SphereCastNonAlloc,
/// Physics.CapsuleCast, Physics.CapsuleCastNonAlloc, depending on your settings</para>
/// </summary>
public class SphereCastSensor : CastSensor
{
/// <summary>
/// Radius of sphere, when sphere radius is zero, behaves like a ray
/// <para>Radius of sphere, when sphere radius is zero, behaves like a ray</para>
/// </summary>
[Tooltip("Radius of sphere, when sphere radius is zero, behaves like a ray")]
public float radius;

/// <summary>
/// With of sphere, when non zero, makes this sensor behave like a capsule, when zero, behaves like a sphere
/// <para>Width of sphere, when non zero, makes this sensor behave like a capsule, when zero, behaves like a sphere</para>
/// </summary>
[Tooltip("Width of sphere, when non zero, makes this sensor behave like a capsule, when zero, behaves like a sphere")]
public float width;

protected override int DoCast(Ray ray, RaycastHit[] hitArray)
Expand Down
Loading

0 comments on commit 9a93660

Please sign in to comment.