消灭星星游戏程序设计【连载四】——图片的移动

消灭星星游戏程序设计【连载四】——图片的移动

大家每次都可以在页面中下载本节内容的实现代码,一步一步从简单开始,逐步完成游戏的各种功能,如果大家有任何问题也欢迎留言交流。

游戏整体效果展示:

在这里插入图片描述

1、图片可以开始动起来了

我们在前边讲过在游戏程序中显示出漂亮的图片的方法,游戏画面好看多了。但是,我们显示的图片是静止不动的,如果图片能够动起来,是不是会有更好的效果呢。我们能不能让图片动起来呢?

在这里插入图片描述

我们现在就来尝试一下。聪明的你一定会想到,我们只需要改变一下图片显示代码中的指定位置,图片应该就能够移动了。对了就是这样,我们这里尝试让图片跟随鼠标坐标位置的移动而移动,来感受一下效果。但首先,我们要怎样才能获取鼠标坐标位置呢,获取鼠标位置的方法不止一种,这里为了方便演示,我们采用一种特殊的方式,这种方式可以随时随地获取鼠标的位置,并将位置保存到POINT变量中。

	//用于保存鼠标位置
	
	POINT tempCursorPos;

	//获取鼠标在显示器屏幕中的位置
	
	GetCursorPos(&tempCursorPos);

	//鼠标屏幕位置转换为程序内位置
	
	ScreenToClient(hWnd,&tempCursorPos);

同时,将我们要显示图片的显示位置修改为刚刚获获取的鼠标位置,就能达到图片随鼠标移动的效果。你只需要在显示图片时,将TransparentBlt函数的第2个和第3个参数修改为鼠标的坐标位置tempCursorPos.x和tempCursorPos.y即可。

		//显示图片

		if(true)
		{

			//获取图像大小信息
			
			BITMAP BM;
			
			GetObject(hPopStar,sizeof(BITMAP),&BM);

			//显示图像
			
			HDC hTemDC=CreateCompatibleDC(hDC);
			
			SelectObject(hTemDC,hPopStar);
			
			//TransparentBlt(hDC,165-BM.bmWidth/2,100,BM.bmWidth,BM.bmHeight,hTemDC,0,0,BM.bmWidth,BM.bmHeight,RGB(0,0,0));
			
			TransparentBlt(hDC,tempCursorPos.x,tempCursorPos.y,BM.bmWidth,BM.bmHeight,hTemDC,0,0,BM.bmWidth,BM.bmHeight,RGB(0,0,0));
			
			DeleteDC(hTemDC);

		}

但我们一定要注意,需要在WM_MOUSEMOVE消息处理中加入重新绘制窗口的命令,否则窗口不重绘就无法看到图片移动的效果。(这里需要注意,我们在WM_MOUSEMOVE中添加InvalidateRect刷新操作只是临时操作,后期添加完定时器后必须删除,否则会出现卡顿)

	case WM_MOUSEMOVE:

		//当鼠标移动式刷新窗口内容

		InvalidateRect(hWnd,NULL,false);

		return 0;

2、图片的移动效果出乎我们的意料

修改后运行了一下效果,我们发现图片是可以跟随鼠标移动了,但移动后的效果出乎我们的意料,图片的残影很快覆盖了整个窗口屏幕,这不是我们想要的结果,我们想要的只是在鼠标旁边只显示一个图片(说句题外话,这残影的效果还是挺不错的),效果图如下:

在这里插入图片描述
移动后会在程序界面内留下残影,这显然并不是我们想要的效果。发生这样的情况,主要是由于图片每次移动到新的位置后,原来位置上的图片并没有擦除掉,这需要我们对原来位置上的图片进行手动擦除。

3、图片残影的解决办法

我们可以将图片原来显示位置的区域用黑色进行擦除,这样就能始终保存画面的清洁,只在图片的最新位置显示图片。但由于我们这里是一个小游戏,为了方便操作,我们在每一帧窗口重新绘制前,将整个屏幕用黑色进行擦除,会简单很多。如果朋友们有需要逐个擦除的需求,可以自行进行相应处理,此处就不再研究。

解决办法是我们需要在WM_PAINT消息开始处理所有绘图前,用黑色擦除程序界面。

			RECT tempClientRect;

			GetClientRect(hWnd,&tempClientRect);
			
			//用黑色擦除整个屏幕
			
			BitBlt(hDC,0,0,tempClientRect.right,tempClientRect.bottom,NULL,0,0,BLACKNESS);

处理后显示界面恢复了正常,图片已经能够跟随鼠标移动正确的显示出来了。

在这里插入图片描述

