一、设计简介
该项目是设计一个坦克大战小游戏,该游戏算不上精美,但是有始有终。有明确的游戏开始、单人模式、双人模式、游戏暂停和游戏失败等事件。设计内容包含图片双缓存技术,解决游戏屏幕闪动问题;还包含了击毁坦克的爆炸特效与子弹消失;还包含了碰撞检测,包括墙体和边界的。
二、相关工作
由于该游戏设计是实现了图形化界面,因此要有游戏元素的gif图片。在网上找到的图片要么是格式不对,要么就是像素太高,直接覆盖了整个画布,无法展示准确游戏元素。况且,这也与设计中游戏元素尺寸不符。所以,对于坦克元素玩家一、坦克元素玩家二、敌方坦克元素、围墙元素和基地元素都是我自己通过系统画图软件设计。可以自己调整像素值,使其符合游戏元素尺寸设定。如图2.1到2.5所示。
图2.1 图2.2 图2.3 图2.4 图2.5
可见,这些游戏元素都是灰色打底,那是因为设计的游戏界面就是灰色背景,为了带来视觉上的和谐,所以将图片背景填充为灰色。再者,就是坦克移动要有四个方向,所以每个坦克游戏元素,也都有对应的四个方向图片这里以玩家一的坦克为例,如图2.6到2.9。
图2.6 图2.7 图2.8 图2.9
还有就是爆炸特效用到的一连串图片,由小到大排列。这里就不在一一展示,放在下文实验结果和实验原理中展示。
三、设计原理
3.1图片双缓存技术原理。使用双 缓存的方法来解决屏幕闪动,大体的思路是重新创建一个空的图片,把所有组件,先绘制到空的图片上,再把绘制好图片,一次性绘制到主窗口中。
//定义双缓存图片
Image offScreemImage=null;
......
//创建和容器一样大小的Image图片
if(offScreemImage==null) {
offScreemImage=this.createImage(width,height);
}
//获得该图片的画笔
Graphics gImage=offScreemImage.getGraphics();
//设置画笔颜色,设置背景颜色
gImage.setColor(Color.gray);
//绘制实心矩形,填充整个画布(Image)图片
gImage.fillRect(0, 0, width, height);
//改变画笔颜色
gImage.setColor(Color.blue);
//改变文字大小和样式
gImage.setFont(new Font("仿宋",Font.BOLD,50));
......
//将缓存区绘制好的图形整个绘制到窗口容器的画布中
g.drawImage(offScreemImage, 0,0,null);
3.2键盘监视器原理。首先编写的GamePanel类是继承JFrame类的,这样才有创建窗口,监听键盘鼠标等事件的功能。而编写的KeyMonitor类,又是继承KeyAdapter类。这里出现了一个@Override的符号,含义是重写父类中的方法。
//键盘监视器
class KeyMonitor extends KeyAdapter{
//按下键盘
@Override
public void keyPressed(KeyEvent e) {//继承KeyAdapter类的keyPressed()方法
//返回键值
int key=e.getKeyCode();
switch (key) {
case KeyEvent.VK_1:
a=1;
y=150;
break;
case KeyEvent.VK_2:
a=2;
y=250;
break;
......
default:
playerOne.keyPressed(e);
playerTwo.keyPressed(e);
}
}
//松开键盘
@Override//重写父类@Override
public void keyReleased(KeyEvent e) {
playerOne.keyReleased(e);
playerTwo.keyReleased(e);
}
}
3.3坦克移动原理。这里键盘事件值得注意的是,为了让坦克移动可以按住移动键,而不是朝一个方向移动要快速按下该方向键。这里对坦克移动做了设计。还有就是坦克移动要改变其方向,图片元素也要跟着改变。坦克移动的设计代码如下。
//按下键盘,变为true,执行对应方法。
//按住时,因为程序快速执行true和false的变换,所以一直处于运动状态,松开时不在为ture所以不再移动
public void keyPressed(KeyEvent e) {
int key =e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
left=true;
break;
......
default:
break;
}
}
//松开键盘,自动变为false。
public void keyReleased(KeyEvent e) {
int key =e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
left=false;
break;
......
}
}
public void move(){//除了构造函数,其他函数不会自动调用
if(left) {
leftward();
}
......
}
3.4线程原理。对于游戏界面的重绘,是需要调用repaint()的,由repaint()调用update()来刷新界面,删去以前的界面,变为现在的界面。然后对paint()函数进行重写覆盖父类。其中paint()函数是系统线程自动调用的。
repaint();//重绘构建,但是会闪烁-->双缓冲
try {
Thread.sleep(25);//线程暂停25ns
}catch(Exception e) {
e.printStackTrace();
}
再有就是关于坦克发射子弹冷却时间的考量。这里就需要引入新的线程。
//新线程
class AttackCD extends Thread{
public void run() {
//将攻击功能设置为冷却状态
attackCoolDown=false;
//休眠1秒
try {
Thread.sleep(attackCoolDownTime);
}catch(Exception e) {
e.printStackTrace();
}
//将攻击功能解除冷却
attackCoolDown=true;
//线程终止
this.stop();
}
3.5碰撞检测原理。与围墙和边界的碰撞都采取先检测,在移动的规则。以防止坦克开进墙里的情况。所以传参数的时候,也是传下一个位置的坐标。如:
if(hitWall(x+speed, y) && moveToBorder(x+speed, y)) {
this.x+=speed;
3.6继承原理。我认为该坦克大战游戏设计,贯穿设计核心的就是继承关系。首先创建游戏元素类GameObject,作为游戏的父类。然后是创建了坦克类Tank,继承了GameObject类。然后是玩家一的坦克类,和玩家二的坦克类,都继承Tank类。子弹类Bulllet也是继承GameObject类。关于子类的构造函数,可以快速调用父类的构造函数。Super(x,y,z....);
3.7游戏元素列表原理。通过创建游戏元素列表,方便游戏元素的增删。特殊的,对于子弹类元素的删除,必须再创建一个remove()列表,否则删除子弹就会报错。我想,这应该和子弹的自动移动有关。
//游戏元素列表
ArrayList<Bullet> bulletList=new ArrayList<Bullet>();
ArrayList<Bot> botList=new ArrayList<Bot>();
ArrayList<Bullet> removeList=new ArrayList<Bullet>();
ArrayList<Tank> playerList=new ArrayList<Tank>();
ArrayList<Wall> wallList=new ArrayList<Wall>();
ArrayList<Base> baseList=new ArrayList<Base>();
ArrayList<Blast> blastList=new ArrayList<Blast>();
四、实现结果
4.1游戏主界面。
4.2游戏开始,以选择双人模式为例。
4.3按P,游戏暂停。
4.4击毁墙壁,并且击毁敌方坦克产生爆炸特效。
4.5玩家坦克被摧毁,或者我方基地被摧毁,游戏失败。
4.6敌方坦克被消灭,游戏胜利。
五、项目心得
通过本项目,我受益颇多。深切感受到了面向对象编程的魅力,丰富的游戏元素抽象为丰富的类,再衍生出子类,继承或者重写覆盖父类中的方法。还有键盘监听事件的巧妙运用,在设计过程中出现了很多严重的BUG,比如玩家坦克被击毁后还可以发射炮弹,这也在我为坦克添加布尔变量alive后得以解决。该设计虽然算不上功能丰富,但是也是可以称得上一个小休闲游戏了。程序也难免依然存在未发现的BUG,但是作为第一个Java小程序,做成这样有头有尾,编写了近千行代码,还是很有成就感的。
在代码编写过程中,我也遇到一些陌生的知识符号,比如说@Override,经在网上查阅后了解,是对父类的重写。还有就是GamePanel类中的paint()方法,我起初奇怪,没有调用它,为何会在屏幕中调用实现,经过我的一番推理,我觉得launch()方法中的repaint()应该和它相关,经过查阅资料,确实是系统自动调用。
标签:Java,游戏,KeyEvent,ArrayList,元素,实践,大战,new,坦克 From: https://www.cnblogs.com/nuist7bloger/p/17326734.html