Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Игры";
Текущий архив: 2006.12.03;
Скачать: [xml.tar.bz2];

Вниз

И опять о плавности...   Найти похожие ветки 

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.055 c
15-1163193656
ArtemESC
2006-11-11 00:20
2006.12.03
Как сделать поддержку субтитров?


15-1163347205
К.
2006-11-12 19:00
2006.12.03
Ноутбук, гаснет экран


2-1163451529
HRust
2006-11-13 23:58
2006.12.03
Веб приложение


15-1163151320
HeadHunter
2006-11-10 12:35
2006.12.03
Требуется Delphi программист (Минск)


2-1163406956
TrainerOfDolphins
2006-11-13 11:35
2006.12.03
Хранение настроек приложения в файле





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский