本系列文章由@二货梦想家张程 所写,转载请注明出处。

本文章链接:http://blog.csdn.net/terence1212/article/details/44163799

作者:ZeeCoder  微博链接:http://weibo.com/zc463717263

我的邮箱:michealfloyd@126.com   欢迎大家发邮件来和我交流编程心得

you are what you read!与大家共勉!

--------------------------------------------------------------------------------------分割线ZeeCoder------------------------------------------------------------------------------------------

由于本科的专业不是计算机,但对计算机有很大的兴趣,也一直在自学C语言和VC++,MFC编程,所以接触VC++游戏编程上手不算太难,刚做好了传说中的五毛特效透明和半透明处理,所以写下这篇笔记。

OK,下面归入正题。

1.透明效果

P话就不多说了, 直接讲解代码。

透明效果需要用到万能的贴图函数BitBlt

BOOL BitBlt(
			HDC hdc;	//目的DC
			int x;		//目的DC的x坐标
			int y;		//目的DC的y坐标
			int nWidth;	//贴到目的DC的宽度
			int nHeight;//贴到目的DC的高度
			HDC mdc;	//来源DC
			int xSrc;	//来源DC的x坐标
			int ySrc;	//来源DC的y坐标
			DWORD dwRop;//贴图方式
);

dwRop贴图方式有下面N种:

BLACKNESS           使用黑色填充目标区域
DSTINVERT              目标矩阵区域颜色取反
MERGECOPY            使用与运算组合原设备矩形区域的颜色和目标设备的画刷
MERGEPAINT           使用或运算将反向的源矩形区域的颜色和目标矩形区域的颜色合并
NOTSRCCOPY          复制源设备区域的反色到目标设备中
NOTSRCERASE        使用或运算组合源设备区域与目标设备区域的颜色,然后对结果颜色取反
PATCOPY                  复制源设备当前选中的画刷到目标设备
PATINVERT               使用异或运算组合目标设备选中的画刷和目标设备区域的颜色
PATPAINT                 通过或运算组合目标区域当前选中的画刷和源设备区域反转的颜色
SRCAND                   使用与运算组合源设备和目标设备区域的颜色
SRCCOPY                 直接复制源设备区域到目标设备中
SRCERASE               使用与运算组合目标设备区域的反色与源设备区域的颜色
SRCINVERT              使用异或运算组合源设备区域颜色和目标设备区域颜色
SRCPAINT                 使用或运算组合源设备区域颜色和目标设备区域颜色
WHITENESS             使用白色填充目标区域

透明效果需要用到SRCAND 和SRCPAINT这两种贴图方式。

好了,下面直接上代码。(本笔记均在VS2010平台下编程)

1、首先定义全局变量

<pre name="code" class="cpp">//全局变量
HINSTANCE hInst;
HBITMAP bg , character; // 这里两个位图对象分别储存背景图和人物图
HDC mdc; //声明一个DC来暂存位图
void MyPaint(HDC hdc); //声明自定义的函数

2、初始化函数

//****初始化函数*************************************
// 1.建立与窗口DC兼容的内存DC
// 2.从文件加载背景图与恐龙图
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
   HDC hdc;
   hInst = hInstance; // Store instance handle in our global variable

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

   if (!hWnd)
   {
      return FALSE;
   }
   MoveWindow(hWnd , 10 ,10 , 650 , 600 ,true);
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   hdc = GetDC(hWnd);//获得窗口DC
   mdc = CreateCompatibleDC(hdc);////创建与窗口兼容的内存DC(mdc)

   bg = (HBITMAP)LoadImage(NULL , _T("res.bmp") , IMAGE_BITMAP , 640 , 360 ,LR_LOADFROMFILE);//加载背景图到bg中
   character = (HBITMAP)LoadImage(NULL , _T("dra.bmp"), IMAGE_BITMAP , 170 , 99 , LR_LOADFROMFILE);//加载恐龙图到character中 

   MyPaint(hdc);
   return TRUE;
}

3、自定义贴图函数

