绘图原理

  • frame类继承JFrame是窗口的框架。

  • Mypanel类继承JPanel是画布。

  • 重写画布类的paint()方法绘制图形。

  • 在框架类中初始化画布类,将画布加入窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import javax.swing.*;
import java.awt.*;

public class draw {
public static void main(String[] args) {
new frame();
}
}

class frame extends JFrame{
Mypanel mp = null;
public frame() {
mp = new Mypanel();
this.add(mp);
this.setSize(500,500);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口就退出程序
}
}

class Mypanel extends JPanel{
//MyPanel是一个画板
//Graphics g是画笔
//Graphics提供了绘图方法
@Override
public void paint(Graphics g) {
super.paint(g);
//画一个圆形,前两个参数是圆形左上角的坐标(坐标原点是左上角)
//g.drawOval(10,10,100,100);//椭圆
//g.drawLine(10,10,200,200);//直线
//g.drawRect(10,10,100,100);//矩形
g.setColor(Color.blue);//设置画笔颜色
//g.fillRect(10,10,200,200);//填充矩形
//g.fillOval(10,10,200,200);
//---------画图片---------//
//1.获取图片资源
//Image image = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bg.png"));
//图片放到out文件夹下
//g.drawImage(image,10,10,175,221,this);
//---------画图片---------//
//写字
g.setFont(new Font("宋体",Font.BOLD,50));
g.drawString("哈哈",100,100);
}
}

绘制坦克

  • Tank类为所有角色的父类
  • Player玩家类继承自Tank
  • MyPanel画布类继承JPanel类,绘制图形
  • Frame画框类实现主函数,初始化画布
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.tankgame;

public class Tank {
private int x; //坦克的横纵坐标
private int y;

public Tank(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}
}


1
2
3
4
5
6
7
8
9
10
package com.tankgame;
/*
* 玩家
* */
public class Player extends Tank {
public Player(int x, int y) {
super(x, y);
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.tankgame;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;

public class MyPanel extends JPanel {
Player player = null;
public MyPanel(){
player = new Player(100,100);//初始化玩家
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0,0,1000,750);//填充矩形,默认黑色
drawTank(player.getX(), player.getY(),g,0,0);
}

/**
*
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x,int y,Graphics g,int direction,int type){
//设置颜色
switch(type){
case 0:
g.setColor(Color.cyan);
break;
case 1:
g.setColor(Color.yellow);
break;
}
//跟据坦克方向绘制坦克
switch(direction){
case 0:
g.fill3DRect(x,y,10,60,false);
g.fill3DRect(x+30,y,10,60,false);
g.fill3DRect(x+10,y+10,20,40,false);
g.fillOval(x+10,y+20,20,20);
g.drawLine(x+20,y+30,x+20,y);
break;
default:
System.out.println("敬请期待");
}
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.tankgame;

import javax.swing.*;
import java.awt.*;

public class Frame extends JFrame {
MyPanel mp=null;
public static void main(String[] args) {
new Frame();
}

public Frame() {
mp = new MyPanel();
this.add(mp);
this.setSize(1000,750);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);

}
}

效果图

坦克大战01

事件处理机制

事件处理机制解决如何接收键盘输入实现小球移动问题

  • MyPanel类实现KeyListener接口,重写其中的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Override
    public void keyTyped(KeyEvent e) {

    }

    //某个键按下时,该方法触发
    @Override
    public void keyPressed(KeyEvent e) {

    }

    //某个键释放时,该方法触发
    @Override
    public void keyReleased(KeyEvent e) {

    }
  • class BallMove extends JFrame类里加入this.addKeyListener(mp);即可监听面板发生的键盘事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.event_;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class BallMove extends JFrame {
MyPanel mp = null;
public static void main(String[] args) {
new BallMove();
}
public BallMove(){
mp = new MyPanel();
this.add(mp);
//窗口JFrame监听键盘事件,即可以监听面板发生的键盘事件
this.addKeyListener(mp);
this.setSize(400,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);

}
}
//继承监听器,监听键盘事件
class MyPanel extends JPanel implements KeyListener {
//为了让小球移动,把左上角的坐标设置为变量
int x = 10;
int y = 10;
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x,y,20,20 );

}
//有字符输出时,该方法触发
@Override
public void keyTyped(KeyEvent e) {

}

//某个键按下时,该方法触发
@Override
public void keyPressed(KeyEvent e) {
//System.out.println((char)e.getKeyCode()+" was pressed");
if(e.getKeyCode()==KeyEvent.VK_DOWN){ //如果按方向键下
y++;
}
else if(e.getKeyCode()==KeyEvent.VK_UP){
y--;
}
else if(e.getKeyCode()==KeyEvent.VK_LEFT){
x--;
}
else if(e.getKeyCode()==KeyEvent.VK_RIGHT){
x++;
}
this.repaint();
}

//某个键释放时,该方法触发
@Override
public void keyReleased(KeyEvent e) {

}
}
//代码实现了用方向键控制小球移动

让坦克动起来

  • Tank类增加属性directionspeed分别表示坦克的方向和速度。
  • Tank类增加四个移动函数,改变坦克的方向和位置
  • MyPanel类绘制另外三个方向的坦克
  • 添加监听事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.tankgame02;

public class Tank {
private int x; //坦克的横纵坐标
private int y;
private int direction;//坦克方向
private int speed = 4;

public int getSpeed() {
return speed;
}

public void setSpeed(int speed) {
this.speed = speed;
}

public int getDirection() {
return direction;
}

public void setDirection(int direction) {
this.direction = direction;
}

public Tank(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public void moveup() {
direction = 0;
y -= speed;
}

public void moveright() {
direction = 1;
x += speed;
}

public void movedown() {
direction = 2;
y += speed;
}

public void moveleft() {
direction = 3;
x -= speed;
}

}




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.tankgame02;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class MyPanel extends JPanel implements KeyListener {
Player player = null;

public MyPanel() {
player = new Player(100, 100);//初始化玩家
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
default:
System.out.println("敬请期待");
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
}
this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.tankgame02;

import javax.swing.*;

public class Frame extends JFrame {
MyPanel mp = null;

public static void main(String[] args) {
new Frame();
}

public Frame() {
mp = new MyPanel();
this.add(mp);
this.addKeyListener(mp);
this.setSize(1000, 750);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);

}
}


增加敌人

  • 添加Enemy类继承Tank,修改方向让敌人的炮筒指向下
  • Vector存放敌人
1
2
3
4
5
6
7
8
9
package com.tankgame02;

public class Enemy extends Tank {
public Enemy(int x, int y) {
super(x, y);
this.setDirection(2);
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.tankgame02;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
int enemySize = 3;


public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) {
enemies.add(new Enemy((i * 100 + 100), 0));
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
default:
System.out.println("敬请期待");
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
}
this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}
}


效果图

坦克大战02

发射子弹

玩家发射子弹

实现按下J键,玩家坦克发射子弹

  • 创建Bullet类,用重写方式实现线程重写run()方法
  • run()方法里实现子弹向炮筒的方向移动
  • Player类里实现shoot()方法,每次调用该方法就启动一个子弹线程
  • MyPanel类里添加按键操作,和绘制子弹方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.tankgame03;
/*
* 子弹
* */

public class Bullet implements Runnable {
private int x;
private int y;
private int direction = 0;//子弹方向
private int speed = 8;
private boolean isLive = true;

public Bullet(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}

@Override
public void run() { //射击行为

while (true) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//跟据方向移动
switch (direction) {
case 0: //上
y -= speed;
break;
case 1: //右
x += speed;
break;
case 2: //下
y += speed;
break;
case 3: //左
x -= speed;
break;
}
System.out.println("x "+x+"y "+y);
//子弹出界,销毁
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750)) {
isLive = false;
break;
}
}

}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.tankgame03;

