《Windows游戏编程大师技巧》三、Windows高级编程


Windows编程很绝的地方在于:你不用了解太多细节,就可以完成很多工作。

使用资源

资源就是你的程序代码结合在一起的多块数据,可以被程序本身在运行时加载。
资源应当也放在程序的.EXE文件中的原因是:

1.同时包含代码和数据的.EXE文件更容易发布。
2.外力不容易任意删改程序的数据文件(如.BMP和.WAV文件)。

对于想编译进程序中的数据类型没有限制,下列这些预定义的资源类型就可以
满足大部分需要:

图标 - 小的位图文件
光标 - 鼠标指针的位图
字符串 - 可以硬编码在代码中,也可以集中放在这
声音 - 大部分Windows程序都使用.WAV格式
位图 - 这是标准的位图,使用.BMP扩展名
对话框 - 也可以作为资源来存储
图元 - 一系列图像操作记录的回放



要添加资源文件,必须有一个以ASCII形式的资源描述文件.RC。编译过程如下:



下面是如何在.RC脚本文件中定义一个ICON资源:

windowicon ICON star.ico (使用字符串)
124 ICON ship.ico          (使用数字)

使用字符串定义时会产生歧义,windowicon可能是个字符串也可能是个#define定义的符号常量。
所以还需要一个.H文件来解析符号索引。

RESOURCES.H的内容:

#define ID_ICON1 100
#define ID_ICON2 101
#define ID_ICON3 102

RESOURCES.RC的内容:

#include "RESOURCES.H"

ID_ICON1 ICON star.ico
ID_ICON2 ICON ball.ico
ID_ICON3 ICON cross.ico

现在,将RESOURCES.RC和.ICO文件添加到工程,并在程序中#include RESOURCES.H。
若使用字符串定义,则:winclass.hIcon = LoadIcon(hInstance, "icon_name");
若使用符号索引,则:winclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON1));
注意第一个参数不再是NULL而是hInstance。

其他资源也都是类似这样定义和使用的。
光标:LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));
字符串表:LoadString(hInst, IDS_STRING109, string3, 20);


GDI简介

应该了解GDI,以便知道如何在不使用DirectX的情况下如何在Windows环境绘制各种图形。
而理解WM_PAINT消息对于标准的GDI图形和Windows编程来讲是非常重要的,因为大部分
Windows程序的显示都围绕该消息。例外是游戏编程中DirectDraw或Direct3D负责图形绘制。

PAINTSTRUCT ps;     // used in WM_PAINT
HDC hdc;                 // handle to a device context
case WM_PAINT:
{
// simply validate the window
hdc = BeginPaint(hwnd, &ps);
// do all your painting here
EndPaint(hwnd, &ps);
// return success
return (0);
}

参看下面图示,当一个窗口被移动、改变大小或被其他窗口“弄脏”时,该窗口的用户区的
部分或全部需要重画。这时,WM_PAINT消息就被发送了。



对BeginPaint()和EndPaint()函数的调用可以完成一系列任务。首先,它们使用户区有效;
其次,它们用该窗口创建时参照的Windows类中定义的背景刷来填充该窗口的背景。

你只能访问实际上需要刷新的该窗口用户区的一部分。无效矩阵区域的坐标都保存在
BeginPaint()函数返回值PAINTSTRUCT的rcPaint字段中。如果要访问整个用户区的话,
这就是一个问题。解决方法是通过GetDC()直接获得图形设备描述表。

但BeginPaint()-EndPaint()会向Windows发消息指示窗口有效,而GetDC()-ReleaseDC()不会,
所以WM_PAINT消息将一直不停地传递下去,因为必须使该窗口有效。因此在ReleaseDC()
后还要调用ValidateRect()。

