Как сделать ограничитель кадров?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Как сделать ограничитель кадров?

Сообщение Don Leno » 14.04.2021 (Ср) 20:24

Есть простой цикл:

Код: Выделить всё
   
Do Until rendering = False
        'Здесь выполняется нужный код
        FPS = FPS + 1
        DoEvents
    Loop
    End


Так вот мне нужно сделать ограничение кадров за секунду. К примеру =50. Как это правильно в коде оформить?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сделать ограничитель кадров?

Сообщение The trick » 14.04.2021 (Ср) 21:26

UA6527P

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Как сделать ограничитель кадров?

Сообщение Mikle » 15.04.2021 (Чт) 14:36

Don Leno писал(а):мне нужно сделать ограничение кадров за секунду. К примеру =50. Как это правильно в коде оформить?

Если не очень важна точность, то можно обойтись Sleep.

Код: Выделить всё
Do Until rendering = False

Эта строка эквивалентна такой:
Код: Выделить всё
Do While rendering

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сделать ограничитель кадров?

Сообщение The trick » 15.04.2021 (Чт) 14:57

Можно еще ограничить по vsync. https://www.vbforums.com/showthread.php ... ost5467901
Код: Выделить всё
' //
' // VSync
' // Vista and later
' // By The trick
' //

Option Explicit

Private Type LUID
    LowPart         As Long
    HighPart        As Long
End Type

Private Type D3DKMT_OPENADAPTERFROMHDC
    hDC             As Long
    hAdapter        As Long
    AdapterLuid     As LUID
    VidPnSourceId   As Long
End Type

Private Type D3DKMT_WAITFORVERTICALBLANKEVENT
    hAdapter        As Long
    hDevice         As Long
    VidPnSourceId   As Long
End Type

Private Type D3DKMT_CLOSEADAPTER
    hAdapter        As Long
End Type

Private Declare Function D3DKMTOpenAdapterFromHdc Lib "gdi32" ( _
                         ByRef tAdapter As D3DKMT_OPENADAPTERFROMHDC) As Long
Private Declare Function D3DKMTWaitForVerticalBlankEvent Lib "gdi32" ( _
                         ByRef tEvt As D3DKMT_WAITFORVERTICALBLANKEVENT) As Long
Private Declare Function D3DKMTCloseAdapter Lib "gdi32" ( _
                         ByRef tAdapter As D3DKMT_CLOSEADAPTER) As Long

Private m_bIsRunning    As Boolean
Private m_lFPSCounter   As Long

Private Sub cmdStop_Click()
    m_bIsRunning = False
End Sub

Private Sub Form_Load()
    Dim tAdapterOpen    As D3DKMT_OPENADAPTERFROMHDC
    Dim tWaitVSync      As D3DKMT_WAITFORVERTICALBLANKEVENT
    Dim tAdapterClose   As D3DKMT_CLOSEADAPTER
    Dim lCounter        As Long
   
    Me.Show
   
    ' // Open adapter from HDC
    tAdapterOpen.hDC = Me.hDC
   
    If D3DKMTOpenAdapterFromHdc(tAdapterOpen) < 0 Then
        MsgBox "Unable to open adapter", vbCritical
        Exit Sub
    End If
   
    m_bIsRunning = True
   
    ' // Set wait event param
    tWaitVSync.hAdapter = tAdapterOpen.hAdapter
    tWaitVSync.VidPnSourceId = tAdapterOpen.VidPnSourceId
   
    Do While m_bIsRunning
       
        ' // Wait until vsync
        If D3DKMTWaitForVerticalBlankEvent(tWaitVSync) < 0 Then
            MsgBox "Unable to ait vsync", vbCritical
            Exit Do
        End If
       
        m_lFPSCounter = m_lFPSCounter + 1
       
        ' // To update timer
        DoEvents
       
    Loop
   
    ' // Close adapter
    tAdapterClose.hAdapter = tAdapterOpen.hAdapter
   
    D3DKMTCloseAdapter tAdapterClose
   
End Sub

' // Timer interval = 1000 ms
Private Sub tmrFPS_Timer()
    Me.Caption = "FPS: " & m_lFPSCounter
    m_lFPSCounter = 0
End Sub
UA6527P

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Как сделать ограничитель кадров?

Сообщение Don Leno » 16.04.2021 (Пт) 12:29

Mikle, Trick!
Thanx за ваши коды и примеры. Как всегда выручили.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как сделать ограничитель кадров?

Сообщение Хакер » 17.04.2021 (Сб) 12:09

Don Leno писал(а):Так вот мне нужно сделать ограничение кадров за секунду. К примеру =50. Как это правильно в коде оформить?

Так к делу не подходят.

Задавая такие вопросы, нужно уточнять, с какой точностью требуется выдерживать заданный FPS, а также требования по стабильности частоты обновления экрана/холста, потому что под FPS=50 может скрываться ситуация, когда за 800 мс выводится всего 8 кадров (что составляет эквивалентно 8 FPS), а за оставшиеся 200 мс отрисовываются недостающие 42 кадра, что даёт FPS=50, но ужасно дёрганную картинку.

Исходя из этих требований уже нужно будет выбирать между разными инструментами, дающими разную меру точности и контроля над ситуацией.

Плюс, нужно уточнять, на какой инструментарий уже завязана разрабатываемая программа. Если на Direct3D, то там тебе и VSync и spap chain — проблема стабилизации частоты вывода кадров побудила сделать для прикладных разработчиков такие плюшки, без которых, поскольку у нас не ОС реального времени, выдерживать допуски по частоте и стабильности частоты не так-то просто.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Как сделать ограничитель кадров?

Сообщение Don Leno » 18.04.2021 (Вс) 9:16

Согласен, Хакер.
Невозможно сделать необходимое не зная точной задачи. Я нацелеваюсь на простейшую игру. К примеру, чтобы игра на всех компьютерах разной мощности работала с одинаковой частотой. В играх есть такая практика...правда опциональная. Там можно включить ограничитель кадров или даже самому выставлять необходимую частоту.
Direct3D не использую.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как сделать ограничитель кадров?

Сообщение Хакер » 18.04.2021 (Вс) 10:14

Don Leno писал(а):К примеру, чтобы игра на всех компьютерах разной мощности работала с одинаковой частотой.

А зачем? Пусть работает с разной. Даром что ли мощность у них разная?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Как сделать ограничитель кадров?

Сообщение Don Leno » 18.04.2021 (Вс) 11:10

Хорошо, Хакер)
Видно я чего то не понимаю (либо меня ввели в заблуждение). Иногда бывает такое в играх, когда скорость анимации и других увеличивается (сам было дело сталкивался). То есть все на экране двигается в очень бешенном темпе! Хотя игра работает исправно, и как я тогда понял ошибка была в том, что игра была старенькой, а компьютеры уже стали помощнее и в результате они справлялись со своей задачей сверхположенного)) И тогда не было функции ограничения кадров)) Надеюсь я правильно смог изложить свою мысль))
И чтобы такого не происходило, хотелось бы добавить опционально такую плюху))

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Как сделать ограничитель кадров?

Сообщение Mikle » 19.04.2021 (Пн) 10:17

Для простой игры достаточно обычного таймера. Для таких целей он и создан. Выставить его на 20-30 мс.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как сделать ограничитель кадров?

Сообщение Хакер » 19.04.2021 (Пн) 16:59

Don Leno писал(а):И чтобы такого не происходило, хотелось бы добавить опционально такую плюху))

Для этого надо не частоту кадров ограничивать, а во всех расчётах (касающихся анимации, движения и любых других процессов, скорость которых должна не зависеть от кадровой частоты) использовать время, прошедшее между двумя tick-ами, замеренное с требуемой точностью.

Если условная «ракета» летит со скоростью VEL, то её текущее положение надо обновлять по формуле POS = POS + VEL×DeltaTime, где DeltaTime — интервал между предыдущим тиком и текущим.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Как сделать ограничитель кадров?

Сообщение Don Leno » 19.04.2021 (Пн) 17:43

Хакер, а можно по подробнее?
Как вычислить Дельту?

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4148
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Как сделать ограничитель кадров?

Сообщение Mikle » 19.04.2021 (Пн) 18:52

Don Leno писал(а):Как вычислить Дельту?

Её нужно не вычислять, а замерять, типа такого:
Код: Выделить всё
Do 'Игровой цикл
  DoEvents
  tOld=t
  t=GetTime
  Delta=t-tOld
  'Здесь считаем физику
Loop

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Как сделать ограничитель кадров?

Сообщение Don Leno » 21.04.2021 (Ср) 11:19

Thanx, Mikle, Хакер.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Как сделать ограничитель кадров?

Сообщение Хакер » 21.04.2021 (Ср) 12:18

Don Leno писал(а):Thanx, Mikle, Хакер.

Но нужно учитывать, что на многоядерных/многопроцессорных системах, если не установить аффинность потока, некоторые способы замера текущего времени будут давать результат с «джиттером», от чего дельта-тайм может становится даже отрицательной. Но есть ещё особенности VB, которые тоже вызывают проблему.

Подробный топик об этом: viewtopic.php?f=1&t=56115
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Bing-бот и гости: 51

    TopList