/*
* 玩家
* */
public class Player extends Tank {
private Bullet bullet = null; //一个射击线程

public Player(int x, int y) {
super(x, y);
}

public void shoot() {
switch (getDirection()) {
case 0:
bullet = new Bullet(getX() + 20, getY(), 0);
break;
case 1:
bullet = new Bullet(getX() + 60, getY() + 20, 1);
break;
case 2:
bullet = new Bullet(getX() + 20, getY() + 60, 2);
break;
case 3:
bullet = new Bullet(getX(), getY() + 20, 3);
break;
}
//启动射击线程
new Thread(bullet).start();
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.tankgame03;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
int enemySize = 3;


public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) {
enemies.add(new Enemy((i * 100 + 100), 0));
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
drawBullet(g);
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
}
}

public void drawBullet(Graphics g) {
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}
}

public void keyPressed(KeyEvent e)这个函数里每次按下键盘画面重绘一次。虽然能够实现坦克的移动(因为不按键盘坦克就会静止也就不需要重绘了),但是子弹不能一直移动,也是只能每次按一下键盘才能动一次。

所以为了让MyPanel不停重绘画面,让MyPanel类继承Runnable类,在run()方法中不断刷新

最后在Frame里启动线程


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package com.tankgame03;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
int enemySize = 3;


public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) {
enemies.add(new Enemy((i * 100 + 100), 0));
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
drawBullet(g);
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
}
}

public void drawBullet(Graphics g) {
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.repaint();
}
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.tankgame03;

import javax.swing.*;

public class Frame extends JFrame {
MyPanel mp = null;

public static void main(String[] args) {
new Frame();
}

public Frame() {
mp = new MyPanel();
new Thread(mp).start();
this.add(mp);
this.addKeyListener(mp);
this.setSize(1000, 750);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);

}
}


敌人发射子弹

  • Enemy类创建Vector存储敌人子弹
  • 每创建一个敌人,就创建一个子弹线程并启动
  • 重绘子弹

1
2
3
4
5
6
7
8
9
10
11
12
package com.tankgame04;

import java.util.Vector;

