Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Raycast only shooting on certain layers?

Discussion in 'Scripting' started by Pantomorphic, Nov 17, 2014.

  1. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    I'm making a Portal clone, and I have a code that is supposed to shoot only onto objects with certain layers. I start by defining the variable:

    Code (CSharp):
    1. public LayerMask canShootAt;
    Later in the script when I incorporate raycasting:

    Code (CSharp):
    1. RaycastHit hit;
    2. if(Physics.Raycast(ray, out hit, canShootAt))
    3. //The code that shoots the Portal
    I created two layers: "Shootable" and "Nonshootable." I put the layer "Shootable" on the objects I want to be able to shoot onto, and you can figure out the rest.;)

    The problem is that when I change "canShootAt" to "Shootable" in the inspector, you can still shoot at every object in the level. How do I fix this?
     
  2. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    just looking at the overloads for Physics.raycast()

    the only one i can see that takes these parameters, is the one that takes one other parameter of 'length' before the layermask. hope that helps a bit.

    upload_2014-11-17_9-10-52.png
     
    DevDop likes this.
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,184
    The layermask is being used as the distance, yeah.

    The fix is to just throw in the distance parameter. The default of float.PositiveInfinity will do the job nicely.
     
  4. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    sorry yeah, distance not length, my typing was a bit pants, just in a rush this morning. cool least its working :)
     
  5. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    I'm confused. What would this look like in my code and how would it change anything? :confused:
     
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Add a float value as the third parameter, so your layermask will be the fourth (fourth is an interger defining the layermask, so you can use 'canShootAt.value') . Then you match the overload of the method which @OboShape has posted.

    What you're currently trying is to use the parameter list with the types:

    - Ray ,
    - out RaycastHit ,
    - LayerMask

    which does not exist.
     
  7. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    So right now this doesn't work:
    Code (CSharp):
    1. Ray ray = mainCamera.GetComponent<Camera>().ScreenPointToRay(new Vector3(x,y));
    2. RaycastHit hit;
    3.  
    4. if(Physics.Raycast(ray, out hit, float distance, canShootAt))
    5. //Do the Portal thing
    The error says it's expecting a "," or ")" at the if statement line.
     
  8. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    You cannot pass 'float distance', you have to declare the variable and pass only the name afterwards. Note that you have to assign it when doing so or you could also just pass a constant value as an argument for the float.
     
  9. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    It works for the most part now (thanks :D) though I still have some issues. If you try shooting onto a non shootable object, the portal will not appear there, which is supposed to happen. Though, if there is a shootable object behind the non shootable object, the gun will shoot the portal through the non shootable object onto the shootable one. The code basically does the same thing as an "Ignore Raycast" layer. Is there a way to make it so that the portal will not shoot through non shootable objects?
     
    Last edited: Nov 17, 2014
  10. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    The idea of layermasks is to ignore certain layers. I guess you're rather looking for tag (or layer) comparison in order to determine whether your portal can be spawned on top of the object or not.
     
    OboShape likes this.
  11. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    i dont think so, but im not that up on raycasting to be honest.

    but its doing what it says on the tin, by returning the first collider that isnt on a layer to be ignored.

    you might have to consider other mechanics for distinguishing where to put portals.

    if you were to set your raycast to not ignore that layer, you could find what layer the object you hit is on, then base your logic on that.
    so the first thing you hit, you can check what layer its on. if its on the 'dontputaportalhere' layer then do nothing, otherwise carry on.
    when your ray hits, get that gameobject and use the gameObject.layer, and that will give you an int based on what layer it has hit so you can make a comparison.

    least that way your ray will fire, hit the first thing, and check what layer that objects on, and then create/dontcreate a portal.

    i cant mind the right code to use as i dont have an example in front of me right now.
     
  12. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    I know what you are talking about. I had something like that in mind but I didn't know how I would go about coding it. I sort of have an idea now. Is there a function in Unity that is basically "End Script" or "Do Nothing" so that nothing below the line will happen?
     
  13. GetUpKidAK

    GetUpKidAK

    Joined:
    Apr 9, 2013
    Posts:
    84
    That's not how layermarks work with raycasting. Any object that's on a layermask that is being ignored will be effectively invisible to the raycast, so it will go straight through it. Any object that isn't included in the layermask will behave *exactly* the same as the Ignore Raycast layer.

    If you want the ray to hit all the walls, but only actually interact with certain walls the you need to use tags.

    My understanding of layermasks is that they're used for performance reasons (in raycasting,at least) - if your scene is full of objects that are irrelevant to your raycast then you don't want the engine to be checking against all these objects if you're never going to do anything with that information. The ray will only "see" the objects the objects on the layers you want it to see, so it filters the useless objects out.
     
  14. A.Killingbeck

    A.Killingbeck

    Joined:
    Feb 21, 2014
    Posts:
    483
    Create another layermask with only the layers you want to interact with.

    First do the raycast with the layermask which includes everything , then inside the if statement, query the gameobjects layer which it collides with and test it's layer against your "interactive" layermask.
     
    OboShape likes this.
  15. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    I can make all of this work if there is a function that makes it so that nothing below the line happens...
     
  16. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    not exactly sure what your after.
    if its within a loop then you can use 'break' to exit the loop.
    or try conditional statements to see if something needs done or not.
     
  17. GetUpKidAK

    GetUpKidAK

    Joined:
    Apr 9, 2013
    Posts:
    84
    I assume "below the line" means after the raycast hits something? If so, that's the default behaviour of a raycast. The RaycastHit variable will provide information on the first object the ray interacts with.
     
  18. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    By below the line I mean like this:
    Code (CSharp):
    1. //check if layer is "non shootable"
    2. //don't do anything below this line
    3. //check if layer is "shootable"
    4. //shoot a portal
     
  19. GetUpKidAK

    GetUpKidAK

    Joined:
    Apr 9, 2013
    Posts:
    84
    If an object is on a layer that isn't in the raycasts layermask, the raycast won't see it.

    You'll need something like this:

    Code (CSharp):
    1. void Update()
    2. {
    3.     if (Physics.Raycast(yourRay, out hit, yourLayermask))
    4.     {
    5.         if ( hit.collider.tag == "Shootable" )
    6.         {
    7.             // Do portal stuff
    8.         }
    9.     }
    10. }
    The tag check isn't strictly necessary if the only objects that use the layer you're masking against are the shootable walls, though. In that case, this should work:

    Code (CSharp):
    1. void Update()
    2. {
    3.     if (Physics.Raycast(yourRay, out hit, yourLayermask))
    4.     {
    5.         // Do portal stuff
    6.     }
    7. }
     
    Pantomorphic likes this.
  20. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    Yes but wouldn't it still recognize the shootable walls behind the non shootable walls and therefore do the same thing as my old code?
     
  21. GetUpKidAK

    GetUpKidAK

    Joined:
    Apr 9, 2013
    Posts:
    84
    The second method? Yes, if the ray was long enough. Hence my original suggestion:

    Personally, I'd put all the walls on a "Wall" layer, then I'd tag shootable walls as "Shootable" and non-shootable walls as "Non-shootable", then you can use the first example I posted above.

    That way, the ray is only checking against walls (ignoring everything else) and will only interact with Shootable walls, unless you want to add logic (like a sound effect or some other player feedback) to the Non-shootable walls.

    If you need to ray to interact with something other than walls then you can either leave the layermask off, or add the other objects to a new layer and add that to the ray's layermask as well.
     
  22. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    OK so here is my code right now:
    Code (CSharp):
    1. if(Physics.Raycast(ray, out hit, shootDistance, canShootAt))
    2. {
    3. if(hit.collider.tag == "Shootable")
    4. {
    5. //Do portal stuff
    6. }
    7. }
    I made sure all objects have the right layers and tags, but it still shoots through non shootable objects.
     
  23. GetUpKidAK

    GetUpKidAK

    Joined:
    Apr 9, 2013
    Posts:
    84
    What layer/tag are the objects on?

    Shootable objects need to be tagged "Shootable" and on the canShootAt layer.
    Non-shootable objects need to be tagged "Non-Shootable" (or anything but "Shootable") and also on the canShootAt layer.
     
  24. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    Oh. The non shootable layers didn't have the canShootAt layer. It works now thanks!
     
  25. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    'return;'
     
  26. Pantomorphic

    Pantomorphic

    Joined:
    May 8, 2013
    Posts:
    53
    Thanks!