Windows游戏编程复习--2

感谢毛星云先生的书籍,让我对Windows不理解的地方又更深入的理解了!

游戏随机数系统初步:

srand rand() 这两个简单的函数咱们在这里 简单地提一下
一般咱们玩过传奇 地下城与勇士 魔兽世界的朋友肯定都知道 爆装备 其实就是一个取随机数的概念
一个游戏 或大或小都有很多的算法来支持我们游戏的运作 一般玩游戏的人只会在乎 游戏的华丽 可玩性
而不知道这些光鲜 华丽的东西的背后有一个东西是最为重要的 那就是算法 当然我不会在这边多提算法的问题


当然在我以前接触游戏时候 用过很多种方法来开 爆出好东西 现在想想好傻 哈哈 就以前的事情 算了不提了
学过c语言的肯定都知道随机数函数 和取随机数种子
srand() 和 rand()这里我来简单介绍一下吧 不管你有没有学过 或者 接触过那么都可以再看一遍


首先我们看看函数原型的声明 
int rand(void); void表示调用的时候不用设置参数 直接这样写即可 在用此函数需要包含 time.h
比如 rand();
PS:rand函数其实用的是线性同余法  他不是真的随机数 但是你可以把它看成随机数
在未声明随机数种子的时候 系统都会默认为1
rand()产生伪随机数 如果不用srand 去初始化 就会被我们看做不会变的,每一次使用srand 他的随机数序列
都会不一样
如果我们想写一个0 - 10中取随机数的话可以这样写
int a = rand() % 11; 这样写是没有问题的 但是我们每次运行的时候a都是一个值 为什么呢?
因为我们没有给他设置随机数种子 那么怎么设置 srand(unsigned(time(0)));


好了 随机数讲完了,其实也没啥子好讲的;只需要大家记住:
计算机的伪随机数是由随机数种子根据一定的计算方法计算出来的数值,所以只要计算方法一定 
随机种子一定的话 那么产生的随机数就是固定的


第三方不设置随机种子的话 那么沉默的种子为0


那么相信大家坚持看到我这里的朋友肯定有抱着学下去的信心 和 意志,那么加油 这才是windows编程的一
小步 我们一起学习


我们来复习一下文字的输出 TextOut函数
讲到TextOut函数 我就想到我当时学到这里的时候 感觉字体好丑,嫌弃 后来学到后面才知道可以修改。
首先TextOut函数讲解一下简单来说就是设置 x y 坐标然后 输出字符串
PS:以后的代码我都会用MSDN来查原型 然后一个一个来解释
BOOL TextOut(
  HDC hdc,           // handle to DC
  int nXStart,       // x-coordinate of starting position
  int nYStart,       // y-coordinate of starting position
  LPCTSTR lpString,  // character string
  int cbString       // number of characters
);
第一个参数需要数据的DC句柄
第二个参数是开始书写字符串的左上角x坐标
第三个参数是开始书写字符串的左上角y坐标
第四个参数是指向字符串的指针 因为字符串本身就是指针 所以可以直接填写
第五个参数是字符串自己字符数 就是他的大小(中文占两个字节 英文占一个字节
 又分全角半角有疑问百度!)


TextOut(dc,100,100,"你好呀,c语言",12);
(解析代码 在x为100 y为100的位置输出 "你好呀,c语言" 这个字符串的长度是12)


接下来再讲一下取字符串长度 因为有时候我们不知道他的长度为多少 所以我们要用下面的函数
sizeof :取得字符串的字节长度,包含 '/0'。
strlen:取得多字节字符串中字符长度,不包含 '/0'。
wcslen:取得宽字节字符串中字符长度,不包含 '/0'。
tcslen:取得宽字节/多字节字符串中字符长度,不包含 '/0'。




打印出来的东西很丑 我也觉得 当然我接下来学习一下 设置文本颜色 SetTextColor
COLORREF SetTextColor(
  HDC hdc,           // handle to DC
  COLORREF crColor   // text color
);
第一个参数是当前dc句柄
第二个参数是需要填写的颜色 咱们一般用RGB宏来写


SetTextColor(dc,RGB(0,255,0)); 
设置字体颜色为绿色 RGB(r,g,b); 不理解的同学去看看画图的调色盘就能理解