public class Enemy extends Tank {
Vector<Bullet> bullets = new Vector<>();
public Enemy(int x, int y) {
super(x, y);
this.setDirection(2);
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package com.tankgame04;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
int enemySize = 3;


public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0);
enemies.add(enemy);
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
//绘制子弹
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
for (int i = 0; i < enemies.size(); i++) {
// 画出敌人坦克
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
//画出敌人坦克子弹
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet.isLive()) {
g.fill3DRect(bullet.getX(),bullet.getY(),5,5,false);
}
else{
enemy.bullets.remove(bullet);
}
}
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

@Override
public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.repaint();
}
}
}

攻击效果

实现玩家子弹攻击到敌人时,敌人消失的效果。

  • MyPanel类实现hitTank()方法实现子弹玩家子弹击中敌人效果

    • 跟据敌人的方向分为上下和左右两组
    • 分别实现两组击中判断
    • 如果击中将子弹和玩家的isLive设置为false,并将对应敌人从集合删除
  • run()方法中循环hitTank()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package com.tankgame04;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
int enemySize = 3;


public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0);
enemies.add(enemy);
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
//绘制子弹
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
for (int i = 0; i < enemies.size(); i++) {
// 画出敌人坦克
Enemy enemy = enemies.get(i);
if (enemy.isLive) {
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
//画出敌人坦克子弹
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet.isLive()) {
g.fill3DRect(bullet.getX(), bullet.getY(), 5, 5, false);
} else {
enemy.bullets.remove(bullet);
}
}
}
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

//判断玩家的子弹是否击中敌人坦克
public void hitTank(Bullet b, Enemy e) {
switch (e.getDirection()) {
case 0: //坦克向上
case 2: //坦克向下
if (b.getX() > e.getX() && b.getX() < e.getX() + 40 && b.getY() > e.getY() && b.getY() < e.getY() + 60) {
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}
break;
case 1: //坦克向右
case 3: //坦克向左
if (b.getX() > e.getX() && b.getX() < e.getX() + 60 &&
b.getY() > e.getY() && b.getY() < e.getY() + 40) {
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}

}
}

@Override
public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
if (player.getBullet() != null && player.getBullet().isLive()) {
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
hitTank(player.getBullet(), enemy);
}
}
this.repaint();
}
}
}

爆炸效果

玩家击中敌人时出现爆炸效果。爆炸效果用三张图片实现

  • 创建爆炸效果Bomb类,实现lifeDown函数,生存时间递减。
  • MyPanel类创建集合存储Bomb对象,当击中坦克时加入一个对象
  • 遍历集合绘制爆炸效果,当生存时间为0,在集合中删除对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.tankgame04;

/**
* 爆炸效果
*/

public class Bomb {
private int x;
private int y;
private int life = 9;
private boolean isLive = true;

public Bomb(int x, int y) {
this.x = x;
this.y = y;
}

public void lifeDown() {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (life > 0) {
life--;
} else {
isLive = false;
}
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public int getLife() {
return life;
}

public void setLife(int life) {
this.life = life;
}

public boolean isLive() {
return isLive;
}

public void setLive(boolean live) {
isLive = live;
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package com.tankgame04;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
//定义爆炸集合
//当子弹击中坦克时加入一个bomb
Vector<Bomb> bombs = new Vector<>();
//定义三张图片,用于显示爆炸效果
Image image1 = null;
Image image2 = null;
Image image3 = null;


int enemySize = 3;

public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0);
enemies.add(enemy);
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_1.gif"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_2.gif"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_3.gif"));
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
//绘制子弹
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
for (int i = 0; i < enemies.size(); i++) {
// 画出敌人坦克
Enemy enemy = enemies.get(i);
if (enemy.isLive) {
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
//画出敌人坦克子弹
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet.isLive()) {
g.fill3DRect(bullet.getX(), bullet.getY(), 5, 5, false);
} else {
enemy.bullets.remove(bullet);
}
}
}
}
//绘制爆炸效果
for (int i = 0; i < bombs.size(); i++) {
Bomb bomb = bombs.get(i);
//跟据life值画出对应的图片
if (bomb.getLife() > 6) {
g.drawImage(image1, bomb.getX(), bomb.getY(), 60, 60, this);
} else if (bomb.getLife() > 3) {
g.drawImage(image2, bomb.getX(), bomb.getY(), 60, 60, this);
} else {
g.drawImage(image3, bomb.getX(), bomb.getY(), 60, 60, this);
}
bomb.lifeDown();
if(bomb.getLife()==0){
bombs.remove(bomb);
}
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

//判断玩家的子弹是否击中敌人坦克
public void hitTank(Bullet b, Enemy e) {
switch (e.getDirection()) {
case 0: //坦克向上
case 2: //坦克向下
if (b.getX() > e.getX() && b.getX() < e.getX() + 40 && b.getY() > e.getY() && b.getY() < e.getY() + 60) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);

}
break;
case 1: //坦克向右
case 3: //坦克向左
if (b.getX() > e.getX() && b.getX() < e.getX() + 60 &&
b.getY() > e.getY() && b.getY() < e.getY() + 40) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}

}
}

