Unity Performance Optimization - Script Code Optimization

Unity Performance Optimization - Script Code Optimization

References: https://unity3d.com/cn/learn/tutorials/topics/performance-optimization

Script code optimization

Managed Code and Managed Runtime Introduction

In the Build  process of the Unity project  , the C#  code is first compiled into  CIL (Common Intermediate Language) , and then compiled into the corresponding Native Code according to the target operating platform of the project  .
The code that is compiled into CIL (that is, C#) is called  Managed Code . When managed code is compiled into native code, it is integrated into the  Managed Runtime . The managed runtime will handle such things as automatic memory management and security checks.

Causes of poor code performance

  • The first possible reason: the code structure is not good. For example, repeatedly calling methods that do not require multiple executions.
  • The second possible cause: unnecessary overhead caused by calling other code. For example, unnecessary calls between managed code and engine code (C++).
  • The third possible reason: Call code that does not need to be called. For example, call the method of simulating the enemy's line of sight when the player is far from the enemy (AI).
  • The last possible reason: The code is too rigorous. For example, a very detailed simulation of a large number of agents using complex AI.

Increase code efficiency

  • Reduce the number of loop executions and the number of instructions in the loop.
  • The method does not require frequent execution of the  Update() removal of.
  • Only execute code when changes occur. For example, it does not repeat the output of the unchanged amount.
  • Change the method that needs to be executed frequently and cannot be triggered by the event to execute every few frames. For example, by recording the number of frames (Time.frameCount) and skipping certain frames through a modulo operation, it is also possible to make several methods do not execute in the same frame.
  • Use cached storage values ​​that need to be retrieved and used repeatedly. For example, storing the return value of the GetComponent() method in a variable avoids repeated fetches.
  • Choose the right data structure for your needs, especially in the data-driven development model. Related tutorials
  • Use object pools to optimize memory usage and reduce CPU overhead. The overhead of creating and destroying objects is usually higher than the cost of activating and deactivating objects, especially for objects that contain initialized content. Related tutorials

Avoid calling expensive Unity APIs

  • SendMessage() and BroadcastMessage() . Under the premise of understanding the project structure, the SendMessage() and BroadcastMessage() methods are very flexible and easy to use, but it uses reflection and reflections cause more CPU overhead. When you know which method of which component to invoke, you should call the method directly through the component's reference; when it is unclear what components and methods to use, consider using  event  and  delegate  substitution.
  • Find() . The Find() method will iterate over each GameObject and component in memory, and as the size of the project expands, its overhead will increase. Do not frequently use Find() and methods similar to it. Consider setting a reference to an object in the Inspector, or create a script that is used to manage references to objects that need to be searched.
  • Transform . Setting position and rotation triggers the internal OnTransformChanged event and propagates it to all child objects. This is a costly operation for objects with very child objects, and you should  reduce changes to position and rotation . If you want to set the xyz of the position in a method, you can create a Vector3 and then set the xyz to the Vector3, and finally set the Vector3 to the position, instead of setting the xyz of the position each time. Try using localPosition instead of position . localPosition is stored in the transform. When the value is accessed, Unity will return it directly, and position will be recalculated on each access. If you want to get the position often, you can cache it.
  • Update() . Each invocation of event methods such as Update() and LateUpdate() requires communication between the engine code and the managed code, and Unity also performs security checks (whether the GameObject state is valid, etc.) even if the method body of these event methods is empty , the engine will still call it. Therefore, to avoid wasting CPU time, empty event methods should be  removed . If the game contains a lot of MonoBehavior with Update() method, you should try to change the code structure to reduce overhead. There is a related blog .
  • Vector2 and Vector3 () . Mathematical operations of vectors are more complex than ordinary floating-point arithmetic and mathematical operations of integers. Some properties of access vectors may bring implicit overhead, such as the magnitude attribute (not only for vectors, such as the Transform.position mentioned above. ). Each time you visit magnitude, the engine will perform a square root operation, although a single calculation will not consume much time, but when the order of magnitude is large enough, this overhead will become apparent. You can try to use sqrMagnitude (magnitude squared) instead of magnitude to reduce the square root operation.
  • Camera.main . The problem caused by Camera.main is similar to the Find() method. You should avoid using Camera.main and manually manage references to the camera.
  • Other Unity API calls and optimizations .
Some members of the object appear to be variables, but in fact it is a get (set,), in addition to the return value, it also contains additional operations, such as mathematical calculations, trigger events or call the engine code in managed code . The position in Transform, the magnitude in Vector, and Camera.main in the above mentioned are all accessors. During the encoding process, you should pay attention to whether the frequently accessed data contains an accessor. 
Here's more guidance on Unity's performance optimization .

Run code only when needed

  • Frustum Culling . Implements code related to its visual effects only when the object is visible, whether the object is visible through GetComponent().isVisible, or through the event methods OnBecameInvisible() and OnBecameVisible() to modify the code when the object becomes visible/invisible Implementation modalities.
  • Level of Detail (LOD) . With LOD technology, high-precision meshes and textures are rendered for objects close to the player, and low-precision meshes and textures are rendered for objects far from the player. LOD-like optimization can be performed in the code. For example, high-precision analog operations can be performed only for near-AI players, while remote AIs do not perform complex analog operations. The CullingGroup Handbook introduces more about how to use LOD.
Original Source: http://gad.qq.com/u/profile/2169065

Comments

Popular posts from this blog

Deep analysis of GC optimization for each value type of XLua under Unity

Unity UI Process-Oriented Programming Template for Lua

Tencent Open Hand Mobile Hot Update: Introduction to XLua under Unity3D