PAINTSTRUCT ps;
HDC hdc;
RECT rect;
case WM_PAINT:
{
// simply validate the window
hdc = GetDC(hwnd);
// do all your painting here
ReleaseDC(hwnd, hdc);
// get client rectangle of window
GetClientRect(hwnd, &rect);
// validate window
ValidateRect(hwnd, &rect);
// return success
return(0);
}

注意GetClientRect是用来获取用户矩形区域的坐标。每个窗口都有两套坐标系:
Windows坐标系和用户坐标系。区别见下图:



你很可能会说:“非得这么麻烦吗”是的,非得如此,因为这是Windows。哈哈!
本书的大多数例程里,将在WM_PAINT消息以外的地方使用GetDC()-ReleaseDC(),
BeginPaint()-EndPaint()只用于WM_PAINT消息句柄中。


基本文本显示

Windows有最复杂且最强悍的文本渲染系统。当实际运用在实时游戏中时,用GDI文本
引擎输出文本就显得太慢了,还是要亲手设计基于DirectX的文本引擎。但先了解下有助于
调试和输出。

输出文本有两个常用函数:TextOut()和DrawText()。TextOut()是一个寒酸的文本输出函数,
而DrawText()则像凌志汽车一样豪华。我经常使用TextOut()因为它运行比较快。