@Override
public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
if (player.getBullet() != null && player.getBullet().isLive()) {
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
hitTank(player.getBullet(), enemy);
}
}
this.repaint();
}
}
}

敌人移动

  • Enemy类实现Runnable接口
  • run()方法中实现敌人自由移动
  • 每次新建一个敌人就启动一个线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.tankgame04;

import java.util.Vector;

public class Enemy extends Tank implements Runnable {
Vector<Bullet> bullets = new Vector<>();
boolean isLive = true;

public Enemy(int x, int y) {
super(x, y);
this.setDirection(2);
}

@Override
public void run() {
//坦克向前方移动,然后随机改变方向
while (true) {
int direction = (int) (Math.random() * 4);
switch (direction) {
case 0:
for (int i = 0; i < 30; i++) {
moveup();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 1:
for (int i = 0; i < 30; i++) {
moveright();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 2:
for (int i = 0; i < 30; i++) {
movedown();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 3:
for (int i = 0; i < 30; i++) {
moveleft();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}


}
}

public boolean isLive() {
return isLive;
}

public void setLive(boolean live) {
isLive = live;
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package com.tankgame04;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
Player player = null;
Vector<Enemy> enemies = new Vector<>(); //敌人坦克数组
//定义爆炸集合
//当子弹击中坦克时加入一个bomb
Vector<Bomb> bombs = new Vector<>();
//定义三张图片,用于显示爆炸效果
Image image1 = null;
Image image2 = null;
Image image3 = null;


int enemySize = 3;

public MyPanel() {
player = new Player(100, 100);//初始化玩家
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0);
enemies.add(enemy);
new Thread(enemy).start();
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_1.gif"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_2.gif"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_3.gif"));
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
//drawTank(player.getX(), player.getY(),g,0,0);
//drawTank(player.getX(), player.getY(),g,1,1);
//drawTank(player.getX(), player.getY(),g,2,1);
drawTank(player.getX(), player.getY(), g, player.getDirection(), 1);
//绘制子弹
if (player.getBullet() != null && player.getBullet().isLive()) {
g.fill3DRect(player.getBullet().getX(), player.getBullet().getY(),
5, 5, false);
}
for (int i = 0; i < enemies.size(); i++) {
// 画出敌人坦克
Enemy enemy = enemies.get(i);
if (enemy.isLive) {
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 0);
//画出敌人坦克子弹
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet.isLive()) {
g.fill3DRect(bullet.getX(), bullet.getY(), 5, 5, false);
} else {
enemy.bullets.remove(bullet);
}
}
}
}
//绘制爆炸效果
for (int i = 0; i < bombs.size(); i++) {
Bomb bomb = bombs.get(i);
//跟据life值画出对应的图片
if (bomb.getLife() > 6) {
g.drawImage(image1, bomb.getX(), bomb.getY(), 60, 60, this);
} else if (bomb.getLife() > 3) {
g.drawImage(image2, bomb.getX(), bomb.getY(), 60, 60, this);
} else {
g.drawImage(image3, bomb.getX(), bomb.getY(), 60, 60, this);
}
bomb.lifeDown();
if(bomb.getLife()==0){
bombs.remove(bomb);
}
}
}

/**
* @param x 坦克左上角横坐标
* @param y 坦克左上角纵坐标
* @param g 画笔
* @param direction 方向
* @param type 类型 0:玩家 ,1:敌人
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//设置颜色
switch (type) {
case 0:
g.setColor(Color.yellow);
break;
case 1:
g.setColor(Color.cyan);
break;
}
//跟据坦克方向绘制坦克
//0:向上,1:向右,2:向下,3:向左
switch (direction) {
case 0: //向上
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}

this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

//判断玩家的子弹是否击中敌人坦克
public void hitTank(Bullet b, Enemy e) {
switch (e.getDirection()) {
case 0: //坦克向上
case 2: //坦克向下
if (b.getX() > e.getX() && b.getX() < e.getX() + 40 && b.getY() > e.getY() && b.getY() < e.getY() + 60) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);

}
break;
case 1: //坦克向右
case 3: //坦克向左
if (b.getX() > e.getX() && b.getX() < e.getX() + 60 &&
b.getY() > e.getY() && b.getY() < e.getY() + 40) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}

}
}

@Override
public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
if (player.getBullet() != null && player.getBullet().isLive()) {
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
hitTank(player.getBullet(), enemy);
}
}
this.repaint();
}
}
}

限制移动范围

将敌人和玩家的移动范围限制在窗口内

修改Tank类的移动函数,加入判断条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void moveup() {
if (getY() > 0) {
direction = 0;
y -= speed;
}
}

public void moveright() {
if (getX() + 60 < 1000) {
direction = 1;
x += speed;
}
}

public void movedown() {
if (getY() + 60 < 750) {
direction = 2;
y += speed;
}
}

public void moveleft() {
if (getX() > 0) {
direction = 3;
x -= speed;
}
}

完善子弹

玩家可以连发

现在玩家只能发射一颗子弹,每次按下J键,上一颗子弹会消失然后发射一颗新子弹。现在实现连发功能

  • Player类里初始化集合bullets存储所有的子弹
  • shoot()方法里实现每次发射一颗子弹就将子弹加入集合
  • 修改击中逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.tankgame04;

import java.util.Vector;

/*
* 玩家
* */
public class Player extends Tank {
···
Vector<Bullet> bullets = new Vector<>();
···
public void shoot() {
···
bullets.add(bullet); //添加这句
new Thread(bullet).start();
···
}
}

1
2
3
4
5
6
7
8
9
10
11
12
package com.tankgame04;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
public void paint(Graphics g) {
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        for (int i = 0; i < player.bullets.size(); i++) { //绘制每一颗子弹
Bullet bullet = player.bullets.get(i);
g.fill3DRect(bullet.getX(), bullet.getY(),
5, 5, false);
if (!bullet.isLive()) {
player.bullets.remove(bullet);
}
}
}

public void run() { //重绘
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
for (int i = 0; i < player.bullets.size(); i++) { //遍历子弹数组和敌人数组判断是否击中
Bullet bullet = player.bullets.get(i);
if (bullet != null && bullet.isLive()) {
for (int j = 0; j < enemies.size(); j++) {
Enemy enemy = enemies.get(j);
hitTank(bullet, enemy);
}
}
}
this.repaint();
}
}
}

