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. Dismiss Notice

Resolved I need help optimizing this.

Discussion in 'Scripting' started by jlorenzi, Aug 20, 2022.

  1. jlorenzi

    jlorenzi

    Joined:
    May 2, 2021
    Posts:
    270
    I'm currently making some settings in my game, one of those includes swapping out snap turning to smooth turning. So the way I'm doing it right now is using Easy Save to save a bool that is true when snap turn is on, and false when smooth turn is on, then I load in that bool in update and check if it's true or false, if it's true switch to snap turning and vice versa. I definitely think this can be optimized because I'm sure loading in a file isn't fast and doing it every frame just makes it slower. How would I optimize this? Because I have multiple scenes in my game so I do need to communicate through them somehow, and if the player changes the setting midway through and I'm only checking for the variable in the start function then it won't have any effect.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.XR.Interaction.Toolkit;
    5.  
    6. public class LocomotionManager : MonoBehaviour
    7. {
    8.     private void Update()
    9.     {
    10.         bool snapTurn = ES3.Load<bool>("Snap Turn");
    11.  
    12.         var snapTurnProvider = GetComponent<DeviceBasedSnapTurnProvider>();
    13.         var smoothTurnProvider = GetComponent<DeviceBasedContinuousTurnProvider>();
    14.  
    15.         if ( snapTurn )
    16.         {
    17.             if ( smoothTurnProvider )
    18.             {
    19.                 Destroy(smoothTurnProvider);
    20.  
    21.                 gameObject.AddComponent<DeviceBasedSnapTurnProvider>();
    22.             }
    23.         }
    24.  
    25.         else
    26.         {
    27.             if ( snapTurnProvider )
    28.             {
    29.                 Destroy(snapTurnProvider);
    30.  
    31.                 gameObject.AddComponent<DeviceBasedSnapTurnProvider>();
    32.             }
    33.         }
    34.     }
    35. }
    36.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    I don't see where you're loading a file. Are you sure this optimization is even necessary?

    DO NOT OPTIMIZE "JUST BECAUSE..." If you don't have a problem, DO NOT OPTIMIZE!

    If you DO have a problem, there is only ONE way to find out. Always start by using the profiler:

    Window -> Analysis -> Profiler

    Failure to use the profiler first means you're just guessing, making a mess of your code for no good reason.

    Not only that but performance on platform A will likely be completely different than platform B. Test on the platform(s) that you care about, and test to the extent that it is worth your effort, and no more.

    https://forum.unity.com/threads/is-...ng-square-roots-in-2021.1111063/#post-7148770

    Remember that optimized code is ALWAYS harder to work with and more brittle, making subsequent feature development difficult or impossible, or incurring massive technical debt on future development.

    Notes on optimizing UnityEngine.UI setups:

    https://forum.unity.com/threads/how...form-data-into-an-array.1134520/#post-7289413

    At a minimum you want to clearly understand what performance issues you are having:

    - running too slowly?
    - loading too slowly?
    - using too much runtime memory?
    - final bundle too large?
    - too much network traffic?
    - something else?

    If you are unable to engage the profiler, then your next solution is gross guessing changes, such as "reimport all textures as 32x32 tiny textures" or "replace some complex 3D objects with cubes/capsules" to try and figure out what is bogging you down.

    Each experiment you do may give you intel about what is causing the performance issue that you identified. More importantly let you eliminate candidates for optimization. For instance if you swap out your biggest textures with 32x32 stamps and you STILL have a problem, you may be able to eliminate textures as an issue and move onto something else.

    This sort of speculative optimization assumes you're properly using source control so it takes one click to revert to the way your project was before if there is no improvement, while carefully making notes about what you have tried and more importantly what results it has had.
     
  3. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    There's a few different ways to go about it.

    One way is to create a "SaveData" struct that encapsulates all the data you want to save/load on file:
    Code (CSharp):
    1. // Haven't used ES3 before, so I'm not sure if [Serializable] is necessary, but I'll assume it is.
    2. [Serializable]
    3. public struct SaveData
    4. {
    5.   public bool snapTurn;
    6.  
    7.   // Whatever other fields you want to save...
    8. }
    Then create a central save-manager utility that handles saving/loading this data, as well as caches the current saved-state of that data.
    Basic example:
    Code (CSharp):
    1. public static class SaveManager
    2. {
    3.   // An in-memory representation of the current data saved on file.
    4.   public static SaveData Data { get; private set; }
    5.  
    6.   private const string saveDataFile = "SaveData";
    7.  
    8.   public static SaveData Load()
    9.   {
    10.     // Load the saved data from file and set it to the cached "Data" property.
    11.     Data = ES3.Load<SaveData>(saveDataFile);
    12.     return Data;
    13.   }
    14.  
    15.   public static void Save(SaveData saveData)
    16.   {
    17.     // Save the data to file.
    18.     ES3.Save(saveDataFile, saveData);
    19.  
    20.     // Update the cached "Data" property with the new saved data.
    21.     Data = saveData;
    22.   }
    23. }
    Then have your
    LocomotionManager
    script simply point to the
    Data
    property of
    SaveManager
    :
    Code (CSharp):
    1. public class LocomotionManager : MonoBehaviour
    2. {
    3.   private void Update()
    4.   {
    5.     SaveData data = SaveManager.Data;
    6.     bool snapTurn = data.snapTurn;
    7.  
    8.     // Do things with "data" and "snapTurn"...
    9.   }
    10. }
    Now any time some other script wants to change
    snapTurn
    or other data, have it do so through
    SaveManager.Save()
    . The LocomotionManager script pointing to the
    SaveManager.Data
    property will ensure it's always reading the most recent saved data.
     
  4. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    Optimization starts with using the right algorithms and data structures. Very important. Doing everything in the naive way just means you end up rewriting whole bunches of code that you knew beforehand shouldn't be implemented in the naive way.

    Loading a file every frame, as in the OP's example, is of course not the right way to do things, hence their question.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    Yes, but you have not addressed what I wrote in the first place:

    Put your finger on the file open statement being run every frame. :)
     
  6. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    See line ten of OP's code (ES3 is Easy Save 3):
    Code (csharp):
    1. bool snapTurn = ES3.Load<bool>("Snap Turn");
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    In August 2022 there's virtually no chance that is opening a file every frame.

    The first frame sure, but after that it is going to be cached in a Dictionary<T1,T2>()

    I mean come on, even PlayerPrefs inside of Unity has worked that way or 10+ years!
     
  8. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    While that's indeed highly likely, you're still making assumptions about the underlying code. It's better to just do it the right way from the start, which, in my opinion, is: Load saved game, set properties, access properties in Update() method.

    People get things wrong regardless of what year it is.