Java实现的坦克
设计思路:
坦克游戏主类:TankGame
控制自己坦克的类:MyTank
自己发出的炮弹的线程类:MyShell
敌人坦克运动线程类:EnemyTank
敌人炮弹线程类:Shell
监听敌人敌人炮弹队列的线程类:ShellThread
定时产生敌人坦克的线程类:CreateTank
游戏参数配置借口:Config
坦克游戏主类:TankGame
1.坦克游戏主类是程序运行开始的入口。
2.包含显示窗体的方法showUI();
3.以及重写后的重绘方法paint(g);
重绘方法中调用了以下方法:
drawNumber();//显示我方坦克剩余数
deploy();// 调用显示障碍物的方法
paintEnemyTank();//显示敌方坦克
drawMyTank();// 画出我自己的坦克
控制自己坦克的类:MyTank
MyTank类是控制自己坦克的类,这是一个监听器处理类,它继承了抽象类java.awt.event.KeyAdapter,用来监听键盘按键并控制我方坦克的运动。
java.awt.event.KeyAdapter类是键盘事件的抽象类,它实现了java.awt.event.KeyListener接口。
KeyListener接口中有3个方法:
keyPressed:按下按键时调用的方法;
keyTyped:键入某个键时调用此方法 ,可响应多次键击组合生成的字符 ;
keyReleased:释放按键时调用的方法。
自己发出的炮弹的线程类:MyShell
MyShell继承了Thread类。
用于控制我方发出的炮弹的运动情况。
其中含有几个判断方法
判断炮弹是否打出游戏区域
判断炮弹是否打中敌方坦克
通过遍历敌人坦克队列中的坦克对象,获取坦克对象的坐标并比较座标间的关系来判断是否打中坦克。
判断炮弹是否打到障碍物
敌人坦克运动线程类:EnemyTank
继承了Thread类的线程类,每一个EnemyTank的实例化对象就是一个敌人坦克。每一个线程对象独立控制各个敌人坦克的运动情况,包括:
坦克的运动方向
随机生成一个数字,根据数字判断运动方向
坦克是否运动到游戏区域边界,并限制它在游戏区域内运动
不能让坦克穿过实体障碍物(如:砖块和石头)
坦克控制发射炮弹
监听自己是否中弹,若中弹则消失
线程中每一次循环,都调用判断是否中弹的方法。获取我的炮弹的坐标跟敌人坦克的坐标进行比较。
敌人炮弹线程类:Shell
Shell继承了Thread类。
用于表示敌方发出的炮弹的运动情况。
其中含有几个判断方法
判断炮弹是否打出游戏区域
判断炮弹是否打中我方坦克
若打中,则我方坦克消失,敌人炮弹消失
判断炮弹是否打中敌方坦克
若打中,则只是炮弹消失
判断炮弹是否打到障碍物
若打中砖块,砖块消失
若打中石头,则只是炮弹消失
监听敌人炮弹队列的线程类:ShellThread
在敌方坦克线程中,每实例化一个敌人炮弹线程对象,就将这个炮弹线程对象添加到一个炮弹线程对象队列中。
队列的创建如下:
protected static java.util.ArrayList<Shell> shellList = new java.util.ArrayList<Shell>();
在ShellThread线程中,通过不断地询问炮弹队列中的炮弹是否已经消失,将已经消失的炮弹从队列中移除。
定时产生敌人坦克的线程类:CreateTank
根据游戏区域现有的敌方坦克数目和既定的时间,产生新的敌方坦克。
每隔一定时间判断一下游戏区域现有的敌方坦克数目是否小于既定的数目,如果小于则实例化敌方坦克对象,补充敌方坦克。
游戏参数配置接口:Config
窗体的大小参数
游戏区域大小参数
障碍物大小参数
坦克大小参数
坦克每次移动的距离
炮弹每次移动距离
障碍物布局二维数组等
碰到的问题
问题一、敌方坦克发射炮弹时,敌方坦克就会不停地闪烁。
尝试的解决方法:
1.最初尝试使用双缓冲技术,降低了闪烁频率。
2.使用双缓冲技术虽然在一定程度上解决了闪烁问题,但是出现了新的问题。在使用双缓冲技术之前,游戏区域的背景色是黑色,而在之后,背景色为无色。
3.经过分析,发现坦克闪烁的根源是:发射的炮弹把坦克覆盖了。于是,改进方案是:
1、改变发射炮弹的初始坐标,使初始坐标不在坦克的图片范围内。
2、改变炮弹图片的大小,将炮弹图片缩小。如:原来的图片是30*30的,可以将图片改成15*15,或10*10.
问题二、敌方坦克在中弹后还会继续运动一小段距离才会爆炸消失。
问题分析:
最初的设计是:在我的炮弹类中监听是否打中敌方坦克。若打中敌方坦克,就将我的炮弹设置为死亡,同时将被打中的坦克对象中的isOver属性设置为“true”,即终结坦克线程的run()方法中while循环。但是,由于各个线程独立运行,在坦克对象接收到新的isOver值有一定的时差,所以导致问题的出现。
解决方案:
改进前,只是在我的炮弹类中判断是否打中敌方坦克。改进后,在每一个敌方坦克线程对象中,都判断是否被我的炮弹击中,一旦被击中,则坦克线程会立即终止循环,终止线程。
<!--EndFragment-->