敌人可以连发

现在敌人只能发一次子弹。实现子弹连发功能

  • Enemy类实现Shoot()方法,直接复制玩家类的
  • Shoot()方法加入到run()方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package comclone.tankgame04;

import java.util.Vector;

public class Enemy extends Tank implements Runnable {
public void shoot() {
switch (getDirection()) {
case 0:
bullet = new Bullet(getX() + 20, getY(), 0);
break;
case 1:
bullet = new Bullet(getX() + 60, getY() + 20, 1);
break;
case 2:
bullet = new Bullet(getX() + 20, getY() + 60, 2);
break;
case 3:
bullet = new Bullet(getX(), getY() + 20, 3);
break;
}
bullets.add(bullet);
new Thread(bullet).start();
}

@Override
public void run() {
    shoot();
    
1
2
    }
}

玩家被击中效果

现在只有玩家能击中敌人,敌人不能击中玩家

  • MyPanel类添加hitHero()方法,实现击中玩家逻辑
  • 如果玩家被击中,将玩家的isLive设置为false
  • 为绘制玩家增加判断玩家是否存活的判断条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
package comclone.tankgame04;


import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {

Player player = null;
Vector<Enemy> enemies = new Vector<>();
//创建爆炸效果数组
Vector<Bomb> bombs = new Vector<>();
int enemieSize = 4;
Image image1 = null;
Image image2 = null;
Image image3 = null;

public MyPanel() {
player = new Player(500, 500);
for (int i = 0; i < enemieSize; i++) {
Enemy enemy = new Enemy((100 + i * 100), 0);
enemies.add(enemy);
new Thread(enemy).start();
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_1.gif"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_2.gif"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource
("/bomb_3.gif"));
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色
if (player != null && player.isLive()) {
drawTank(player.getX(), player.getY(), g, player.getDirection(), 0);

for (int i = 0; i < player.bullets.size(); i++) { //绘制玩家 子弹
Bullet bullet = player.bullets.get(i);
if (bullet != null && bullet.isLive()) {
g.fill3DRect(bullet.getX(), bullet.getY(),
5, 5, false);
}
}
}

for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), g, enemy.getDirection(), 1);
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet.isLive()) {
g.fill3DRect(bullet.getX(), bullet.getY(), 5, 5, false);
} else {
enemy.bullets.remove(bullet);
}
}
}
for (int i = 0; i < bombs.size(); i++) {
Bomb bomb = bombs.get(i);
if (bomb.getLife() > 6) {
g.drawImage(image1, bomb.getX(), bomb.getY(), 60, 60, this);
} else if (bomb.getLife() > 3) {
g.drawImage(image1, bomb.getX(), bomb.getY(), 60, 60, this);
} else {
g.drawImage(image1, bomb.getX(), bomb.getY(), 60, 60, this);
}
bomb.lifeDown();
if (bomb.getLife() <= 0) {
bombs.remove(bomb);
}
}
}

