BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
首先我们需要一张天空的背景图
用Bitblt函数进行贴图
SelectObject(g_bufdc, g_hBackGround);
BitBlt(g_mdc, 0,0 , g_iBGOffset, WINDOW_HEIGHT, g_bufdc, WINDOW_WIDTH - g_iBGOffset, 0, SRCCOPY);
BitBlt(g_mdc, g_iBGOffset, 0, WINDOW_WIDTH - g_iBGOffset, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);
BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
这里用到缓冲链技术,两张图贴到g_mdc中再贴到g_hdc也就是屏幕,虽然这里差别不大,但是贴图如果多的话不用缓冲链直接贴图游戏显示会很不流畅。
g_tNow = GetTickCount(); //获取当前系统时间
if (g_tNow - g_tPre >= 5) //当此次循环运行与上次绘图时间相差0.005秒时再进行重绘操作
Game_Paint(hwnd);
g_tPre = GetTickCount();
g_iBGOffset是一个变量每次循环都会+5
下面在主函数里加入循环使Paint函数每隔o.oo5s重绘一次。
这样动态天空就实现了。
下面是完整代码
//--------------------------程序说明-----------------------------
//程序名称:GDIdemo
//描述:GDI绘图模版
//---------------------------------------------------------------
//------------------------头文件部分------------------------------
#include<Windows.h>
#include<time.h>
//可以在此区域继续添加头文件
//--------------------------------------------------------------------
//------------------------宏定义-------------------------------------
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE L"GDI程序框架"
//-------------------------------------------------------------------
//----------------------全局变量声明部分-----------------------------
HDC g_hdc = NULL,g_mdc=NULL,g_bufdc=NULL;//全局设备环境句柄
HBITMAP g_hBitmap = NULL;//定义一个位图句柄
DWORD g_tPre = 0, g_tNow = 0;//记录绘图时间
int g_iNum = 0, g_iX = 0, g_iY = 0;//图号和图的横纵坐标
//----------------全局函数声明部分---------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//窗口过程函数
BOOL Game_Init(HWND hwnd);//在此函数进行资源初始化
VOID Game_Paint(HWND hwnd);//在此函数进行绘图代码的书写
BOOL Game_CleanUp(HWND hwnd);//在此函数进行资源的清理
//--------------------WinMain---------------------------------------
//Windows应用程序的入口函数
//---------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//[1]窗口创建四部曲之一:开始设计一个完整的窗口类
WNDCLASSEX wc = {};//用WNDCLASSEX定义了一个窗口类
wc.cbSize = sizeof(WNDCLASSEX);//设置结构体的字节数大小
wc.style = CS_HREDRAW | CS_VREDRAW;//设置窗口的样式
wc.lpfnWndProc = WndProc;//设置指向窗口过程的指针
wc.cbClsExtra = 0;//窗口类的附加内存
wc.cbWndExtra = 0;//窗口的附加内存
wc.hInstance = hInstance;//制定包含窗口过程的程序的实例句柄
wc.hIcon = (HICON)::LoadImage(NULL, L"", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);//本地加载自定义图标“”
wc.hCursor = LoadCursor(NULL, IDC_ARROW);//指定窗口类的光标句柄
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);//指定一个灰色画刷句柄
wc.lpszClassName = L"WINDOW";//用一个空终止的字符串,指定窗口类的名字
wc.lpszMenuName = NULL;//用一个空终止的字符串,指定菜单资源的名字
//[2]窗口的创建四部曲之二:注册窗口类
if (!RegisterClassEx(&wc))//设计完窗口,需要对窗口类进行注册,这样才能创建该类型的窗口
return -1;
//[3]窗口创建四部曲之三:正式创建窗口
HWND hwnd = CreateWindow(L"WINDOW", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
//窗口创建四部曲之四:窗口的移动,显示与更新
MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);//调整窗口显示時的位置位于(250,80)处
ShowWindow(hwnd, nShowCmd);//调用showwindow来显示窗口
UpdateWindow(hwnd);//队窗口进行更新
//游戏资源的初始化,若初始化失败弹出一个消息框并返回FALSE
if (!Game_Init(hwnd))
{
MessageBox(hwnd, L"初始化资源失败", L"消息窗口", 0);//使用MESSASGEBOX创建一个消息窗口
return FALSE;
}
MSG msg = { 0 };//定义并初始化msg
while (msg.message != WM_QUIT)//使用while循环,如果消息不是wm-quit消息,就继续循环
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))//查看应用程序消息队列,有消息時就将队列中的消息派发出去
{
TranslateMessage(&msg);//将虚拟消息转换为字符消息
DispatchMessage(&msg);//分发一个消息给窗口程序
}
else
{
g_tNow = GetTickCount();
if (g_tNow - g_tPre >= 5)
Game_Paint(hwnd);
}
}
//[6]窗口类的注销
UnregisterClass(L"WINDOW", wc.hInstance);//程序准备结束注销窗口类
return 0;
}
//-----------------------------WinProc函数-----------------------------------------
//对窗口消息进行处理
//---------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT paintStruct;//定义一个paintstruct来记录绘制信息
switch (message)//switch程序开始
{
case WM_KEYDOWN://键盘按下消息
if (wParam == VK_ESCAPE)//如果按下esc
DestroyWindow(hwnd);//销毁窗口并发送wm-destroy消息
break;
case WM_DESTROY://若是窗口销毁信息
Game_CleanUp(hwnd);
PostQuitMessage(0);//向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
break;//跳出该switch语句
default://若上述case条件都不符合,则执行default语句
return DefWindowProc(hwnd, message, wParam, lParam);//调用默认的窗口过程
}
return 0;//正常退出
}
//-------------------------【Game_Init】
BOOL Game_Init(HWND hwnd)
{
g_hdc = GetDC(hwnd);
HBITMAP bmp;
g_hBitmap = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, 800, 600, LR_LOADFROMFILE);//位图加载
g_mdc = CreateCompatibleDC(g_hdc);//和g_ hdc兼容的DC
g_bufdc = CreateCompatibleDC(g_hdc);//缓冲DC
bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
SelectObject(g_mdc, bmp);
g_iX = 0;
Game_Paint(hwnd);
//ReleaseDC(hwnd, g_hdc);//这句话导致不能平移!!!!!!!!!!!!!!!!释放掉了再调用肯定不行啊都根屏幕失去连接了
return TRUE;
}
//-------------------------【Game_Paint】
VOID Game_Paint(HWND hwnd)
{
if (g_iX==800)
{
g_iX = 0;
}
SelectObject(g_bufdc, g_hBitmap);//将位图对象选入到g_mdc内存dc中
BitBlt(g_mdc, g_iX, 0, WINDOW_WIDTH-g_iX, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);
BitBlt(g_mdc, 0, 0, g_iX, WINDOW_HEIGHT, g_bufdc, WINDOW_WIDTH - g_iX, 0, SRCCOPY);
BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
g_tPre = GetTickCount();
g_iX+= 5;
}
//-----------------------------[Game_CleanUp]
BOOL Game_CleanUp(HWND hwnd)
{
DeleteObject(g_hBitmap);
DeleteDC(g_mdc);
DeleteDC(g_hdc);
DeleteDC(g_bufdc);
return TRUE;
}