- Home /
Physics.Raycast lagging behind
I am making a game where players can be onboard fast moving ships. These ships have controls in the form of panels and I use raycasting to find out which one, if any, the player is currently aiming at. The ships are moved using forces and physics while the player merely keeps the same relative position through a script. Each panel has a kinematic rigidbody, and is a child of the ship rigidbody.
When the ship moves slowly things work perfectly, but when the speed is high raycasts aimed at the leading side of the panels cease to hit. Through debugging I've managed to confirm that the raycast originates at the correct position, and it does cross the panel, but Physics.Raycast won't hit it. Getting the actual collider and using its Raycast method does however hit. Raycasting from where the ship is going to where the ship was before (ie head on) hits perfectly, the hit is where the edge of the collider is, not embedded inside it.
I'm guessing Physics.Raycast checks if the ray crosses the bounds of a rigidbody before doing more precise calculations against the actual collider, and that in this case the bounds of my panel isn't correctly placed (the data is one fixedupdate old).
What is causing this, is it a bug in unity or intended, and how might I work around it?
Edit: I did some more testing and managed to make a minimal example. Using this script:
using UnityEngine;
using System.Collections;
public class RaycastTester : MonoBehaviour {
void Update() {
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit)) {
Debug.DrawLine(transform.position, hit.point, Color.red);
} else {
Debug.DrawRay(transform.position, transform.forward * 10);
}
}
}
In the scene I set up a cube with a rigidbody and a constant force, meaning it will continuously accelerate, and then attached a child kinematic rigidbody. In addition I attached two empties to the parent, gave them the script above, and aimed them so that the raycasts would hit the leading edge of each cube.
Shortly after hitting play:
After letting the cube accelerate for a little while:
The selected cube is the parent and they move towards positive X. Thus it seems to me that movement through parenting happens after all physics is done, presumably in every Update or thereabout. Moving the Raycast to FixedUpdate causes the Raycast to happen before things move giving the appearance of the lines lagging one frame behind in position, but not changing whether the raycasts hit or not.
Sounds almost like a perfect example of (from the docs) "If you move colliders from scripting or by animation, there needs to be at least one FixedUpdate executed so that the physics library can update it's data structures..."
But you write that it's all physics based (and you moving the raycast pos by hand wouldn't matter.)
Even so, it lends credence to your "lagging bounds" theory.
I tend to change the raycast to a skinny sphereCast, and call it done (except sphereCasts can't hit triggers. Grrr.)
Answer by aldonaletto · Jul 05, 2014 at 08:55 PM
Physics.Raycast indeed checks the collider bounds prior to spend time with more precise calculations, but this isn't causing your problem - it's probably due to some lag between the Raycast and the physics movement. Unity executes physics cycles between frames, trying to keep the correct physics timing in average: it renders a frame, then executes as many physics cycles as necessary to update the internal physics clock, and finally updates the transform associated to the rigidbody. When the frame rate is higher than the physics rate (default = 50), more than one frame may be rendered between physics cycles.
Check your code with this in mind: maybe you're running part of your code inside FixedUpdate, part in Update, and this is causing the lag (NOTE: Physics.Raycast executes immediately)
Thanks for the answer, but I given the $$anonymous$$imal test case I managed to find (see edit above), I don't think that's the problem, I think it's something with how the unity internals work.
Do feel free to correct me if you think I'm wrong, because if you're right then that would certainly be the easiest way to fix the problem. :)