public void drawTank(int x, int y, Graphics g, int direction, int type) {
switch (type) {
case 0: //自己
g.setColor(Color.cyan);
break;
case 1: //坦克
g.setColor(Color.yellow);
break;
}
switch (direction) {
case 0:
g.fill3DRect(x, y, 10, 60, false);
g.fill3DRect(x + 30, y, 10, 60, false);
g.fill3DRect(x + 10, y + 10, 20, 40, false);
g.fillOval(x + 10, y + 20, 20, 20);
g.drawLine(x + 20, y + 30, x + 20, y);
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x + 60, y + 20);
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false);//左轮
g.fill3DRect(x + 30, y, 10, 60, false);//右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//盖子
g.fillOval(x + 10, y + 20, 20, 20);//圆形
g.drawLine(x + 20, y + 30, x + 20, y + 60);//炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false);
g.fill3DRect(x, y + 30, 60, 10, false);
g.fill3DRect(x + 10, y + 10, 40, 20, false);
g.fillOval(x + 20, y + 10, 20, 20);
g.drawLine(x + 30, y + 20, x, y + 20);
break;
}
}


@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyPressed(KeyEvent e) {
if (player != null && player.isLive()) {
if (e.getKeyCode() == KeyEvent.VK_W) {
player.moveup();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
player.moveright();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
player.movedown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
player.moveleft();
} else if (e.getKeyCode() == KeyEvent.VK_J) {
player.shoot();
}
}
this.repaint();
}

@Override
public void keyReleased(KeyEvent e) {

}

public void hitTank(Bullet b, Enemy e) {
switch (e.getDirection()) {
case 0:
case 2:
if (b.getX() > e.getX() && b.getX() < e.getX() + 40 && b.getY() > e.getY() && b.getY() < e.getY() + 60) {
Bomb bomb = new Bomb(e.getX(), e.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}
break;
case 1:
case 3:
if (b.getX() > e.getX() && b.getX() < e.getX() + 60 &&
b.getY() > e.getY() && b.getY() < e.getY() + 40) {
Bomb bomb = new Bomb(e.getX(), e.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
}
}
}

public void hitHero(Bullet b, Player p) { //敌人击中玩家
switch (p.getDirection()) {
case 0:
case 2:
if (b.getX() > p.getX() && b.getX() < p.getX() + 40 && b.getY() > p.getY() && b.getY() < p.getY() + 60) {
Bomb bomb = new Bomb(p.getX(), p.getY());
bombs.add(bomb);
b.setLive(false);
p.setLive(false);
p = null;
}
break;
case 1:
case 3:
if (b.getX() > p.getX() && b.getX() < p.getX() + 60 &&
b.getY() > p.getY() && b.getY() < p.getY() + 40) {
Bomb bomb = new Bomb(p.getX(), p.getY());
bombs.add(bomb);
b.setLive(false);
p.setLive(false);
p = null;
}
break;
}
}

@Override
public void run() {
while (true) {
for (int i = 0; i < player.bullets.size(); i++) { //判断玩家是否击中坦克
Bullet bullet = player.bullets.get(i);
if (bullet != null && bullet.isLive()) {
for (int j = 0; j < enemies.size(); j++) {
Enemy enemy = enemies.get(j);
hitTank(bullet, enemy);
}
}
}
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
for (int j = 0; j < enemy.bullets.size(); j++) {
Bullet bullet = enemy.bullets.get(j);
if (bullet != null && bullet.isLive() && player.isLive()) {
hitHero(bullet, player);
}
}
}
this.repaint();
}
}
}

防止坦克重叠

为坦克增加碰撞体积防止坦克重叠

  • 在敌人类添加Vector<Enemy> enemies,用来记录所有的敌人
  • 遍历集合,判断当前坦克是否和其他坦克产生碰撞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package com.tankgame05;


public class MyPanel extends JPanel implements KeyListener, Runnable {
···
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0);
enemy.setEnemies(enemies); //将所有坦克加入集合
enemies.add(enemy);
new Thread(enemy).start();
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
}


------------------------------------------------------------------------------------------------------------



import java.util.Vector;

