在游戏开发中背景卷轴的详细分析(转)[@more@]
在 Windowed Mode(窗口模式) 下使用计时器卷动背景图象。
编译成功后拖曳窗口改变大小,确认图象可以随着画面伸缩。
另外,尝试进一步简化源程序。
卷轴有各种各样的卷法,这回我们用下面的方式卷:
1. 用两张相同的图片左右并排拼成一张。
(下面是我用的图片, 640*240 。用两张 320*240 的图片拼的,命名为 "约塞米蒂山谷.bmp" ,放在 G:DirectX 8 下。)
2. 因为画面的初始大小是 640*480 ,所以把上面的图片扩展到 1280*480 ,储存在 BmpSurface :
if (FAILED(hr= g_pDisplay->CreateSurfaceFromBitmap(&g_pBmpSurface,
"E:DirectX 8约塞米蒂山谷.bmp",1280,480)))
return hr;
3. 启动计时器控制卷轴速度。
指定计时间隔 20 毫秒:
#define ID_TIMER 32767
:
SetTimer(hWnd,ID_TIMER,20,NULL);
4. 在计时器(WM_TIMER)中计数 g_cnt :
int g_cnt = 0;
:
case WM_TIMER:
g_cnt++;
break;
5. 把作为背景描绘的 BmpSurface 的矩形区域设定为 RECT 结构体。
画面初始大小是 640*480 :
RECT rt;
top= 0;
rt.bottom= 480;
rt.left= g_cnt%640;
rt.right= rt.left+640;
6. 从图片的左端(横坐标 = 0)向中间(横坐标 = 639)一边挪动一边描绘:
g_pDisplay->Blt(0,0,g_pBmpSurface,&rt);
if (FAILED(hr= g_pDisplay->Present())) return hr;
7. 横坐标达到 640 就返回到左端(横坐标 = 0)。(注意那个 g_cnt%640)。
如果你的图片不是用两张相同的图片左右拼起来的,卷轴的时候看起来就很不舒服:卷到末尾、忽然跳到开头;再卷到末尾、再忽然跳到开头……感觉并不是连续卷轴。你可以把一张图片裁成 640*240 试试。
8. 退出程序时关闭计时器:
case WM_DESTROY:
KillTimer(hWnd, ID_TIMER);
下面把创建窗口的代码给它尽量简化。
640*480 是窗口的初始大小,我们用 ddutil.cpp 里面的 CreateWindowedDisplay() 函数重新设定窗口大小:
WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,
NULL,NULL,NULL,NULL,NAME
};
if (RegisterClass(&wc)==0) return FALSE;
HWND hWnd = CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,0,0,640,480,
GetDesktopWindow(),NULL,wc.hInstance,NULL);
if (hWnd==NULL) return FALSE;
虽说有 WNDCLASS 和 WNDCLASSEX 两种类型,如果不使用扩展机能,实际上用哪个都一样。
这里开出 WNDCLASSEX 的代码:
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0L,0L,hInst,
NULL,NULL,NULL,NULL,NAME,NULL
};
if (RegisterClassEx(&wc)==0) return FALSE;
实际决定窗口大小的 CreateWindowedDisplay() :
if (FAILED(hr = g_pDisplay->CreateWindowedDisplay(hWnd,640,480)))
{ ERMSG("Failed initializing DirectDraw.");
return hr;
}
下面说明工程的创建方法。
1. 新建一个 Win32 Application 空白工程,命名为 "Scrool"。
2. 向工程中新建一个 C++ Source File ,命名为 "scrool" ,向其中键入篇末附带的源程序。
3. 把下面4个文件复制到工程文件夹(我是 G:DirectX 8Scrool):
E:MssdksamplesMultimediaCommonincludeddutil.h
E:MssdksamplesMultimediaCommonincludedxutil.h
E:MssdksamplesMultimediaCommonsrcddutil.cpp
E:MssdksamplesMultimediaCommonsrcdxutil.cpp
然后选择菜单 [Project|工程]-[Add To Project|添加到工程]-[Files...|文件...] ,向工程中添加这4个文件。
4. 准备合适的图象文件(我是在 G:DirectX 8 下放了张 "约塞米蒂山谷.bmp" ,参见本章开头)。
5. 选择菜单 [Project|工程]-[Settings...|设定...] 打开[Project Settings|工程设定] 面板,点击 [Link|链接] 标签,向 [Object/library modules|对象、库模块] 栏内添加下面4个库文件:
dxguid.lib
ddraw.lib
dxerr8.lib
winmm.lib
6. 编译并执行!
源程序:
/*****************************************/
/*★ 背景卷轴 2001-01-14 前田 稔 ★*/
/*****************************************/
#define NAME "BMP Scrool"
#define STRICT
#include
#include
#include
#include "ddutil.h"
#define ID_TIMER 32767
// Defines, constants, and global variables
#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
#define ERMSG(x) MessageBox(hWnd, x, "DirectDraw Samplee", MB_OK);
CDisplay* g_pDisplay = NULL;
CSurface* g_pBmpSurface = NULL;
BOOL g_bActive = FALSE;
int g_cnt = 0;
// Function-prototypes
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitDraw(HWND hWnd);
VOID FreeDraw();
HRESULT DisplayFrame();
//★ Windows Main
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
{ MSG msg;
/*
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0L,0L,hInst,
NULL,NULL,NULL,NULL,NAME,NULL
};
if (RegisterClassEx(&wc)==0) return FALSE;
*/
WNDCLASS wc = { CS_CLASSDC,WndProc,0L,0L,hInst,
NULL,NULL,NULL,NULL,NAME
};
if (RegisterClass(&wc)==0) return FALSE;
HWND hWnd = CreateWindow(NAME,NAME,WS_OVERLAPPEDWINDOW,0,0,640,480,
GetDesktopWindow(),NULL,wc.hInstance,NULL);
if (hWnd==NULL) return FALSE;
if (FAILED(InitDraw(hWnd)))
{ if (g_pDisplay)
g_pDisplay->GetDirectDraw()->SetCooperativeLevel(NULL, DDSCL_NORMAL);
ERMSG("DirectDraw init failed. The sample will now exit.");
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
SetTimer(hWnd,ID_TIMER,20,NULL);
while(TRUE)
{ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{ if (0 == GetMessage(&msg, NULL, 0, 0)) return (int)msg.wParam;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{ if (g_bActive)
{ if (FAILED(DisplayFrame()))
{ SAFE_DELETE(g_pDisplay);
ERMSG("Displaying the next frame failed");
return FALSE;
}
}
else WaitMessage();
}
}
}
//★ WndProc()
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_KEYDOWN:
PostMessage(hWnd,WM_CLOSE,0,0);
return 0L;
case WM_TIMER:
g_cnt++;
break;
case WM_PAINT:
if (g_pDisplay)
{ // Display the new position of the sprite
if (DisplayFrame() == DDERR_SURFACELOST)
{ PostMessage(hWnd,WM_CLOSE,0,0);
}
}
break;
case WM_MOVE:
if (g_pDisplay) g_pDisplay->UpdateBounds();
return 0L;
case WM_SIZE:
// Check to see if we are losing our window...
if (SIZE_MAXHIDE==wParam||SIZE_MINIMIZED==wParam) g_bActive= FALSE;
else g_bActive= TRUE;
if (g_pDisplay) g_pDisplay->UpdateBounds();
break;
case WM_DESTROY:
KillTimer(hWnd, ID_TIMER);
FreeDraw();
PostQuitMessage(0);
return 0L;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//★ InitDraw()
HRESULT InitDraw(HWND hWnd)
{ HRESULT hr;
g_pDisplay = new CDisplay();
if (FAILED(hr = g_pDisplay->CreateWindowedDisplay(hWnd,640,480)))
{ ERMSG("Failed initializing DirectDraw.");
return hr;
}
if (FAILED(hr= g_pDisplay->CreateSurfaceFromBitmap(&g_pBmpSurface,
"G:DirectX 8约塞米蒂山谷.bmp",1280,480)))
retur
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-952195/,如需转载,请注明出处,否则将追究法律责任。