2
\$\begingroup\$

How do I ignore raycasts for specific objects? I want a filter, to ignore raycasts for some objects. As an example, when my player selects the ground, I do not want them to accidentally select bullets.

Is it possible to add boolean to the BoxCollider2D component, to identify raycast targets? I want to make it similar to the Image component.

The Image component has a "Raycast Target" trigger. I would like to be able to add this to the BoxCollider2D component.

My problem is that when several objects overlap, I need some of the objects to ignore the raycast.

I can't use Queries Hit Trigger or disable the collider component, because I need them to enter the OnCollisionEnter and OnTriggerEnter methods.


Here is my Update method:

void Update () 
{
    if (Input.GetMouseButtonDown(0))
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity,
                1 « LayerMask.NameToLayer("Object"));

        if (hit)
        {
          Debug.Log(hit.collider.gameObject.name);
        }
    }
}
\$\endgroup\$
1
\$\begingroup\$

If you cannot accomplish what you want with Layer Masking, or with the Collision Matrix, then I can suggest an alternative approach to the problem.

You can put a tag on the collider objects you want to avoid raycasting, and then doing something like this:

void Update(){
    if (Input.GetMouseButtonDown (0)) {

        Vector2 pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        RaycastHit2D[]  hits = Physics2D.RaycastAll (pos, new Vector2 (0, 0), 0.01f);

        for (int i = 0; i < hits.Length; i++) {
            if (hits[i].collider.gameObject.tag != "IgnoreRaycast")
            {
                 Debug.Log(hit.collider.gameObject.name);
            }
        }
}

However, if you want similar behavior as described above, you may want to consider extending the main MonoBehaviour class into a custom one that you will derive all of your Collidable objects from.

Consider the following class:

public class BaseEntity : MonoBehaviour
{
    [SerializeField]
    bool IgnoreRaycast; 
}

Then, deriving from this class, instead of directly to MonoBehaviour will expose a new property entitled IgnoreRaycast, to all of your GameObjects.

Unfortunately, it doesn't just ignore ray So your update loop would then look like this:

void Update(){
    if (Input.GetMouseButtonDown (0)) {

        Vector2 pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        RaycastHit2D[]  hits = Physics2D.RaycastAll (pos, new Vector2 (0, 0), 0.01f);

        for (int i = 0; i < hits.Length; i++) {
            if (!hits[i].collider.gameObject.GetComponent<BaseEntity>().IgnoreRaycast)
            {
                 Debug.Log(hit.collider.gameObject.name);
            }
        }
}
\$\endgroup\$
1
\$\begingroup\$

Your problem appears to be in your understanding of what your actually trying to do. As such, I can identify two seperate questions. I will answer both, in case it provides more context. Ultimately, you would benefit greatly from using layers to selectively ignore raycasts.


How do I ignore raycasts for specific objects?

With layers. Let's take a look at the API reference:

Physics2D.RaycastAll

public static RaycastHit2D[] RaycastAll(Vector2 origin, Vector2 direction, float distance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, float minDepth = -Mathf.Infinity, float maxDepth = Mathf.Infinity);

Parameters

...
layerMask Filter to detect Colliders only on certain layers.
minDepth Only include objects with a Z coordinate (depth) greater than or equal to this value.
maxDepth Only include objects with a Z coordinate (depth) less than or equal to this value.

...

The layerMask can be used to detect objects selectively only on certain layers (this allows you to apply the detection only to enemy characters, for example).

This very clearly points to two ways we can filter game objects, when we raycast; by layer mask and by depth.


Filtering Raycasts by Layer Mask

Layer mask is good when you know what your looking for. Put simply, your raycast will only hit objects that use the same layer as layerMask. By default, layerMask = DefaultRaycastLayers, so your raycast will normally hit all objects that use the default raycast layers. Assuming you were looking for a particular object, you would ensure that object had a unique tag, and specifically use that tag as your layerMask parameter.

If you use a layer mask, your raycast will only hit objects that use the same layer. This is case-sensitive, so ensure that you use correct capitalisation.


Filtering Raycasts by Depth

Depth is good when you do not necessarily know what object your looking for, but know roughly which physical layer it should be in. Filtering by depth requires a bit of pre-plan, but it does allow a bit more diversity in what you are looking for.

Simply put, you would ensure that you ordered your game objects along the z-Axis in order to categorise them for particular interactions. For example, if your floor is at a z-Axis of -1, and your enemies are at a z-Axis of 1, you could use a depth of minDepth = -1, maxDepth = -1. If your enemies were anywhere between 1 and 10, along the z-Axis, you could specifically target them with a depth of minDepth = 1, maxDepth = 10.

It is important to remember that the z-Axis is not considered, when applying general collision and physics in 2D. As such, you can use the z-Axis to layer your objects, without interrupting normal collision you would expect from them.


Further Consideration

There are going to be times where you will still want to look through the array, returned by RaycastAll(), both to provide extended filtering and to ensure that you have actually retrieved the intended game object.

  • Consider if there are any other parameters that would naturally filter your intended target. For example, RaycastAll() sorts the array of raycasts by distance before it is returned. As such, if you know your intended object will be the furthest away, you should always look at the last entry.
  • Consider that it is still good form to validate your findings. For example, if you know that your returned object should ultimately be an enemy, it can not hurt to ensure the returned object contains relevant enemy components.

Is it possible to add boolean to the BoxCollider2D component, to identify raycast targets?

Not that I am aware of; but it appears your reasoning may be based off an incorrect assumption.

Firstly, BoxCollider2D is a sealed class. This means that we can not inherit from it, which would be required to add our own elements.

Secondly, the boolean in question does not allow you to ignore raycasts from specific objects. It only allows you to ignore raycasts completely. Enabling RaycastTarget simply allows the image to react to ray-casts. Anything you would want from this behavior can be replicated by accessing and disabling/enabling the collider. You have previously stated that this is not going to work for you, but regardless, it is a good comparison of behavior.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.