Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[SOLVED] Checking if RaycastHit != null not working

Discussion in 'Scripting' started by Shushustorm, Nov 28, 2015.

  1. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    Hello everyone!
    I am running into a weird problem. Do you have any idea what's wrong?

    Code (CSharp):
    1. RaycastHit RaycastHitDown;
    2. void UPDATE_ParticlesWallsDown () {
    3.     if ( PlayerMovingFast ) {
    4.     Debug.Log("<color=orange>UPDATE_ParticlesWallsDown: PLAYER MOVING FAST</color>");
    5.         Physics.Raycast(SphereMesh.gameObject.transform.position, -Vector3.up, out RaycastHitDown, 1.0f);
    6.         if (RaycastHitDown != null) { // *
    7.             Debug.Log(RaycastHitDown.collider.gameObject.name);
    8.         }
    9.     }
    10. }
    11.  
    12. // * error CS0019: Operator `!=' cannot be applied to operands of type `UnityEngine.RaycastHit' and `null':
    Many thanks for any help!
    Greetings,
    Shu
     
  2. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    Alright, this time I could fix it pretty quickly myself.
    This is the code that works:
    Code (CSharp):
    1. RaycastHit RaycastHitDown;
    2. void UPDATE_ParticlesWallsDown () {
    3.     if ( PlayerMovingFast ) {
    4.     Debug.Log("<color=orange>UPDATE_ParticlesWallsDown: PLAYER MOVING FAST</color>");
    5.     bool RaycastDown = Physics.Raycast(SphereMesh.gameObject.transform.position, -Vector3.up, out RaycastHitDown, 1.0f);
    6.         if (RaycastDown != null) {
    7.             Debug.Log(RaycastHitDown.collider.gameObject.name);
    8.         }
    9.     }
    10. }
    Still weird that I can't check RaycastHit directly.
     
    Ganicuus and Protozoaire like this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    RaycastHit is a struct, structs can not be null.

    That's why the 'RaycastHit' info comes back as a 'out' parameter. And the function actually returns true or false. You check if the function returns true, and if it does, you know that the RaycastHit info has been set.

    I notice you grab that bool in your second code, but still test if that bool is not null. Again, bool can never be null. But null has an implicit conversion to boolean (false) so you don't have a compiler error.

    The appropriate way to use the Raycast method is like so:

    Code (csharp):
    1.  
    2. void UPDATE_ParticlesWallsDown () {
    3.     if( PlayerMovingFast)
    4.     {
    5.         RaycastHit hitInfo;
    6.         if(Physics.Raycast(SphereMesh.transform.position, -Vector3.up, out hitInfo, 1.0f))
    7.         {
    8.             Debug.Log(hitInfo.collider.name);
    9.         }
    10.     }
    11. }
    12.  
     
  4. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    @lordofduct
    I see! Thanks for the explanation! It totally makes sense!
    Only one question, though: Isn't it more efficient to have RaycastHit hitInfo outside of UPDATE_ParticlesWallsDown()? Because as its name suggests, it's inside Update(). Or is it the same performance when it's inside the function and it will only make a difference when actually writing RaycastHit hitInfo = new RaycastHit();?
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    Putting it outside the function makes it a member of the class.

    Something should be a member of the class if and only if it represents the state of the class.

    There could be minor arguments made by some that there's an eensy-weensy efficiency increase for a struct to be stored as a class level member because their is a spot in memory already allocated for it. But the thing is, a function level variable of a struct is allocated on the stack... this process is so fast that you'd have to have millions of these occurring in a nearly simultaneous moment to really notice.

    With that same argument I could say that you're increasing the heap level footprint of the memory by making it a class level member, because now the struct persists for the lifetime of the object, rather than the lifetime of the function call. And in the case of 'millions' of nearly simultaneous actions you've increased your memory footprint by millions * the size of the struct (which in the case of RaycastHit is 48 bytes), meaning you'd have a memory footprint increase of 50 MB before you'd really even notice an impact of speed... and still the speed is negligible.

    Note, this all changes if this were an object (instance of a class). If you were calling 'new blarghablargh' every update, and blarghablargh were a class, that means you were creating a new object every frame. This could lead to large inefficiencies. But most classes aren't designed to be used that way... I could see this happening with say a 'List<T>', which yes, don't create a new List every frame... cache that for later use. In the same respect the memory argument I made is inconsequential here. A List's member field footprint is 4 bytes, and it's allocation in the heap isn't copied.


    TL;DR

    No, it's no big deal at all.

    Don't code to arbitrarily small efficiencies, all you do is introduce arbitrary inefficincies.

    Class member fields should be just that, class member fields. Function member variables that persist only for the life of a funciton, should remain function member variables.
     
    Shushustorm likes this.
  6. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    @lordofduct
    Alright! Thank you very much for your detailed post! It's very informative!
     
  7. RPGia

    RPGia

    Joined:
    Jan 23, 2017
    Posts:
    44
    Hi, can you tell me what you think the price would be?