class Enemy extends Tank implements Runnable {
//判断碰撞函数
//跟据当前坦克的方向分类,坦克前进方向的两个顶点如果与其他坦克重叠就代表发生碰撞
public boolean isTouch() {
//判断当前敌人(this)方向
switch (getDirection()) {
case 0: //up
//遍历每一个敌人坦克做判断
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
//不和自己比较
if (enemy != this) {
//如果敌人坦克是上或下
if (enemy.getDirection() == 0 || enemy.getDirection() == 2) {
//判断左端点
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 40 &&
getY() >= enemy.getY() &&
getY() >= enemy.getY() + 60) {
return true;
}
//判断右端点
if (getX() + 40 >= enemy.getX() &&
getX() + 40 <= enemy.getX() + 40 &&
getY() >= enemy.getY() &&
getY() >= enemy.getY() + 60) {
return true;
}
}
//敌人坦克向右或向左
if (enemy.getDirection() == 1 || enemy.getDirection() == 3) {
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 60 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 40) {
return true;
}
if (getX() + 40 >= enemy.getX() &&
getX() + 40 <= enemy.getX() + 60 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 40) {
return true;
}
}
}
}
break;
case 1: //right
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
if (enemy != this) {
//如果敌人坦克是上或下
if (enemy.getDirection() == 0 || enemy.getDirection() == 2) {
if (getX() + 60 >= enemy.getX() &&
getX() + 60 <= enemy.getX() + 40 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 60) {
return true;
}
if (getX() + 60 >= enemy.getX() &&
getX() + 60 <= enemy.getX() + 40 &&
getY() + 40 >= enemy.getY() &&
getY() + 40 <= enemy.getY() + 60) {
return true;
}

}
//敌人坦克向右或向左
if (enemy.getDirection() == 1 || enemy.getDirection() == 3) {
if (getX() + 60 >= enemy.getX() &&
getX() + 60 <= enemy.getX() + 60 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 40) {
return true;
}
if (getX() + 60 >= enemy.getX() &&
getX() + 60 <= enemy.getX() + 60 &&
getY() + 40 >= enemy.getY() &&
getY() + 40 <= enemy.getY() + 40) {
return true;
}
}
}
}
break;
case 2: //down
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
if (enemy != this) {
//如果敌人坦克是上或下
if (enemy.getDirection() == 0 || enemy.getDirection() == 2) {
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 40 &&
getY() + 60 >= enemy.getY() &&
getY() + 60 <= enemy.getY() + 60)
return true;
if (getX() + 40 >= enemy.getX() &&
getX() + 40 <= enemy.getX() + 40 &&
getY() + 60 >= enemy.getY() &&
getY() + 60 <= enemy.getY() + 60)
return true;
}
//敌人坦克向右或向左
if (enemy.getDirection() == 1 || enemy.getDirection() == 3) {
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 60 &&
getY() + 60 >= enemy.getY() &&
getY() + 60 <= enemy.getY() + 40) {
return true;
}
if (getX() + 40 >= enemy.getX() &&
getX() + 40 <= enemy.getX() + 60 &&
getY() + 60 >= enemy.getY() &&
getY() + 60 <= enemy.getY() + 40) {
return true;
}
}
}
}
break;
case 3: //left
for (int i = 0; i < enemies.size(); i++) {
Enemy enemy = enemies.get(i);
if (enemy != this) {
//如果敌人坦克是上或下
if (enemy.getDirection() == 0 || enemy.getDirection() == 2) {
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 40 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 60) {
return true;
}
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 40 &&
getY() + 40 >= enemy.getY() &&
getY() + 40 <= enemy.getY() + 60) {
return true;
}
}
//敌人坦克向右或向左
if (enemy.getDirection() == 1 || enemy.getDirection() == 3) {
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 60 &&
getY() >= enemy.getY() &&
getY() <= enemy.getY() + 40) {
return true;
}
if (getX() >= enemy.getX() &&
getX() <= enemy.getX() + 60 &&
getY() + 40 >= enemy.getY() &&
getY() + 40 <= enemy.getY() + 40) {
return true;
}
}
}
}
break;
}
return false;
}
}
------------------------------------------------------------------------------------------------------------
//修改移动逻辑
switch (direction) {
case 0:
for (int i = 0; i < 30; i++) {
if (!isTouch()) //如果发生碰撞就不能移动
moveup();
this.setDirection(0); //移动函数是和换方向在一起的,如果没有这句就会出现坦克卡住不动的情况
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}

存档

记录玩家总成绩

记录玩家击毁坦克总数。

创建Recorder类,实现文件操作


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.tankgame05;
/*
用于记录相关信息,和文件交互
*/

import java.io.*;

public class Recorder {
//定义变量,记录玩家击杀数
private static int kills = 0;
//定义IO对象,用于写数据到文件中
private static BufferedWriter bw = null;
private static BufferedReader br = null;
private static String recordFile = "src\\myRecord.txt";

//保存文件
public static void saveRecord() {
try {
bw = new BufferedWriter(new FileWriter(recordFile));
bw.write(String.valueOf(kills));
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//加载文件
public static void loadRecord() {
try {
br = new BufferedReader(new FileReader(recordFile));
String line = br.readLine();
if (line != null) {
kills = Integer.parseInt(line);
}
} catch (IOException | NumberFormatException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


public static int getKills() {
return kills;
}

public static void setKills(int kills) {
Recorder.kills = kills;
}

//击杀
public static void addKill() {
Recorder.kills++;
}
}

  • Mypanel的构造函数添加loadRecord()

  • 击中敌人时增加杀敌数

  • Frame中实现关闭窗口时调用saveRecord()

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.tankgame05;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
public MyPanel() {
    Recorder.loadRecord();
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    }



public void hitTank(Bullet b, Enemy e) {
switch (e.getDirection()) {
case 0: //坦克向上
case 2: //坦克向下
if (b.getX() > e.getX() && b.getX() < e.getX() + 40 && b.getY() > e.getY() && b.getY() < e.getY() + 60) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
Recorder.addKill(); //击杀坦克增加杀敌数
}
break;
case 1: //坦克向右
case 3: //坦克向左
if (b.getX() > e.getX() && b.getX() < e.getX() + 60 &&
b.getY() > e.getY() && b.getY() < e.getY() + 40) {
Bomb bomb = new Bomb(b.getX(), b.getY());
bombs.add(bomb);
b.setLive(false);
e.setLive(false);
enemies.remove(e);
Recorder.addKill(); //击杀坦克增加杀敌数
}

}
}
}
```

```java
package com.tankgame05;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Frame extends JFrame {
MyPanel mp = null;

public static void main(String[] args) {
new Frame();
}

public Frame() {
mp = new MyPanel();
this.add(mp);
new Thread(mp).start();
this.addKeyListener(mp);
this.setSize(1300, 797);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
//相应关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Recorder.saveRecord();
System.exit(0);
}
});
}
}