//****自定义绘图函数*********************************
//透明贴图
void MyPaint(HDC hdc)
{
	SelectObject(mdc , bg);
	BitBlt(hdc , 0 , 0 , 650 ,360 , mdc , 0 ,0 ,SRCCOPY );//先将背景图贴到显示窗口中

	SelectObject(mdc , character);//选用character图到"mdc"中
	BitBlt(hdc , 200 , 200 , 85 , 128 , mdc , 85 , 0 , SRCAND);//进行制作贴图的第一步骤,即将屏蔽图与背景图做"AND"运算,屏蔽图在整张恐龙图中,最左上角起始位置点得坐标为(85,0),BitBlt()函数中最后一个Raster参数值设置为SRCAND。
	BitBlt(hdc , 200 ,200 ,85 ,128 , mdc , 0 ,0 , SRCPAINT);//进行制作透明贴图的第二步骤,即将前景图与背景图做"OR"运算,前景图在整张恐龙图中,最左上角起始位置的坐标为(0,0),BitBlt()函数最后一个参数值设置为SRCPAINT。
}

4.效果图:

2.半透明效果

半透明效果主要分为以下几个步骤:

(1)取得位图结构

int GetObject(
	HGDIOBJ hgdiobj,	//取得GDI结构对象
	int cbBuffer,		//结构大小
	LPVOID lpvObject	//结构变量
);

上面这个函数在此处为了取得位图的信息,则输入一个位图结构的地址,windows Api 中所定义的位图结构(BITMAP)如下:

typedef struct tagBITMAP
{
	LONG        bmType; //位图类型必须设为0
	LONG        bmWidth;//位图宽度
	LONG        bmHeight;//位图长度
	LONG        bmWidthBytes;//每一列像素所占Bit数
	WORD        bmPlanes;//颜色平面数
	WORD        bmBitsPixel;//像素的位数
	LPVOID      bmBits;//位图内存指针
} BITMAP;

所以要取得位图信息的话,程序代码如下

GetObject( bitmap , sizeof(BITMAP) , &bm);

(2)建立暂存数组

用动态指针来建立一个暂存数组来存储位图中所有像素的颜色值。

程序代码如下:

 unsigned char *px1 = new unsigned char [bm.bmHeight * bm.bmWidthBytes];

(3)取得位图位值

取得位图中所有的颜色值,需要用到如下函数:

GetBitmapBits(
	HBITMAP hbit,	//取得位图位值
	LONG cb,	//要取得的bit数
	LPVOID lpvBits	// 存储的数组指针
	);

(4)合成像素颜色值

按照不透明度来设定半透明区域的每个像素的颜色

(5)重设位图颜色

根据上个步骤中获得的暂存数组的半透明颜色值来重设位图的颜色值

这里用到windowsApi提供的函数:

SetBitmapBits(
		HBITMAP hbm,		//位图
		DWORD cb,		//颜色数组的大小
		CONST VOID *pvBits	//数组指针
	);

OK,全部的步骤就介绍到这里,下面看具体怎么实现。

1、全局变量设定

HINSTANCE hInst;								// current instance
HBITMAP bg , dra ;
HDC mdc;
//常数定义
const int xstart = 50 ;
const int ystart = 20 ;

2、初始化函数

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

   hInst = hInstance; // Store instance handle in our global variable

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

   if (!hWnd)
   {
      return FALSE;
   }

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

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

   BITMAP bm1 , bm2 ;
   unsigned char *px1 , *px2 ;
   //处理背景图
   bg = (HBITMAP)LoadImage(NULL , _T("res.bmp") , IMAGE_BITMAP , 640 , 360 ,LR_LOADFROMFILE);
   GetObject(bg , sizeof(BITMAP) , &bm1);

   if (bm1.bmBitsPixel != 32 && bm1.bmBitsPixel != 24)
   {
	   MessageBox(NULL, _T("此程序只能在32bit或24bit显示模式中运行" ), _T("警告") , 0);
	   return FALSE;
   }
   px1 = new unsigned char [bm1.bmHeight * bm1.bmWidthBytes];
   GetBitmapBits(bg , bm1.bmHeight * bm1.bmWidthBytes , px1);

   //处理前景图
   dra = (HBITMAP)LoadImage(NULL , _T("14.bmp"), IMAGE_BITMAP , 120 , 128 , LR_LOADFROMFILE);
   GetObject(dra , sizeof(BITMAP) , &bm2);
   px2 = new unsigned char [bm2.bmHeight * bm2.bmWidthBytes];
   GetBitmapBits(dra , bm2.bmHeight * bm2.bmWidthBytes , px2);

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

   xend = xstart + 120 ;
   yend = ystart + 128 ;

   //处理背景图像素颜色
   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(dra , bm2.bmHeight * bm2.bmWidthBytes , px2);

   MyPaint(hdc);
   ReleaseDC(hWnd ,hdc);

   delete [] px1;
   delete [] px2;
   return TRUE;
}

