Unity 3D Optimization Construction and Simple Optimization Settings!
In this article, we will make Unity 3D Optimization and Unity 3D the best optimization settings. For this, you can read the article to the end and you will be able to perform an optimization process of 60% to 90%. This is often a one-on-one feature for slowdown issues.
I have used the term Garbage Collector (GC) in some optimization techniques, I want to talk about it briefly. Unlike C ++, in C#, unused memory is automatically freed (automatic memory management). The Garbage Collector does this. Clearing unused memory is important because otherwise this memory cannot be used again and the RAM your game uses will gradually increase until the game now consumes all the RAM and crashes. When the Garbage Collector runs, it passes through all the RAM the game is using and finds and cleans up the parts of RAM that are no longer used.
This process takes some time and the game freezes during this time (this freezing time is directly proportional to the amount of RAM the game uses); therefore, it is essential that the garbage collector work as little as possible. So when does the garbage collector work? While the RAM assigned to the game is full to the brim, a little more memory is needed for a new object (an instantiated object, a new array, etc.).
In this case, the garbage collector works, the unused memory is cleared and if the space for the newly created object is cleared, the object starts to use that part of the memory. If enough space is not cleared, the amount of RAM used by the game will necessarily increase; this means that subsequent garbage collector operations take longer. Of course, if the game was already using RAM completely, then unfortunately the game crashes (if you are not making a huge game, don’t worry about it, this problem never happened to me). To summarize:
- Objects, arrays, etc. you create with Instantiate or with the new tag. takes up memory space, if the memory is full, the garbage collector will run. The new event here is actually a bit more complicated because when running an array garbage collector created with new int [] it does not run a vector created with new Vector3 because the memory Vector3 uses is not in the heap where the garbage collector is running, but in a separate, the memory is kept in the stack (as I said, this is a bit complicated issue, just know that the new Vector3 we use a lot in Unity is not a problem and has no effect on the garbage collector).
- While the Garbage collector is running, the game freezes completely, this time increases in direct proportion to the amount of RAM the game uses.
The GC Alloc column of the Profiler window shows how much new memory has been used in that frame. Especially in mobile games, this value should be 0 bytes in the majority of the game. If a certain amount of memory is used in each frame, so that the garbage collector works as little as possible, identify the code using the memory with Profiler and optimize that code to 0 bytes (say if a new array is constantly being created, this array will instead Create once at the beginning of the game and use it over and over again).
Script Optimization
- Do not leave empty Unity functions in your scripts (especially Update, LateUpdate, and FixedUpdate). These functions are listed as Messages under MonoBehaviour in the Unity Script Reference and if any of these functions are present in your scripts, that function is called even if it is empty. Be especially careful about these functions, as the Update, LateUpdate, and FixedUpdate functions are called many times during the game: Are you not using the function? Then delete it from your code.
- If you access a component multiple times in your code, instead of accessing that component with GetComponent each time, keep it inside a variable and use this variable next time.
Before optimization:
void FixedUpdate()
{
GetComponent<Rigidbody>().AddForce( Vector3.up );
}
public void MuzikCal()
{
GetComponent<AudioSource>().Play();
}
Post optimization:
private Rigidbody cachedRigidbody;
private AudioSource cachedAudioSource;
void Awake()
{
cachedRigidbody = GetComponent<Rigidbody>();
cachedAudioSource = GetComponent<AudioSource>();
}
void FixedUpdate()
{
cachedRigidbody.AddForce( Vector3.up );
}
public void MuzikCal()
{
cachedAudioSource.Play();
}
- Accessing an object in the scene with GameObject.Find is a slow process. The more optimized version of this is GameObject.FindWithTag. However, a better optimization is keeping the object of interest in a variable. This optimization is much more important, especially if you are using Object.FindObjectOfType.
Before optimization:
void Update ()
{
// Teleport this object to where Object2 is
transform.position = GameObject.Find ("Object2") .transform.position;
}
void Object3uDeactiveEt ()
{
GameObject.FindWithTag ("Object3Tag") .SetActive (false);
}
Post optimization:
Private Transform object2'sTransform;
private GameObject object3;
void Awake ()
{
object2'nTransform = GameObject.Find ("Object2") .transform;
object3 = GameObject.FindWithTag ("Object3Tag");
}
void Update ()
{
// Teleport this object to where Object2 is
transform.position = object2ninTransform.position;
}
void Object3uDeactiveEt ()
{
object3.SetActive (false);
}
NOTE: Unity 3D Optimization, The Camera.main variable allows you to easily access the camera in the scene, but calls the GameObject.FindWithTag (“Main Camera“) function in the background. So if you access Camera.main frequently, throw the result to a variable and use that variable.
- GetComponents or GetComponentsInChildren functions find all components of a certain type and return them as an array. Each new array means a little more work for the garbage collector. Instead, use the List parameter-taking versions of these functions. In this way, the results found are stored in the List that already exists, a new array will not be created.
Before optimization:
void Colliderl()
{
Collider[] colliderlar = GetComponents<Collider>();
for( int i = 0; i < colliderlar.Length; i++ )
colliderlar[i].enabled = false;
}
Post optimization:
private readonly List<Collider> colliderlar = new List<Collider>();
void Colliderl()
{
GetComponents<Collider>( colliderlar );
for( int i = 0; i < colliderlar.Count; i++ )
colliderlar[i].enabled = false;
}
Sometimes you may need to constantly Instantiate and Destroy an object throughout the game (e.g. bullet prefix in an FPS game or an explosion particle effect). However, too much use of these Instantiate and Destroy commands is not a good thing in terms of performance. For exactly such situations, a technique called pooling pattern has been developed. The working principle of this is simple: instead of destroying the clone of a prefab that you use all the time, you deactivate it and drop it into the pool. Later, when you need another clone of this prefab, you first check to see if there is a clone in the pool; if you are using the clone in the pool. Only if there are no clones in the pool then you are installing a new clone. This simple technique is suitable for use in many game genres, from FPS games to infinite runner games.
- At the beginning of your game, give a value to Application.target framerate. This variable determines the FPS value the game is targeting. Let’s say you set the value to 60, the game will not go above 60 FPS. Running the game at 60 FPS compared to running the game at 120 FPS helps to spend the battery slower, especially on mobile devices, the device warms up slower and the CPU is less tired. On mobile devices, set targetFrameRate to 30 if possible, and 60 if your game doesn’t look very fluid. An even higher number will not do you any good.
- Vector structs (eg Vector3) have a function named Distance and a variable named magnitude. These two commands are essential for measuring the length of a vector. However, since it is necessary to use the square root during the calculation, this process is actually more troublesome than you think. If you are not going to show this length value directly to the user (for example, if you are trying to compare the lengths of two vectors), then consider using the faster variable sqrMagnitude. This variable returns the square of the length of a vector, and calculating this value is faster than magnitude (and Distance).
Before optimization:
public float maximumDistance = 5f;
Vector3 is vector1, vector2, vector3;
void One Function ()
{
// if the distance between vektor1 and vektor2 is less than maxDistance
if (Vector3.Distance (vektor1, vektor2) <= maximumDistance)
{
// bla bla
}
// if the length of vektor3 is greater than 8.0
if (vektor3.magnitude> 8f)
{
// bla bla
}
}
Post optimization:
public float maximumDistance = 5f;
private float maximumSquare;
Vector3 is vector1, vector2, vector3;
void Start ()
{
maximumDistanceSquare = maximumDistance * maximumDistance;
}
void One Function ()
{
// if the distance between vektor1 and vektor2 is less than maxDistance
if ((vektor1 - vektor2) .sqrMagnitude <= maximumSquare)
{
// bla bla
}
// if the length of vektor3 is greater than 8.0
if (vektor3.sqrMagnitude> 64f)
{
// bla bla
}
}
- If you are constantly dividing a number or variable by a certain number in your codes; then replace this division with a multiplication operation because multiplication is computed much faster than division.
Physics Optimization
While physics has a very important place in some games, physical interactions are minimal in some games (maybe even no physics is used). The calculation of physics events is done in FixedUpdate and the FixedUpdate function is run at a certain frequency. If you enter Edit-Project Settings-Time, you can see that physics calculations take place with a default period of 0.02 seconds. (Fixed Timestep)
If the physics events do not have a big place in your game, increase this value gradually and check the effect of this on the physical interactions in your game. The more you increase this value, the better for performance, but if you increase the value too much then the physical interactions don’t work as intended, so it’s best to tweak it by trial and error.
- You have an object with a collider and does this object move during the game? Then make sure there is also a Rigidbody in either this object or a parent of this object (check the “Is Kinematic” in the Rigidbody if you do not want the object to be affected by physical forces [is gravity, is AddForce, etc.]). Otherwise, every time this object without Rigidbody but with collider moves, the physics engine will have to do some heavy calculations.
- Use as few Mesh Colliders as possible on your physics objects. You can actually approximate the shape of most objects that use Mesh Colliders by actually using a few primitive colliders (Box Collider, Sphere Collider, and Capsule Collider) (which “approximate” mimicry is sufficient for most physical interactions). So what are we doing? We are trying to imitate the Mesh Colliders in our objects with the primitive colliders provided by Unity (then do not forget to delete the Mesh Collider component). If necessary, you can also give these colliders to the child GameObjects of the object (for example, if you need to give the collider a little slope).
- In your raycast functions, set a maximum length for this raycast beam. In most cases, instead of sending an infinite length of raycast beam, it is sufficient to send, for example, a 100 unit long raycast beam. Another important issue is the use of layer masks. As you can imagine, you will get faster results if you only raycast against objects on a certain layer instead of performing a raycast test on all objects in the scene. For example, if you want to check whether a character is in the air or on the ground, you don’t need to mix the clouds in the sky into raycast, you just need to raycast against ground objects. For this, you can give the ground objects a layer called “Ground” and use this layer in your Raycast function.
Functions such as Physics.RaycastAll and Physics.OverlapSphere gradually exploit the device’s memory, returning a new array each time (this exploitation does not apply to Physics.Raycast). Most of these functions have versions called NonAlloc that do not eat from memory: Physics.RaycastNonAlloc and Physics.OverlapSphereNonAlloc.
These NonAlloc functions take a RaycastHit[] array as their parameter and store the RaycastHit results they find in this array. The int value returned by the function indicates how many RaycastHits have been found (so how many RaycastHits have been added to the array). Let’s say you give the function a RaycastHit [] array with a capacity of 10 and the function returns 3, the RaycastHits returned by the function are stored in indexes 0, 1, and 2 of the array. If you give the function a very small array (let’s say an array of 2 elements in this example), the function will automatically stop after finding 2 RaycastHits, not other RaycastHits.
UI Optimization
For the UI to run more efficiently and your sprites to take up less space, use sprite atlas in the UI. Fortunately, Unity helps us a lot in this regard. In the Edit-Project Settings-Editor, pull the Sprite Packer to Always Enabled or Enabled For Builds. The first allows Unity to use sprite atlases in the editor, while the second allows sprite atlases to be created only when building the game; I am using the first one. The next step depends on your version of Unity:
- Unity 2017.1 and later: Create a new sprite atlas with Create-Sprite Atlas in the Project panel. Turn off the Allow Rotation and Tight Packing values (it can cause trouble in the UI) and add the sprites you want to add to the sprite atlas to the Objects for Packing section. If you add a folder here, all sprites in the folder will automatically be included in the sprite atlas. If you wish, you can view the resulting sprite atlas by clicking the Pack Preview button.
- Older versions: Set the Packing Tags in the Inspectors of the sprites you want to add to the Sprite Atlas as desired (eg “UIAtlas“). Sprites carrying the same Packing Tag are automatically added to the same sprite atlas.
Do not stack all your UI objects on a single Canvas. If a single property of a single UI element inside the canvas changes (position, color, etc.), the entire canvas will have to be renewed (yes, ALL CANVAS). For example, keep your dynamic UI objects and static (never changing) UI objects in separate canvases. Some of your dynamic UI objects change too often, but if some change rarely, put these frequently changing UI objects on a separate canvas. The good thing here is that these two canvases do not need to be completely independent of each other, a canvas object can be a child object of another canvas object; this is called nested canvas. Even if a UI object in the parent canvas changes, as long as there is no change in the UI objects in the nested canvas, the nested canvas is not renewed and the CPU is not wasted. The only thing you should be careful about with nested canvas is that if there is a UI object inside the nested canvas that can interact with the mouse or finger, such as Button, make sure that the nested canvas has a Graphic Raycaster component; Graphic Raycaster in parent canvas does not affect the nested canvas.
Graphics Optimization
Do not throw the textures in your game into Unity in .jpeg format so that the size is low. Or similarly, do not reduce the original 512 × 512 quality texture from your image editor (Photoshop, etc.) to 256 × 256 and send it to Unity to make it low in size. Send to Unity the best quality source file you have (eg .psd or .png and 512 × 512). No matter what format you assign an image file to Unity, this image file is automatically converted into a texture in Unity. Meanwhile, how many MB of this image file does not affect the size of the texture, while the quality of the image file directly affects the quality of the texture created by Unity. Even if you send a 512 × 512 image file to Unity, you can also automatically convert it from the “Max Size” at the bottom in the Inspector to a 256 × 256 texture.
Other Optimizations
Don’t make your objects as children of Empty GameObjects just to keep Hierarchy in order. When the Transform of a child object changes, Unity in itself marks all siblings of that Transform as potentially changed, and this process eats from the CPU. For this, the moving objects in your scene are at the root of Hierarchy, that is, they do not have a parent. But if all the objects in an Empty GameObject are immobile, that Empty GameObject can stay that way, it’s okay.
Here for more; Unity 3D
If you are going for most excellent contents
like me, only pay
a quick visit this web page every day because it offers feature contents,
thanks
Here is my page: Graham Mallinson