游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2402|回复: 3

关于BITBLT贴位图刷新时图象闪烁的问题

[复制链接]

3

主题

4

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2006-5-11 12:46:00 | 显示全部楼层 |阅读模式
最近尝试了一下用BITBLT贴位图,并在点击鼠标时使图象移动,开始时窗口不能强制重画,现在用了invalidate之后,图象能动了,可是图象闪烁的厉害,请问如何解决,代码如下:
#include "Game.h"
#include <windows.h>
#define MAX_LOADSTRING 100
#define SCREEN_HEIGHT 480
#define SCREEN_WIDTH 640

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

int Game_Init(void *parms = NULL, int num_parms = 0);
int Game_ShutDown(void *parms = NULL, int num_parms = 0);
int Game_Main(void *parms = NULL, int num_parms = 0);


iPos iPosSence(0,0);

// 全局变量:
HINSTANCE hInst;                                                                // 当前实例
TCHAR szTitle[MAX_LOADSTRING];                                        // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];                        // 主窗口类名
HBITMAP                hSence;
HDC hdcMem,hdc;
HWND hWnd;

// 此代码模块中包含的函数的前向声明:
ATOM                                MyRegisterClass(HINSTANCE hInstance);
BOOL                                InitInstance(HINSTANCE, int);
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK        About(HWND, UINT, WPARAM, LPARAM);


int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
        // TODO: 在此放置代码。
        MSG msg;
        HACCEL hAccelTable;

        // 初始化全局字符串
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadString(hInstance, IDC_GAME, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);

        // 执行应用程序初始化:
        if (!InitInstance (hInstance, nCmdShow))
        {
                return FALSE;
        }

        hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_GAME);

        Game_Init();

        // 主消息循环:
        while(TRUE)
        {
                if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
                {
                        if (msg.message == WM_QUIT)
                                break;
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
                Game_Main();
                Sleep(30);
        }

        Game_ShutDown();
        return (int) msg.wParam;
}

//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望在已添加到 Windows 95 的
//    “RegisterClassEx”函数之前此代码与 Win32 系统兼容时,
//    才需要此函数及其用法。调用此函数
//    十分重要,这样应用程序就可以获得关联的
//   “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
        WNDCLASSEX wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style                        = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc        = (WNDPROC)WndProc;
        wcex.cbClsExtra                = 0;
        wcex.cbWndExtra                = 0;
        wcex.hInstance                = hInstance;
        wcex.hIcon                        = LoadIcon(hInstance, (LPCTSTR)IDI_GAME);
        wcex.hCursor                = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground        = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName        = (LPCTSTR)IDC_GAME;
        wcex.lpszClassName        = szWindowClass;
        wcex.hIconSm                = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_GAME);

        return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HANDLE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
        int xScrn, yScrn,x,y;
        HDC hScrDC;
        hInst = hInstance; // 将实例句柄存储在全局变量中
        hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
        xScrn = GetDeviceCaps(hScrDC, HORZRES);
        yScrn = GetDeviceCaps(hScrDC, VERTRES);
        x = (xScrn - SCREEN_WIDTH)/2;
        y = (yScrn - SCREEN_HEIGHT)/2;
        hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      x, y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);
        hSence= LoadBitmap (hInst, MAKEINTRESOURCE(IDB_SENCE)) ;
        if (!hWnd)
        {
                return FALSE;
        }

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

        return TRUE;
}

//
//  函数: WndProc(HWND, unsigned, WORD, LONG)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND        - 处理应用程序菜单
//  WM_PAINT        - 绘制主窗口
//  WM_DESTROY        - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        int wmId, wmEvent;

        switch (message)
        {
        case WM_LBUTTONDOWN:
                iPosSence.x+=10;
                break;
        case WM_COMMAND:
                wmId    = LOWORD(wParam);
                wmEvent = HIWORD(wParam);
                // 分析菜单选择:
                switch (wmId)
                {
                case IDM_ABOUT:
                        DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                        break;
                case IDM_EXIT:
                        DestroyWindow(hWnd);
                        break;
                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
                }
                break;
        case WM_PAINT:
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
}

// “关于”框的消息处理程序。
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
        switch (message)
        {
        case WM_INITDIALOG:
                return TRUE;

        case WM_COMMAND:
                if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
                {
                        EndDialog(hDlg, LOWORD(wParam));
                        return TRUE;
                }
                break;
        }
        return FALSE;
}


int Game_Init(void *parms, int num_parms)
{
               
        return 0;
}

int Game_ShutDown(void *parms, int num_parms)
{
        return 0;
}

int Game_Main(void *parms, int num_parms)
{
        PAINTSTRUCT ps;
        hdc = BeginPaint(hWnd, &ps);
        hdcMem = CreateCompatibleDC (hdc) ;
        SelectObject (hdcMem, hSence) ;
        BitBlt (hdc, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, hdcMem, iPosSence.x, iPosSence.y, SRCCOPY) ;
        DeleteDC( hdcMem );       
        EndPaint(hWnd, &ps);
        RECT rctA;
        rctA.left = 0;
        rctA.top = 0;
        rctA.right  = 640;
        rctA.bottom = 480;
        ::InvalidateRect(hWnd,&rctA,TRUE);
        return 0;
}

64

主题

855

帖子

856

积分

高级会员

Rank: 4

积分
856
QQ
发表于 2006-5-11 12:50:00 | 显示全部楼层

Re:关于BITBLT贴位图刷新时图象闪烁的问题

试试双缓冲原理

12

主题

124

帖子

124

积分

注册会员

Rank: 2

积分
124
QQ
发表于 2006-5-11 14:59:00 | 显示全部楼层

Re:关于BITBLT贴位图刷新时图象闪烁的问题

他已经用了双缓冲了。

问题在于:你每次循环执行 GameMain 时都调用了 InvalidateRect(hwnd, &rcA, TRUE) 进行刷新,第三个参数用 TRUE 的话代表用擦除背景,当然会闪烁。

要么用 FALSE, 要么在需要更新的时候手动擦除。

顺便说一句:楼主,下次不要这样贴这么长的代码,贴重点就行了,完整的代码可以用附件。不然没几个人有耐心拖半天滚动条的。

3

主题

4

帖子

10

积分

新手上路

Rank: 1

积分
10
 楼主| 发表于 2006-5-12 08:15:00 | 显示全部楼层

Re:关于BITBLT贴位图刷新时图象闪烁的问题

谢谢LS,已经解决了,以后我会注意了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-24 11:34

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表