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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Raycast not detecting moving objects

Discussion in 'Physics' started by Fra123X, Jul 1, 2016.

  1. Fra123X

    Fra123X

    Joined:
    Mar 10, 2013
    Posts:
    40
    I know this question was probably asked multiple times, but despite all my efforts I've never managed to fix it, in any way.
    I have an helicopter, and a camera sitting inside it. Inside the cockpit there are various switches that the user can interact with.
    The script that detects when the cursor is hovering one of the switches is this:
    Code (CSharp):
    1.  
    2. void FixedUpdate () {
    3.   RaycastHit hit;
    4.   if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),
    5.     out hit)) {
    6.  
    7.     if (hit.collider.Equals (GetComponent<Collider>())) {
    8.          
    9.       // Set cursor to "selection"
    10.       Cursor.SetCursor(cursor, Vector2.zero, CursorMode.Auto);
    11.       hovering = true;
    12.  
    13.     } else if (hovering) {
    14.       Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
    15.       hovering = false;
    16.     }
    17.   }
    18. }
    19.  
    20. void Update() {
    21.   if (Input.GetMouseButtonDown(0) && hovering) {
    22.     Toggle(!value);    // Do whatever this switch has to do and set its
    23.                        // value to its opposite
    24.   }
    25. }
    26.  
    When the helicopter is landed, these switches work perfectly. After taking off tough, the raycast starts flickering between true and false, and after gaining some horizontal speed the little switches become almost completely unclickable, while some larger colliders are still roughly clickable at realtively slow speeds.
    While the switches and their colliders are children of the helicopter GameObject, the camera is not. It's being repositioned each frame to the correct position, tough that doesn't really seem to be the issue here.
    The helicopter's rigidbody is set to Continuous and to Interpolate, I tried switching these values around and no combination of them fixes this issue..
    A lot of people suggested moving the behaviour that handles the object's movement from Update to FixedUpdate, but I'm not actually handling the movement of the helicopter myself, what makes the helicopter move is this bit:

    Code (CSharp):
    1.  
    2. GetComponent<Rigidbody>().AddRelativeForce(Vector3.up * calculateLift(), ForceMode.Force);
    3.  
    which is controlled by the Rigidbody component, and even moving it to FixedUpdate did absolutely nothing (it currently is in FixedUpdate)...
    I tried adding kinematic rigidbodies to the switches themselves and that didn't fix it either.
    I tried adding a kinematic rigidbody to the camera and that did nothing as well.
    I have also noticed that the strobe light in front of the helicopter (which is a flare) is correctly hidden by the cockpit while the helicopter is landed, but then begins flickering once the helicopter gains speed.
    I don't really know what to do here, any help would be immensely appreciated :)

    If more of the resources are necessairy or if someone needs to test the game I will edit this message
     
    Last edited: Jul 1, 2016
  2. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    438
    Just a guess, the helicopter propellers or other child objects that start hitting the ray. Because you compare to object itself and not its tag, you can't include them all in the ray test.
     
  3. Fra123X

    Fra123X

    Joined:
    Mar 10, 2013
    Posts:
    40
    So, should I be comparing the object's tag with the hit's tag and see if they match?
    Because I wanted to avoid relying on names to determine if the raycast was successful, but I will give it a try, thanks :)
     
  4. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    438
    I guess the tag is faster than going through a list of all objects that makes a helicopter. You'll need to add it to the child objects too then. You didn't say if they are the cause though.
     
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You'll need to use RaycastAll if comparing tags, otherwise the ray will stop there and not go further.

    The right approach is instead to use layers, not tags. Then you can ignore the object and the ray will never hit what you don't want it to.

    Depends since tags compare strings so that's slow in a different way. Use layers.
     
  6. Fra123X

    Fra123X

    Joined:
    Mar 10, 2013
    Posts:
    40
    Well, I tried both approaches but none of them seem to be working, the behaviour for the switches is currently this:

    Code (CSharp):
    1.  
    2. public class Switch : MonoBehaviour {
    3.   public Transform @ref;
    4.   public bool value = false;
    5.   public static LayerMask mask = 1 << 8;   // Layer 8 = 'clickable', includes switches and other small clickable elements
    6.  
    7.   // This will execute once the value changes
    8.   public switch_action action;
    9.  
    10.   // Rotation axis
    11.   public Vector3 direction = new Vector3(1, 0, 0);
    12.   public float angleStart, angleEnd;
    13.  
    14.   public Texture2D cursor;
    15.   bool hovering = false;
    16.  
    17.   // Use this for initialization
    18.   void Start () {
    19.      if (!@ref) @ref = transform;
    20.      refresh();
    21.   }
    22.  
    23.   public void Toggle (bool stat) {
    24.      action.Invoke(stat);
    25.      value = stat;
    26.      refresh();
    27.      GetComponent<AudioSource>().Play(); // Plays a clicking sound
    28.   }
    29.  
    30.   void refresh() {
    31.      Vector3 r = @ref.localEulerAngles;
    32.      r = direction * (value ? angleEnd : angleStart);
    33.      @ref.localEulerAngles = r;
    34.   }
    35.  
    36.   void FixedUpdate () {
    37.      RaycastHit hit;
    38.      if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, mask)) {
    39.         // I did try using "hit.collider.tag == tag" but that didn't seem to solve the issue either
    40.         // I even tried using "hit.collider.CompareTag(tag)" and that didn't fix it either :(
    41.         if (hit.collider.Equals (GetComponent<Collider>())) {
    42.  
    43.            Cursor.SetCursor(cursor, Vector2.zero, CursorMode.ForceSoftware);
    44.            hovering = true;
    45.  
    46.         } else if (hovering) {
    47.            Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
    48.            hovering = false;
    49.         }
    50.      }
    51.   }
    52.  
    53.   void Update() {
    54.      if (Input.GetMouseButtonDown(0) && hovering) {
    55.         Toggle(!value);
    56.      }
    57.   }
    58. }
    59.  
    is there something I'm missing?

    EDIT:

    Ok, reducing the "Fixed timestep" from 0.02 to 0.005 seems to 'fix' the issue but it doesn't look like a very clean solution and it sounds like it could have severe performance impacts as the project grows bigger and more physical parts are added, should I keep this change?
     
    Last edited: Jul 2, 2016
    Boodums likes this.
  7. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Remember that your raycast won't necessarily be giving you the right data if its testing against moving colliders with rigidbody. Because rigidbody.position will hold the "real" physics position that is not interpolated (transform is interpolated if Interpolation is used).
     
  8. Fra123X

    Fra123X

    Joined:
    Mar 10, 2013
    Posts:
    40
    Well, the helicopter does have a rigidbody, which is set to interpolate, and the switches and their colliders are a child of the helicopter, but the switches themselves don't have any rigidbodies, they are just colliders.
    If the issue is related to the helicopter's rigidbody, can it still be fixed? Or is reducing the fixed timestep the only possible solution?
     
  9. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Well it's just your switches have a different position to your visual, as the visual meshes are being interpolated. There's a few potential solutions. You just have to realise the physics geometry is nowhere near the actual geometry. So casting a ray from the camera likely isn't going to work properly, if the camera is a child of an interpolated transform.

    Begin the ray from the rigidbody position + offset. This will be in sync and won't miss. Visually, it'll be normal, just ensure the casting ray is done right.

    Camera.main.ScreenPointToRay is the problem here. It's operating on the camera's position obviously, but this camera is at an interpolated position that grows further apart the faster you go.

    Alternatively, as it returns a ray, you can simply offset the ray by the difference between the rigidbody position and the transform position, then use that final ray for the raycast.

    Do some debugging, ie click then call Debug.Break(); to pause the unity editor. Make sure you draw a Debug.DrawRay or log the rigidbody position vs transform position, they should be different, with rigidbody.position lagging behind.
     
    Boodums and eses like this.
  10. Fra123X

    Fra123X

    Joined:
    Mar 10, 2013
    Posts:
    40
    Thanks for the suggestions, I'll try applying them now :)