VC++游戏编程----游戏画面特效制做2

1、半透明效果

半透明效果在游戏世界里是用的很频繁的,好比鬼魂,隐形人物。html

简单的说,半透明是前景图案和背景图案像素颜色的混合。能够简单的把半透明处理,整理为一个公式:数组

半透明图色彩 = 前景图色彩× 不透明度 + 背景图色彩 × (1 -不透明度)框架


半透明处理的步骤:函数

1.      获取位图结构。
GetObject()获取位图的结构后,可获得位图信息。编码

2.      创建暂存数组
得到了位图结构后,接下来须要先创建一个暂时存储位图像素的颜色值。这个暂存数组的大小有前一步得到位图信息的bmHeight, bmWidthBytes决定。spa

这里有必要提一下BITMAP结构,由于在以后将会用到。3d

typedef struct tagBITMAP {
  LONG   bmType; //位图类型
  LONG   bmWidth; //位图宽度
  LONG   bmHeight; //长度
  LONG   bmWidthBytes; //每一列像素所占Byte数
  WORD   bmPlanes; //颜色平面数
  WORD   bmBitsPixel; //像素位数
  LPVOID bmBits; //位图内存指针
} BITMAP, *PBITMAP;

3.      取得位图位值。
创建数组后,能够用GetBitmapBits()来得到位图位值。指针

4.      合成像素颜色值
得到位图的全部像素颜色值后,按照公式完成半透明颜色值的合成。code

5.      重设位图颜色。
根据数组的内容来从新设位图的颜色。使用SetBitmapBits() 。htm

完成后,最后就是贴图了。

 

范例:

首先建立win32项目。让系统生成基本框架代码。

在程序开始处添加全局变量。

HBITMAP bg, girl;
HDC mdc;
//常量
const int xstart= 50;
const int ystart= 20;

而后在InitInstance()函数中添加代码

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
   HDC hdc;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   MoveWindow(hWnd, 10, 10, 600, 450, true);
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   hdc = GetDC(hWnd);
   mdc = CreateCompatibleDC(hdc);

   BITMAP bm1, bm2;
   unsigned char *px1,*px2;//用于存储位图额色彩值
   
   //处理背景

   bg = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, 600, 450, LR_LOADFROMFILE);
   GetObject(bg, sizeof(BITMAP), &bm1);//将bg的位图信息获取到bm1
   
   px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];//动态定义数组,大小有获取位图决定
   GetBitmapBits(bg, bm1.bmHeight * bm1.bmWidthBytes, px1);//得到位图位值到px1
   
   girl = (HBITMAP)LoadImage(NULL, L"girl.bmp", IMAGE_BITMAP, 298, 329, LR_LOADFROMFILE);
   GetObject(girl, sizeof(BITMAP), &bm2);//将girl的位图信息获取到bm2
   
   px2 = new unsigned char [bm2.bmHeight * bm2.bmWidthBytes];
   GetBitmapBits(girl, bm2.bmHeight * bm2.bmWidthBytes, px2);

   int xend, yend;
   int x, y, i;
   int rgb_b;
   int PxBytes = bm1.bmBitsPixel / 8;
   xend = xstart + 298;//位图的大小为:*329
   yend = ystart + 329;

   //处理背景像素颜色
   //从(xstart,ystart)开始遍历半透明化位置的每一个像素点
   for (y = ystart; y < yend; y++) {
	   for (x = xstart; x < xend; x++) {
		   //rgb_b用于找到位图在px1中的位置(px1为一维数组)
		   rgb_b = y * bm1.bmWidthBytes + x * PxBytes;
		   px1[rgb_b] = px1[rgb_b] * 0.7;
		   px1[rgb_b+1] = px1[rgb_b+1] * 0.7;
		   px1[rgb_b+2] = px1[rgb_b+2] * 0.7;
       }
   }
   //处理前景图像像素颜色
   //因为前景是从girl位图的(0,0)开始的
   for (y = 0; y < (bm2.bmHeight); y++) {
	   for (x = 0; x < bm2.bmWidth; x++) {
		   rgb_b = y * bm2.bmWidthBytes + x * PxBytes;
		   i = (ystart+y) * bm1.bmWidthBytes + (xstart+x) * PxBytes;
		   px2[rgb_b] = px2[rgb_b] * 0.3 + px1[i];
		   px2[rgb_b+1] = px2[rgb_b+1] * 0.3 + px1[i+1];
		   px2[rgb_b+2] = px2[rgb_b+2] * 0.3 + px1[i+2];
	   }
   }

   SetBitmapBits(girl, bm2.bmWidthBytes * bm2.bmHeight, px2);
   MyPaint(hdc);

   ReleaseDC(hWnd, hdc);
   delete [] px1;
   delete [] px2;

   return TRUE;
}

