Question

J'utilise l'API Win32 pour faire une partie avec des sprites.Pour une raison quelconque quand j'ai plus d'un sprite à l'écran, ils clignotent parfois comme s'ils disparaissent et revenaient.Lorsqu'il n'y a qu'un seul sprite à l'écran, il s'affiche correctement.

J'utilise C ++, Win32 API et travaillez avec Visual Studio 08

Ce qui suit est à peu près ce que j'ai:

//creates rect based on window client area
GetClientRect(ghwnd, &screenRect);  
// Initialises front buffer device context (window)
frontHDC = GetDC(ghwnd);    
// sets up Back DC to be compatible with the front  
backHDC = CreateCompatibleDC(frontHDC);
// Create another hdc to store the bitmap in before the backbuffer
bitmapHDC = CreateCompatibleDC(frontHDC);
//creates bitmap compatible with the front buffer
theOldFrontBitMap = CreateCompatibleBitmap(frontHDC, screenRect.right, screenRect.bottom);
//creates bitmap compatible with the back buffer
theOldBackBitMap = (HBITMAP)SelectObject(backHDC, theOldFrontBitMap);

HBITMAP originalBitMap = (HBITMAP)SelectObject(bitmapHDC,bitmap);

//Transparency function
TransparentBlt( backHDC,
                m_Position.x,
                m_Position.y,
                m_Size.x,
                m_Size.y,
                bitmapHDC,
                0,
                0,
                m_Size.x,
                m_Size.y,
                0x00FFFFFF);

SelectObject(bitmapHDC,originalBitMap);

BitBlt(frontHDC, screenRect.left, screenRect.top, 
       screenRect.right, screenRect.bottom, backHDC, 0, 0, SRCCOPY);

Est-ce que je le fais correctement?Et si oui, où suis-je mal?Si je n'ai pas donné suffisamment d'informations, dites-moi et je vais rectifier cela.

Était-ce utile?

La solution

Le problème de la création d'un jeu Win32 est que, même si vous utilisez un double tampon, vous n'avez aucun moyen d'attendre que la retrace verticale du moniteur affiche le tampon.

Affichage du tampon ou de la sprite pendant que la retrace verticale est en cours peut provoquer une déchirure ou même la disparition de la sprite que vous ressentez.

Le seul moyen réel autour de cela est d'utiliser un SDK comme OpenGL ou DirectX pour gérer et afficher les tampons.

Voici un exemple de programme qui peut vous aider, utilisez les touches fléchées pour déplacer la boîte blanche sur le fond tamponné double:

#include <Windows.h>

RECT rcSize;
HDC hdcBackBuffer, hdcSprite;
HBITMAP hbmBackBuffer, hbmSprite;
int spriteX = 175, spriteY = 175;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static PAINTSTRUCT ps;

    switch (msg)
    {
    case WM_CREATE:
        {
            HDC hdcWindow = GetDC(hWnd);

            // make back buffer
            GetClientRect(hWnd, &rcSize);
            hdcBackBuffer = CreateCompatibleDC(hdcWindow);
            hbmBackBuffer = CreateCompatibleBitmap(hdcBackBuffer, rcSize.right - rcSize.left, rcSize.bottom - rcSize.top);
            SelectObject(hdcBackBuffer, hbmBackBuffer);  // SHOULD SAVE PREVIOUS...

            // make sprite
            hdcSprite = CreateCompatibleDC(hdcWindow);
            hbmSprite = CreateCompatibleBitmap(hdcSprite, 50, 50);
            SelectObject(hdcSprite, hbmSprite);  // SHOULD SAVE PREVIOUS...
            RECT rcSprite;
            SetRect(&rcSprite, 0, 0, 50, 50);
            FillRect(hdcSprite, &rcSprite, (HBRUSH)GetStockObject(WHITE_BRUSH));

            ReleaseDC(hWnd, hdcWindow);
            return 0;
        }
    case WM_KEYDOWN:
        {
            // SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
            switch (wParam)
            {
            case VK_LEFT:
                spriteX--;
                break;
            case VK_RIGHT:
                spriteX++;
                break;
            case VK_UP:
                spriteY--;
                break;
            case VK_DOWN:
                spriteY++;
                break;
            }
            return 0;
        }
    case WM_ERASEBKGND:
        {
            return 1; // INDICATE THAT WE ERASED THE BACKGROUND OURSELVES
        }
    case WM_PAINT:
        {
            BeginPaint(hWnd, &ps);
            // clear back buffer
            FillRect(hdcBackBuffer, &rcSize, (HBRUSH)GetStockObject(BLACK_BRUSH));
            // render sprite to back buffer
            BitBlt(hdcBackBuffer, spriteX, spriteY, 50, 50, hdcSprite, 0, 0, SRCCOPY);
            // render back buffer to screen
            BitBlt(ps.hdc, 0, 0, rcSize.right - rcSize.left, rcSize.bottom - rcSize.top, hdcBackBuffer, 0, 0, SRCCOPY);
            EndPaint(hWnd, &ps);
            return 0;
        }
    case WM_DESTROY:
        {
            // TODO - DESTROY ALL BITMAPS AND DEVICE CONTEXTS
            PostQuitMessage(0);
            return 0;
        }
    default:
        {
            return DefWindowProc(hWnd, msg, wParam, lParam);
        }
    }
}

