在 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 8\Scrool\):
E:\Mssdk\samples\Multimedia\Common\include\ddutil.h
E:\Mssdk\samples\Multimedia\Common\include\dxutil.h
E:\Mssdk\samples\Multimedia\Common\src\ddutil.cpp
E:\Mssdk\samples\Multimedia\Common\src\dxutil.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)))
return