void MyPaint(HDC hdc)
{
	SelectObject(mdc, bg);
	BitBlt(hdc, 0, 0, 600, 450, mdc, 0, 0, SRCCOPY);

	SelectObject(mdc, girl);
	BitBlt(hdc, xstart, ystart, 298, 329, mdc, 0, 0, SRCCOPY);
}
最后在WndProc函数的WM_PAINT消息中添加MyPaint()函数




2、透明半透明效果

看到上面例子中效果还不太好,由于前景图还能够看到原来位图矩形边框。这里咱们要把它作得更好。这里使用一个内存DC和位图对象,在DC中先完成透明效果,再来取出DC内存位图进行半透明处理。这样就达到了目的。

这个范例中的前景图必需要有以下图所示:

 


下面的编码和上面相似。

添加全局变量


HBITMAP bg, girl; 
HDC mdc;
const int xstart = 50;
const int ystart = 20;

在InitInstance()函数中,添加代码:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   HDC hdc, bufdc;
   HBITMAP bmp;
   BITMAP bm1, bm2;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   MoveWindow(hWnd, 10, 10, 600, 450, true); // 初始窗口位置和大小
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   bg = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, 600, 450, LR_LOADFROMFILE);
   bmp = (HBITMAP)LoadImage(NULL, L"girlmask.bmp", IMAGE_BITMAP, 596, 329, LR_LOADFROMFILE);

   GetObject(bg, sizeof(BITMAP), &bm1);

   hdc = GetDC(hWnd);
   mdc = CreateCompatibleDC(hdc);
   bufdc = CreateCompatibleDC(hdc);
   girl = CreateCompatibleBitmap(hdc, 298, 329);

   SelectObject(mdc, girl);
   //前景图和背景图透明处理,保存在mdc
   SelectObject(bufdc, bg);
   BitBlt(mdc, 0, 0, 298, 329, bufdc, xstart, ystart, SRCCOPY);
   SelectObject(bufdc, bmp);
   BitBlt(mdc, 0, 0, 298, 329, bufdc, 298, 0, SRCAND);
   BitBlt(mdc, 0, 0, 298, 329, bufdc, 0, 0, SRCPAINT);
   
   //开始半透明处理
   unsigned char *px1,*px2;

   //处理背景图
   px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];
   GetBitmapBits(bg, bm1.bmHeight * bm1.bmWidthBytes, px1);

   //处理前景图
   GetObject(girl, sizeof(BITMAP), &bm2);
   px2 = new unsigned char [bm2.bmHeight * bm2.bmWidthBytes];
   GetBitmapBits(girl, bm2.bmHeight * bm2.bmWidthBytes, px2);

   int x, y, xend, yend;
   int i;
   int rgb_b;
   int PxBytes = bm1.bmBitsPixel / 8;

   xend = xstart + 298;
   yend = ystart + 329;

   //处理背景图
   for (y = ystart; y < yend; y++)
   {
	   for (x = xstart; x < xend; x++)
	   {
		   rgb_b = y * bm1.bmWidthBytes + x * PxBytes;
		   px1[rgb_b] = px1[rgb_b] * 0.7;
		   px1[rgb_b+1] = px1[rgb_b+1] * 0.7;
		   px1[rgb_b+2] = px1[rgb_b+2] * 0.7;
	   }
   }
   //处理前景图像素颜色
   for(y=0;y<(bm2.bmHeight); y++) 	
   {
	   for(x=0;x<bm2.bmWidth; x++) 
	   {
		   rgb_b = y * bm2.bmWidthBytes + x * PxBytes ;
		   i = (ystart+y) * bm1.bmWidthBytes + (xstart+x) * PxBytes;

		   px2[rgb_b]	 = px2[rgb_b] *0.3 + px1[i];	
		   px2[rgb_b+1] = px2[rgb_b+1] *0.3 + px1[i+1];	
		   px2[rgb_b+2] = px2[rgb_b+2] *0.3 + px1[i+2];	
	   }
   }

   SetBitmapBits(girl,bm2.bmHeight*bm2.bmWidthBytes,px2);

   MyPaint(hdc);//贴图
   
   ReleaseDC(hWnd, hdc);
   DeleteDC(bufdc);
   DeleteObject(bmp);
   delete [] px1;
   delete [] px2;

   return TRUE;
}

void MyPaint(HDC hdc)
{
	//将背景图和处理后的透明半透明图贴入
	SelectObject(mdc, bg);
	BitBlt(hdc, 0, 0, 600, 450, mdc, 0, 0, SRCCOPY);
	SelectObject(mdc, girl);
	BitBlt(hdc, xstart, ystart, 298, 329, mdc, 0, 0, SRCCOPY);
}

最后把MyPaint()函数写入消息循环中的WM_PAINT消息中:

case WM_PAINT:
	hdc = BeginPaint(hWnd, &ps);
	// TODO: 在此添加任意绘图代码...
	MyPaint(hdc);
	EndPaint(hWnd, &ps);
	break;
这样,咱们的程序就写好了。运行程序。