Windows编程 GDI简单图形的绘制 简单实现锁帧效果

发表于2017-11-09
评论0 1.2k浏览

现在书的进度进入都最后一章的Windows编程,嘛,和作者的态度差不多,Windows编程实在是枯燥乏味,但是也是必须去了解一些基础的知识,不然看到别人的程序就懵逼了。

 

最后一章我分为两个章节来讨论,首先是GDI图形绘制(相比于使用GPU硬件加速的D3D肯定要慢)、锁帧效果,之后是作者做的游戏控制台程序,说不定我能玩出点花样来,现在还没有看。

 

好了,让我们进入正题吧。

 

点,所有图形的基础,想要绘制一个图形就得要知道怎么绘制一个点。让我们来看看代码(代码放在GameMain函数处,不清楚的请看一下我写的Windows编程第二节,即游戏循环框架的基本实现):

  1. HDC hdc = GetDC(hwnd);  //获取图像设备表  
  2. int x = rand() % 400;   //随机x、y坐标  
  3. int y = rand() % 400;  
  4. COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色  
  5. SetPixel(hdc, x, y, color); //画点!  
  6. Sleep(100);  
  7. ReleaseDC(hwnd, hdc);   //释放  

画点很简单吧,但是点太小了吧,根本看不清啊,来个大点的:

  1. HDC hdc = GetDC(hwnd);  //获取图像设备表  
  2. int x = rand() % 400;   //随机x、y坐标  
  3. int y = rand() % 400;  
  4. COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色  
  5. int size = 4;   //设置点的大小  
  6. for (int i = 0; i < size;  i)  
  7.     for (int j = 0; j < size;  j)  
  8.         SetPixel(hdc, x i, y j, color); //画点!  
  9. Sleep(100);  
  10. ReleaseDC(hwnd, hdc);   //释放  

效果:



嗯,很棒!有点了,然后就是要画线了,画线的话首先要学到一个画笔的系统,在画之前首先就要设置画笔,这跟画点有点不一样,画点什么都不用管,看代码:

  1. int x = rand() % 400;   //随机x、y坐标  
  2. int y = rand() % 400;  
  3. int x2 = rand() % 400;  //随机x2、y2坐标  
  4. int y2 = rand() % 400;  
  5. COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色  
  6.   
  7. HDC hdc = GetDC(hwnd);  //获取图像设备表  
  8. HPEN pen = CreatePen(PS_SOLID, 1, color);   //获取铅笔  
  9. SelectObject(hdc, pen); //设置铅笔  
  10.               
  11. MoveToEx(hdc, x, y, NULL);  //把点移动到初始点  
  12. LineTo(hdc, x2, y2);    //画线!  
  13.   
  14. Sleep(100);  
  15.   
  16. DeleteObject(pen);  
  17. ReleaseDC(hwnd, hdc);   //释放  

效果:



以上就实现了画线的效果,需要注意的是画边框之类的线条结构,基本都是要设置HPEN铅笔的,而实心结构则需要设置画刷HBRUSH。

 

下面讲随机画矩形的示例,这边即用到了画笔画出矩形的边框,又用画刷填充矩形:

  1. // 初始化坐标数据  
  2. int x = rand() % 400;   //随机x、y坐标  
  3. int y = rand() % 400;  
  4.   
  5. // 设置绘图相关数据  
  6. HDC hdc = GetDC(hwnd);  //获取图像设备表  
  7.   
  8. COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色  
  9. HPEN pen = CreatePen(PS_SOLID, 1, color);   //获取铅笔  
  10. SelectObject(hdc, pen); //设置铅笔  
  11.   
  12. color = RGB(rand() % 255, rand() % 255, rand() % 255);  //再来随个  
  13. HBRUSH brush = CreateSolidBrush(color); //获取画刷  
  14. SelectObject(hdc, brush);   //设置画刷  
  15.   
  16. //绘制  
  17. Rectangle(hdc, x, y, x   10, y   10);  
  18.   
  19. Sleep(100);  
  20.   
  21. //释放对象  
  22. DeleteObject(pen);  
  23. DeleteObject(brush);  
  24. ReleaseDC(hwnd, hdc);  

非常好!这样我们就能随机绘制正方形了。细心的玩家可能注意到了,在设置铅笔和画刷的时候使用的函数都是一样的,都是SelectObject、DeleteObject。我想这个方法肯定不止用在这,否则也不会叫做Object了。具体我就不探究了。

 

什么,你想画圆?也很简单,之前不是学了画矩形嘛,在Windows中画圆其实就是绘制矩形的内切圆,参数是一模一样的,只需要把绘制矩形的代码写成:

  1. Ellipse(hdc, x, y, x   10, y   10);  

就是这种弧线锯齿很严重,非常想学抗锯齿的知识!

 

接下来是多边形,给大家一个画六边形的代码,具体更多有趣的玩法,请自己尝试尝试。

 

下面是代码:

  1. POINT poly[6] = { {x   10, 0   y}, {x   30, 0   y}, {x   40, 17.3   y}, {x   30, 34.6   y}, {x   10, 34.6   y}, {x   0, 17.3   y} };    //六边形的坐标  
  2. Polygon(hdc, poly, 6);  //根据6个点进行绘制,注意点的顺序很有关系  


把绘制矩形的代码替换成以上代码,就能获得一下效果:



其实想想看,关键绘制的代码就那么一两句,而且hdc、pen、brush之类的非常常用,所以真正编写的时候设置成全局的变量会比较舒服吧,这样实际的代码会非常的简洁,以后要改什么功能也不必关注这类初始化、销毁的细节。

 

最后作者问了一个问题,如果你绘制时点的顺序是混乱的,绘制多边形的时候很容易绘制出凹多边形,那么如何判断一个多边形是否是凸多边形呢?

 

我一开始的想法有点简单了,后来百度查了一下了解到了凸多边形的定义,就是任意两个临近的点画一条直线,所有其他的点都在直线的一侧就可以判断出是凸多边形了。

 

具体代码实现给大家讲一个思路,循环临近的所有两点,根据其他点的x坐标,算出临近两点画出直线对应的y坐标,这个y坐标是在直线上的,跟判断点的y坐标对比一下,看看其他的各点是否都大于(或都小于)y坐标。

 

最后讲一下实现锁帧的效果,当然也是GameMain处的代码:

  1. DWORD start_time = GetTickCount();  //获取开始的时间  
  2. //画点画线的各种处理  
  3. while ((GetTickCount() - start_time) < 1000);// 延时代码  

这里的代码就增强的Sleep的效果,没想到锁帧这么容易吧?

 

对了,突然想起来忘记比较重要的定时器了,嗯……简单介绍一下:

  1. UNIT SetTimer(HWND hWnd,    //图形设备表  
  2. UINT nIDevent,  //定时器的id  
  3. UINT nElapse,   //延时的毫秒数  
  4. TIMERPROC lpTimerFunc); //延时的回调函数,NULL的话默认WinProc处理  

待定时完成,就会触发处理事件WinProc,事件的类型是WM_TIMER,然后根据参数wparam就能判断出定时器的id,进行相应的处理。

 

KillTimer(hwnd, timer)是删除定时器的函数。具体例子就不说了,其实跟cocos的schdule非常像。

 

简单却很重要,就是这个东西吧。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引