📄 g9.htm
字号:
<html>
<head>
<title>游戏制作</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
<!--
body { font-size: 14px}
td { font-size: 14px}
a:active { text-decoration: none}
a:link { text-decoration: none}
a:visited { color: #FFFFFF; text-decoration: none}
a:hover { text-decoration: underline}
-->
</style>
</head>
<body bgcolor="#e8ffe8">
<br>
<table width="85%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>程序状态的转换 <br>
我们在写DirectX程序的时侯,总有一种偏见,那就是不希望Windows界面出现在我们的 <br>
游戏里。于是什么都需要我们自己做。比如说窗口。因为窗口的刷新需要我们自己管理, <br>
就觉得没有必要生成多个窗口了。这样所有的窗口消息就必须在唯一的一个函数里实现。 <br>
可是我们的游戏里有很多种不同的操作,比如界面,系统菜单,播放视频等,这些内容就 <br>
都必须在这个地方处理。所以我们就引入了程序状态这个概念。我们定义了一系列的状态 <br>
,在每个状态里,有固定的操作和响应,状态之间的转换也在特定的时侯进行。这样我们 <br>
就很容易把一些关系不大的内容独立开来,降低程序的复杂性。 <br>
其实我们在实现这一部分的时侯是很混乱的。你很难在代码中找到所有状态转换的地方 <br>
。但是它的实现很简单,一般的规则就是程序的对称性。有专门的装入函数和释放函数, <br>
然后有显示函数,计算函数,鼠标消息响应函数,热键响应函数。在内部,需要结束本状 <br>
态时就发出一个状态转换的消息。在外部,只要在主程序的主循环和消息响应函数处针对 <br>
不同的状态执行它们不同的函数就可以了。 <br>
这里的关键在于状态的转换。因为状态在转换中一定会释放和申请大量内存,如果有的 <br>
内存没有释放,转换次数一多就会出现问题。如果我们把状态转换的地方写好了,程序看 <br>
起来也非常干净整齐,Bug也会比较少。 <br>
现在编写游戏,需要装入的图量非常大,很有必要制作一个装入时的画面,并且显示百 <br>
分比。这是我们可能需要一个装入中的状态。遗憾的是<赤壁>并没有实现这个,它的淡入 <br>
淡出效果仅仅是效果,程序在执行这部分时停止在这里。 <br>
有关内容请详见CBGame.cpp和Interfac.cpp。 <br>
<br>
执行任务 <br>
一个士兵在接到我的命令之后,便开始了它的行动。它察看了一下它的命令,这是由两 <br>
个部分组成的。它先取出第一个部分,是行走。于是根据自己现在的位置和目的地位置先 <br>
计算了一下路线,把自己当前的状态设置为正在移动,然后根据计算好的方向和自己的速 <br>
度把自己移动到一个位置。如果这个位置已经到达目的地了,它就停止行走。又察看了一 <br>
下剩余命令的部分,是攻击。于是它拔出刀砍向附近的一个敌人。敌人死了么?它不停地 <br>
问自己。如果敌人真的"哇"的一声倒下了,它就得意地站在一旁,微笑着。 <br>
这就是我们在战场的一个角落所看到的一个士兵的表现。而实事上,在程序里我们也是 <br>
这样做的。 <br>
我们把每个士兵做为一个单元,独立地处理自己的事物。我们把每个命令划分得更加细 <br>
致,而称其为状态,执行每个状态时所需要的参数的执行的步骤是最简化的。每个命令都 <br>
是由一个或多个状态组成的。一个状态满足后就自动转向下一个状态。我们为每个状态都 <br>
编写专门的开始,运行中,和结束代码。这样每个士兵都在独立地按照顺序处理自己的事 <br>
务,一个个复杂的单元行动就变得有条有理了。 <br>
有关内容请详见CBRun.cpp。 <br>
<br>
阴影 <br>
有人说Warcraft做得好,有人说C&C做得好。我属于前者一派,这不仅仅因为我对 <br>
Warcraft的观察多一些,而且有一个理由足以说明Warcraft在程序上比C&C更高一筹。那 <br>
就是阴影。大家都知道Warcraft是双层阴影,而C&C是单层。双层阴影的好处是更加真实 <br>
。在我们去过一个地方之后,虽然我已经看清楚了地形,但是这里敌人的活动,我们不应 <br>
该永远知道。可是要把单层阴影变成双层,并不是只要加上一层显示就可以解决问题的。 <br>
<br>
首先,增加一层阴影就增加了需要显示的时间。时间对于即时战略来讲是至关重要的。 <br>
它直接影响到游戏的表现效果和操作速度。多加一层阴影就意味着减少了我们增加效果的 <br>
机会。在我们这里,双层阴影占用了大约5-10%的显示时间。 <br>
其次,增加一层阴影就增加了特殊的计算。一层阴影只需要一个二进制数组记录哪里被 <br>
打开,哪里被隐藏就可以了。而现在则不同,我们需要把那些已经打开的阴影再关上。我 <br>
们的做法是生成一个二维数组,每位表示一个图素格子。当有一个士兵的视野可以打开这 <br>
个格子上的阴影时,就把那里的计数器加一,离开时减一。当为0时则这块地形被重新隐 <br>
藏。 <br>
第三,阴影下的单元需要特殊的处理。当我的士兵离开敌人阵地的时侯,敌人附近被半 <br>
透明的阴影重新覆盖了,这时我们需要把正在那里活动的敌人士兵隐藏起来,而建筑不动 <br>
。 <br>
这就是双层阴影所带来的。可是为了效果,我们不得不如此。看起来还是达到了效果。 <br>
<br>
除了双层阴影以外,阴影的边界也是很重要的问题。我们不可能把阴影做得和刀切的一 <br>
样,而让它必须和打开的地面相结合。于是我们必须要有一套贴图,用于阴影边界的各个 <br>
方向。好在我们在这里利用了一个偷懒的办法(当然是很巧的办法,是Onefish想出来的) <br>
。我们采用了一个椭圆的贴图,让相邻的椭圆相切,从而造成边界。因为椭圆是没有方向 <br>
之分的,我们也就节省了一些贴图的内存和对使用哪张贴图的复杂计算。 <br>
有关内容请详见CBShadow.cpp。 <br>
<br>
<br>
选中谁了 <br>
<赤壁>战场里的格子是菱形的。这一点有多少人发现了?又有多少人知道它的代价?或许 <br>
有人认为菱形的格子并不是个很好的注意,但我们恰巧在这里使用了它。当鼠标按下时我 <br>
们需要知道它放在哪个格子里了。过去的经验是只要知道该点的位置和每个格子的宽度我 <br>
们就可以很快地算出格子的序号。但是在这里不行,因为格子是菱形的,在一个矩形区域 <br>
里的点不能被确定它到底属于哪个格子。 <br>
怎么办呢?我制作了一个二进制二维数组,大小是格子的宽和高。在这个区域里,如果是 <br>
属于矩形内接菱形区域内的点设置为1,否则为0。当鼠标在某个矩形区域里时,我就用这 <br>
个栅格去判断该点的位置上的数值是1还是0。是1则这个点在这个菱形格子里,否则不在 <br>
。这个办法是我遇到的比较迅速的一个办法。 <br>
<br>
<br>
命令的产生 <br>
一个由游戏者发出的命令,一般有三个部分:命令主体,命令本身和命令客体。命令主 <br>
体就是执行命令的人。我想对这支部队下达命令,这支部队就是命令的主体,在游戏里就 <br>
是我们用鼠标选中的一群士兵。命令本身是命令的标识。我想下达的是什么样的命令,在 <br>
游戏里,可能是我按下了某个命令按钮。命令客体是命令结果的接受者,如果我选择了攻 <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -