Как остановить растяжение во время изменения размера окна в XNA?

8

В моей игре XNA с оконным режимом, когда пользователь изменяет размеры окна, игра перестает обновлять окно, и последний нарисованный кадр растягивается и искажается до тех пор, пока пользователь не отпустит мышь и изменение размера не завершится.

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

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

Брэдли Аффнер
источник
Зарегистрируйте событие для изменения размера окна и обновите разрешение GraphicsDevice. Это может обновить соотношение сторон и исправить растяжение.
Густаво Масиэль
Я не знаю о C # / XNA, но в C ++ / D3D у меня просто был цикл рендеринга, работающий в отдельном потоке от основного потока с циклом сообщений. Основной поток выполняет изменение размера буфера, когда происходит событие изменения размера, синхронизированное через мьютекс.
1
Густаво, я уже обработал это событие для других целей в игре. К сожалению, он не срабатывает до тех пор, пока пользователь не отпустит мышь, когда изменение размера будет завершено.
Брэдли Аффнер
Эта пара вопросов / ответов может быть полезна. Он говорит вам, как продолжить рендеринг (хотя это не исправляет растяжение).
Эндрю Рассел

Ответы:

3

Есть как минимум 3 сообщения, которые вы можете отслеживать.

  • WM_SIZE- изменение размера окна, мини / максимизация, полноэкранное / оконное переключение. Вы должны прочитать wParam, чтобы узнать, что именно произошло, и lParam для текущего размера.
  • WM_ENTERSIZEMOVE - начать изменение размера окна в оконном режиме
  • WM_EXITSIZEMOVE - завершить изменение размера окна в оконном режиме

Обычно вы не захотите изменять размер вашего приложения каждый кадр между WM_ENTERSIZEMOVE и WM_EXITSIZEMOVE, потому что он слишком медленный и уродливый. Но попробуйте, это, конечно, лучше, чем растяжение, может быть, вам понравится =)

case WM_SIZE:
    // Save the new client area dimensions.
    m_ptViewportSize.x  = LOWORD(lParam);
    m_ptViewportSize.y = HIWORD(lParam);
    if( wParam == SIZE_MINIMIZED )
    {
        m_bAppSuspended = true;
        m_bMinimized = true;
        m_bMaximized = false;
    }
    else if( wParam == SIZE_MAXIMIZED )
    {
        m_bAppSuspended = false;
        m_bMinimized = false;
        m_bMaximized = true;
        OnResize();
    }
    else if( wParam == SIZE_RESTORED )
    {
        // Restoring from minimized state
        if( m_bMinimized )
        {
            m_bAppSuspended = false;
            m_bMinimized = false;
            OnResize();
        }
        // Restoring from maximized state
        else if( m_bMaximized )
        {
            m_bAppSuspended = false;
            m_bMaximized = false;
            OnResize();
        }
        else if( m_bResizing )
        {
            // Resizing in processs
            // You woldn't wanto to handle a massive stream of
            // WM_SIZE here because buffers resizing is very slow
        }
        else
        {
            // Resizing finished and you can handle it. For ex. with 
            // m_SwapChain->SetFullscreenState
            OnResize();
        }

    }
    return 0;

// WM_EXITSIZEMOVE is sent when the user grabs the resize bars.
case WM_ENTERSIZEMOVE:
    m_bAppSuspended = true;
    m_bResizing  = true;
    g_pTimer->Stop();
    return 0;
// WM_EXITSIZEMOVE is sent when the user releases the resize bars.
// Here we reset everything based on the new window dimensions.
case WM_EXITSIZEMOVE:
    m_bAppSuspended = false;
    m_bResizing  = false;
    g_pTimer->Start();
    OnResize();
    return 0;
Иван Аксаментов - Дроп
источник
1
Обработка сообщений Windows в .NET включает переопределение System.Windows.Forms.Form.WndProc(). При работе в XNA у вас нет прямого доступа к a, Formчтобы переопределить этот метод. Хотя это можно сделать, это не тривиальный объем работы, и он должен был бы обойти дизайн XNA.
Cypher
Если кто-то выберет этот путь, этот список констант wm_ * должен оказаться полезным: pinvoke.net/default.aspx/Constants/WM.html
Cypher
Как уже говорили другие, мне все еще нужен способ замкнуть «движок» XNA и заставить его снова рисовать во время правильных событий. Из того, что я могу сказать, XNA вроде «засыпает» во время процедуры изменения размера.
Брэдли Аффнер