打印出来的东西依旧很丑 但是比我们第一次打印的TextOut好看多了 不是吗 我们发现打印出来的东西有背景
会有点不美观 所以我们要设置文字背景透明 所以我们接下来学习的就是SetBkMode函数


int SetBkMode( 
 HDC hdc,      // handle to DC 
 int iBkMode   // background mode
);
第一个参数是咱们当前dc句柄
第二个参数是咱们需要设置的int类型的变量 (可取值范围是宏 OPAQUE 和 TRANSPARENT)
OPAQUE 是表示当前背景的画刷的颜色输出显示文字的背景
TRANSPARENT 是使用透明 文字的背景颜色是不改变的。


一般这种代码在初始化的时候调用一次即可 后面咱们使用都是透明的了。


接下来讲一下CreateFont函数 这个是咱们设置字体的函数了,你看着确实比最开始好多了 但是
字体咱们一定要设置一下 和 咱们沉默的肯定要不一样一些!
HFONT CreateFont(
  int nHeight,               // height of font
  int nWidth,                // average character width
  int nEscapement,           // angle of escapement
  int nOrientation,          // base-line orientation angle
  int fnWeight,              // font weight
  DWORD fdwItalic,           // italic attribute option
  DWORD fdwUnderline,        // underline attribute option
  DWORD fdwStrikeOut,        // strikeout attribute option
  DWORD fdwCharSet,          // character set identifier
  DWORD fdwOutputPrecision,  // output precision
  DWORD fdwClipPrecision,    // clipping precision
  DWORD fdwQuality,          // output quality
  DWORD fdwPitchAndFamily,   // pitch and family
  LPCTSTR lpszFace           // typeface name
);
不要看这个东西有点多 我们一定可以克服  来吧和我一起
第一个参数字体的逻辑高度
第二个参数字体的逻辑宽度
第三个参数字体显示的角度
第四个参数字体的角度
第五个参数 字体磅数
第六个参数 是否为斜字体
第七个参数是否带下划线
第八个参数是否带删除线
第九个参数搜徐字符集 一般填写GB2312_CHARSET
第十个参数输出的精度
第十一个参数裁剪的精度
第十二个参数输出的质量
第十三个参数字体的间距的字符集
第十四个参数字体名称 


哇写了这么多大家肯定不明白什么意思 看我怎么用这个函数
HFONT hfont =  CreateFont(45,0,0,0,0,0,0,0,GB2312_CHARSET,0,0,0,0,("微软雅黑"));
以为设置好了就完了? 其实不是 还有SelectObject(dc,hfont); 将字体推入选入设备环境中 这样才可以


接下来用一下这个
HFONT hfont =  CreateFont(45,0,0,0,0,0,0,0,GB2312_CHARSET,0,0,0,0,("微软雅黑"));
SelectObject(dc,hfont);
SetTextColor(dc,RGB(100,255,100));
SetBkMode(dc,TRANSPARENT);
TextOut(dc,100,100,"123abc你好",10);
首先设置了字体为微软雅黑 高度为45
将他推入字体 
设置字体的颜色
设置透明  这样咱们字体是不是很好看了?


位图绘制基础 总于到了咱们图片的加载了,一般游戏都是有图片的
位图加载需要有四个步骤
第一步 加载位图 从文件中加载位图对象
第二步 建立兼容DC 建立一个与窗口环境DC兼容的内存设备环境DC
第三步 选用位图对象 内存DC使用步骤1中所建立的位图对象
第四步 将内存DC的内容贴到窗口DC中


咱一步一步来说 一步一步来说 关键字Load加载
一般我们都是从文件加载位图 使用的是LoadImage函数
LoadImage 不只是可以加载位图 也可以加载 光标 图标 等图像资源


