给你们的助教展示你们的程序。组内所有的成员必须参加并且给出一个简短的演示以及回答与他的工作相关的问题,陈述与演示不应该超过15分钟。除了另外的半个小时的问题与讨论。
返回顶部
设计竞赛
当你们提交你们的最终实现和评估时,可以在第一页文档中指明你们是否想要下列奖项:
- 最佳设计:具有最佳抽象,最佳模块化,最佳扩展性,简洁性等的将获得此奖,同时最终报告也会考虑到。
- 最佳撞球游戏:这项奖励将给于具有最佳游戏性的项目。此奖的申请书应该包括一个建立游戏区域的输入文件;这个奖是设给游戏本身的可玩性,而不是设给建造游戏的工具箱。
- 最佳艺术奖:设给具有最佳视觉效果的项目。申请书应该包括一个建立游戏区域的输入文件,当用此文件运行游戏的时候,在没有用户操作任何键的情况下,弹球也应该永远反弹。
在考虑最佳设计奖项时将不考虑你的程序是否只实现了基本的功能或者有额外的功能,但是另外两项奖项将会考虑这点。
获奖情况开始由助教提名,最终获奖将有讲师宣布。一个项目可以获得多个奖项。获奖者将在最后一堂课中宣布。
返回顶部
我们将给你的
用 Java™ 实现动画非常有挑战性。 你要用java.awt和javax.swing包来构建你的图形用户界面(GUI), 我们在Example.Java™ t中提供了一个例程来展示如何动画演示小球在窗体中的碰撞反弹过程。同时它还演示了如何让你的程序监听用户事件,比如点击一个工具栏按钮,按下一个键或者拖动一个鼠标。组内的所有成员都应该编译执行这个例程。
我们还提供了一个物理例程 (参看附录 3) 用以计算弹性碰撞的动力学状态。你可以随意的使用这些代码。
返回顶部
提示 概要
返回顶部
编码
撞球文件的语法设计得容易阅读。 BufferedReader.readLine() 方法可以读到一个命令,StringTokenizer 类可以将命令分解到它的组成部分中。
在尝试编写你的图形用户界面前你应该拥有关于SWING的基本知识。参考SUN公司的Swing 指南 (特别是快速漫游 和总体概览 部分)。
不要用实时时钟去计算时间。相反,应该每祯时间内接受一个时间事件,并且处理仿真还有屏幕更新。如果你落后了并且时间变慢了,那就由它吧。解决这个问题的简单的方法是用类Javax.swing.Timer , 就像在例子 GUI。用这种方法可以简化代码实现,并且可以避免处理在多线程程序中的同步问题。
如果你使用SWING并且希望用它来绘制你的部件就像你为了绘制底板物件还有弹球,你应该扩展Javx.swing.JComponent 并且实现你自己的绘图例程。为了这么做,你必须重载你的paint 方法,绘图工作时通过调用所提供的Java.awt.Graphics 对象。除非你很明确地把它关掉了,否则SWING的部件会自动双缓冲地减少闪烁。如果你不理解,别担心。除了图形 Java™ 现在还有一个可选的图形上下文Java.awt.Graphics2D ,它比传统的图形对象提供更复杂的功能。要注意到你的部件受到的用于绘图的调用总会有一个GRAPHICS2D,这个调用是作为参数传递的。所以如果你想使用 你应该简单的列出这个图形对象。你可以用任何一种图形风格实现撞球游戏,但是你可能会考虑这两种绘图风格的一些区别:
- 图形对象以整数值表示的像素工作,允许你更直接的控制哪个像素应该被更新。
- 另一方面,Graphics2d接受浮点值定义几何外形用以润色和实现光栅。这个在某种程度上是自动的,但是也使直接设置单个像素更加困难。
- Graphics2D类同样允许将 应用于它。(一个仿射变换是一种保持平行的变换。)
为了响应用户的鼠标和键盘动作,你需要创建和安装MouseListener, MouseMotionListener, 和 KeyListener 所有这些你都可以在Java.awt.event 包中找到。 关于 Java™ 键控代码的信息可以在Java.awt.event.KeyEvent的文档中找到。
按键
撞球游戏中对于键盘操纵的说明必须写明当那个键被按下或者释放,与此键相连的对象必须被触发。这个提供的行为与真正的撞球游戏一样:按下按钮使挡板向上运动,释放按钮则挡板回到原来的位置。
键盘事件
Java™ 关于Java.awt.event.KeyEvent 的说明描述了三种类型的键盘的事件:KEY_PRESSED, KEY_TYPED, and KEY_RELEASED。这些文件中指明当一个键被用户按下后,KEY_PRESSED 事件发生,当这个键被释放后,KEY_RELEASED 事件发生。因此当收到邦定到小物件的KEY_PRESSED 或者KEY_RELEASED 事件时它就是一个合理的触发。
不幸的,当用户只按下一个键时,大多数 Java™ 运行时用了多重的KEY_PRESSED 以及有些情况下多重的KEY_RELEASED 事件。 此外,在有些环境下你可能释放一个键而不会受到KEY_RELEASED 事件。这是因为这两个事件是系统依赖的。这个行为通过与操作系统交互发生,如果你按下一个键持续一段时间那么这个行为将重复发生。
在Windows下
在windows下,当按下一个键时Java™ 将产生多个KEY_PRESSED 事件,当这个键释放时却只产生一个KEY_RELEASED 事件,例如,按下“A”键将会产生下列事件:
PRESSED 'A'
PRESSED 'A'
...
RELEASED 'A'
在Unix下
在unix下,当按下一个键时多个成对的key事件将发生:
PRESSED 'A'
RELEASED 'A'
PRESSED 'A'
RELEASED 'A'
...
PRESSED 'A'
RELEASED 'A'
返回顶部
测试程序
如果你想在你的环境下看看你的程序的行为,你可以用提供的KeypressTest 类。这个应用程序将把所有的键盘事件传递到控制台用以监视。
源程序可以点击这里看到:KeypressTest.java
返回顶部
解决方案
当你察看程序包时你应该很容易的把握Java™ API 的细微差别,一个简单的解决办法是关闭操作系统的键盘自动按键重复机制,因此可以让事件KEY_PRESSED和KEY_RELEASED 与它的实际动作响应的更贴合。
- Unix/Linux: 键入“xset -r”关闭自动重复,开启自动重复用“xset r”
- Windows: 进入控制面板的辅助功能选项程序,在键盘选项卡上选择筛选键设置按钮,选择忽略快速击键并减缓重复速度,选择下一个设置按钮。确保选择“没有键盘重复”。滑动slowkeys滑动快到短边(0.00)。按下ok键两次。选定“使用筛选键”并且按下ok。同样,取消这个功能只需反向操作即可。
要求最终用户进行这样的设置是可以接受的,但是这一点应该包括在你的撞球文档中。
另一种方法是利用提供的一种特别的键监听装置。这个类以编译过的形式存在gb-lib.jar 文件中,名称为staffui.MagicKeyListener。参考关于 MagicKeyListener 的文档或者直接用提供的源代码 作为你的出发点。
返回顶部
系统管理以及计算机工具 返回顶部 修正控制
我们强烈的建议你们使用修正控制包比如CVS 来帮助你们协调工作,防止代码丢失,允许给以前的版本进行备份。
返回顶部
构造:系统模型
另一个你会觉得有用的工具是make,这个工具允许你编写一个一个makefile文件,它是你系统的一个模型:哪一个文件包含代码,编译系统要做些什么工作,测试时需要做什么工作,清理词典需要做什么工作,等等。一旦你编写了这个文件,你可以通过键入一个简单的命令来做前面说到的任务中的任何一个。
在Athena中,键入info make。
返回顶部
Java™ Archive (JAR) 文件
你应该把你的应用程序的所有部分收集起来创建一个jar文件提交给你的助教。jar文件是非常有用的,用它可以存储所有的源代码,编译过得代码,把一些数据文件(比如图像或者声音)关联到一个集中的文档中,便于以后发布。
要了解更多的jar文件,参看Sun公司的jar 工具 手册。
作为一个快速的参考,这里有一些使用jar命令的例子:
从gizmo和ball包的类中创建gizmo.jar:
jar cvf gizmo.jar gizmo ball
列出jar文件的内容,使用:
jar tf gizmo.jar
要创建一个可运行的gizmo.jar,使用:
jar cvfm gizmo.jar JarMainManifest gizmo ball
在上面的例子中,文件JarMainManifest应该包括命名进入点的单独的一行:
Main-Class: gizmo.StartGizmoball
运行这个应用程序,使用:
Java -jar gizmo.jar
要点: 注意,当使用-jar选项运行一个应用程序时,CLASSPATH变量以及-cp命令行开关是被忽略的 。因此,为了把存储在可运行jar中的应用程序中的物理库包括进来,你必须把.class文件从我们的jar中提取出来,并且把它们包含在你们自己的里面。你可以用这种方法把一个jar文件提取到当前目中:
jar xvf /mit/6.170/lib/gb-lib.jar
使用makefile,就像上面部分说过的,可以很简单并且自动的创建jar文件,对于将physics类文件合并到你的应用程序中所包含的复杂性以及维护问题,我们建义你使用一个Makefile来自动完成这个过程 。
返回顶部
附录
1: 详细需求 概要
你的实现必须支持两种执行模式:建造和运行。在建造模式,用户可以在游戏区增加小物件并且能修改已经存在的小物件。在运行模式,弹球在游戏区运动并且与小物件发生碰撞。
游戏区
游戏区必须至少20L宽,20L高,也就是说,在游戏区可放置400块障碍物,并且没有重叠。左上角是(0,0),右下角是(20,20)。当我们说一个小物件在某个位置时,指的是它的原点在那个位置。每个小物件的原点指的是它的外围框的左上角。所以在一个20LX20L的面板上一个小物件被放置的位置的最深点是(19,19)。弹球的原点在它的中心。
在建造模式,小物件必须一格一格的放置,也就是说,用户只能这样放置小物件:(0,0),(0,1),(0,2)...
在运行模式,动画珊格的粗糙度不能超过0.05L.假设弹球在位置(1,1)并且正向(1,0)方向运动,也就是由左到右,图像每绘制一桢小球移动0.05L。弹球应该依次显示在位置(1,1)(1.05,1)(1.10,1),如果你希望动画流畅一些,应该在更多的位置显示弹球。挡板的旋转动画可以显示的粗糙一些;可以参看下面关于--的详细描述。如果弹球运动比每桢图像中绘制珊格的速度还快,那就不需要在每个动画珊格位置重新绘制图像。
返回顶部
建造模式
在建造模式,用户可以:
- 在游戏区增加任何一种可用的小物件类型。
- 尝试把一个小物件放置在一个已有的小物件上面或者游戏区的边界上面是不允许的(也就是说,它应该是无效的)。
- 在游戏区把一个小物件从一个位置移动到另一个位置。
- 尝试把一个小物件放置在一个已有的小物件上面或者游戏区的边界上面是不允许的(也就是说,它应该是无效的)。
- 对任何一个小物件进行顺时针90度旋转。
- 旋转对于轴向对称的小物件是不起作用的。例如,圆形的障碍物不管对它进行多少次旋转,它看起来都是一样的。
- 把某个特定小物件的触发连接到某个特定的小物件的动作上。
- 当弹球碰撞一个标准小物件时,它产生一个触发,并且最多展示一个动作(例如,移动一个挡板,把弹球从吸收器弹射出去,变幻一个障碍物的颜色)。一个小物件产生的触发能被连接到多个小物件的动作上。同样的,一个小物件的动作也可以被多个触发激活。最基本的小物件的要求的触发与动作 在下面描述。
- 注意触发并不形成链,也就是说当A被连接到B,B被连接到C,弹球碰撞A只能引起B的动作的触发。
- 把一个按键触发连接到一个小物件的动作上。
- 每个键盘键当按下时都产生一个唯一的触发。同小物件产生的触发一样,键盘键触发同样可以被连接到许多小物件的动作上面。
- 从游戏区删除一个小物件。
- 向游戏区添加一个弹球。
- 用户可以确定弹球的起始位置以及运动速度。
- 尝试将弹球放置在一个小物件或者游戏区边框上面是不被允许的(也就是说,它应该是无效的),在标准小物件设置中有一个例外:静止的弹球应该被放置在吸收器里面。
- 将设置保存在用户自己命名的文件中。
- 你必须能按照附录 2给出的 标准格式 将你的设置存入文件中,如果你愿意,你可以定义一个标准格式的扩展,用来处理你的实现中的一些特别之处。果真如此的话用户必须有选择两种格式中一种的可能。
- 存储的文件必须包括所有在游戏区的小物件,所有的触发与动作之间的连接,弹球的现在位置以及运动速度的信息。
- 装载用户命名的文件。你必须能够把保存的游戏装载进来。
- 切换到运行模式。
- 退出程序。
返回顶部
运行模式
在运行模式,用户可以:
- 在任何时候可以切换到建造模式。
- 当一个挡板正在运动时,用户要求切换到建造模式,此时可以延迟切换,等到挡板运动到它的轨道的末端。
- 同样当小物件的状态正在改变时也是允许延迟的。
- 按键,因此产生连接到小物件动作的触发。
- 退出程序。
在运行模式,撞球游戏应该:
- 提供比较流畅的弹球的运动动画。
- 默认的弹球的直径大约必须为0.5L。
- 弹球的速度可在0.01L/秒到200L/秒的范围内变化,并且能覆盖很大的范围。如果你愿意游戏应该能支持.0/秒(静止)。
- 应该用一个可以接受的刷新频率来产生比较流畅的动画。我们发现每秒20桢的刷新速度在一个相当宽范围的平台上也可以工作的不错。
- 在游戏区显示比较合理的弹球与小物件的行为动作。也就是说,弹球应该弹回它应该弹回的方向,并且应该拥有它该有的速度,就像在实际撞球游戏中一样。
- 不断的修改弹球的速度模仿重力的影响。
- 你应该支持标准的重力加速度:25L/秒2, 就像在撞球游戏中倾斜的游戏表面一样。
- 不断的修改弹球的速度模仿摩擦的影响。
- 你应该用摩擦常数mu 和 mu2。来给摩擦建模,对于充分小的delta_t's 你可以用如下公式计算:Vnew = Vold * (1 - mu * delta_t - mu2 * |Vold| * delta_t).
- 默认的mu值是每秒0.025。
- 默认的mu2值是每L0.025。
返回顶部
标准小物件
你必需提供7种标准的小物件:障碍物(方块,圆圈和三角),挡板(左边的和右边的),吸收器,以及外围墙。
1.0的反射系数是指弹球离开障碍物时的能量与它撞击障碍物时的能量是相等的,只是撞击以后运动方向改变了。作为一个扩展,你可以让你的程序支持大于或者小于1.0的反射系数。
方块障碍物
边长为 1L的方型障碍物
触发: 当弹球撞击它时产生
动作: 没有要求
反射系数:1.0
返回顶部
圆形障碍物
直径为 1L的圆形障碍物
触发: 当弹球撞击它时产生
动作:没有要求
反射系数:1.0
返回顶部
三角形障碍物
一边为 1L 斜边为 Sqrt(2)L的右三角形
触发: 当弹球撞击它时产生
动作: 没有要求
反射系数: 1.0
返回顶部
挡板
边框为 2Lx2L的矩形旋转框
触发:当弹球撞击它时产生
动作:旋转90度 (参看下面)
反射系数: 0.95 (参看下面)
挡板有两种类型,左挡板和右挡板。左挡板按逆时针旋转,右挡板顺时针旋转。
在运行模式,挡板不能超出它的外框。在编辑模式,挡板不能放置的在运行模式挡板会超出它的边框,或者它的边框会与其它小物件(的边框