在游戏开发中背景卷轴的详细分析(转)

在游戏开发中背景卷轴的详细分析(转)[@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/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8225414/viewspace-952195/

你可能感兴趣的:(在游戏开发中背景卷轴的详细分析(转))