4、又出现了问题,屏幕偶尔会出现闪烁

当图片跟随鼠标快速移动时,有没有感觉屏幕中的图片或文字会偶尔出现闪烁的问题,这种情况我们必须要进行处理,否则游戏的体验感会下降很多。

这主要时由于窗体在响应WM_PAINT消息的时候,要进行复杂的图像处理,重绘时由于过频的刷新操作而引起的闪烁现象。

5、屏幕闪烁的解决办法

这里需要使用双缓冲技术解决这个问题。我理解双缓冲技术相当于把原来直接在屏幕hDC上绘制各种图像的方式,改变成先在兼容的hMemDC中绘制各种图像,绘制完毕再直接将hMemDC整屏复制到用户屏幕hDC上,具体使用双缓冲的整个步骤大致如下:

(1)、定义内存hMemDC设备
(2)、创建并加载与原屏幕兼容的hMemDC设备
(2)、将所有绘图由原来的hDC设备变更为在hMemDC设备中绘制
(3)、在hMemDC设备中绘制完毕后,将hMemDC中的图像整屏复制到hDC设备中

完成以上操作后,图形绘制时屏幕没有任何闪烁。添加双缓存方案后整个WM_PAINT内的代码修改如下:

	case WM_PAINT:

		PAINTSTRUCT	PS;	

		hDC=BeginPaint(hWnd,&PS);
		
		//刷新整个程序界面
		
		if(true)
		{			

			//获取窗口大小
			
			RECT tempClientRect;
			
			GetClientRect(hWnd,&tempClientRect);

			//双缓冲后每次创建的兼容设备都是初始化黑色平面,无需在手动重绘黑色,后续删除
			
			//BitBlt(hDC,0,0,tempClientRect.right,tempClientRect.bottom,NULL,0,0,BLACKNESS);

			//创建与原窗口兼容位图
			
			HBITMAP hMemBM=CreateCompatibleBitmap(hDC,tempClientRect.right,tempClientRect.bottom);
			
			//创建与原窗口兼容的DC设备

			HDC hMemDC=CreateCompatibleDC(hDC);

			//将位图载入内容DC设备
			
			SelectObject(hMemDC,hMemBM);
			
			//这里添加文字和图片
			
			if(true)
			{
				
				char szTemp[1024]="PopStar";
				
				SetTextColor(hMemDC,RGB(255,0,0));
				
				TextOut(hMemDC,10,10,szTemp,strlen(szTemp));
				
			}
			
			if(true)
			{
				
				char szTemp[1024]="PopStar";
				
				RECT tempRect={10,30,100,50};
				
				SetTextColor(hMemDC,RGB(255,0,0));
				
				DrawText(hMemDC,szTemp,strlen(szTemp),&tempRect,DT_LEFT);
				
			}
						
			//用于保存鼠标位置
			
			POINT tempCursorPos;
			
			//获取鼠标在显示器屏幕中的位置
			
			GetCursorPos(&tempCursorPos);
			
			//鼠标屏幕位置转换为程序内位置
			
			ScreenToClient(hWnd,&tempCursorPos);
			
			//显示图片
			
			if(true)
			{
				
				//获取图像大小信息
				
				BITMAP BM;
				
				GetObject(hPopStar,sizeof(BITMAP),&BM);
				
				//显示图像
				
				HDC hTemDC=CreateCompatibleDC(hDC);
				
				SelectObject(hTemDC,hPopStar);
				
				//TransparentBlt(hDC,165-BM.bmWidth/2,100,BM.bmWidth,BM.bmHeight,hTemDC,0,0,BM.bmWidth,BM.bmHeight,RGB(0,0,0));
				
				TransparentBlt(hMemDC,tempCursorPos.x,tempCursorPos.y,BM.bmWidth,BM.bmHeight,hTemDC,0,0,BM.bmWidth,BM.bmHeight,RGB(0,0,0));
				
				DeleteDC(hTemDC);
				
			}
			
			//这里添加文字和图片
			
			BitBlt(hDC,0,0,tempClientRect.right,tempClientRect.bottom,hMemDC,0,0,SRCCOPY);
			
			//删除兼容DC设备
			
			DeleteDC(hMemDC);
			
			//删除位图资源
			
			DeleteObject(hMemBM);
			
		}

		ReleaseDC(hWnd,hDC);				

		return 0;

6、小结

完成以上图片的移动后,游戏界面已经不在那么生硬了,具有一定的互动性。同时在解决了图片的显示问题后,游戏初期的基础工作已经铺垫完成,后续继续完善游戏内容。如果大家有任何问题也欢迎留言交流。

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhooyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值