Czasami zdarza się, że coś dzieje się inaczej, niż się tego spodziewamy. W takich sytuacjach często konieczne jest dokładne zbadanie przyczyn i przebiegu działania naszego kodu. Zwykle pierwszym krokiem jest dodanie gdzieś Debug.Log
w miejscu, w którym spodziewamy się wystąpienia problemu. Co jednak, gdy to nie wystarczy?
Kolejny parametr w Debug.Log
Problem: Masz wiele obiektów o tej samej nazwie, które trudno odróżnić.
Rozwiązanie: Pierwszym krokiem do wzmocnienia komunikatu w logu jest dodanie dodatkowego parametru do wywołania. Zgodnie z dokumentacją:
public static void Log(object message, Object context);
Jeśli przekażesz GameObject lub Component jako opcjonalny argument context, Unity podświetli ten obiekt w oknie Hierarchy, gdy klikniesz komunikat w konsoli.
Co to oznacza w praktyce? Załóżmy, że nasz debug wygląda tak:
public class FindMe : MonoBehaviour {
void Start() {
Debug.Log("ヘ(・ω| Gdzie jestem?", this);
}
}
Wystarczy kliknąć w komunikat, aby odpowiadający mu obiekt został podświetlony. W tym przykładzie przekazaliśmy Component
(this odnosi się do klasy dziedziczącej po Component). Podobnie możemy przekazać dowolny GameObject
.
Z oficjalnego opisu może wynikać, że działają tylko obiekty widoczne w Hierarchy. Jednak nagłówek metody wskazuje, że możemy użyć dowolnego UnityEngine.Object
. Dzięki temu możemy zlokalizować cokolwiek, co ma Instance ID – m.in. Material
, ScriptableObject
czy Mesh
.
Bonus: Możemy też użyć EditorGUIUtility.PingObject
, aby skorzystać z tej funkcji bez zapisywania logów. Link
Spraw, żeby logi się wyróżniały
Problem: Musisz logować wiele rzeczy i szybko je kategoryzować. Wyszukiwarka i zwijanie logów to za mało – kolejność wiadomości jest ważna, a wyszukiwany tekst może być trudno zauważalny.
Rozwiązanie: Uatrakcyjnij logi wizualnie. Komunikaty mogą zawierać tagi Rich Text.
Przerwanie wykonywania
Problem: Specjalny przypadek oznaczony kolorem nie jest wystarczająco zrozumiały po jego wystąpieniu.
Rozwiązanie: Najpierw znana metoda – breakpoint. Unity i Visual Studio dobrze współpracują w tym zakresie. Aby to działało w Unity:
- Kliknij na lewym marginesie wiersza, w którym chcesz breakpoint.
- Załącz debugger do Unity.
- Wciśnij Play.
Możesz też użyć Debug.Break
– działa jak naciśnięcie pauzy. Alternatywnie Debug.LogError
przy opcji „pause on error”.
Dostosowywanie okna Konsoli
Problem: Dane nie mieszczą się w jednej linii logu.
Rozwiązanie: Włącz multiline logs lub znaczniki czasu.
Co właśnie zbudowałem?
Problem: Komunikat Build completed with a result of ‚Succeeded’ nie mówi wiele.
Rozwiązanie: „Open Editor Log” i przeskocz do sekcji Build Report.
Logowanie z użyciem dyrektyw preprocesora
Problem: Masz wiele komunikatów debugowych w wersji deweloperskiej.
Rozwiązanie: Użyj własnej klasy z dyrektywą:
using UnityEngine;
#if NET_LOGGER && (UNITY_EDITOR || DEVELOPMENT_BUILD)
public static class DebugNet {
public static void Log(string message) {
Debug.Log($"[NET] {message}");
}
public static void LogWarning(string message) {
Debug.LogWarning($"[NET] {message}");
}
public static void LogError(string message) {
Debug.LogError($"[NET] {message}");
}
}
#else
public static class DebugNet {
public static void Log(string message) { }
public static void LogWarning(string message) { }
public static void LogError(string message) { }
}
#endif
Liczby to za mało?
Problem: Potrzebujesz czegoś więcej niż tylko cyferek.
Debug.DrawLine
[SerializeField] float hitDist = 1000;
void Update() {
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, hitDist)) {
Debug.DrawLine(ray.origin, hit.point, Color.green);
// obsługa trafienia
}
else {
Debug.DrawLine(ray.origin, ray.GetPoint(hitDist), Color.red);
}
}
Gizmos i Handles
public class BoundingBox : MonoBehaviour {
[SerializeField] Bounds bounds;
[SerializeField] bool filled;
void OnDrawGizmosSelected() {
Gizmos.matrix = transform.localToWorldMatrix;
if (filled) {
Gizmos.DrawCube(bounds.center, bounds.size);
}
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}
void OnDrawGizmos() {
Handles.Label(transform.position,
$"{gameObject.name} {transform.position}",
EditorStyles.miniButton);
}
Podsumowanie…
Na koniec warto wspomnieć, że czasami do wsparcia kodu debugowania przydają się narzędzia lub skrypty firm trzecich. Należy jednak zachować ostrożność przy ich dodawaniu, ponieważ mogą oferować funkcje zbędne w projekcie, a nawet go utrudniać. Mimo to mam nadzieję, że poznałeś techniki, które możesz wykorzystać przy usuwaniu nowych błędów lub pogłębieniu zrozumienia systemu.