PerformanzUnity 4.x Cookbook
Softwaretechnologie II (Teil 2) - Maximilian Berndt
„Performanz ist die Menge nützlicher Arbeit durch ein Computersystem oder Computernetzwerk im Verhältnis zu der dafür benötigten Zeit und den Ressourcen.“
Bei Überanspruchung der Ressourcen Weniger Bilder pro Sekunde, gestörte Wiedergabe, „ruckeln“
Feststellung des Problems
1. Reduzierung detaillierter Objekte, Bewegungen und Texturen (Qualitätseinbußen)
2. Verändern des Quellcodes hin zu mehr Effizienz in der Berechnung (Optimierung)
Zwei Möglichkeiten
1. Möglichkeit, bei gleicher Rechenleistung mehr Details oder Objekte darstellen zu können
2. Möglichkeit, unter Beibehaltung des Detailgrades ein flüssiges Spielerlebnis zu bieten
Ziele einer Performanzoptimierung
1. Objekte lokalisieren, die die meisten Ressourcen benötigen
2. Objekte löschen, die nicht länger benötigt werden
◦ Schont sowohl Speicher als auch Rechenressourcen
3. Anzahl aktiver Objekte verringern4. Methoden so selten wie möglich aufrufen5. Aktionen minimieren, die Unity zur
Reflektion zwingen
Lösungsmöglichkeiten
using UnityEngine;public class ProfileScript : MonoBehaviour {
private void Awake() {
Profile.StartProfile(" Spieldauer ");}private void Start(){
Profile.StartProfile(„Rechnung");int answer = 2 + 2;print("2 + 2 = " + answer);Profile.EndProfile(„Rechnung");Profile.PrintResults();
}private void OnApplicationQuit() {
Profile.EndProfile(" Spieldauer ");Profile.PrintResults();
}}
Flaschenhälse finden
Skript misst Zeit zwischen Start und Ende des Spiels und für die Dauer der Berechnung (2+2)
Angewandt auf andere Anwendungsgebiete, wie z.B. Ladezeiten lassen sich genaue Angaben über die Performanz machen
Erläuterung
using UnityEngine;using System.Collections; public class DisableWhenInvisible : MonoBehaviour {
public Transform player;void OnBecameVisible() {enabled = true;print („ist sichtbar");}
void OnBecameInvisible() {gameObject.SetActive(false);GUILayout.Label („Boot wurde deaktiviert");}private void OnGUI() {float d = Vector3.Distance( transform.position, player.position);GUILayout.FlexibleSpace();GUILayout.Label ("Distanz des Spielers zum Boot = " + d);}
}
Deaktivieren wenn unsichtbar
Ständige Entfernungsberechnung vom Spielers zum Objekt bei jedem frame
Sobald OnBecameInvisible() eintritt, wird das Objekt deaktiviert
Keine Update() und OnGUI() Benachrichtigungen mehr, reduziert Rechenkapazitäten
Bei OnBecameVisible() wird das Objekt wieder aktiv
Erläuterung
using UnityEngine;using System.Collections; public class Reactivate : MonoBehaviour {
public GameObject cubeGo;private void OnGUI() {bool makeObjectActiveButtonClicked =
GUILayout.Button("Boot reaktivieren");if( makeObjectActiveButtonClicked )
cubeGo.SetActive(true);}
}
Reaktivieren
Wird zu Reaktivierung benötigt, da gesamtes Objekt „Boot“ inaktiv, also handlungsunfähig
Muss daher mit zweitem Objekt angewandt werden
Hierzu Objekt wählen, dass dauerhaft aktiv ist
Erläuterung
using UnityEngine;using System.Collections; public class TimedMethod : MonoBehaviour {
private void Start() {StartCoroutine(Tick()); // wird als Koroutine gestartet}
private IEnumerator Tick() {float delaySeconds = 5.0F; // Verzögerung der Ausführungwhile (true) {print("tick " + Time.time);yield return new WaitForSeconds(delaySeconds);}}
}
TimedMethod
Dient dazu, eine Ausführung aufzuschieben
Sinnvoll, wenn eine dauerhafte Ausführung einer Methode nicht zwingend notwendig ist
Erläuterung
using UnityEngine;using System.Collections; public class SegmentedCalculation : MonoBehaviour {
private const int ARRAY_SIZE = 50;private const int SEGMENT_SIZE = 10; // legt Menge der Elemente fest, die
bei jedem frame berechnet werdenprivate int[] randomNumbers;private void Awake(){
randomNumbers = new int[ARRAY_SIZE]; // Zufallsinteger werden in Awake() erstellt
for(int i=0; i<ARRAY_SIZE; i++){randomNumbers[i] = Random.Range(0, 1000);}StartCoroutine( FindMinMax() ); // Start der Koroutine
}
SegmentedCalculation
private IEnumerator FindMinMax() {int min = 9999;int max = -1;for(int i=0; i<ARRAY_SIZE; i++){if( i % SEGMENT_SIZE == 0) {print("frame: " + Time.frameCount + ", i:" + i + ", min:" + min + ", max:" + max);yield return null; // setzt Ausführung für einen frame aus}if( randomNumbers[i] > max){max = randomNumbers[i]; } else if( randomNumbers[i] < min) {min = randomNumbers[i];}}
print("** completed - disabling scripted component");enabled = false;}}
SegmentedCalculation
Gerade bei komplexen Berechnungen (AI) ist es oft sinnvoll, nicht alle Berechnungen in einem frame stattfinden zu lassen Koroutinen
Komplexe Berechnung wird auf mehrere Frames geteilt Flüssigere Darstellung
Erläuterung
using UnityEngine;using System.Collections; public class PauseMenu : MonoBehaviour {
public bool expensiveQualitySettings = true;private Rect butRect;private float ctrlWidth = 200;private float ctrlHeight = 30;private bool isPaused = false;
void Awake () {butRect = new Rect((Screen.width - ctrlWidth)/2,0,ctrlWidth,ctrlHeight);
}private void Update() {
if (Input.GetKeyDown(KeyCode.Escape)) {
if(isPaused)ResumeGameMode();elsePauseGameMode();
}
}
PauseMenu 1/4
private void ResumeGameMode() {Time.timeScale = 1.0f;isPaused = false;Screen.showCursor = false;GetComponent<MouseLook>().enabled = true;}private void PauseGameMode() {Time.timeScale = 0.0f;isPaused = true;Screen.showCursor = true;GetComponent<MouseLook>().enabled = false;}private void OnGUI(){if(isPaused)PauseGameGUI();}
PauseMenu 2/4
private void PauseGameGUI(){string[] names = QualitySettings.names;string message = "Hier kann die Qualität der Darstellung
angepasst werden.";
butRect.y = (Screen.height - ctrlHeight)/10);if (GUI.Button (butRect,"Weiter")){ResumeGameMode ();}
butRect.y += ctrlHeight + 20; if (GUI.Button (butRect,„Szene schliessen"))
{Application.Quit(); }
PauseMenu 3/4
GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height));GUILayout.FlexibleSpace();GUILayout.BeginHorizontal();GUILayout.FlexibleSpace();GUILayout.BeginVertical();GUILayout.Label(message, GUILayout.Width(200));for(int i = 0; i < names.Length; i++) {
if(GUILayout.Button(names[i], GUILayout.Width(200)))QualitySettings.SetQualityLevel(i,
expensiveQualitySettings);}
GUILayout.EndVertical();GUILayout.FlexibleSpace();GUILayout.EndHorizontal();GUILayout.FlexibleSpace();GUILayout.EndArea();}
}
PauseMenu 4/4
Sichtweite Reduzieren
Bereich animierter Objekte eingrenzen
Weitere Möglichkeiten
1. Objekte lokalisieren, die die meisten Ressourcen benötigen
2. Objekte löschen, die nicht länger benötigt sind
3. Anzahl aktiver Objekte verringern4. Methoden so selten wie möglich aufrufen5. Aktionen minimiere, die Unity zur
Reflektion zwingen6. Sichtweite Reduzieren7. Bereich animierter Objekte eingrenzen
Zusammenfassung