版本:VS2015 语言:C++
快要到9月份了,天气渐渐凉了,没有空调的我终于渐渐看到了光明。
现在书的进度进入都最后一章的Windows编程,嘛,和作者的态度差不多,Windows编程实在是枯燥乏味,但是也是必须去了解一些基础的知识,不然看到别人的程序就懵逼了。
最后一章我分为两个章节来讨论,首先是GDI图形绘制(相比于使用GPU硬件加速的D3D肯定要慢)、锁帧效果,之后是作者做的游戏控制台程序,说不定我能玩出点花样来,现在还没有看。
好了,让我们进入正题吧。
点,所有图形的基础,想要绘制一个图形就得要知道怎么绘制一个点。让我们来看看代码(代码放在GameMain函数处,不清楚的请看一下我写的Windows编程第二节,即游戏循环框架的基本实现):
HDC hdc = GetDC(hwnd); //获取图像设备表
int x = rand() % 400; //随机x、y坐标
int y = rand() % 400;
COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色
SetPixel(hdc, x, y, color); //画点!
Sleep(100);
ReleaseDC(hwnd, hdc); //释放
画点很简单吧,但是点太小了吧,根本看不清啊,来个大点的:
HDC hdc = GetDC(hwnd); //获取图像设备表
int x = rand() % 400; //随机x、y坐标
int y = rand() % 400;
COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色
int size = 4; //设置点的大小
for (int i = 0; i < size; ++i)
for (int j = 0; j < size; ++j)
SetPixel(hdc, x+i, y+j, color); //画点!
Sleep(100);
ReleaseDC(hwnd, hdc); //释放
效果:
嗯,很棒!有点了,然后就是要画线了,画线的话首先要学到一个画笔的系统,在画之前首先就要设置画笔,这跟画点有点不一样,画点什么都不用管,看代码:
int x = rand() % 400; //随机x、y坐标
int y = rand() % 400;
int x2 = rand() % 400; //随机x2、y2坐标
int y2 = rand() % 400;
COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色
HDC hdc = GetDC(hwnd); //获取图像设备表
HPEN pen = CreatePen(PS_SOLID, 1, color); //获取铅笔
SelectObject(hdc, pen); //设置铅笔
MoveToEx(hdc, x, y, NULL); //把点移动到初始点
LineTo(hdc, x2, y2); //画线!
Sleep(100);
DeleteObject(pen);
ReleaseDC(hwnd, hdc); //释放
效果:
以上就实现了画线的效果,需要注意的是画边框之类的线条结构,基本都是要设置HPEN铅笔的,而实心结构则需要设置画刷HBRUSH。
下面讲随机画矩形的示例,这边即用到了画笔画出矩形的边框,又用画刷填充矩形:
// 初始化坐标数据
int x = rand() % 400; //随机x、y坐标
int y = rand() % 400;
// 设置绘图相关数据
HDC hdc = GetDC(hwnd); //获取图像设备表
COLORREF color = RGB(rand() % 255, rand() % 255, rand() % 255); //随机来个颜色
HPEN pen = CreatePen(PS_SOLID, 1, color); //获取铅笔
SelectObject(hdc, pen); //设置铅笔
color = RGB(rand() % 255, rand() % 255, rand() % 255); //再来随个
HBRUSH brush = CreateSolidBrush(color); //获取画刷
SelectObject(hdc, brush); //设置画刷
//绘制
Rectangle(hdc, x, y, x + 10, y + 10);
Sleep(100);
//释放对象
DeleteObject(pen);
DeleteObject(brush);
ReleaseDC(hwnd, hdc);
非常好!这样我们就能随机绘制正方形了。细心的玩家可能注意到了,在设置铅笔和画刷的时候使用的函数都是一样的,都是SelectObject、DeleteObject。我想这个方法肯定不止用在这,否则也不会叫做Object了。具体我就不探究了。
什么,你想画圆?也很简单,之前不是学了画矩形嘛,在Windows中画圆其实就是绘制矩形的内切圆,参数是一模一样的,只需要把绘制矩形的代码写成:
Ellipse(hdc, x, y, x + 10, y + 10);
就是这种弧线锯齿很严重,非常想学抗锯齿的知识!
接下来是多边形,给大家一个画六边形的代码,具体更多有趣的玩法,请自己尝试尝试。
下面是代码:
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} }; //六边形的坐标
Polygon(hdc, poly, 6); //根据6个点进行绘制,注意点的顺序很有关系
把绘制矩形的代码替换成以上代码,就能获得一下效果:
其实想想看,关键绘制的代码就那么一两句,而且hdc、pen、brush之类的非常常用,所以真正编写的时候设置成全局的变量会比较舒服吧,这样实际的代码会非常的简洁,以后要改什么功能也不必关注这类初始化、销毁的细节。
最后作者问了一个问题,如果你绘制时点的顺序是混乱的,绘制多边形的时候很容易绘制出凹多边形,那么如何判断一个多边形是否是凸多边形呢?
我一开始的想法有点简单了,后来百度查了一下了解到了凸多边形的定义,就是任意两个临近的点画一条直线,所有其他的点都在直线的一侧就可以判断出是凸多边形了。
具体代码实现给大家讲一个思路,循环临近的所有两点,根据其他点的x坐标,算出临近两点画出直线对应的y坐标,这个y坐标是在直线上的,跟判断点的y坐标对比一下,看看其他的各点是否都大于(或都小于)y坐标。
最后讲一下实现锁帧的效果,当然也是GameMain处的代码:
DWORD start_time = GetTickCount(); //获取开始的时间
//画点画线的各种处理
while ((GetTickCount() - start_time) < 1000);// 延时代码
这里的代码就增强的Sleep的效果,没想到锁帧这么容易吧?
对了,突然想起来忘记比较重要的定时器了,嗯……简单介绍一下:
UNIT SetTimer(HWND hWnd, //图形设备表
UINT nIDevent, //定时器的id
UINT nElapse, //延时的毫秒数
TIMERPROC lpTimerFunc); //延时的回调函数,NULL的话默认WinProc处理
待定时完成,就会触发处理事件WinProc,事件的类型是WM_TIMER,然后根据参数wparam就能判断出定时器的id,进行相应的处理。
KillTimer(hwnd, timer)是删除定时器的函数。具体例子就不说了,其实跟cocos的schdule非常像。
简单却很重要,就是这个东西吧。