Zoeken…


Opmerkingen

  1. Schakel indien mogelijk scripts voor objecten uit wanneer ze niet nodig zijn. Als u bijvoorbeeld een script hebt op een vijandelijk object dat zoekt naar en vuurt naar de speler, overweeg dan om dit script uit te schakelen wanneer de vijand bijvoorbeeld te ver van de speler verwijderd is.

Snelle en efficiënte controles

Vermijd onnodige bewerkingen en methodeaanroepen waar u maar kunt, vooral in een methode die vele malen per seconde wordt aangeroepen, zoals Update .

Afstand / bereikcontroles

Gebruik sqrMagnitude plaats van magnitude bij het vergelijken van afstanden. Dit voorkomt onnodige sqrt bewerkingen. Merk op dat bij het gebruik van sqrMagnitude de rechterkant ook vierkant moet zijn.

if ((target.position - transform.position).sqrMagnitude < minDistance * minDistance))

Grenzencontroles

Kruispunten van objecten kunnen grof worden gecontroleerd door te controleren of hun Collider / Renderer grenzen elkaar kruisen. De Bounds structuur heeft ook een handige Intersects methode die helpt bepalen of twee grenzen elkaar kruisen.

Bounds helpen ons ook bij het berekenen van een benadering van de werkelijke (oppervlakte tot oppervlakte) afstand tussen objecten (zie Bounds.SqrDistance ).

Voorbehoud

Controle van grenzen werkt echt goed voor convexe objecten, maar grenscontroles op concave objecten kunnen leiden tot veel hogere onnauwkeurigheden, afhankelijk van de vorm van het object.

Het gebruik van Mesh.bounds wordt niet aanbevolen, omdat dit grenzen van de lokale ruimte retourneert. Gebruik MeshRenderer.bounds plaats daarvan MeshRenderer.bounds .

Coroutine vermogen

Gebruik

Als u een langdurige operatie uitvoert die afhankelijk is van de niet-thread-safe Unity API, gebruikt u Coroutines om deze over meerdere frames te splitsen en uw applicatie responsief te houden.

Coroutines helpen ook bij het uitvoeren van dure acties elk nde frame in plaats van die actie bij elk frame uit te voeren.

Langlopende routines verdelen over meerdere frames

Coroutines helpen bij het verspreiden van langlopende bewerkingen over meerdere frames om de framerate van uw toepassing te behouden.

Routines die procedureel schilderen of terrein genereren of lawaai genereren, zijn voorbeelden waarvoor de Coroutine-behandeling nodig kan zijn.

for (int y = 0; y < heightmap.Height; y++) 
{
    for (int x = 0; x < heightmap.Width; x++)
    {
        // Generate pixel at (x, y)
        // Assign pixel at (x, y)
        
        // Process only 32768 pixels each frame
        if ((y * heightmap.Height + x) % 32 * 1024) == 0)
            yield return null; // Wait for next frame
    }
}

De bovenstaande code is een gemakkelijk te begrijpen voorbeeld. In productiecode is het beter om de controle per pixel te vermijden die controleert wanneer het yield return (misschien om de 2-3 rijen) en om van tevoren de luslengte for berekenen.

Duurdere acties minder vaak uitvoeren

Coroutines helpen u minder vaak dure acties uit te voeren, zodat het niet zo'n groot succes is als wanneer elk frame zou worden uitgevoerd.

Neem het volgende voorbeeld rechtstreeks uit de handleiding :

private void ProximityCheck() 
{
    for (int i = 0; i < enemies.Length; i++) 
    {
        if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance)
                return true;
    }
    return false;
}

private IEnumerator ProximityCheckCoroutine() 
{
    while(true) 
    {
        ProximityCheck();
        yield return new WaitForSeconds(.1f);
    }
}

Nabijheidstests kunnen nog verder worden geoptimaliseerd met behulp van de CullingGroup API .

Gemeenschappelijke valkuilen

Een veelgemaakte fout die ontwikkelaars maken is toegang tot resultaten of bijwerkingen van coroutines buiten de coroutine. Coroutines retourneren controle naar de beller zodra een yield return wordt aangetroffen en het resultaat of bijwerking mogelijk nog niet is uitgevoerd. Te omzeilen problemen waar je moet het resultaat / side effect te gebruiken buiten de coroutine, controleert dit antwoord .

strings

Je zou kunnen stellen dat er in Unity grotere resource hogs zijn dan de bescheiden string, maar het is een van de gemakkelijkere aspecten om al in een vroeg stadium op te lossen.

String operaties bouwen afval op

De meeste stringbewerkingen bouwen kleine hoeveelheden afval op, maar als die bewerkingen tijdens een enkele update meerdere keren worden aangeroepen, stapelt het zich op. Na verloop van tijd zal het de automatische Garbage Collection activeren, wat kan resulteren in een zichtbare CPU-piek.

Cache je string operaties

Overweeg het volgende voorbeeld.

string[] StringKeys = new string[] {
    "Key0",
    "Key1",
    "Key2"
};

void Update()
{
    for (var i = 0; i < 3; i++)
    {
        // Cached, no garbage generated
        Debug.Log(StringKeys[i]);
    }

    for (var i = 0; i < 3; i++)
    {
        // Not cached, garbage every cycle
        Debug.Log("Key" + i);
    }

    // The most memory-efficient way is to not create a cache at all and use literals or constants.
    // However, it is not necessarily the most readable or beautiful way.
    Debug.Log("Key0");
    Debug.Log("Key1");
    Debug.Log("Key2");
}

