GameObject Update & FixedUpdate Confusion

I’ve been you tubing, googling etc for a definitive answer, but it seems very inconsistent, even the unity online tutorials Space Shooter, Tanks, 2D UFO etc are inconsistent.

On the net some post’s have control (getAxis), Update and move the gameobject in FixedUpdate.

Yesterday I had everything in fixedupdate e.g

  1. Joystick movement.
  2. Animation settings eg. Setinteger etc.
  3. Physics2D.LineCast
  4. Gameobject.transform.position

But today I set about splitting, things up but only putting the movement in fixedupdate, everything went well, on the PC it was slow to I increased the speed, and it was really nice but on my Android device it was too fast all characters moved with lightning speed, I guess this is because of not fixed time frame using Update??

A part of the code I’m using for one of the 8 directions is:

mOffset = Vector2.up * speed * Time.DeltaTime;

So what I’m trying to find out is this what part of 1-4 should go where e.g

Update

  1. Joystick movement.
  2. Animation settings eg. Setinteger etc.

FixedUpdate

  1. Physics2D.LineCast
  2. Gameobject.transform.position

Or should it be something else??

Also if I use Update should it be speed * Time.DeltaTime and if it’s Fixeupdate should it be speed * Time. fixedDeltaTime instead.

I’m trying to get the maximum amount of refreshrate.

My old(before yesterday) Update/FixedUpate are this

