
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.