Het ziet er misschien gek en overbodig uit, maar als je met Shaders werkt, kun je situaties zoals deze tegenkomen. Het cachen van de toetsen zal het verschil maken.

Merk op dat stringliterals en constanten geen afval genereren, omdat ze statisch in de stapel van het programma worden geïnjecteerd. Als u tijdens het uitvoeren strings genereert en gegarandeerd dezelfde strings genereert als in het bovenstaande voorbeeld, zal caching zeker helpen.

Voor andere gevallen waarin de gegenereerde tekenreeks niet elke keer hetzelfde is, is er geen ander alternatief voor het genereren van die tekenreeksen. Als zodanig is de geheugenpiek met het handmatig genereren van tekenreeksen meestal te verwaarlozen, tenzij tienduizenden tekenreeksen tegelijkertijd worden gegenereerd.

De meeste tekenreeksbewerkingen zijn foutopsporingsberichten

Stringbewerkingen uitvoeren voor foutopsporingsberichten, dat wil zeggen. Debug.Log("Object Name: " + obj.name) is prima en kan niet worden vermeden tijdens de ontwikkeling. Het is echter belangrijk om ervoor te zorgen dat irrelevante foutopsporingsberichten niet in het vrijgegeven product terechtkomen.

Een manier is om het kenmerk Voorwaardelijk te gebruiken in uw debug-aanroepen. Hiermee worden niet alleen de methodeaanroepen verwijderd, maar ook alle tekenreeksen die erin worden verwerkt.

using UnityEngine;
using System.Collections;

public class ConditionalDebugExample: MonoBehaviour
{
    IEnumerator Start()
    {
        while(true)
        {
            // This message will pop up in Editor but not in builds
            Log("Elapsed: " + Time.timeSinceLevelLoad);
            yield return new WaitForSeconds(1f);
        }
    }

    [System.Diagnostics.Conditional("UNITY_EDITOR")]
    void Log(string Message)
    {
        Debug.Log(Message);
    }
}

Dit is een vereenvoudigd voorbeeld. Misschien wilt u wat tijd besteden aan het ontwerpen van een volwaardige logboekroutine.

String vergelijking

Dit is een kleine optimalisatie, maar het is het vermelden waard. Het vergelijken van strings is iets ingewikkelder dan men zou denken. Het systeem zal standaard proberen rekening te houden met culturele verschillen. U kunt ervoor kiezen om in plaats daarvan een eenvoudige binaire vergelijking te gebruiken, die sneller presteert.

// Faster string comparison
if (strA.Equals(strB, System.StringComparison.Ordinal)) {...}
// Compared to
if (strA == strB) {...}

// Less overhead
if (!string.IsNullOrEmpty(strA)) {...}
// Compared to
if (strA == "") {...}

// Faster lookups
Dictionary<string, int> myDic = new Dictionary<string, int>(System.StringComparer.Ordinal);
// Compared to
Dictionary<string, int> myDictionary = new Dictionary<string, int>();

Cache referenties

Cachereferenties om dure oproepen te voorkomen, vooral in de updatefunctie. Dit kan worden gedaan door deze referenties in het cachegeheugen op te slaan indien beschikbaar of indien beschikbaar en te controleren op null / bool flat om te voorkomen dat de referentie opnieuw wordt opgehaald.

Voorbeelden:

Verwijzingen naar cachecomponenten

verandering

void Update()
{
    var renderer = GetComponent<Renderer>();
    renderer.material.SetColor("_Color", Color.green);
}

naar

private Renderer myRenderer;
void Start()
{
    myRenderer = GetComponent<Renderer>();
}

void Update()
{
    myRenderer.material.SetColor("_Color", Color.green);
}

Cache-objectverwijzingen

verandering

void Update()
{
    var enemy = GameObject.Find("enemy");
    enemy.transform.LookAt(new Vector3(0,0,0));
}

naar

private Transform enemy;

void Start()
{
    this.enemy = GameObject.Find("enemy").transform;
}

void Update()
{
    enemy.LookAt(new Vector3(0, 0, 0));
}

Waar mogelijk kunt u dure oproepen, zoals oproepen naar Mathf, in de cache opslaan.

Vermijd het aanroepen van methoden met tekenreeksen

Vermijd het aanroepen van methoden met tekenreeksen die methoden kunnen accepteren. Deze aanpak maakt gebruik van reflectie die je spel kan vertragen, vooral wanneer het wordt gebruikt in de updatefunctie.

Voorbeelden:

    //Avoid StartCoroutine with method name
    this.StartCoroutine("SampleCoroutine");

    //Instead use the method directly
    this.StartCoroutine(this.SampleCoroutine());

    //Avoid send message
    var enemy = GameObject.Find("enemy");
    enemy.SendMessage("Die");

    //Instead make direct call
    var enemy = GameObject.Find("enemy") as Enemy;
    enemy.Die();

Vermijd lege eenheidsmethoden

Vermijd lege eenheidsmethoden. Afgezien van een slechte programmeerstijl, is er een zeer kleine overhead betrokken bij runtime scripting. In veel gevallen kan dit de prestaties verhogen en beïnvloeden.

void Update
{
}

void FixedUpdate
{
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow