[Colección de optimización de proyectos de Unity] Optimización y evitación a nivel de código

Bienvenido al grupo de intercambio QQ de la industria de Unity: 956187480

Uno: mejorar la eficiencia del código

1. Use la menor cantidad posible de lógica de bucle para simplificar el código del cuerpo del bucle (While, for, foreach, recursion)

Intente evitar la lógica de bucle al nivel de los requisitos comerciales. Si realmente se necesita lógica de bucle, aclare la lógica. El código del cuerpo del bucle principal no puede tener variables redundantes ni ocupación de memoria redundante. además:

for(int i=0;i<myArray.Length;i++)//避免

int length=myArray.Length;  
for(int i=0;i<length;i++) //提倡

2. Utilice hábilmente las funciones de ciclo de vida Update y LateUpdata.

Aclarar el significado de la función de cada frame de Updata y frame fijo de LateUpdata. Al utilizar ambos, es necesario aclarar si la demanda actual requiere llamadas de ejecución de alta frecuencia. Si es realmente necesario ejecutar la llamada para cada frame o realizar lógicas procesamiento en un solo cuadro (como representación de pantalla, etc.) entonces usamos Updata; además, si no tenemos requisitos altos para la frecuencia de ejecución de actualización (como rotación de desplazamiento físico y otra lógica), podemos usar LateUpdata ; eliminar el método de actualización vacío

    void Update()
    {
        if (isTrue) { isTrue = false;}//一定要加条件保护
    }
    private void LateUpdate()
    {
        transform.Rotate(Vector3.up * Time.fixedDeltaTime * speed);
    }

3. Ejecute el código solo cuando se produzcan cambios (actualización de datos de la interfaz de usuario).

La mayoría de las veces, no necesitamos tener especial cuidado con la lógica, como la actualización de datos de la interfaz de la interfaz de usuario. A muchos principiantes les gusta poner la lógica de actualización de la interfaz de usuario directamente en Updata. Aunque esto es muy fácil, no necesitamos administrar los datos de la interfaz por separado y el mantenimiento, pero si la interfaz tiene una gran cantidad de datos y actualizaciones frecuentes, causará una gran carga de representación para el programa. Podemos usar el delegado y otros métodos para llame a la lógica de actualización de la interfaz de la interfaz de usuario solo cuando haya una actualización de datos.

public delegate void MyDelegate(int score);//定义委托
public MyDelegate myDelegate; //声明委托
   
private int score = 0;
public int Score
{
    get => score;
    set
    {
        score = value; myDelegate?.Invoke(score);
    }
}
private void Start()
{
    myDelegate += UpdataUIData;//委托注册事件
}
public void UpdataUIData(int score)
{
    //刷新ui界面数据
}

4. Cambie el método que debe ejecutarse con frecuencia y que no puede ser activado por eventos que deben ejecutarse cada pocos fotogramas. Por ejemplo, el marco fijo de lateUpdata que acabamos de mencionar. Además de esto, también podemos usar la colaboración de manera flexible e iniciar una colaboración desde el principio.

private void Start()
{
    InvokeRepeating("RunSomeThing",1,5);//一秒钟执行五次
}
private int interval = 3;//间隔帧
void Update()
{
    if (Time.frameCount % interval == 0)//每三帧执行一次
    {
        RunSomeThing();
    }
}
public void RunSomeThing() { }

5. Use un caché para almacenar valores que deben recuperarse y usarse repetidamente.

Los componentes adquiridos dinámicamente se pueden almacenar en variables globales. Cuando se usan, se pueden obtener directamente para evitar la adquisición repetida
. Las variables temporales que se usan repetidamente se pueden almacenar globalmente cuando se declaran
. Objetos instanciados dinámicamente, queremos El método es fácil de administrar y usar directamente la próxima vez

6. Trate de evitar el uso de float para tipos numéricos y use int, especialmente en juegos móviles, trate de usar funciones matemáticas menos complejas, como seno, coseno y otras funciones. Cambie la división/multiplicación, por ejemplo: use x*0.5f en lugar de x/2.0f.

7. Recolección de basura activa

void Update()
{
    //固定时间GC回收但也不能太频繁,建议跳转场景的时候或者重要模块切换的时候回收
    if (Time.frameCount % 50 == 0)
    {
        GC.Collect();
    }
}

Dos: Evite llamar a las costosas API de Unity

1. SendMessage() y BroadcastMessage() usan reflexión y la reflexión causará más sobrecarga de CPU. Puede llamarlo directamente o hacerlo a través de un delegado de C#.

2. El método Find() recorrerá cada GameObject y componente en la memoria, y su sobrecarga aumentará a medida que se expanda la escala del proyecto. Evite usar Find() y métodos similares, e intente no usar el método de búsqueda en Update o FixedUpdate tanto como sea posible.

3. Establecer la posición y la rotación en Transform activará el evento interno OnTransformChanged y se propagará a todos los subobjetos. Para objetos con subobjetos muy diferentes, esta operación es muy costosa y la modificación de la posición y la rotación debe reducirse. . Si desea establecer el xyz de la posición por separado en un método, puede crear un Vector3 y luego establecer el xyz en el Vector3 respectivamente, y finalmente establecer el Vector3 en la posición, en lugar de establecer el xyz de la posición por separado cada vez. . Intenta usar localPosition en lugar de position. La posición local se almacena en la transformación. Al acceder al valor, Unity lo devolverá directamente y la posición se recalculará cada vez que se acceda. Si desea obtener la posición con frecuencia, puede almacenarla en caché.

4. Cada invocación de métodos de eventos como Update() y LateUpdate() requiere comunicación entre el código del motor y el código administrado, y requiere que Unity realice controles de seguridad (si el estado de GameObject es legal, etc.), incluso si el cuerpo del método de estos métodos de evento está vacío, el motor aún lo llamará. Por lo tanto, para evitar perder tiempo de CPU, se deben eliminar los métodos de eventos vacíos. Además, si un script en un GameObject con estado activo (gameObject.active == true) contiene el método Awake(), el método Awake() se ejecutará incluso si el script no está habilitado (habilitado==false). Si su juego tiene muchos MonoBehaviors con métodos Update(), debe intentar cambiar la estructura del código para reducir los gastos generales, hay una publicación de blog relacionada.

5. Las operaciones matemáticas de los vectores Vector2 y Vector3() son más complicadas que las de los números ordinarios de punto flotante y los enteros. Acceder a algunas propiedades de los vectores puede generar una sobrecarga implícita, como la propiedad de magnitud (no solo para vectores, como el Transform.posición mencionada en el artículo). Cada vez que se accede a la magnitud, el motor realiza una operación de raíz cuadrada y, aunque un solo cálculo no lleva mucho tiempo, cuando el orden de magnitud es lo suficientemente grande, esta sobrecarga se vuelve notable. Puede intentar usar sqrMagnitude (es decir, el cuadrado de la magnitud) en lugar de magnitud para reducir la operación de raíz cuadrada.

6. El problema causado por Camera.main es similar al método Find() Debe evitar usar Camera.main y administrar manualmente la referencia a la cámara.

Supongo que te gusta

Origin blog.csdn.net/qq_37310110/article/details/123107938
Recomendado
Clasificación