即使使用双缓冲,屏幕也会闪烁

时间:2010-03-01 21:24:13

标签: c windows winapi gdi

我是编程方面的新手。 对于我的第一个程序,我尝试使用windows api在c中制作一个小游戏。 以下代码是一个几乎工作的蛇,(一些错误还没有修复) 但我找不到一个解决这个闪烁的工作解决方案。 (我不知道双缓冲,所以我从这里开始:[http://www.codeguru.com/forum/archive/index.php/t-272723.html][1]

// snake1.02.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "snake1.02.h"
#include "stdio.h"

#define ID_MYTIMER 1234567
#define ID_BERRY 1
#define SEGMENTSIZE 10

const WCHAR szClassName[] = L"Snake1.02";
HWND hWnd;
UINT myTimer;

struct point {
    int x, y;
};



point snake[500];



int dx = SEGMENTSIZE;  //Change direction l=l+1
int dy = 0;
int snakelength=3;
int highscore=0;
WCHAR nachricht[100];
int map[80][60]; //Wenn Bildschirmgröße angepasst wird, auch hier anpassen!!!



// Global Variables:
HINSTANCE hInst;                                // current instance

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;

    // Initialize global strings
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    myTimer = SetTimer ( hWnd, ID_MYTIMER, 40, NULL );

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    KillTimer ( hWnd, myTimer );
    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+2);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = szClassName;
    wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

    return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{


   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szClassName, szClassName, WS_OVERLAPPED,
      CW_USEDEFAULT, 0, 800, 600, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   for(int i=snakelength; i>=0; i--){
   snake[i].x =100-(i*SEGMENTSIZE);
   snake[i].y=20;}

   for(int x=0; x<78;x++){
   map[x][0]=1;
   map[x][56]=1;


   }

   for(int y=0; y<57;y++){
    map[0][y]=1;
    map[78][y]=1;

   }


    map[50][70]=2;





   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    HDC memDC;
    HBITMAP hMemBmp;
    HBITMAP hOldBmp;


    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        memDC = CreateCompatibleDC(hdc);                                //flimmerfrei
        hMemBmp = CreateCompatibleBitmap(hdc, 800, 600);
        hOldBmp = (HBITMAP)SelectObject(memDC, hMemBmp);
        // TODO: Add any drawing code here...

        for (int i = 0; i<=snakelength; i++) {
            Rectangle(memDC, snake[i].x,snake[i].y,snake[i].x+10,snake[i].y+10);
        }
        for (int y=0; y<60;y++){
        for (int x=0; x<80;x++){
            if(map[x][y]==1||map[x][y]==2){
        Rectangle(memDC,x*SEGMENTSIZE,y*SEGMENTSIZE,x*SEGMENTSIZE+SEGMENTSIZE,y*SEGMENTSIZE+SEGMENTSIZE);
            }}
        }
        BitBlt(hdc, 0, 0, 800, 600, memDC, 0, 0, SRCCOPY);


        SelectObject(memDC, hOldBmp);
        DeleteObject(hMemBmp);
        DeleteDC(memDC);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_TIMER:
        switch (wParam)
        {
        case ID_MYTIMER:  {
            if (map[snake[0].x/10][snake[0].y/10]==1){              //crashcheck
                KillTimer ( hWnd, myTimer );
                wsprintf (nachricht,L"Game Over. Punktestand: %d",highscore);
                MessageBox(hWnd, (LPCWSTR)nachricht,L"Ende",0);
                }
            if (map[snake[0].x/10][snake[0].y/10]==2)               //grow
            {               
                for (int i = snakelength; i>0; i--) 
                {
                    snake[i].x = snake[i-1].x;
                    snake[i].y = snake[i-1].y;
                }
                snake[0].x = snake[1].x + dx;
                snake[0].y = snake[1].y + dy;
                map[snake[0].x/10][snake[0].y/10]=0;
                snakelength++;
                highscore+=10;

            }

            for (int i = snakelength; i>0; i--) {
                snake[i].x = snake[i-1].x;
                snake[i].y = snake[i-1].y;
            }
                snake[0].x = snake[1].x + dx;
                snake[0].y = snake[1].y + dy;   



            InvalidateRect(hWnd, 0,1);
            return 0;
            }
                          }
        break;
    case WM_KEYDOWN: {
        switch (wParam) {


            case VK_DOWN:{
                if(dy!=-SEGMENTSIZE){
                dy=SEGMENTSIZE;
                dx=0;
                }
                  }
            break;


            case VK_RIGHT:{
                if (dx!=-SEGMENTSIZE){
                dy=0;
                dx=SEGMENTSIZE;
                }
                  }
            break;
            case VK_UP:{
                if (dy!=SEGMENTSIZE){
                dy=-SEGMENTSIZE;
                dx=0;
                }
                  }
            break;
            case VK_LEFT:{
                if(dx!=SEGMENTSIZE){
                dy=0;
                dx=-SEGMENTSIZE;
                }
                }
                break;
            case VK_ESCAPE:{
                ExitProcess(0);
                  }
            break;
        }
        }
     break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

1 个答案:

答案 0 :(得分:4)

在WndProc的主开关语句中添加一个案例:

case WM_ERASEBKGND: 
    return TRUE;