3、自定义绘图函数

void MyPaint(HDC hdc)
{
	SelectObject(mdc , bg);
	BitBlt(hdc , 0 , 0 , 650 ,360 , mdc , 0 ,0 ,SRCCOPY );

	SelectObject(mdc , dra);
	BitBlt(hdc , xstart , ystart , 120 , 128 , mdc , 0 , 0 , SRCCOPY);
}

程序运行效果图

写到这里这篇博客也算完工了,第一次写,很多地方做的不够好,希望各位路过的看客多给我提意见。

end!

【Visual C++】游戏编程学习笔记之一:五毛钱特效之透明和半透明处理的更多相关文章

  1. 【Visual C++】游戏编程学习笔记之四:透明动画实现

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...

  2. 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  3. 【Visual C++】游戏编程学习笔记之七:键盘输入消息

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  4. 【Visual C++】游戏编程学习笔记之六:多背景循环动画

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44264153 作者:ZeeCod ...

  5. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  6. DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  7. 【Visual C++】游戏编程学习笔记之五:单一背景滚动

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...

  8. 【Visual C++】游戏编程学习笔记之三:游戏循环的使用

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44208419 作者:Zee ...

  9. 【Visual C++】游戏编程学习笔记之九:回合制游戏demo(剑侠客VS巡游天神)

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.com ...

随机推荐

  1. 基于BaseAdapter的Listview小Demo

    ListView是android开发中比较常用的控件, 其中适配器模式可以选择: ArrayAdapter:简单易用,通常用于将数组或者List集合的读个包值封装成多个列表项 SimpleAdapte ...

  2. Android自定义处理崩溃异常

    用过安卓手机的用户以及安卓开发者们会时长碰到程序异常退出的情况,普通用户遇到这种情况,肯定非常恼火,甚至会骂一生垃圾软件,然后卸载掉.那么开发者们在开发过程中遇到这种情况给怎么办呢,当然,你不可能世界 ...

  3. NewSQL数据库VoltDB特性简介

    VoltDB是一个革命性的新型数据库产品,被称作NewSQL数据库.它基于H-Store,号称比当前数据库产品的吞吐量高45倍,同时又具有很高的扩展性.它的特性主要有以下几点: Ø  高吞吐.低延迟: ...

  4. Dynamics CRM2013 用户进入系统所必需的那些权限

    本篇以CRM2013为例,在CRM中新建一个安全角色后该安全角色基本是空的,如果新建的安全角色作为一个账号的唯一安全角色时,那这个安全角色除了需要配置业务场景所需的权限外,是要优先具备进入CRM系统的 ...

  5. iOS下JS与OC互相调用(三)--MessageHandler

    使用WKWebView的时候,如果想要实现JS调用OC方法,除了拦截URL之外,还有一种简单的方式.那就是利用WKWebView的新特性MessageHandler来实现JS调用原生方法. Messa ...

  6. 使用Spring+Junit4.4进行测试

    http://nottiansyf.iteye.com/blog/345819 使用Junit4.4测试 在类上的配置Annotation @RunWith(SpringJUnit4ClassRunn ...

  7. 剑指Offer——网易笔试之不要二——欧式距离的典型应用

    剑指Offer--网易笔试之不要二--欧式距离的典型应用 前言 欧几里得度量(euclidean metric)(也称欧氏距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的 ...

  8. Cocos2D中Node的userObject实例变量使用时一个要注意的地方

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为us ...

  9. 02_NoSQL数据库之Redis数据库:string类型和hash类型

     Strings类型及操作 String是最简单的类型,一个key对应一个Value,String类型是二进制安全的.Redis的String可以包含任何数据,比如jpg图片或者序列化的对象. S ...

  10. HDFS追本溯源:体系架构详解

    Hadoop是一个开发和运行处理大规模数据的软件平台,是Apache的一个用Java语言实现开源软件框架,实现在大量计算机组成的集群中对海量数据进行分布式计算.用户可以在不了解分布式底层细节的情况下, ...