private void Update()
{
   if (mMonsterType == MonsterTypes.Sorcerer)
     {
      if (mCameraComponent.ObjectCoordinatesInScaledCameraView(0.1F, 0.125F, (int)this.gameObject.transform.position.x, (int)this.gameObject.transform.position.y) == false)
       return;

      if (DateTime.Now > mDateTime)
        {
         mVisible = !mVisible;

         if (mVisible == true)
           {
            int mSeconds = UnityEngine.Random.Range(2, 5);
            mRenderer.color = new Color(1F, 1F, 1F, 1F);
            mDateTime = DateTime.Now.AddSeconds(mSeconds);
           }
         else
             {
              mRenderer.color = new Color(1F, 1F, 1F, 0F);
              mDateTime = DateTime.Now.AddSeconds(2);
             }
        }
     }
}

  private void FixedUpdate()
  {
   Profiler.BeginSample("Monster FixedUpdate");

   if (mHero == null)
    mHero = GameObject.Find("Hero" + GameObject.Find("World").GetComponent<WorldComponent>().HeroType.ToString().ToLower());
   else if (mCameraComponent == null)
    mCameraComponent = (CameraComponent)Camera.main.gameObject.GetComponent(typeof(CameraComponent));

   if (mCameraComponent != null && mHero != null)
    if (mDirectionType != DirectionTypes.None)
      {
       if (mAnimator.GetInteger("Direction") != (int)mDirectionType)
        mAnimator.SetInteger("Direction", (int)mDirectionType);

       //mCameraComponent.DrawViewPort(mCameraComponent.CameraViewPort(), Color.red, 5F); 

       //mCameraComponent.DrawViewPort(mCameraComponent.CameraScaledViewPort(0.3F, 0.3F), Color.green, 5F); 
       //Debug.Log("Current Direction " + mCurrentDirection.ToString());

       //float mDistanceToHero = Vector3.Distance(this.transform.position, mHero.transform.position);
       //if (mDistanceToHero >= 8)
       if (mCameraComponent.ObjectCoordinatesInScaledCameraView(0.1F, 0.125F, (int)this.gameObject.transform.position.x, (int)this.gameObject.transform.position.y) == false)
         {
          mAnimator.enabled = false;
          //mRenderer.color = new Color(0f, 0f, 255f, 1f);
          return;
         }
       else
           {
             // mRenderer.color = new Color(0f, 255f, 0f, 1f);
            if ( mAnimator.enabled == false)
             mAnimator.enabled = true;       
           }

       if (mMonsterType == MonsterTypes.Demon)
        if (mProjecTileRegenerationTime != DateTime.MinValue)
         if (DateTime.Now > mProjecTileRegenerationTime)
           {
            float mX = Math.Abs(this.transform.position.x - mHero.transform.position.x);
            float mY = Math.Abs(this.transform.position.y - mHero.transform.position.y);
            float mDistance = Vector3.Distance(this.transform.position, mHero.transform.position);
            if (((mX < 6) && Utilitles.isVertical(mDirectionType) == true) || ((mY < 6) && Utilitles.isHorizontal(mDirectionType) == true) || ((mDistance < 6) && Utilitles.isDiagonal(mDirectionType) == true))
              {
               OnAddProjecTile(new ProjecTileEventArgs(mDirectionType));
               mProjecTileRegenerationTime = DateTime.Now.AddMilliseconds(mProjecTileRegenerationRate);
              }
           }

       if (mMonsterType == MonsterTypes.Lobber)
        if (mProjecTileRegenerationTime != DateTime.MinValue)
         if (DateTime.Now > mProjecTileRegenerationTime)
           {
            //float mX = Math.Abs(this.transform.position.x - mHero.transform.position.x);
            //float mY = Math.Abs(this.transform.position.x - mHero.transform.position.x);
            float mDistance = Vector3.Distance(this.transform.position, mHero.transform.position);
            if (mDistance < 8)
              {
              
               OnAddProjecTile(new ProjecTileEventArgs(mDirectionType));
               mProjecTileRegenerationTime = DateTime.Now.AddMilliseconds(mProjecTileRegenerationRate);
              }
           }

       if (mIsThinking == true && --mThinking > 0)
         {
          if (mAnimator.GetFloat("HSpeed") != 0)
           mAnimator.SetFloat("HSpeed", 0);

          if (mAnimator.GetFloat("VSpeed") != 0)
           mAnimator.SetFloat("VSpeed", 0);

          if (this.Mode == ModeType.Debug)
           Debug.Log("Thinking value is: " + mThinking);

          return;
         }

       if (mIsTraveling == true && mTraveling > 0)
         {
          if (mAnimator.GetFloat("HSpeed") != 1)
            mAnimator.SetFloat("HSpeed", 1);

          if (mAnimator.GetFloat("VSpeed") != 1)
           mAnimator.SetFloat("VSpeed", 1);

          if (this.Mode == ModeType.Debug)
           Debug.Log("Traveling value is: " + mTraveling);

          Step((Vector2)this.gameObject.transform.position, mLocationComponent, mDirectionType, countdown(mTraveling), mSpeed * Time.deltaTime);
          return;
         }

       List<DirectionTypes> mDirections = Utilitles.CalculateDirections(this.gameObject, mHero, mSpeed * Time.deltaTime, mDirectionType, out CalculatedDirection);
        if (mDirections != null && mDirections.Count > 0)
          {
           if (this.Mode == ModeType.Debug)
            Debug.Log("Number Of Directions: " + mDirections.Count);

           foreach (DirectionTypes direction in mDirections)
           {
            int mIndex = mDirections.IndexOf(direction);

            //Debug.Log("Index is: " + mIndex);
            //float mValue = mIndex < 2 ? 0 : mTravelingRate * ((mIndex - 2));
            // float mValue = (mTravelingRate * 2);
            float mValue = mTravelingRate;

            if (this.Mode == ModeType.Debug)
             Debug.Log("Enemy Checking Direction " + direction.ToString());

            if (Step((Vector2)this.gameObject.transform.position, mLocationComponent, direction, mValue, mSpeed * Time.deltaTime) == true)
              {
               if (this.Mode == ModeType.Debug)
                 {
                  Debug.Log("Enemy Selected Direction is: " + direction.ToString());
                  Debug.Log("Direction index " + mDirections.IndexOf(direction));
                 }

               return;
              }
            else
                {
                 if (this.Mode == ModeType.Debug)
                  Debug.Log("Cannot Move in the Following direction: " + direction.ToString());
                }  
           }

          }
        else
            {
             if (this.Mode == ModeType.Debug)
              Debug.Log("No usable directions!!");
            }


      }

   Profiler.EndSample();
  }

A few points:
Update - happens every frame, which can be pretty random on how long a paticular frame takes to render. Time.deltaTime will tell you how long since the last Update

FixedUpdate – happens at regular intervals. I believe its currently 50 fps TIme.deltaTime will tell you the time since the last fixedUpdate and should be 0.02

You should put all your code that doesn’t involve RigidBodies and physics in Update. This includes checking the input, moving transforms around manually or setting the velocity of an object directly.

You should put physics stuff in FixedUpdate.

I think one of the problems you having in writing for multiple devices is your setting the Velocity of your Rigidbodies directly. I suggest using the Physics Engine .AddForce and applying this in a FixedUpdate. I think this would make things move the same speed regardless of resolution. While adding a velocity directly is going to move faster on a smaller screen than a larger one.

