在前面将场景创建完成后,下一步就是控制坦克的移动了,如果是仅是移动实现起来也比较简单,但是除了简单的移动还要处理好坦克到达边界的问题以及后面的多个坦克重叠的问题。
首先最重要的是进行按键的监听,在原先的类中写入按键监听
//键盘监听
private class Keynote extends KeyAdapter{
//键盘按下
@Override
public void keyPressed(KeyEvent e) {
mytank.keyPressed(e);
}
//键盘抬起
public void keyReleased(KeyEvent e) {
mytank.keyReleased(e);
}
}
按键监听的处理传给了另一个类进行处理,即需要专门建一个坦克类,将坦克要处理的事件全部写到坦克类中。
//定义变量
public static final int speed=8;//坦克速度
double speedxd=(speed*Math.sqrt(2))/2;//斜角速度
public int x,y;//坐标
Image zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50.png");//坦克图片
//在新建的坦克类中对按键事件进行处理
public void keyPressed(KeyEvent e){
int key=e.getKeyCode();
char keyc=e.getKeyChar();
if(key==KeyEvent.VK_RIGHT || keyc=='d'){//右
}else if(key==KeyEvent.VK_LEFT || keyc=='a'){//左
}else if(key==KeyEvent.VK_UP || keyc=='w'){//上
}else if(key==KeyEvent.VK_DOWN || keyc=='s'){//下
}
}
public void keyReleased(KeyEvent e){
int key=e.getKeyCode();
char keyc=e.getKeyChar();
if(key==KeyEvent.VK_RIGHT || keyc=='d'){//右
}else if(key==KeyEvent.VK_LEFT || keyc=='a'){//左
}else if(key==KeyEvent.VK_UP || keyc=='w'){//上
}else if(key==KeyEvent.VK_DOWN || keyc=='s'){//下
}
}
四个方向的按键写完之后,要让坦克移动其实只需要进行x与y的加减就好了,当时我要实现的坦克需要进行八个方向的移动,即同时按下“上键”与“左键”可向左上方移动,所以就不能简单的将坐标移动写在单个的按键事件中,而是通过四个变量记录按键是否被按下,在进行相应的移动处理。
//加入四个变量记录按键是否被按下并记录坦克的当前方向
private boolean bl=false,bu=false,br=false,bd=false;
enum Direction{l,lu,u,ru,r,rd,d,ld,stop}; //枚举
private Direction dir=Direction.stop;
//在按键监听的最后调用此方法判断坦克的移动方向
public void locateDirection(){
if(bl && !bu && !br && !bd){dir=Direction.l;}//左
else if(bl && bu && !br && !bd){dir=Direction.lu;}//左上
else if(!bl && bu && !br && !bd){dir=Direction.u;}//上
else if(!bl && bu && br && !bd){dir=Direction.ru;}//右上
else if(!bl && !bu && br && !bd){dir=Direction.r;}//右
else if(!bl && !bu && br && bd){dir=Direction.rd;}//右下
else if(!bl && !bu && !br && bd){dir=Direction.d;}//下
else if(bl && !bu && !br && bd){dir=Direction.ld;}//左下
else if(!bl && !bu && !br && !bd){dir=Direction.stop;}//停
}
加入四个变量后,但按下对应的按键就只需将对应变量的bool值修改true,抬起按键时修改为false就行了
//将坦克类的方法完善,让其他类只需要进行调用就能实现坦克相关的方法
//构造方法
public Tank(int x, int y,boolean good,tankedz tc) {
this.x = x;
this.y = y;
this.good = good;
this.tc = tc;
if(!good){
djtk();
}
}
//绘制坦克
public void draw(Graphics g){
if(!live){return;}
g.drawImage(zhutk,x, y,null);
move();//移动
}
//坦克的移动方法
public void move(){
int yx=x;int yy=y;//记录坦克移动前的位置
switch(dir){
case l:
x -= speed;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50l.png");
break;
case lu:
x -= speedxd;y -= speedxd;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50zs.png");
break;
case u:
y -= speed;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50.png");
break;
case ru:
x += speedxd;y -= speedxd;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50ys.png");
break;
case r:
x += speed;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50r.png");
break;
case rd:
x += speedxd;y += speedxd;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50yx.png");
break;
case d:
y += speed;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50x.png");
break;
case ld:
x -= speedxd;y += speedxd;
zhutk = Toolkit.getDefaultToolkit().getImage("img/ztk50zx.png");
break;
case stop:
break;
}
if(dir!=Direction.stop){
ptdir=dir;
}
//判断移动后位置是否超过窗口的限制,如果超过就让位置恢复到移动前的位置;
if(x<=0 || y<=25 || x >= (tankedz.width-50) || y>=(tankedz.height-50) || gitTanks()){
x=yx;y=yy;
}
}
这样就完成了坦克的移动,同时要创建坦克也只需要进行调用就可以了
Tank mytank = new Tank(600, 400,true,this);
坦克可以发射炮弹消灭敌军
要想让坦克发射炮弹这个也需要按键的监听,但在这之前还要创建一个新类“炮弹类”,这样发射炮弹时同样也只需要调用炮弹类的方法就可以了。
int x,y;//位置
char zdfx;//子弹方向
public static final int speed=16;//子弹速度
double speedxd=(speed*Math.sqrt(2))/2;//斜角速度
Tank.Direction dir;
private tankedz tc;
//子弹是否存亡
//子弹在击中敌军及超出边界时因让子弹消失不再继续绘制
private boolean live = true;
public boolean islive() {
return live;
}
//子弹图片
Image paodam = Toolkit.getDefaultToolkit().getImage("img/paodan.png");
//绘制子弹
public void draw(Graphics g){
g.drawImage(paodam,x, y,null);
move();
}
定义子弹类的关键变量记方法后,下一步就是子弹的移动了,主要方法与坦克基本一致
//dir由坦克调用子弹类时传入,同时注意子弹移动没有停止的状态
public void move(){
switch(dir){
case l:
x -= speed;break;
case lu:
x -= speedxd;y -= speedxd;break;
case u:
y -= speed;break;
case ru:
x += speedxd;y -= speedxd;break;
case r:
x += speed;break;
case rd:
x += speedxd;y += speedxd;break;
case d:
y += speed;break;
case ld:
x -= speedxd;y += speedxd;break;
}
//超出边界子弹死亡
if(x<0 || y<0 || x > tankedz.width || y>tankedz.height){
live=false;
}
}
由于子弹不可能只存在一个,所以在主类中用List进行对所有子弹进行存放
//子弹
List<Missile> missiles =new ArrayList<Missile>();
//在主类paint方法中循环list,如果子弹没消亡就继续绘制,否则移除
for(int i=0;i<missiles.size();i++){
Missile m =missiles.get(i);
m.gitTanks(tankes);
if(!m.islive()){
missiles.remove(m);
}else{m.draw(g);}
}
下面是坦克的调用了,在坦克的按键监听中再加入子弹键的监听,当子弹键按下时创建子弹并加入子弹的list;
if(key==KeyEvent.VK_SPACE || key==10 || key==17){
tc.missiles.add(fire());
Timer timer = new Timer();
timer.schedule(new TimerTaskTest(),500);
}
public Missile fire(){
Missile miss =new Missile(x,y,ptdir,tc);
return miss;
}
这样子弹就能发射炮弹了