Jeżeli twoja gra nie chodzi płynnie najpierw trzeba ustalić gdzie leży problem. Czy problemem jest kod wykonywany w funkcji Update? Czy może chodzi o rendering?
Często trudno określić położenie wąskiego gardła intuicyjnie, łatwo się też pomylić i stracić wiele godzin optymalizując kod, który tego nie wymagał. Na szczęście z pomocą przychodzi nam FrameProfiler.
Jak to działa?
FrameProfiler zapisuje zmierzone wartości w logu dla każdej ramki np.:
-------------------- FrameProfiler begin Frame time: 0.02 secs (we should have 64.29 FPS based on this): - BeforeRender: 0% - Render: 94% (0.01 secs, we should have 68.38 "only render FPS" based on this) - TCastleTransform.Render transformation: 2% - TCastleScene.Render: 38% - ShapesFilterBlending: 2% - Update: 5% - TCastleSceneCore.Update: 0% - Other: -------------------- FrameProfiler end
Czas tworzenia klatki podzielony jest na 4 etapy:
- BeforeRender – czas przygotowania zasobów przed rozpoczęciem renderowania
- Render – czas renderowania
- Update – czas wykonywania funkcji Update (w tym fizyka, animacje, itp.)
- Other – inne, w tym zakresie pojawiają się pomiary użytkownika wykonywane poza Update, BeforeRender, Render.
Uruchomienie FrameProfilera
Aby włączyć FrameProfiler wystarczy dodać moduł CastleTimeUtils
do sekcji uses i skorzystać z singeltona FrameProfiler
:
FrameProfiler.Enabled := true;
Mierzenie czasu wykonania kroku fizyki
Gdy PR #144 zostanie połączony, FrameProfiler będzie posiadał dodatkową linię „Update Kraft Physics” pokazująca czas wykonania kroku fizyki:
-------------------- FrameProfiler begin Frame time: 0.02 secs (we should have 64.29 FPS based on this): - BeforeRender: 0% - Render: 94% (0.01 secs, we should have 68.38 "only render FPS" based on this) - TCastleTransform.Render transformation: 2% - TCastleScene.Render: 38% - ShapesFilterBlending: 2% - Update: 5% - TCastleSceneCore.Update: 0% - Update Kraft Physics: 2% (0.00037 secs) - Other: -------------------- FrameProfiler end
Własne pomiary w FrameProfiler
Informacje zwracane przez FrameProfiler dotyczą wszystkich obiektów, jeżeli chcemy mierzyć czas wykonania określonego typu/funkcji możemy to zrobić używając FrameProfiler.Start
/FrameProfiler.Stop
z identyfikatorem tekstowym np.:
Jeżeli mamy klasę gracza TMyPlayer
zaimplementowaną jako klasa dziedzicząca z TCastleScene
i chcemy sprawdzić czas wywołania funkcji Update możemy to zrobić w następujący sposób:
TMyPlayer.Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); begin FrameProfiler.Start('TMyPlayer.Update'); // kod update TMyPlayer FrameProfiler.Stop('TMyPlayer.Update'); end;
Wtedy log będzie wyglądał następująco:
-------------------- FrameProfiler begin Frame time: 0.01 secs (we should have 84.17 FPS based on this): - BeforeRender: 0% - Render: 13% (0.00 secs, we should have 655.95 "only render FPS" based on this) - TCastleTransform.Render transformation: 0% - TCastleScene.Render: 3% - ShapesFilterBlending: 0% - Update: 86% - TCastleSceneCore.Update: 0% - TMyPlayer.Update: 85% - Other: -------------------- FrameProfiler end
Aktualnie silnik umożliwia prowadzenie do 16 własnych pomiarów co z pewnością wystarczy.
Optymalizacje
Gdy poznamy położenie wąskiego gardła, dokładnie wiemy co należy zoptymalizować. Wiele przydatnych informacji na temat optymalizacji możemy znaleźć tutaj.