HANDLE LoadImage(HINSTANCE hinst,
    LPCTSTR lpszName,
    UINT uType,
    int cxDesired,
    int cyDesired,
    UINT fuLoad
);
第一个参数 是HINSTANCE类型的hinst  被包含加载图像的模型的实例句柄 一般填NULL
第二个参数是 资源文件所在的路径和文件名或资源 一般在.vcproj为根路径 进行填充
第三个参数是 加载资源的类型 一般有三种 IMAGE_BITMAP 加载位图文件(.bmp) IMAGE_CUSOR 加载光标(.cur) 
IMAGE_ICON 加载图标(.ico)
第四个参数是 内存中的存储宽度 一般填0 表示整个图片的宽
第五个参数是 内存中的存储高度 一般也填0 表示整个图片的高
第六个参数UNIT类型的fuLoad 若是位图加载方式 则设置为LR_LOADFROMFILE


调用一个实例:
HBITAMP g_hBitmap = (HBITAMP)LoadImage(NULL,"位图名字.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
把位图加载入 g_hBitmap 加入句柄中 高和宽都是原图的高宽 


第二步是建立兼容设备DC
关键字兼容 Compatible
为了绘制出位图,我们需要创建一个和设备环境兼容的内存设备环境 这样才会有暂时存放位图对象的地方
一会我们就用SelectObject函数选入到内存设备环境中 然后再用贴图函数 把内存设备环境中的内容贴到
设备环境中。我们通常吸怪吧内存设备环境的叫做内存DC
内存DC只是起一个中转的作用 暂时储存加载好的位图 最后把这个暂存的DC贴到真正的DC上 所以DC要和窗口
DC做到无缝衔接 在属性和性质上面兼容,在GDI中 一般我们调用CreateCompatible()函数来建立内存DC
HDC CreateCompatibleDC(__in HDC hdc); 创建与窗口DC兼容的内存DC


唯一的一个参数 HDC类型的hdc 填需要与内存DC兼容目的DC的句柄,如果这个句柄为NULL CreateCompatibleDC
函数讲创建一个与运用程序使用的当前显示器相兼容的内存 设备的上下文环境跟窗口DC(HDC)一样内存DC
使用后需要调用DeleteDC() 而不是releaseDc()


BOOL DeleteDC(  HDC hdc   // handle to DC);
填入我们加载的DC句柄 GetDC函数得到的 程序是不能使用DeleteDC删除该设备上下文环境 
他应该调用ReleaseDC


第三步是咱们选用位图对象
选用位图对象 关键字Select
GDI中一般采用SelectObject(); 以前讲过所以不再赘述


第四步进行贴图 关键字 Bitblt()
前面三步都是在为这一步做准备 我们将内存DC复制到设备DC上面 这就实现了绘图的效果
绘图的函数很多 比如Bitblt()  TransparentBlt()


BOOL BitBlt(
  HDC hdcDest, // handle to destination DC
  int nXDest,  // x-coord of destination upper-left corner
  int nYDest,  // y-coord of destination upper-left corner
  int nWidth,  // width of destination rectangle
  int nHeight, // height of destination rectangle
  HDC hdcSrc,  // handle to source DC
  int nXSrc,   // x-coordinate of source upper-left corner
  int nYSrc,   // y-coordinate of source upper-left corner
  DWORD dwRop  // raster operation code
);
第一个参数 HDC类型的设备DC句柄
第二个参数int类型的左上角X轴坐标
第三个参数int类型的左上角Y轴坐标
第四个参数int类型的原矩形的区域逻辑宽度
第五个参数int类型的原矩形的区域逻辑高度
第六个参数HDC类型的 环境句柄 就是后备的DC
第七个参数int类型的原矩形区域左上角的X轴逻辑坐标
第八个参数int类型的原矩形区域左上角的Y轴逻辑坐标
第九个参数DWORD类型的dwrop 指定光栅操作代码 即贴图的方式常用的是SRCCOPY
SRCCOPY(将原矩形区域直接拷贝到目标矩形区域)
SRCAND(通过AND操作符来将原和目标矩形区域内的颜色合并)  其他见MSDN 或者 其他资料


实例:
BitBlt(dc,0,0,800,600,g_dc,0,0,SRCCOPY);
g_dc表示后备dc  dc表示环境dc 从0 0点开始画800 600大小的矩形


四步一起做:
g_bitdc = (HBITMAP)LoadImage(NULL,"a.bmp",WMAGE_BITMAP,640,480,LP_LOADFROMFILE);加载位图
g_dc = CreateCompaatibleDC(g_hdc);创建兼容设备环境内存dc
SeleteObject(g_hdc,g_bitdc);将位图对象选入到g_dc内存dc中
BitBlt(g_hdc,0,0,640,480,g_dc,0,0,SRCCOPY);
这样就能把a.bmp这张图 绘制在客户区的0 0点坐标 大小是640 480


学习了BitBlt这个函数 咱们一般用这个来做地图背景的操作 因为我们不涉及到透明 如果有游戏元素(
比如 英雄 道具 技能 NPC这种咱们一般不用这个函数) 因为 人物贴图他是有背景的如果我们用的话他,
不会透明 看起来肯定就不好看,但是BltBit不是不能做这样的一个操作 
所以我们要学习另外一个函数叫做 TransparentBlt() 原型如下


BOOL TransparentBlt(
  HDC hdcDest,        // handle to destination DC
  int nXOriginDest,   // x-coord of destination upper-left corner
  int nYOriginDest,   // y-coord of destination upper-left corner
  int nWidthDest,     // width of destination rectangle
  int hHeightDest,    // height of destination rectangle
  HDC hdcSrc,         // handle to source DC
  int nXOriginSrc,    // x-coord of source upper-left corner
  int nYOriginSrc,    // y-coord of source upper-left corner
  int nWidthSrc,      // width of source rectangle
  int nHeightSrc,     // height of source rectangle
  UINT crTransparent  // color to make transparent
);
我们在贴图时 需要事先把我们需要透明的颜色填充为某种颜色 和RGB相近 接下来解释一下这个代码
第一个参数 目标设备环境句柄
第二个参数 目标矩形左上角的X轴坐标
第三个参数 目标矩形左上角的Y轴坐标
第四个参数 目标矩形的宽度
第五个参数 目标矩形的高度
第六个参数 原设备环境的句柄
第七个参数 原矩形的左上角X轴坐标
第八个参数 原矩形的左上角Y轴坐标
第九个参数 原矩形的宽度
第十个参数 原矩形的高度
第十一个参数 指定为透明色的RGB颜色值


TransparentBlt 实例:
TransparentBlt(g_hdc,100,100,350,350,g_mdc,0,0,350,350,RGB(0,0,0));
注意在添加使用TransparentBlt函数的时候需要包含Msimg32.lib库,前面章节讲过怎么包含音乐的库 所以
这里不再赘述


这里还有很多东西我就跳过不讲了讲了几个简单的- - 确实自己没耐心写 太多了,所以咱们直接跳过


windows动画技术 讲解  定时器  前面咱们讲解的全是WM_PAINT消息 现在我们讲一下WM_TIMER消息
首先我们来认识一下WM_TIMER消息
定时器也有三步需要操作的东西我们来解析一下:
第一步 创建定时器
第二步 边写WM_TIMER代码
第三步 删除定时器


第一步 创建定时器 SetTimer函数
UINT_PTR SetTimer(HWND hWnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC lpTimerFunc
);
为窗口创建一个定时器
第一个参数 HWND的hwnd 接受定时器消息的窗口句柄
第二个参数 定时器的代号 值不能为0
第三个参数 UINT类型的uelapse 以毫秒为单位 设置为1000 则为1秒 发出一个WM_TIMER消息
第四个参数 一般设置为NULL


实例:
SetTimer(hwnd,1,1000,NULL);
创建一个每个一秒发出WM_TIMER消息且不设定响应函数的定时器


第二步 写出定时器所需要干的事情


第三步 销毁定时器 KillTimer


BOOL KillTimer(HWND hWnd,
    UINT_PTR uIDEvent
);
第一个参数 hwnd类型的hwnd 我们的窗口句柄
第二个参数是UINT_PTR类型的uIDEvent 我们想删除的定时器代号


定时器不是异步,因为定时器使用硬件定时器终端 有人会产生误解 会认为程序会异步地被中断来处理
然而并不是异步的 因为他和其他的消息一样 是和其他消息排列在一起 队列中 因此SetTimer呼叫中不
能保证程序每隔1000毫秒 或者 999毫秒都会受到一个WM_TIMER消息 如果其他程序执行超过一秒我们则、
接收不到任何的WM_TIMER消息



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值