```

## 记录敌人信息

增加继续游戏新功能,加载上局敌人信息

* 创建`Node`类,每一个`Node`对象是一个敌人信息,记录坐标和方向
* 在`Recorder`类中实现存储和加载功能
* 开始游戏前接收玩家输入来决定是新游戏还是继续游戏

---

```java
package com.tankgame05;
/*
一个Node对象表示一个敌人坦克信息
*/

public class Node {
private int x;
private int y;
private int direction;

public Node(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public int getDirection() {
return direction;
}

public void setDirection(int direction) {
this.direction = direction;
}
}

```

---

```java
package com.tankgame05;
/*
用于记录相关信息,和文件交互
*/

import java.io.*;
import java.util.Vector;

public class Recorder {
//定义变量,记录玩家击杀数
private static int kills = 0;
//定义IO对象,用于写数据到文件中
private static BufferedWriter bw = null;
private static BufferedReader br = null;
private static String recordFile = "src\\myRecord.txt";
//定义Vector指向MyPanel敌人数组
private static Vector<Enemy> enemies = null;

//保存敌人信息
private static Vector<Node> nodes = new Vector<>();


//读取recordFile,恢复相关信息
public static Vector<Node> load(){
try {
br = new BufferedReader(new FileReader(recordFile));
kills = Integer.parseInt(br.readLine());
//循环读取文件生成nodes集合
String line = "";
while((line=br.readLine())!=null){
String[] xyd = line.split(" ");
Node node = new Node(Integer.parseInt(xyd[0]),
Integer.parseInt(xyd[1]),
Integer.parseInt(xyd[2]));
nodes.add(node);

}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return nodes;
}

//保存文件
public static void saveRecord() {
try {
bw = new BufferedWriter(new FileWriter(recordFile));
bw.write(String.valueOf(kills));
bw.newLine();
//遍历敌人坦克的集合,跟据情况保存
for(Enemy i:enemies){
if(i.isLive()){
String record = i.getX()+" "+i.getY()+" "+i.getDirection();
//写入文件
bw.write(record+"\r\n");
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//加载文件





public static int getKills() {
return kills;
}

public static void setKills(int kills) {
Recorder.kills = kills;
}

//击杀
public static void addKill() {
Recorder.kills++;
}

public static void setEnemies(Vector<Enemy> enemies) {
Recorder.enemies = enemies;
}
public static String getRecordFile() {
return recordFile;
}
}

```

---

````java
package com.tankgame05;
/*
* 游戏的绘图区
* */

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

public class MyPanel extends JPanel implements KeyListener, Runnable {
```
//恢复敌人坦克坐标
Vector<Node> nodes = new Vector<>();

public MyPanel(String key) {
File file = new File(Recorder.getRecordFile());
if(file.exists()){
nodes = Recorder.load();
}
else {
key = "1";
}
switch(key){
case "1": //新游戏
Recorder.load();
player = new Player(600, 500,0);//初始化玩家
for (int i = 0; i < enemySize; i++) { // 创建敌人
Enemy enemy = new Enemy((i * 100 + 100), 0,2);
enemy.setEnemies(enemies);
enemies.add(enemy);
new Thread(enemy).start();
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
break;
case "2": //继续游戏
nodes = Recorder.load();
player = new Player(600, 500,0);//初始化玩家
for (int i = 0; i < nodes.size(); i++) { // 创建敌人
Node node = nodes.get(i);
Enemy enemy = new Enemy(node.getX(),node.getY(),node.getDirection());
enemy.setEnemies(enemies);
enemies.add(enemy);
new Thread(enemy).start();
Bullet bullet = new Bullet(enemy.getX() + 20, enemy.getY() + 60, enemy.getDirection());
enemy.bullets.add(bullet);
new Thread(bullet).start();
}
break;
default:
System.out.println("输入有误");
}
```
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.tankgame05;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;

public class Frame extends JFrame {
MyPanel mp = null;

public static void main(String[] args) {
new Frame();
}

public Frame() {
System.out.println("请输入选择,1:新游戏 2:继续游戏");
Scanner scanner = new Scanner(System.in);
String key = scanner.next();
mp = new MyPanel(key);
this.add(mp);
new Thread(mp).start();
this.addKeyListener(mp);
this.setSize(1300, 797);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
//相应关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Recorder.saveRecord();
System.exit(0);
}
});
}
}