case WM_PAINT: {
               hdc = BeginPaint (hwnd, &ps) ;
               GetClientRect (hwnd, &rect) ;
                  
               char buffer[50];
               static int counter = 0;
               sprintf(buffer, "WM_PAINT called %d times ", ++counter);
               TextOut(hdc, rect.left, rect.top, buffer, strlen(buffer));

               DrawText (hdc, TEXT (“Hello text”), -1, &rect,
                    DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;               

               EndPaint (hwnd, &ps) ;
               return 0 ;
}

==========================================================

2012年4月22日 更新

补充学习处理重要事件:Window操作、键盘操作、鼠标操作。

1.Window操作

WM_CLOSE消息在WM_DESTROY和WM_QUIT之后发送,它表示用户正试图关闭窗口。
如果在WinProc()里仅return (0),那么用户不能关闭窗口。WM_SIZE消息对于窗口游戏
非常重要,当窗口尺寸改变时,必须调整图像显示来适应。


2.键盘操作

在Windows环境下,可以以多种方式访问键盘消息:
2.1 通过WM_CHAR消息:保存产生的ASCII码,如'a'或'A',字处理程序要关心这个。
2.2 通过WM_KEYDOWN/UP消息:保存产生的扫描码,即键盘上每一个按键的编码,
如ESC键VK_ESCAPE。游戏只需关心WASD移动,F开火而不必关心产生的是大写字符
还是小写字符,所以不必关心WM_CHAR消息。
2.3 通过调用GetAsyncKeyState():在状态表中跟踪该键的最后已知状态,使用它的
妙处是它与事件循环没有耦合,可以在任何地方测试按键。


3.鼠标操作

鼠标移动事件WM_MOUSEMOVE。lParam保存鼠标位置,wParam保存按键状态。

case WM_MOUSEMOVE:
{
int mouse_x = (int) LOWORD(lParam);
int mouse_y = (int) LOWORD(lParam);
int buttons = (int) wParam;
if (buttons & MK_LBUTTON)
...
if (buttons & MK_RBUTTON)
...
} break;

鼠标只是移动没有按键产生的事件。

case WM_LBUTTONDBLCLK:
{
int mouse_x = (int) LOWORD(lParam);
int mouse_y = (int) LOWORD(lParam);
     ...
// tell windows you handled it
return (0);
} break;


4.自行发送消息

自行传递消息有两种方法:
SendMessage()向窗口传递一个要求立即处理的消息。
PostMessage()将消息发往窗口的消息队列。

为什么要自行发送消息?因为Window的设计者希望你这样做,这也是窗口环境下的工作原理。
下一章中学习按键控件时将会看到,发送消息是和控件窗口交流的唯一途径!

转载于:https://www.cnblogs.com/xiaomaohai/archive/2012/04/18/6157844.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262786.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

结构型模式--装饰模式

下面先用java,然后用Objective-C行对装饰模式的讲解: 对于java的装饰模式讲解和使用比较详细和难度有点偏高,而对于Objective-C的装饰模式讲解和使用方面比较简单,而且和java的装饰模式略有差异&#xff0c…

ArcGIS.Server.9.2.DotNet自带例子分析(三、一)

目的: 1.arcgis server9.2 ADF的AddGraphics。 准备工作: 1.用ArcGis Server Manager或者ArcCatalog发布一个叫world的Map Service,并且把这个Service启动起来。 2.找到DeveloperKit\SamplesNET\Server\Web_Applications目录下的Common_AddGraphicsCShar…

aspose将datatable导出excel 比自己拼好的多 Bug少-。.net

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; using System.Data; using Aspose.Cells; /// <summary> ///OutFileDao 的摘要说明 /// </summary> publicclass OutFileDao { public OutFileDa…

整理:Android apk 框架 布局 集锦

2019独角兽企业重金招聘Python工程师标准>>> 看到好的技术教程就想分享一下&#xff0c;不喜勿喷&#xff01;谢谢配合&#xff0c;仅供菜鸟学习研究(^o^)/~ 友情推荐《爱加密》Android apk加密保护视频教程剪辑&#xff1a;http://www.ijiami.cn/Video?v3 Andro…

IE8不兼容你的网页 怎么办? - 简单开启兼容模式

自从用了IE8 整个世界都变了形.   呵呵,问题没那么严重,如果你的网站还来不及修改以适合IE8访问的时候,咱们可以通过非常简单的方法,加几行代码就可以让访问的IE8自动调用IE7的渲染模式[/b],这样可以保证最大的兼容性,方法如下:   只需要在页面中加入如下HTTP meta-tag:  …

springboot打war包汇总

概述 第一次用maven工具打war包&#xff0c;出现各种各样的问题&#xff0c;做个问题记录方便下次查看 maven 一开始用的maven是springboot默认的&#xff0c;在.m2下&#xff0c;要打包时才发现没有mvn指令。索性自己就重新装个maven&#xff0c;去官网下载&#xff0c;我安装…

大数据初探——Hadoop历史

Hadoop是一个开源的分布式框架&#xff0c;是Apache下的一个开源项目。Hadoop运行可以在成千上万个普通机器节点组成的集群上&#xff0c;通过分布式的计算模型和存储模型来处理大数据集。Hadoop具有高容错性、工作在普通的机器节点上扩展性强等众多的优点&#xff0c;是企业选…

BMP格式图像的显示

使用多文档编程 也可以使用单文档编程 建立一个DIB图像的显示类 ImageDib 成员变量&#xff1a; 4个指针&#xff1a; LPBYTE m_lpDib; //指向DIB的指针    LPBITMAPINFOHEADER m_lpBmpInfoHead; //图像信息头指针 LPRGBQUAD m_lpColorTable; //图像颜色表指针 …

深入A*算法

一、前言 在这里我将对A*算法的实际应用进行一定的探讨&#xff0c;并且举一个有关A*算法在最短路径搜索的例子。 二、A*算法的程序编写原理 A*算法是最好优先算法的一种。只是有一些约束条件而已。我们先来看看最好优先算法是如何编写的吧。 如图有如下的状态空间&#xff1a;…

IOS中NSUserDefaults的用法

2019独角兽企业重金招聘Python工程师标准>>> IOS中NSUserDefaults的用法&#xff08;轻量级本地数据存储&#xff09; 分类&#xff1a; IOS开发 Object&#xff0d;C编程语言2012-09-09 10:58 65223人阅读 评论(13) 收藏 举报 存储iosfloatinterfaceintegerdate NS…

【Oracle 学习笔记】Day 1 常用函数整理(转换、DeCode),表的外键

select Convert(varchar,Convert(money,TaxExValue),1) from A--Result 2,794.87 58,119.66 1,367.52 对于SQL Server来说&#xff0c;进行金额的转换&#xff0c;可以按照上面的操作那样&#xff0c;会自动将金额处理为两位小数&#xff0c;并用逗号分隔小数点前面的数字。 当…

LOJ bitset+分块 大内存毒瘤题

题面 $ solution: $ 真的没有想到可以用分块。 但是可以发现一个性质&#xff0c;每个询问只关心这个点最后一次赋值操作&#xff0c;和这个赋值操作后的所有取 $ min $ 操作。这个感觉很有用&#xff0c;但是真的很难让人想到低于 $ n\times m $ 的做法。基于 $ DAG $ 的数据结…

Web开发编程实用手册

不要被这个名字吓到。这本手册&#xff0c;真的很实用。你能猜猜它有多少页么&#xff1f;只有62页&#xff0c;比起那些砖头书来&#xff0c;这本可以说是苗条得不能再苗条了。现在卓越搞活动&#xff0c;购买电子工业出版社图书&#xff0c;凡购买专题内图书满69元&#xff0…

C# 配置文件 自定義結點

1. 對於配置自定義結點&#xff0c;需要繼承ConfigurationSection類。 UrlsSection : ConfigurationSection 2. 配置文件中&#xff0c;需要如下引用&#xff1a; View Code <configSections><section name"orders" type"WebApplication4.UrlsS…

Stream流思想和常用方法

一、IO流用于读写&#xff1b;Stream流用于处理数组和集合数据&#xff1b; 1、传统集合遍历&#xff1a; 2、使用Stream流的方式过滤&#xff1a; 其中&#xff0c;链式编程&#xff08;返回值就是对象自己&#xff09;中&#xff0c;filter使用的是Predicate函数式接口&#…

Stream流方法引用

一、对象存在&#xff0c;方法也存在&#xff0c;双冒号引用 1、方法引用的概念&#xff1a; 使用实例&#xff1a; 1.1先定义i一个函数式接口&#xff1a; 1.2定义一个入参参数列表有函数式接口的方法&#xff1a; 1.3调用这个入参有函数式接口的方法&#xff1a; lambda表达式…

为什么要在定义抽象类时使用abstract关键字

本文为原创&#xff0c;如需转载&#xff0c;请注明作者和出处&#xff0c;谢谢&#xff01;众所周之&#xff0c;在任何面向对象的语言中&#xff08;包括Java、C#&#xff09;&#xff0c;在定义抽象类时必须使用abstract关键字。虽然这已经习已为常了&#xff0c;但实际上ab…

pku 3252 Round Numbers 组合数学 找规律+排列组合

http://poj.org/problem?id3252 看了discuss里面的解题报告才明白的&#xff0c;这个解题报告太强大了&#xff1a;http://poj.org/showmessage?message_id158333不多讲已经很详细了&#xff0c;不明白多看几遍肯定会明白的。 注意这里的公式c(i,j) c(i - 1,j -1) c(i - 1…

《The Coaching Booster》问与答

由Shirly Ronen-Harel和Jens R. Woinowski 编写的《The Coaching Booster》 一书探讨了不同的教练方法和实践&#xff0c;并介绍了一种教练框架&#xff0c;支持教练帮助人们达到他们的目标。\InfoQ 采访了Shirly Ronen-Harel 和 Jens R. Woinowski&#xff0c;谈论了他们的书为…

反射应用和获取Class对象的三种方式

一、写一个“框架”&#xff0c;可以创建任何对象运行任何方法 1、配置文件 2、使用类加载器ClassLoader&#xff0c;Properties集合是可以和IO流结合使用完成读取和写入数据的集合&#xff0c;方法参数列表是IO流&#xff1b; Class类的静态方法forName()创建Class对象&#x…