Hi takatok,

Thanks for been the first person to reply, I get how and what intervals Update/FixedUpdate perform.

Even you say put

, but that’s not always the case in the tutorials I’ve been watching especially the unity versions I know these are for version 4.3 upwards, but you can get confusing.

My original problem was when I was doing all my calculations (joystick, mouse, animation) etc in fixedupdate (before I did any optimisation mind you), it was calling 7210 calls and about 20%+ was with animation which had the effect of grinding the game (on an android device) to a holt.

Yesterday I did workout that if I used this (and it’s 7 other variations)

mOffset=Vector2.up * speed * Time.fixedDeltaTime;

it was steady on PC and Android, it was the fixedDeltaTime was the answer.

My Fixed Update on looks like this now.

  private void FixedUpdate()
  {
   if (mCanMove == true)
    if (mCameraComponent != null && mHero != null)
     if (mDirectionType != DirectionTypes.None)
       {
        if (mMovement.Equals(mInfinity) == false)
         transform.position += (Vector3)mMovement;
       }
  }

So I’m not actually moving it using the rigid body

A Note for others

depending on what sort of game you are designing these idea’s of increasing(or decreasing calls might be an idea)

A) - If your camera is moving with your character whether it’s a child or otherwise and it’s possible only move enemies that are in and slightly off view.

B) - As previous stop animations that are out of view this for me saved about 15% of animation calls.

C) - Before setting animations using the SetIteger etc check the value just in case it’s the same e.g

 if (mAnimator.GetFloat("VSpeed") != 0)
           mAnimator.SetFloat("VSpeed", 0);

I’m not sure if this is needed because unities mechenim might check this before hand if the value are the same.

D) - Also if your using Physics2D.Linecast and you don’t want to the know the collider that has been hit use the
Physics2D.LinecastNonAlloc variant instead as this will save calls from the garbage collector e.g.

public static bool IsValidDirection(Vector2 start, Vector2 finish, ModeType mode)
  {
   RaycastHit2D[] hits = new RaycastHit2D[1];
   int mWallmask = 1 << LayerMask.NameToLayer("Walls");
   int mItemsmask = 1 << LayerMask.NameToLayer("Items");
   int mEnemiesmask = 1 << LayerMask.NameToLayer("Enemies");

   int Masks = mWallmask | mItemsmask| mEnemiesmask;

   if (mode == ModeType.Debug) 
    Debug.DrawLine(start, finish, Color.green, 0.25F, false);

   int mHit = Physics2D.LinecastNonAlloc(start, finish, hits, Masks);
    if (mHit > 0)
     return false;

   return true;
  }

I know there is a load more but for beginners this will help.

by doing these sorts of optimisation

Animation is down from 24% to 6% Max
Draw calls are down from 7210 to (240-500 max)
garbage are down not sure how much but I bet 2-5% if not more

Only draw etc what you need too, if possible.

All of those are great ideas and I suspect thats why your android is now moving at a better speed. (The optimizations). Though I’m not sure fixedDeltaTime vs deltaTime is actaully making a difference. Stick a Debug.Log and I think you’ll find both are equal to 0.2f. Of course I have only tested this on a PC.

You could create a UI Text and check each FixedUpdate if deltaTime vs FixedDeltaTIme was different. Then either write Same/ Different to that text. I suspect even on the Android the 2 values are the same in a FixedUpdate

I’m not sure about this but if you have Canvas Gamebjects for example that are behind you main view, by that I mean you have created a dialog that is behind everything and you move it forward in your scene when a user selects settings for example, I can bet that unity will still render that gameobject(s).

The best idea is too

A) create a handle to the main gameobject e.g.

mDialog = GameObject.Find("Panel");
mDialog.setActive(false);

Note you MUST set it inactive in code or you will not get a reference to it later as unity does not put it in the scene.

Just before you want to display it do this.

mDialog.setActive(true);

add then on closing, set it to inactive again.

mDialog.setActive(false);

hi takatok,

I though Time.DeltaTime was based on Update from the last frame or should I say since the last frame called, but Time.FixedDeltaTime is err!! fixed too 0.02, this does depend on your project settings mind you?

I believe Unity sets Time.deltaTime to the time since the last Update, right before it calls Update. and it sets time.deltaTime to the time since last FIxedUpdate right before a FixedUpdate. You can test it yourself if they are the same fairly easily.