RaycastAll vs RaycastNonAlloc

Using JetBrains ReSharper, it warns that using Physics.RaycastNonAlloc is preferred over Physics.RaycastAll. They do the same thing, but RaycastNonAlloc requires passing in a pre-initiallized RaycastHit array. Unity themselves confirm this is a best practice since it reduces the amount of garbage on the heap.

Working it out, I came up with this InteractWithCombat() method:

private bool InteractWithCombat()
{
  // Raycast through the scene and return 5 hits
  var hits = new RaycastHit[5];
  int numHits = Physics.RaycastNonAlloc(GetMouseRay(), hits);

  // If no hits, then we're done.
  if (numHits <= 0) return false;

    foreach (RaycastHit hit in hits)
    {
      if (hit.transform == null) continue; // Does the hit have a transform?
      if (hit.transform.GetComponent<CombatTarget>() == null) continue; // Does the hit have a CombatTarget?

      var target = hit.transform.GetComponent<CombatTarget>();
                
       // CustomInputNames.Interact == "Interact" in ProjectSettings > Input
      if (Input.GetButtonDown(CustomInputNames.Interact))
      {
        _combatBehavior.Attack(target); // This is initialized in Awake()
      }
      return true; // If we found a target, we're done evaluating hits.
    }

  return false; // We didn't find a target, so we're done.
}

You might be wondering about that extra null check. I am too. Without it and just directly testing that CombatTarget is not null, I get an Object reference not set to an instance of an Object error.

I think the answer to simplifying this would be to user layer masking, which can be passed to RaycastNonAlloc. At that point, I can just skip the null checks and just make sure that numHits > 0, because nothing that is not a valid target should be on the layer.

Is that the way to go, or is there a better way?

We change this a little later as when we raycast for cursor affordances we want to sort what the raycast returns.
As i havent used the NonAlloc on this particular code yet i couldnt say if it would work but if you get to that point and its causing an issue or not please do give me a shout here or in the Q&A :slight_smile:

1 Like

So it’s looking like we’re removing the need for null checks altogether using an interface, which is honestly not even something I thought of doing. With the caveat that I haven’t actually tried this yet, I could probably refactor my code like this:

private bool InteractWithComponent()
{
    var hits = new RaycastHit[5];
    int numHits = Physics.RaycastNonAlloc(GetMouseRay(), hits);

    foreach (RaycastHit hit in hits) {
        IRaycastable[] raycastables = hit.transform.GetComponents<IRaycastable>();
        foreach (IRaycastable raycastable in raycastables)
        {
            if (raycastable.HandleRaycast(this))
            {
                // Handle stuff like cursor affordance here
                return true;
            }
        }
    }
    return false;
}

Thanks @Marc_Carlyon, that actually helps a lot.

2 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms