坦克大战总结
回头一想,做坦克大战这个项目已经有一个月了。这是我第一次做一个游戏项目,第一次在没有任何人的帮助下做的。当然这个项目还有很多东西我还没有做完,而且代码量也不多,就区区800多行左右代码,但是却花了我不少时间。虽然这个项目现在的样子和我想象中的差了十万八千里,但是我认为,毕竟这是我扎扎实实做的,所以多多少少我从里面学到了点什么吧。下面就来谈谈我这个月做这个项目的经历吧。
当我们学完了多线程的时候,龙哥就说我们已经有了做游戏的条件了。那是的我也是比较期待的,能自己做一个游戏出来其实一直是我的一个梦想。后面,龙哥终于要我们做游戏了。我几经考虑,就做了这个坦克大战的游戏。最初困扰我的就是界面问题,由于以前我有一套坦克游戏的图片(这也是我选做坦克项目的原因之一),所以什么切图片什么的毫无压力,最多的就是把图片背景设置为透明而已。但是,怎么样游戏界面不闪一直是我考虑的问题。因此我借鉴了以前龙哥说的双缓冲的方法,将所有的绘图功能都集成才一个paint()方法里。几经波折——处理传值问题——我终于做出主界面了,有游戏开始,游戏设置,排行榜,退出游戏等的图形界面了。那时候深深的体验到了功能模块化的好处了,最最方便我的就是改错的时候不用满天去寻找在那个阴暗的角落写了神马莫名其妙的东西而导致程序功能异常了。尝到甜头之后,我下定决心要先把整个程序的框架给弄出来。这个时候就感觉有一种天下尽在我手的感觉了,因为通过我不断的新建一个又一个的类,我把所有该做的东西都功能内聚的调节到一个个类里面去了,分工明确了,写程序好像思路清晰了很多。这个时候的我觉得作一个坦克,好像也不是什么难事,略施小计就可以轻松解决了。但人生在这个踌躇满志的状态往往很容易发生杯具,而这就是我发生杯具的开始。
我将坦克大战总共设计了11个类来完成运作,分别是游戏主界面,游戏设置,游戏排行,游戏帮助,开始游戏,游戏退出,子弹类,可销毁物品类,坦克类,敌方坦克人工智能类,和游戏引擎类。可以把它们分为两类来看待,也就是游戏核心(引擎)和游戏界面。
游戏主界面:游戏最初进去所看到的界面,它的功能是可以选择游戏开始,游戏设置,查看游戏排行,以及游戏帮助和游戏退出。
游戏开始:真正玩游戏的界面。
游戏设置:设置游戏按键,调整游戏音量,游戏难度等一系列的操作。
游戏帮助:给从来没玩过此类游戏的人员看的,告诉他们这个游戏的规则和操作。
游戏退出:退出游戏的选项。
子弹类:处理坦克发出的子弹的动作,比如说子弹打中坦克,子弹打中另外的子弹
坦克类:处理坦克的所有动作,移动,发子弹
可销毁物体类:处理那些可以被破坏的物体的状态,例如,土墙,钢板
人工智能:控制敌方坦克的移动与发子弹(玩家坦克由写在游戏开始里面的一个键盘监听器来控制)。
游戏引擎:处理游戏事件,负责创建游戏,结束游戏暂停游戏。
把整个框架搭好之后,我就开始一个类一个类的填充。我最先写的就是主界面,因为在窗体的正中央有5个按钮,所以我就在想到底用个什么布局管理器布局,然后搞5个JButton放在相应的位置,给JButton添加上图片,这样就成了。我百度谷歌了好多页面,最后发现那个GRIDLAYOUT好像可以用,但是用法比较复杂,很多属性,API又写的不详细,而在网上也找不到我所要的效果的范例。此时,我就想,可不可以用另外的办法来做这个东西呢。一定要用按钮?好像不用按钮也行呐,按钮被选中时也是一张图片啊。我用一个键盘监听器来监听我的按键,然后在适当的时候贴上图片不就行了吗。我仔细想了一下,觉得确实可行。就开始按这种方法去搞,最后果然成功了,代码如下:
public void keyPressed(KeyEvent e) {
// 按下方向键
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (GameMenuUI.loc == 0) {
GameMenuUI.loc = 4;
} else {
GameMenuUI.loc--;
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
GameMenuUI.loc = (GameMenuUI.loc + 1) % 5;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
if (GameMenuUI.loc == 0) {
GameMenuUI.loc = 4;
} else {
GameMenuUI.loc--;
}
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
GameMenuUI.loc = (GameMenuUI.loc + 1) % 5;
}
我用一个
loc
来记录当前光标所指向的位置,在键盘监听器里每次按下方向键,
loc
就做相应的改变,然后在线程里不断的刷屏就看起来像个按钮的效果一样了。
做完这个后,我就开始做游戏开始界面,因为我觉得这才是一个游戏的核心。由于游戏界面之前我重来没有编写过,我觉得这是整个游戏的难点。我开始就各种贴图,坦克有四个方向,分别对映四张图片。我那时就在想,怎么样让它在我按下箭头的时候,图片转换为坦克的枪口向下,按上它朝上呢。最后,我用一个公有的整形属性来记录它的方向,代码的思想其实和做主界面的按钮是差不多的。
之后,我觉得是时候写一下坦克的碰撞问题了。所以,我开始填充坦克类。我在坦克类里面写了两个方法,一个是坦克碰坦克,一个是坦克碰子弹(可破坏物体先被我晾到了一边去,因为此时我已经渐渐发现这个游戏做的没有想象中的那么简单了)。人有时候总是爱把问题想的太复杂,每次说都要解放思想,可是真正解放思想发散思维,真正做到的又有几个。同样,我在这上面也犯了这种错误。写出来的碰撞总是不对劲,后来去上课,听到吴少聪说他在那个Graphics2D里面发现了碰撞的方法。我当时一拍大腿,心里高兴极了,大叫如此甚好,如此甚好,得来全不费功夫。双手颤抖的打开API输入Graphics2D 找到了碰撞的方法,眯着眼睛上下扫描了不知道多少遍,又发现这个方法好像有不太适合我,我觉得我自己写反而可以更加简单,心里有点小沮丧。最后决定还是自己手写,不用现成的。但是自己写的碰撞总是有缺陷。后来我一边上厕所一边在想这个问题,我看到我的肥皂盒子用手比划了几下,突然就来了灵感,又怕想的不够全面,在心里反反复复的想了好多遍。觉得应该可行,才行动起来,把以前有缺陷的代码都换成了刚刚心里那个简单点的思路。运行一下,效果完美了。有的时候,灵感是很重要的。
写完坦克类之后我接着谢了子弹类,好歹也要让坦克能发子弹啊。子弹类其实和坦克类的结构差不多,我写子弹类是碰到的问题就是,在坦克类里放子弹碰坦克方法好还是在子弹里放好,纠结了半天,我最后将这个方法放到子弹类里面,我觉得这样好一点,坦克就管碰撞和移动就行,而子弹类就管销毁坦克或子弹,这样显得结构合理一点。
写好子弹类了,我就想,游戏好是可以判断游戏胜利,失败,暂停就好了。因此我开始写游戏引擎类,这个东西碰到的问题还满少的,个人感觉很顺,有一点要提的就是这里开始我写的程序在大体上是有序的,而在小的方面则有点小混乱了,值传递,是否该设置变量为静态的。我搞出好多空指针异常来,不过这都不算什么大问题,稍微检查下就出来了。
最后我写的就是人工智能了,唉,这是我写的最差的地方。没有任何头绪啊,设置的度个人感觉好难拿捏,你设置的大部队冲老巢吧,中间又没设置障碍物,那岂不是太变态了。设置的中等,我更本就没辙。太难处理了,清明的大好时光啊,就被我浪费在这上面了,可惜我还是没做出什么来。搞的我清明不快乐啊,最后我就没管那么多了,干脆都随机把,随机方向乱走,乱开枪。结果又坑爹了,那敌方坦克一个个像抽了筋似的,乱走,乱开子弹。但是我也没有更好的方案了。今天是我给自己最后的底线,今天反正要叫货。所以曾经还想在这个游戏上创新,到现在,现成的还没做好做完。强烈的反差啊,好沮丧。
最后就让我总结下我认为我这个项目学到的最重要的吧。第一,我觉得要写好一个程序,必须要先定好合理的框架,不能拿着就写,否则到后面会写不下去的。第二,既然定了框架,就要让功能都模块化,你要处理画面,就统一在一个地方都给处理掉了,不要又在别的地方处理画面。那天我问龙哥的一个问题也是这样的问题,我在监听器里让坦克移动了,这本来是坦克类里面移动方法的事,别的地方是坚决不能出现的,后来我把它放回到坦克类的移动方法里面去,程序就正常了。第三,这其实在我做五子棋的项目就出现过的错误,写程序不能一挥而就,记得那次写五子棋的人机对战,一口气写了2000行,之后我居然害怕点那个运行按钮,生怕它出错。心里反复安慰自己不会出错,最后鼓起勇气紧闭双眼点了运行,果然出错,我的天哪,满江红,console里面不知道有多少页红字。失落感,无力感,各种负面情绪此时毫不留情的侵袭了我,让我当时有砸机器的冲动。后面有一天听胡老师讲话,一个同学也碰到了一样的情况,他问了胡老师,这时候胡老师说,我们要一步一步调试,什么什么的。听他分析好像很科学的样子,于是我照做了,这次坦克的项目没有出现那种悲催的情况了。
第四,或许我该接受理想和现实的落差吧,每次我写的程序总是不完美的,可能我需要的就是尽量做到当下阶段我做的最好的吧。
不知不觉,我在word上面写了3页纸,统计下字数也有3800多字了。该做的总结也做的差不多了,虽然这次的项目我做的不好,但是我希望以后我的项目能越做越好吧。顺便祝福下所有同学,愿你们的编程水平越来越高。