1、1 嵌入式系统开发设计 课程设计 设 计 题 目 软 件 中 的 典 型 算 法 分 析 学 院 名 称 信 息 科 学 与 技 术 学 院 专 业 名 称 学 生 姓 名 学 生 学 号 任 课 教 师 设 计 成 绩 教务处 制 2015 年 3 月 24 日 2 软件中的典型算法分析 摘 要 此次课程设计为加农炮游戏, 这是一款基于 Linux平台,运用 Qt Creater软件开发的一款小游戏。本文将从加农炮的设计及实现出发,分析在实现过程中的一些典型算法。其中包括坐标转换算法、碰撞检测算法、边界检测算法、定时器驱动等。 关键词: 坐标转换算法;碰撞检测算法;边界检测算法;定时器驱动;
2、 Qt Creater 1、 加农炮整体实现流程 1.1 加农炮设计与实 现简述 这是一款基于 Linux平台,运用 Qt Creater 软件开发的一款加农炮小游戏。游戏的界面为一个窗口,在窗口的右边从上到下以此是:quit按钮,该按钮的作用是用于关闭游戏与窗口中的作用相同;Angel LED 显示屏,屏上显示的数据就是炮台当前的角度,下边是一个滚动滑条用于控制炮台的角度,炮台角度的范围是 0 度 70度,当滑条向左边滑动,炮台的角度变小,当滑条向右边滑动,炮台的角3 度变大; Force LED 显示屏,屏上显示的数据是炮台射出的炮弹的力度,下边的滑条用于控制炮台射出炮弹的速度,炮弹的速度
3、范围 是050,当滑条向右边滑动,炮弹的力度变大,当向左边滑动,炮弹的力度变小。窗口的上边一栏从左到右分别是: Shoot按钮,当用户按下这个按钮后炮台会发射一个炮弹,炮弹的轨迹遵循物理定理,将成一个抛物线运动; Hits LED显示屏,屏上的数据显示的是炮台发出的炮弹击中木块的次数,最多显示为 15; Shoots Left LED 显示屏,屏上的数据显示的是炮台还可以发出的炮弹数,默认的初始值为 15,最小为 0; New Game 按钮,当用户按下这个按钮时,其将进入一个新游戏,所有的值都变为初始值。窗口的右下方的大屏幕即为游戏显示界面,炮台位于游戏显示界面的左下角,在游戏显示界面的任意
4、位置处有一个小木条。当用户打开游戏界面后按下 Shoot按钮时,炮台自动发射一个炮弹,如果炮弹击打到小木块,炮弹和小木块会同时消失,同时会在游戏显示界面的另外一个任意位置显示出另外一个小木块,如果用户发射出的炮弹没有击打到小木块,用户可以通过调整炮台的角度,发射炮弹的力度来调整炮弹的运动轨迹以此来使炮弹能够击打到小木块,当用户发射够 15 枚炮弹是,游戏显示界面会显示 Game Over 同时游戏显示界面的炮台和炮弹会消失,当没有发射完后,用户继续 发射。如果用户没有发射完炮弹就想进行新游戏,这个操作也是被允许的。 自定义窗口部件: lcdrange.h 包含 LCDRange 类定义。 4
5、lcdrange.cpp 包含 LCDRange 类实现。 cannon.h 包含 CannonField 类定义。 cannonfield.cpp 包含 CannonField 类实现。 main.cpp 包含 MyWidget 和 main。 1.2 流程图 5 6 1.3 加农炮模块分析及整体界面 1.3.1 按钮 按钮是 执行游戏界 面的退出功能 ; 是执行 炮弹 的发射 功能; 按钮 式执行 新游戏 的功能 。 1.3.2 LED 显示 击中 木块数显示屏 ; 可发送 炮弹数显示屏 ; 炮台角度显示屏及滑动条; 力度显示屏及滑动条。其中, Angel 和 Force 滚动条,两个作用
6、 分别用于 控制 炮台的 角度 与力度 。 7 1.3.3 加农炮界面 2、 坐标转换算法 2.1 坐标转换原理 我们已经能够使用 QPainter的相关函数画出一些东西了。接下来,我们要看的是 QPainter 的坐标系统。 同很多坐标系统一样, QPainter 的默 认坐标的原点 (0, 0)位于屏幕的左上角, X轴正方向是水平向右, Y轴正方向是竖直向下。在这个坐标系统中,每个像素占据 1 x 1 的空间。你可以把它想象成是一张坐标值,其中的每个小格都是 1个像素。这么说来,一个像素的中心实际上是一个“半像素坐标系”,也就是说,像素 (x, y)的中心位8 置其实是在 (x + 0.5
7、, y + 0.5)的位置上。因此,如果我们使用QPainter 在 (100, 100)处绘制一个像素,那么,这个像素的中心坐标是 (100.5, 100.5)。 这种细微的差别在实际应用中,特别是对坐标要求 精确的系统中是很重要的。首先,只有在禁止反走样,也就是默认状态下,才会有这0.5 像素的偏移;如果使用了反走样,那么,我们画 (100, 100)位置的像素时, QPainter 会在 (99.5, 99.5), (99.5, 100.5), (100.5, 99.5)和 (100.5, 100.5)四个位置绘制一个亮色的像素,这么产生的效果就是在这四个像素的焦点处 (100, 100
8、)产生了一个像素。如果不需要这个特性,就需要将 QPainter的坐标系平移 (0.5, 0.5)。 这一特性在绘制直线、矩形等图形的时候都会用 到。下图给出了在没有反走样技术时,使用 drawRect(2, 2, 6, 5)绘制一个矩形的示例。在 No Pen 的情况下,请注意矩形左上角的像素是在 (2, 2),其中心位置是在 (2.5, 2.5)的位置。然后注意下有不同的 Pen 的值的绘制样式,在 Pen宽为 1 时,实际画出的矩形的面积是 7 x 6 的 (图出自 C+ GUI Programming with Qt4, 2nd Edition): 在具有反走样时,使用 drawRec
9、t(2, 2, 6, 5)的效果如下 (图出自 C+ GUI Programming with Qt4, 2nd Edition): 9 注意我们前面说过,通过平移 QPainter 的坐标系来消除着 0.5 像素的差异。下面给出了使用 drawRect(2.5, 2.5, 6, 5)在反走样情况下绘制的矩形 (图出自 C+ GUI Programming with Qt4, 2nd Edition): 请对比与上图的区别。 在上述的 QPainter的默认坐标系下, QPainter提供了视口(viewport)窗口 (window)机制,用于绘制与绘制设备的大小和分辨率无关的图形。视口和窗
10、口是紧密 的联系在一起的,它们一般都是矩形。视口是由物理坐标确定其大小,而窗口则是由逻辑坐标决定。我们在使用 QPainter 进行绘制时,传给 QPainter 的是逻辑坐标,然后, Qt的绘图机制会使用坐标变换将逻辑坐标转换成物理坐标后进行绘制。 通常,视口和窗口的坐标是一致的。比如一个 600 x 800 的widget(这是一个 widget,或许是一个对话框,或许是一个面板等等 ),默认情况下,视口和窗口都是一个 320 x 200的矩形,原点都在 (0, 0),此时,视口和窗口的坐标是相同的。 注意到 QPainter 提供了 setWindow()和 setViewport()函
11、数,用来设置视口和窗口的矩形大小。比如,在上面所述的 320 x 200的 widget10 中,我们要设置一个从 (-50, -50)到 (+50, +50),原点在中心的矩形窗口,就可以使用 painter.setWindow(-50, -50, 100, 100); 其中, (-50, -50)指明了原点, 100, 100 指明了窗口的长和宽。这里的“指明原点”意思是,逻辑坐标的 (-50, -50)对应着物理坐标的 (0, 0);“长和宽”说明,逻辑坐标系下的长 100,宽 100实际上对应物理坐标系的长 320,宽 200。 或许你已经发现这么一个好处,我们可以随时改变 windo
12、w的范围,而不改变底层物理坐标系。这就是前面所说的,视口与窗口的作用:“绘制与绘制设备的大小和分辨率无关的图形”,如下图所示: 除了视口与窗口的变化, QPainter 还提供了一个“世界坐标系”,同样也可以变换图形。所不同的是,视口与窗口实际上是统一图形在两个坐标系下的表达,而世界坐标系的变换是通过改变坐标系来平移、缩放、旋转、剪切图形。为了清楚起见,我们来看下面一个例子: void PaintedWidget:paintEvent(QPaintEvent *event) QPainter painter(this); QFont font(“Courier“, 24); painter.setFont(font); painter.drawText(50, 50, “Hello,