int WINAPI WinMain(HINSTANCE hPrevInstance, HINSTANCE hInstance, LPSTR lpCmdLine, int nShowCmd)
{
    static TCHAR className[] = TEXT("GameClass");
    static TCHAR windowName[] = TEXT("A Game");

    WNDCLASSEX wcex;

    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = NULL;
    wcex.hCursor = LoadCursor(hInstance, IDC_ARROW);
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hIconSm = NULL;
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = className;
    wcex.lpszMenuName = NULL;
    wcex.style = 0;

    if (!RegisterClassEx(&wcex))
        return 0;

    HWND hWnd = CreateWindow(className, windowName, WS_CAPTION | WS_BORDER | WS_SYSMENU, 0, 0, 400, 400, NULL, NULL, hInstance, NULL);
    if (!hWnd)
        return 0;

    ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);

    MSG msg;
    for (;;)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                break;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        InvalidateRect(hWnd, NULL, FALSE);
    }

    return msg.wParam;
}

Autres conseils

Je pense que votre mise en œuvre de votre mémoire tampon est fausse bien que je ne sais pas exactement où.Essayez cette implémentation d'une classe de mémoire tampon séparée.J'espère que ça vous aide.

voici ma classe de tampon arrière.

#ifndef BACKBUFFER_H
#define BACKBUFFER_H

#include <Windows.h>


class BackBuffer
{
public:
    BackBuffer(HWND hWnd, int width, int height);
    ~BackBuffer();

    HDC getDC();

    int width();
    int height();

    void present();

private:
    // Make copy constructor and assignment operator private
    // so client cannot copy BackBuffers.  We do this because
    // this class is not designed to be copied because it
    // is not efficient--copying bitmaps is slow (lots of memory).
    // In addition, most applications will probably only need one
    // BackBuffer anyway.  
    BackBuffer(const BackBuffer& rhs);
    BackBuffer& operator=(const BackBuffer& rhs);
private:
    HWND    mhWnd;
    HDC     mhDC;
    HBITMAP mhSurface;
    HBITMAP mhOldObject;
    int     mWidth;
    int     mHeight;
};


#endif //BACKBUFFER_H

Heres la mise en œuvre:

BackBuffer::BackBuffer(HWND hWnd, int width, int height)
{
    //Save a copy of the main window handle
    mhWnd = hWnd;

    //Get a handle to the device context associated with
    // the window
    HDC hWndDC = GetDC(hWnd);

    //Save the backbuffer dimensions
    mWidth = width;
    mHeight = height;

    //Create system memory device context that is compatible
    //with the window one
    mhDC = CreateCompatibleDC(hWndDC);

    //Create the backbuffer surface bitmap that is compatible
    //with the window device context bitmap format. That is
    //the surface we will render onto.
    mhSurface = CreateCompatibleBitmap(hWndDC, width, height);

    //Done with DC
    ReleaseDC(hWnd, hWndDC);

    //At this point, the back buffer surface is uninitialized,
    //so lets clear it to some non-zero value. Note that it 
    //needs to be a non-zero. If it is zero then it will mess 
    //up our sprite blending logic.

    //Select the backbuffer bitmap into the DC
    mhOldObject = (HBITMAP)SelectObject(mhDC, mhSurface);

    //Select a white brush
    HBRUSH white = (HBRUSH)GetStockObject(WHITE_BRUSH);
    HBRUSH oldBrush = (HBRUSH)SelectObject(mhDC, white);

    //Clear the backbuffer rectangle
    Rectangle(mhDC, 0, 0, mWidth, mHeight);

    //Restore the original brush
    SelectObject(mhDC, oldBrush);

}

BackBuffer::~BackBuffer()
{
    SelectObject(mhDC, mhOldObject);
    DeleteObject(mhSurface);
    DeleteDC(mhDC);
}

HDC BackBuffer::getDC()
{
    return mhDC;
}

int BackBuffer::width()
{
    return mWidth;
}

int BackBuffer::height()
{
    return mHeight;
}

void BackBuffer::present()
{
    //Get a handle to the device context associated with 
    //the window
    HDC hWndDC = GetDC(mhWnd);

    //Copy the backbuffer contents over to the
    //window client area
    BitBlt(hWndDC, 0, 0, mWidth, mHeight, mhDC, 0, 0, SRCCOPY);

    //Free window DC when done
    ReleaseDC(mhWnd, hWndDC);
}

Essayez de travailler votre chemin à travers cette mise en œuvre, les commentaires devraient vous aider à comprendre.J'espère que cela t'aides.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top