📄 tutorial_21.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><!-- 这篇文章由Dancingwind翻译,作者的联系方式zhouwei02@mails.tsinghua.edu.cn --><title>NeHe OpenGL教程第二十一课,DancingWind翻译</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
A:link {COLOR: #ccaaff; TEXT-DECORATION: none}
A:visited {COLOR: #ccaaff; TEXT-DECORATION: none}
A:active {COLOR: #ccaaff; TEXT-DECORATION: none}
A:hover {COLOR: #ffccaa; TEXT-DECORATION: none}
</style></head><body bgcolor="#000000" text="#ffffff"><br><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td height="130" width="326"><img src="Tutorial_21_files/logo.png" height="130" width="326"></td>
<td align="center" valign="middle" width="75%"><font color="#ffccaa" size="+3"><b><i>第21课</i></b></font></td>
</tr></tbody></table>
<!-- 上边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_21_files/tl.jpg" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_21_files/tc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_21_files/tr.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<!-- 中部-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<!-- 中部左边框-->
<td background="Tutorial_21_files/l.gif"><img src="Tutorial_21_files/l.gif" height="28" width="28"></td>
<!-- 中部文字部分-->
<td valign="top" width="100%">
<table border="0" width="100%">
<tbody><tr>
<td width="29%"><img src="Tutorial_21_files/lesson21.jpg" height="180" width="240"></td>
<td width="71%"><p><font class="head">线,反走样,计时,正投影和简单的声音:</font></p>
<p><font size="3">这是我第一个大的教程,它将包括线,反走样,计时,正投影和简单的声音。希望这一课中的东西能让每个人感到高兴。</font></p></td>
</tr>
</tbody></table>
</td>
<!-- 中部右边框-->
<td background="Tutorial_21_files/r.gif"><img src="Tutorial_21_files/r.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<!-- 下边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_21_files/bl.gif" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_21_files/bc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_21_files/br.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%">欢迎来到第21课,在这一课里,你将学会直线,反走样,正投影,计时,基本的音效和一个简单的游戏逻辑。希望这里的东西可以让你高兴。我花了两天的时间写代码,并用了两周的时间写这份HTML文件,希望你能享受我的劳动。
<p>在这课的结尾你将获得一个叫"amidar"的游戏,你的任务是走完所有的直线。这个程序有了一个基本游戏的一切要素,关卡,生命值,声音和一个游戏道具。</p>
<p>我们从第一课的程序来逐步完整这个程序,按照惯例,我们只介绍改动的部分。</p></td><td background="Tutorial_21_files/r.png"><img src="Tutorial_21_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
HDC hDC=NULL;
HGLRC hRC=NULL;
HWND hWnd=NULL;
HINSTANCE hInstance; </pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%">bool类型的变量,vline保存了组成我们游戏网格垂直方向上的121条线,上下水平各11条。hline保存了水平方向上的
121条线,用ap来检查A键是否已经按下。
<p>当网格被填满时, filled被设置为TRUE而反之则为FALSE。gameover这个变量的作用显而易见,当他的值为TRUE时,游戏结束。anti指出抗锯齿功能是否打开,当设置为TRUE时,该功能是打开着的。active
和 fullscreen 指出窗口是否被最小化以及游戏窗口是窗口模式还是全屏模式。</p></td><td background="Tutorial_21_files/r.png"><img src="Tutorial_21_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>bool keys[256];
bool vline[11][10]; <font color="#ffffaa">// 保存垂直方向的11根线条中,每根线条中的10段是否被走过</font>
bool hline[10][11]; <font color="#ffffaa">//保存水平方向的11根线条中,每根线条中的10段是否被走过</font>
bool ap; <font color="#ffffaa">// A键是否已经按下</font>
bool filled; <font color="#ffffaa">// 网格是否被填满?</font>
bool gameover; <font color="#ffffaa">// 游戏是否结束?</font>
bool anti=TRUE; <font color="#ffffaa">// 是否启用反走样?</font>
bool active=TRUE;
bool fullscreen=TRUE; </pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%">接着设置整型变量。loop1 和 loop2 被用来检查网格,查看是否有敌人攻击我们,以及在网格上给对象一个随机的位置。你将看到loop1
/ loop2在后面的程序得到使用。delay 是一个计数器,我用他来减慢那些坏蛋的动作。当delay的值大于某一个馈值的时候,敌人才可以行动,此时delay将被重置。<br>
adjust是一个非常特殊的变量,即使我们的程序拥有一个定时器,他也仅仅用来检查你的计算机是否运行地太快。如果是,则需要暂停一下以减慢运行速度。
在我地GeForce显卡上,程序的运行平滑地简直变态,并且非常非常快。但是在我的PIII/450+Voodoo
3500TV上测试的时候,我注意到程序运行地非常缓慢。我发现问题在于关于时间控制那部分代码只能够用来减慢游戏进行而并不能加速之。因此我引入了一个
叫做adjust
的变量。它可以是0到5之间的任何值。游戏中的对象移动速度的不同依赖于这个变量的值。值越小,运动越平滑;而值越大,则运动速度越快。这是在比较慢的机
器上运行这个程序最简单有效的解决方案了。但是请注意,不管对象移动的速度有多快,游戏的速度都不会比我期望的更快。我们推荐把adjust值设置为3,
这样在大部分机器上都有比较满意的效果。<br>
我们把lives的值设置成5,这样我们的英雄一出场就拥有5条命。level是一个内部变量,用来指出当前游戏的难度。当然,这并不是你在屏幕上所看到
的那个Level。变量level2开始的时候和Level拥有相同的值,但是随着你技能的提高,这个值也会增加。当你成功通过难度3之后,这个值也将在
难度3上停止增加。level 是一个用来表示游戏难度的内部变量,stage才是用来记录当前游戏关卡的变量。</td>
<td background="Tutorial_21_files/r.png"><img src="Tutorial_21_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
<pre>int loop1; <font color="#ffffaa">// 通用循环变量</font>
int loop2; <font color="#ffffaa">// 通用循环变量</font>
int delay; <font color="#ffffaa">// 敌人的暂停时间</font>
int adjust=3; <font color="#ffffaa">// 调整显示的速度</font>
int lives=5; <font color="#ffffaa">// 玩家的生命</font>
int level=1; <font color="#ffffaa">// 内部游戏的等级</font>
int level2=level; <font color="#ffffaa">// 显示的游戏的等级</font>
int stage=1; <font color="#ffffaa">// 游戏的关卡</font>
</pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%">接下来我们需要一个结构来记录游戏中的对象。fx和fy每次在网格上移动我们的英雄和敌人一些较小的象素,以创建一个平滑的动画效果。x和y则记录着对象处于网格的那个交点上。<br>
上下左右各有11个点,因此x和y可以是0到10之间的任意值。这也是我们为什么需要fx和fy的原因。考虑如果我们只能够在上下和左右方向的11个点间移动的话,我们的英雄不得不<br>
在各个点间跳跃前进。这样显然是不够平滑美观的。<br>
最后一个变量spin用来使对象在Z轴上旋转。</td>
<td background="Tutorial_21_files/r.png"><img src="Tutorial_21_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
<pre>struct object <font color="#ffffaa">// 记录游戏中的对象</font>
{
int fx, fy; <font color="#ffffaa">// 使移动变得平滑</font>
int x, y; <font color="#ffffaa">// 当前游戏者的位置</font>
float spin; <font color="#ffffaa">// 旋转方向</font>
};
</pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%"><br>
既然我们已经为我们的玩家,敌人,甚至是秘密武器。设置了结构体,那么同样的,为了表现刚刚创设的结构体的功能和特性,我们也可以为此设置新的结构体。<br>
为我们的玩家创设结构体之下的第一条直线。基本上我们将会为玩家提供fx,fy,x,y和spin值几种不同的结构体。通过增加这些直线,仅需查看玩家的x值我们就很容易取得玩家的位置,同时我们也可以通过增加玩家的旋转度来改变玩家的spin值。<br>
第二条直线略有不同。因为同一屏幕我们可以同时拥有至多15个敌人。我们需要为每个敌人创造上面所提到的可变量。我们通过设置一个有15个敌人的组来实现这个目标,如第一个敌人的位置被设定为敌人(0).x.第二个敌人的位置为(1),x等等<br>
第三条直线使得为宝物创设结构体实现了可能。宝物是一个会时不时在屏幕上出现的沙漏。我们需要通过沙漏来追踪x和y值。但是因为沙漏的位置是固定的所以我们不需要寻找最佳位置,而通过为程序后面的其他物品寻找好的可变量来实现(如fx和fy)</td>
<td background="Tutorial_21_files/r.png"><img src="Tutorial_21_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3"></font><pre><font color="#aaffaa" size="3">struct object player; <font color="#ffffaa">// 玩家信息</font>
struct object enemy[9]; <font color="#ffffaa">// 最多9个敌人的信息</font>
struct object hourglass; <font color="#ffffaa">// 宝物信息</font>
</font></pre><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_21_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_21_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_21_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_21_files/l.png"><img src="Tutorial_21_files/l.png"></td>
<td valign="top" width="100%">现在我们创建一个描述时间的结构,使用这个结构我们可以很轻松的跟踪时间变量。
<p>接下来的第一步,就是创建一个64位的频率变量,它记录时间的频率。</p>
<p>resolution变量用来记录最小的时间间隔。</p>
<p>mm_timer_start和mm_timer_elapsed保存计时器开始时的时间和计时器开始后流失的时间。这两个变量只有当计算机不拥有performance
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -