Я использую двойную буферизацию?

Я создаю приложение Windows MFC. Во время некоторых анимаций, когда объекты сталкиваются на высоких скоростях, мой физический движок ведет себя непредсказуемо. Я считаю, что это как-то связано с тем, что я пропускаю кадры. Мне сказали, что я не использую двойную буферизацию. Я думал, что был, но я все еще довольно новичок в этом. Вот как я рисую на экране в OnPaint:

#include "pch.h"
#include "framework.h"
#include "ChildView.h"
#include "DoubleBufferDC.h"

void CChildView::OnPaint()
{
    CPaintDC paintDC(this);     // device context for painting
    CDoubleBufferDC dc(&paintDC); // device context for painting
    Graphics graphics(dc.m_hDC);    // Create GDI+ graphics context
    mGame.OnDraw(&graphics);

    if (mFirstDraw)
    {
        mFirstDraw = false;
        SetTimer(1, FrameDuration, nullptr);

        /*
         * Initialize the elapsed time system
         */
        LARGE_INTEGER time, freq;
        QueryPerformanceCounter(&time);
        QueryPerformanceFrequency(&freq);

        mLastTime = time.QuadPart;
        mTimeFreq = double(freq.QuadPart);
    }

    /*
     * Compute the elapsed time since the last draw
     */
    LARGE_INTEGER time;
    QueryPerformanceCounter(&time);
    long long diff = time.QuadPart - mLastTime;
    double elapsed = double(diff) / mTimeFreq;
    mLastTime = time.QuadPart;

    mGame.Update(elapsed);
}

void CChildView::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: Add your message handler code here and/or call default
    RedrawWindow(NULL, NULL, RDW_UPDATENOW);
    Invalidate();
    CWnd::OnTimer(nIDEvent);
}

Когда я создаю объект Graphics из объекта CDoubleBufferDC, разве это не создает задний буфер? Затем я передаю этот объект Graphics в OnDraw, где он рисуется. Если он создает задний буфер, я не понимаю, где создается передний буфер и когда он отображается на экране.

Вот мои текущие мысли о том, как я думаю, что это работает:

  1. Объект CPaintDC является передним буфером.
  2. Объект CDoubleBufferDC является задним буфером.
  3. Графический объект создается из объекта CDoubleBufferDC, на котором я рисую текущее состояние игры.

Если это так, то когда передний буфер заменяется новым буфером, созданным сзади? Может ли кто-нибудь помочь мне понять и использовать двойную буферизацию, если я этого еще не сделал?


person Justin    schedule 15.05.2020    source источник
comment
Если вы используете наивный метод обнаружения столкновений, то на высоких скоростях или низких частотах кадров вы получите всевозможные странности. Подумайте о том, чтобы получить хороший справочник, например Обнаружение столкновений в реальном времени, чтобы использовать правильные формулы, использующие линейную интерполяцию для обработки столкновений вместо ААББ-тест. В любом случае вы показали только код рисования, а не код физики, в котором возникла проблема.   -  person tadman    schedule 16.05.2020
comment
Я ценю, что вы указали мне в правильном направлении. Я обязательно проверю это. Однако, если я не делаю двойную буферизацию правильно, я не думаю, что что-то будет работать на 100% правильно. Мне все еще интересно, правильно ли выполняется эта часть.   -  person Justin    schedule 16.05.2020
comment
Если ваш рисунок и физика действительно тесно связаны, чего не должно быть, это не должно быть проблемой. Мне также интересно, почему вы используете действительно старый подход GDI, когда в наши дни вы использовали бы, по крайней мере, базовые функции DirectX.   -  person tadman    schedule 16.05.2020
comment
Я ничего не знаю о функциях DirectX, однако могу поспорить, что использую действительно старый подход GDI, о котором вы говорите. Курс, в котором я учился делать подобные приложения, казался довольно устаревшим. Я использую Gdiplus для рисования. Если бы вы могли направить меня в лучшем направлении, я был бы очень признателен, хотя этот проект прошел довольно долгий путь, и я потратил на него кучу часов.   -  person Justin    schedule 16.05.2020
comment
Недостаточно информации, чтобы ответить на заданный вами вопрос. CDoubleBufferDC не является стандартным классом MFC, и неясно, как, когда и даже передается ли отрендеренное изображение в класс paintDC. Но, как отмечалось выше, ответ на заданный вопрос не поможет вам продвинуться вперед. В любом случае, если вы хотите перейти на систему рендеринга с потенциально лучшими характеристиками производительности, ознакомьтесь с Direct2D.   -  person IInspectable    schedule 16.05.2020
comment
Действительно устаревший в данном случае — это сильное преуменьшение, учитывая, что DirectX существует с 1995 года и Wing существует еще дольше.   -  person tadman    schedule 16.05.2020
comment
Класс не вращался вокруг создания приложений MFC, это был просто класс по разработке программного обеспечения. Однако, если честно, я горжусь тем, что создал этот физический движок с нуля, и он хорошо работает на низких скоростях. Я чувствую, что этот аспект этого проекта действительно единственная часть, которая повышает мое резюме во всем, что мне нужно как новому выпускнику. Я обязательно посмотрю на DirectX. Предоставляют ли они функции для столкновений или что-то, что упрощает эту задачу? Кроме того, стоит ли мне переписать этот проект с использованием DirectX, или это не будет иметь большого значения?   -  person Justin    schedule 16.05.2020


Ответы (1)


Чтобы ответить на ваш фактический вопрос, вероятно, происходит то, что ваш класс CDoubleBufferDC() имеет деструктор, который заменяет контроллеры домена - это обычная идиома (IIRC в «современных» версиях MFC CMemDC делает это тоже). Так что да, я думаю, что вы используете здесь двойную буферизацию, даже если случайно. Вы можете рисовать в GDI(+) для простых игр, если все это является учебным упражнением, этот способ намного легче понять, чем использование DirectX.

Однако вам нужно отделить обнаружение столкновений от ваших процедур рисования, чтобы любые пропущенные кадры не испортили ваш тайминг (то есть, если вы работаете с такими сложными вещами, что они занимают так много времени — в этом случае вы вероятно, не следует использовать GDI...). Другими словами, если ваше обнаружение столкновений предполагает, что каждый вызов OnDraw() завершается менее чем за 1/частоту кадров в секунду, но это происходит не всегда, в какой-то момент вы столкнетесь с проблемами. В Интернете есть много статей о том, как структурировать игровой цикл; У меня недостаточно информации, чтобы связать вас с конкретным. Кроме того, в 2020 году будет непросто найти его с использованием технологии, которую вы используете... Но я думаю, что использование простого OnPaint()/GDI отлично подходит для обучения, поскольку оно скроет большую часть сложности. вам нужны более современные подходы.

person Roel    schedule 25.05.2020
comment
Спасибо за ответ. Теперь я начинаю задаваться вопросом, должен ли я отказаться от подхода GDI. Однако я не уверен, что моя система обнаружения столкновений слишком дорогая — это игра в бильярд, поэтому в каждом кадре мне нужно проверять только 16 объектов. Как вы думаете, это слишком много? - person Justin; 25.05.2020
comment
Нет, это должно быть в порядке - даже тысячи (простых) объектов должны быть в порядке на современных процессорах. Я не знаю, что не так с вашим кодом или почему вы считаете, что пропуск кадров является источником вашей проблемы, но, безусловно, возможно заставить ваш проект (насколько вы описали его здесь) работать с технологией, которую мы используем. о том, о чем вы говорите, и о подходе, который вы показали в своем исходном вопросе. Я думаю, что первое, что вы должны сделать, это описать для себя, что именно идет не так; «ведет себя непредсказуемо» слишком расплывчато, чтобы на него можно было действовать. - person Roel; 26.05.2020
comment
Я на самом деле сделал еще один пост ранее сегодня. Я понял большую проблему - время между каждым розыгрышем слишком велико (70-80 мс). Если я хочу 60 кадров в секунду, мне нужно, чтобы он рисовался примерно в 5 раз быстрее. Насколько я могу судить, мой код довольно оптимизирован. Если вам интересно, вы можете проверить вопрос, который я опубликовал, чтобы сделать Windows Game Loop Faster. Я не уверен, почему мои розыгрыши занимают так много времени. - person Justin; 26.05.2020