Текущий архив: 2006.12.03;
Скачать: CL | DM;
Вниз
И опять о плавности... Найти похожие ветки
← →
HPR (2006-02-05 21:31) [0]В общем решил я забить на таймеры и сделал бесконечный цикл (координаты объектов рассчитываются с плавным шагом dt) в надежде, что рывки прекратятся. Но рывки остались :( К примеру, при запущенном и играющем WinAmp-е Zuma работает плавно, а в моей есть рывки. FPS высокий = 85 при включенном vsync. С таймерами такая же фигня...
Что делаете, чтобы добиться плавности?
← →
Кефир87 © (2006-02-05 22:40) [1]Может дело в руках? 8)
← →
HPR (2006-02-06 11:16) [2]Дело-то всегда в руках, поэтому хочется их натренировать с вашей помощью
Вот привожу главный кусок:
while not NeedToExitGame do
begin
TimeNew := timeGetTime;
delta := (TimeNew-TimeOld)/1000;
Application.ProcessMessages; // обработка сообщений
DXInput.Update; // обновление данных ввода
DXDraw.BeginScene;
Common.UpdateObjects(delta); // обновление объектов
Common.RenderObjects; // рендер объектов в главную поверхность
DXDraw.EndScene;
DXDraw.Flip;
TimeOld := TimeNew;
end;
Что не так?
P.S. Вообще довольно плавно все движется, но опять же при включенном WinAmp рывки...
P.P.S. Использую компонент UnDelphiX с включенным 3D-ускорением
← →
XProger © (2006-02-06 11:35) [3]
delta := (TimeNew-TimeOld)/1000;
TimeOld := TimeNew;
+ ко всему, точность timeGetTime может быть не менее 20 мс (насколько я помню) Попробуй вместо неё использовать следующий код:function ENG_time: Integer;
var
T : LARGE_INTEGER;
F : LARGE_INTEGER;
begin
QueryPerformanceFrequency(Int64(F));
QueryPerformanceCounter(Int64(T));
Result := Trunc(1000 * T.QuadPart / F.QuadPart);
end;
← →
Nic © (2006-02-06 11:54) [4]Я делаю так. Считаю сколько секунд прошло с рендеринга прошедшего кадра до нынешнего. Из этого числа путём преобразований получаю переменную GLOBAL_K. Потом всё что передвигается перемножаю на этот глобальный коэффициент. Получаю FPS независимый рендеринг. Но при резких скачках FPS некоторая грубость перемещений заметна. С WinAmp"ом не экспериментировал.
← →
Don Nikola (2006-02-06 15:27) [5]2XProgrer:
Точность timeGetTime регулируется с помощью timeBeginPeriod/timerEndPeriod
2HPR:
Я такой loop использовал:
---
procedure UpdateTime;
var
CurrentTime, Delta: dword;
begin
CurrentTime:=timeGetTime;
if not ApplicationActive then
begin
LastTickTime:=CurrentTime;
Exit;
end;
if CurrentTime>=LastTickTime then
Delta:=CurrentTime-LastTickTime else
Delta:=CurrentTime+($FFFFFFFF-LastTickTime);
LastTickTime:=CurrentTime;
Time:=Time+Delta;
if (Time-LastFPSTime)>=1000 then
begin
FPS:=FramesAtLastSecond;
FramesAtLastSecond:=0;
LastFPSTime:=Time;
end;
if (not LimitFPS)or((Time-LastFrameTime)>=DesiredFrameTime) then
begin
if LastFrameProcessed then
begin
LastFrameProcessed:=false;
LastFrameTime:=Time;
PostMessage(MainWindow,WM_DOFRAME,0,0);
end;
end;
end;
procedure MainLoop;
var
Msg: TMsg;
begin
PeekMessage(Msg,0,0,0,PM_NOREMOVE);
while Msg.Message<>WM_QUIT do
begin
if PeekMessage(Msg,0,0,0,PM_REMOVE) then
DispatchMessage(Msg) else
begin
UpdateTime;
Sleep(SleepValue); //Do not use all possible CPU time
end;
end;
end;
---
Фрейм отрабатывается в обработчике WM_DOFRAME, который может быть равен WM_APP+1, например.
При SleepValue>=1, программа всеьма скромно пожирает ресурсы CPU.
Единственная проблема - этот код не предполагает наличие VCL, так что использовать этот код просто копипастом нельзя, но представление о методе дает.
← →
VolanD666 (2006-02-06 16:19) [6]Недавно возился с этой проблемой, хорошо попалась статья хорошая и пример к ней. Во-первых, в качестве таймера я использую QueryPerformanceCounter. Во-вторых, для плавности движения при любом приличном FPS необходимо рассчитывать коэффициент, и потом все перемещения на него умножать. Ну а рендерится это все с помощью WM.
← →
XProger © (2006-02-06 16:58) [7]VolanD666, кстати, хочешь краштест для своей игрушки?
if Key = ord("E") then for i := 1 to 1000000000 do;
Затем, во время игры, беги на стену и единожды нажми клавишу "E", если руки прямые - сквозь стену не пролетишь :)
← →
VolanD666 (2006-02-06 19:04) [8]Руки оказались кривые... :(
← →
VolanD666 (2006-02-06 19:06) [9]Хм, а почему так? Ведь при нажатии отрисовка не происходит, а значит и положение камеры не обновляется?
← →
XProger © (2006-02-06 19:35) [10]К тому моменту как программа "отойдёт" от цикла - dt будет иметь настолько большое значение, что Pos + Speed * dt - окажется далеко за стеной :)
Решение:
1) Трассировка вектора до пересечения со стеной, а там уже со сферой
2) Использовать фиксированный UPS (Updates Per Second) безо всяких dt :)
← →
XProger © (2006-02-06 19:49) [11]* 1) Трассировка отрезка %)
А по-второму методу у меня есть примерный код:
function ENG_time: Integer;
var
T : LARGE_INTEGER;
F : LARGE_INTEGER;
begin
QueryPerformanceFrequency(Int64(F));
QueryPerformanceCounter(Int64(T));
Result := Trunc(1000 * T.QuadPart / F.QuadPart);
end;
begin
ups_delta := 10; // 100 обновлений в секунду (в среднем)
ups_time_old := ENG_time - ups_delta;
ups_time := ENG_time;
if ENG_Init then // Инициализация
while not eng_isquit do
begin
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
if eng_isquit then
break;
Time := ENG_time;
Time_Delta := Time - ups_time_old;
while Time_Delta >= ups_delta do
begin
ENG_update; // обновление игры
dec(Time_Delta, ups_delta);
end;
ups_time_old := Time - Time_Delta;
ENG_render; // отрисовка
end;
ENG_Free; // высвобождение ресурсов - завершение работы движка
end;
Также в WndProc
WM_CLOSE :
begin
ENG_Free;
eng_isquit := True;
end;
Что-то в этом духе...
← →
VolanD666 (2006-02-06 20:02) [12]Спасибо! :)
← →
HPR (2006-02-06 21:43) [13]to XProger: Я вызываю timeBeginPeriod(1), так что период= 1 мс. Но QueryPerformanceCounter говорят действительно точнее, попробую использовать...
← →
Don Nikola (2006-02-07 11:43) [14]2HPR: QueryPerformanceCounter это обертка для rdtsc, и предназначен для замера сверхмалых отрезков времени. Использование QPF для замера-регулирования FPS, все равно что использование лазерного гироскопа для замера крена детского велосипеда.
Плюс ко всему, чисто теоретически, QPF может работать не на всех машинах, но это скорее всего относиться к машинам before-Pentium.
← →
VolanD666 (2006-02-07 13:43) [15]Использование QPC- самый оптимальный вариант. После того, как я поменял у себя GetTickCount() на QPC, движения стали значительно "плавнее" :)
← →
HPR (2006-02-07 21:42) [16]В общем поставил QueryPerformanceCounter и Sleep. Вроде бы помогло :) Скорее всего дело в Sleep. Видимо система начинала понижать приоритет моей игре, съедавшей 100% проц. времени.. Хотя это все только теория
← →
HPR (2006-02-08 13:45) [17]Кстати, камрады по цеху, я ведь забыл вас поблагодарить! БОЛЬШОЕ спасибо ;)
Страницы: 1 вся ветка
Текущий архив: 2006.12.03;
Скачать: CL | DM;
Память: 0.5 MB
Время: 0.043 c