2
\$\begingroup\$

I am using a fixed static background. I have a gameobject(Current ref. image) which is moving with the help of waypoints. I have made camera to follow the Current. The camera is stuttering while moving. Can anyone help me to solve the camera stuttering and make it follow the Current smoothly?

This is my code attached to camera following the star

public class CameraController : MonoBehaviour {

    void Start () {    
        GameObject.FindGameObjectWithTag("OptionCamera").GetComponent<Camera>().orthographicSize =
        (20.0f / Screen.width * Screen.height / 2.0f);
    }

    void LateUpdate() {
        if (GameObject.FindGameObjectWithTag ("Current") != null) {
            if (GameObject.FindGameObjectWithTag ("Current").GetComponent<CurrentController>().Greenblast == false &&
                GameObject.FindGameObjectWithTag ("Current").GetComponent<CurrentController>().Redblast == false)
            {
                Vector3 pos = GameObject.FindGameObjectWithTag ("Current").transform.position;
                transform.position = new Vector3 (transform.position.x, pos.y, transform.position.z);
            }
        }
    }
}

Example of Camera movement

\$\endgroup\$
  • \$\begingroup\$ I often see movement stutters where one object is updating on FixedUpdate (without interpolation), and another is updating on Update/LateUpdate. Because these two update loops are decoupled from one another, a camera updating in one to follow an object updating in the other can cause the apparent movement to judder. In this case, when is Current's position being updated? \$\endgroup\$ – DMGregory Aug 3 '15 at 16:08
  • \$\begingroup\$ Current's position is being updated using Waypoints in a FixedUpdate() method. \$\endgroup\$ – user5185619 Aug 4 '15 at 9:39
4
\$\begingroup\$

Based on the comments above, the followed object "Current" is only moving in FixedUpdate.

By default, FixedUpdate runs 50 times per second. In-between FixedUpdates, Unity renders as many frames as it can, each time calling Update, LateUpdate, etc.

Because the rendered framerate is usually not a perfect multiple of the FixedUpdate rate, this can cause a beat frequency between the updates which is perceived as a stutter.

For example, if you're rendering at 60 fps, but the FixedUpdate is running at 50 Hz, your frames might look like this:

Frame         1  2  3  4  5  6  7  8  9 10 11 12
FixedUpdate   1     2  3  4  5  6     7  8  9 10

Sometimes two Update frames get rendered off of the same FixedUpdate state, because less than 0.02s have elapsed since the last FixedUpdate. Visually, everything hesitates a beat once every 6 frames, then runs a little fast to catch up.

The situation is reversed if you're running below 50 fps, say at 30 fps:

Frame         1     2     3  4     5     6  
FixedUpdate   1  2  3  4  5  6  7  8  9 10

In this case, frames 2, 3, 5, and 6 have two FixedUpdates' worth of movement behind them, while there's only one FixedUpdate between frames 3 & 4, causing the apparent motion to slow down for one frame in every 5.

This is usually resolved using interpolation.

If you're moving your object using velocities on a Rigidbody, you can tell Unity to handle this for you by setting its Interpolation mode to either:

  • interpolate (smooth, at the cost of 1 physics frame of latency) or
  • extrapolate (maximum responsiveness, but may overshoot & correct due to mis-prediction)

Automagically, the movement of this object will now appear continuous, no matter your framerate.

You can also implement this yourself by adding a separate visual object that follows the (invisible) Current object in Update or LateUpdate, using Time.deltaTime as a blend weight to interpolate or extrapolate its position smoothly.

Or, if keeping the gameplay in FixedUpdate isn't important in this case (say, you're running at a locked framerate, or this is a non-interactive sequence in the game) you can change the object itself to move in Update so it changes its position with every rendered frame. (The reason this is usually avoided is that, if your framerate is variable, you can get inconsistent results from gameplay in Update, causing hard-to-track-down bugs that depend on precise timings)

For more insight on why the updates are split this way and how you can interpolate the visible game state between frames, check out this article on fixed timesteps.

\$\endgroup\$
2
\$\begingroup\$

You can use Vector3.Lerp(transform.position, WAYPOINT POS, Time.deltaTime) for smooth movement from one point to another.

\$\endgroup\$
0
\$\begingroup\$

The only possibility based on your snippet would be all the collection iterations it has to do each line to find stuff. If you have a lot of objects to hunt through, maybe that could influence performance to cause the stutter although I doubt it.

Have you profiled the code to see if it's a garbage collection issue somewhere other than this snippet?

Are you sure it's the camera and not the star(current) that is stuttering?

To speed up your snippet there, you can try something like this so it only has to find stuff once per call:

//in LateUpdate
GameObject go = GameObject.FindGameObjectWithTag("current");
If(go != null)
{
  CurrentController cc = go.GetComponent<CurrentController>();
  if(!cc.RedBlast && !cc.GreenBlast)
    {
      transform.position.Y = go.transform.position.Y;
    }
}
\$\endgroup\$
  • \$\begingroup\$ It is not a performance issue. The objects(just images with colliders) that are static in background seems to jitter a lot when the current move upwards. \$\endgroup\$ – user5185619 Aug 4 '15 at 9:50
0
\$\begingroup\$

From what you have posted I have a few pointers:

  • There are some Follow scripts you can try to tinker with in the standard assets: **Standard Assets\Utility** and **Standard Assets\2D**
  • You shouldn't have Find functions inside Update() loops as it might slow down your game. Here is how your code can include that:

(not the solution just an improvement)

public class CameraController : MonoBehaviour{

private GameObject target;

void Start () 
{    
GameObject.FindGameObjectWithTag("OptionCamera").GetComponent<Camera>().orthographicSize = (20.0f / Screen.width * Screen.height / 2.0f);   
target = GameObject.FindGameObjectWithTag ("Current");

 }

 void LateUpdate()
 {
     if (target != null) {
         if(target.GetComponent<CurrentController>().Greenblast == false &&
            target.GetComponent<CurrentController>().Redblast == false)
         {
             Vector3 pos = target.transform.position;
             transform.position = new Vector3 (transform.position.x, pos.y, transform.position.z);
         }
     }
 }
 void UpdateTarget(GameObject target) {
     this.target = target;
 }
 }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.