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

Resolved How to make a clickable object non-clickable when on the other side of a wall

Discussion in 'Scripting' started by Theleoboy, Oct 4, 2023 at 2:53 PM.

  1. Theleoboy

    Theleoboy

    Joined:
    Sep 18, 2023
    Posts:
    5
    Hello, big noob here seeking help :p
    Like i vaguely explained in the titel i want a game object, for this instance a cube, to be clickable when the player is on one side of a wall and not clickable when the player is on the other side. I'll post pictures at the bottom to clarifying what i mean.

    I'm using OnMouseDown to register when the cube is clicked and I've tried with box colliders as invisible barriers above the wall, that worked for making it so it's not possible to click the cube when outside the wall but since i use a third-person camera it gets a bit wonky when I'm on the side of the wall where i want the cube to be clickable, is there a way to maybe compare transform values to decide if the player is on the same side of the wall as the cube?

    Im using the following code snippet inside the OnMouseDown to have a sort of "range" to the click and Ive tried to rework it into some how check if the player is on the correct side of the wall but it's not going too well :confused:
    Code (CSharp):
    1. if (Math.Abs(Vector3.Distance(transform.position, Player.transform.position)) < 10f)
    Any tips or ideas on how i could achieve the feature I'm looking for?
    Skärmbild 2023-10-04 152614.png
    Skärmbild 2023-10-04 152627.png
     
    Last edited: Oct 4, 2023 at 7:00 PM
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,735
    In addition to raycasting from the camera for the click location, you'll need to add a raycast from the player capsule towards the target. It'd look something like:
    Code (csharp):
    1.  
    2. Vector3 clickedPoint = raycastHit.point;
    3. Vector3 playerPoint = player.transform.position; // might want to add a bit of height to get it up to player's eye level or something?
    4. bool playerCanSeeIt = false;
    5.  
    6. if (Physics.Raycast(playerPoint, clickedPoint - playerPoint, out var fromPlayerRaycastHit)) {
    7.    if (fromPlayerRaycastHit.collider == raycastHit.collider) {
    8.       playerCanSeeIt = true;
    9.    }
    10. }
    You may need to add a layer mask into the raycast excluding the player's layer so the raycast doesn't immediately end inside the player it's casting from.
     
    Kurt-Dekker likes this.
  3. Theleoboy

    Theleoboy

    Joined:
    Sep 18, 2023
    Posts:
    5
    Thanks for the suggestion, I’ll check that out later tonight when I get home!

    Yesterday I was messing around with Physics.Linecast to try and check if an object is in between the player and the clicked object, is that something you have experience on using? Because just like you said I need to exclude the player but when I added the layer mask of just the player everything else was also excluded even though only the player was assigned that layer, maybe I did something wrong.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,283
    Layers and Layermasks absolutely work so when they don't, just go back and try again, or simplify the problem to understand it: make a blank scene and a couple of specific objects and test what you want.

    It will work if you give it the correct layers or layer masks as well as correctly set each object.

    Also, don't do the cast precisely along the floor. It might just hit the floor. Come up a 1 unit, assuming that's not too high to get over your wall.

    The difference between Layers vs LayerMasks:

    https://forum.unity.com/threads/raycast-layermask-parameter.944194/#post-6161542

    "There are 10 types of people in this world: those who understand binary, and those who don't."
     
    Nad_B and Theleoboy like this.
  5. Theleoboy

    Theleoboy

    Joined:
    Sep 18, 2023
    Posts:
    5
    Thanks Kurt, I tried what you said in that other post and instead of just putting my layer number, in this case 9, i put 1 << 9 and that worked. Now I'm unfortunately not the kind of person that just gets satisfied and feel like I'm done when it works like intended, i also wanna understand WHY it works, so could you maybe give me a better understanding on what you mean by "take 1 and rotate it left by "layer" bit positions" or maybe tell me what i should google to find more about this!

    Cheers! :)
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,283
    Binary arithmetic.
     
    Theleoboy likes this.
  7. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    270
    Just use LayerMasks instead of Layers, it takes care of all that binary stuff and you can pass them to all Casts since it has an implicit converter that converts it to int and do all the necessary binary things.

    Code (CSharp):
    1. // Or better, create a SerializedField and set it in the Editor
    2. var mask = LayerMask.GetMask("Wall");
    3.  
    4. // "mask" is converted automatically to int here, and all necessary bitmask operations are done for you
    5. if (Physics.Raycast(transform.position, transform.forward, 20.0f, mask))
    6. {
    7.     Debug.Log("Fired and hit a wall");
    8. }
     
    Last edited: Oct 5, 2023 at 8:05 PM
    Theleoboy and Chubzdoomer like this.