Java坦克大战(三)

时间:2023-11-25 09:48:32

关于这个坦克大战的项目是在学习Java基础的时候,拿来练习的最近看到这些代码,感觉很亲切,就把他们都复制下来,编辑成博客。回首看去,Java基础的学习确实应该建立在找项目练习上,这样才能将学到的基础知识用到实际当中,不然你知道什么是面向对象编程,什么是线程,什么是死锁,概念都了解了一大堆,等到实际应用的时候,还是力不从心。初学者千万不要灰心,真心是敲着敲着就有感觉了。下面还是循序渐进的介绍这个项目的几个版本,注释我写的很详细,新功能添加后部分代码有改动,如果感兴趣,可以看前几篇博客。

坦克大战(1.4版本)

1.MyTankGame类:

/*
* 删掉很多之前的注释
* 功能:线程(坦克打子弹)进过分析:子弹是个类
*/
package com.fanghua3; import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Vector; import javax.swing.*; public class MyTankGame1_4 extends JFrame { Mypanel1_2 mp = null; public static void main(String[] args) {
new MyTankGame1_4();
} // 构造函数
public MyTankGame1_4() {
mp = new Mypanel1_2(); // 启动mp线程
Thread t = new Thread(mp);
t.start(); this.add(mp);
// 注册监听
this.addKeyListener(mp); this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 我的面板,拓宽思路:Panel本身就是一个刷新体
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable { // 定义我的坦克
Hero1_2 hero = null;
// 定义敌人的坦克(不止一辆,线程安全,集合)
Vector<EnemyTank> ets = new Vector<EnemyTank>();
int enSize = 3;// 敌人坦克保持三个 // 构造函数
public Mypanel1_2() {
hero = new Hero1_2(10, 10);
for (int i = 0; i < enSize; i++) { // 创建一辆敌人的坦克
EnemyTank et = new EnemyTank((i + 1) * 50, 0);
et.setColor(0);
// 坦克默认反向是0(向上),这里改一下
et.setDirect(2);
// 加入
ets.add(et); }
} // 重写paint函数
public void paint(Graphics g) {
// 一定要调用
super.paint(g);
g.fillRect(0, 0, 400, 300);
// 画出自己的坦克(将方向填进去)
this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1); // 画出子弹(后添加 hero.s.isLive==true,节省资源)
if (hero.s != null && hero.s.isLive == true) {
g.draw3DRect(hero.s.x, hero.s.y, 1, 1, false);
} // 画出敌人的坦克
for (int i = 0; i < enSize; i++) {
this.drawTank(ets.get(i).getX(), ets.get(i).getY(), g, ets.get(i)
.getDirect(), 0); } } // 画出坦克的函数
public void drawTank(int x, int y, Graphics g, int direct, int type) {
// 坦克类型
switch (type) {
case 0:
g.setColor(Color.green);
break;
case 1:
g.setColor(Color.yellow);
break;
}
// 方向设置
switch (direct) {
// 向上
case 0:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y);
break;
// 向右
case 1:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x + 30, y + 10);
break;
// 向下
case 2:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y + 30);
break;
// 向左
case 3:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x, y + 10);
break;
} } @Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// 已更正为顺时针
if (e.getKeyCode() == KeyEvent.VK_UP
|| e.getKeyCode() == KeyEvent.VK_W) {
this.hero.moveUp();
this.hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT
|| e.getKeyCode() == KeyEvent.VK_D) {
this.hero.setDirect(1);
this.hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN
|| e.getKeyCode() == KeyEvent.VK_S) {
this.hero.moveDown();
this.hero.setDirect(2);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT
|| e.getKeyCode() == KeyEvent.VK_A) {
this.hero.moveLeft();
this.hero.setDirect(3);
} else if (e.getKeyCode() == KeyEvent.VK_J) {
// 将J键设置为发出子弹
this.hero.shotEnemy();
this.repaint();
} } @Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void run() {
// TODO Auto-generated method stub
// 每隔100毫秒去重绘
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 重绘
this.repaint();
}
}
}

2.Menbers类:

package com.fanghua3;
//子弹类
class Shot implements Runnable{
int x;
int y;
int direct;
//设置子弹的消亡(默认活着的)
boolean isLive=true;
//speed要给个初始值1,之前给0,按J键,子弹没有动
int speed=1;
public Shot(int x, int y,int direct) {
super();
this.x = x;
this.y= y;
this.direct=direct; }
@Override
public void run() {
// TODO Auto-generated method stub while(true){
//设置子弹休息50毫秒 try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} switch(direct){
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>400||y<0||y>300){
this.isLive=false;
break;
}
}
}
} //坦克类
class Tank1_2 { int x = 0;
int y = 0; // 坦克方向:0表示上,1表示右,2表示下,3表示左
int direct = 0;
int speed = 1;
//坦克的颜色
int color; public int getColor() {
return color;
} public void setColor(int color) {
this.color = color;
} public int getSpeed() {
return speed;
} public void setSpeed(int speed) {
this.speed = speed;
} public int getDirect() {
return direct;
} public void setDirect(int direct) {
this.direct = direct;
} 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 Tank1_2(int x, int y) {
this.x = x;
this.y = y; } }
//敌人的坦克
class EnemyTank extends Tank1_2{ public EnemyTank(int x, int y) {
super(x, y);
// TODO Auto-generated constructor stub
}
} //我的坦克
class Hero1_2 extends Tank1_2 {
//子弹
Shot s=null;
public Hero1_2(int x, int y) {
super(x, y);
}
//坦克开火
public void shotEnemy(){ switch(this.direct){
case 0:
s=new Shot(x+10,y,0); break; case 1:
s=new Shot(x+30,y+10,1);
break; case 2:
s=new Shot(x+10,y+30,2);
break; case 3:
s=new Shot(x,y+10,3);
break;
}
//启动子弹线程
Thread t=new Thread(s);
t.start();
} public void moveUp() {
y -= speed;
}
public void moveRight() {
x += speed;
}
public void moveDown() {
y += speed;
}
public void moveLeft() {
x -= speed;
}
}

坦克大战(1.5版本)

1.MyTankGame类:

/*
* 删掉很多之前的注释
* 功能:子弹连发,(线程)最多5颗子弹
* 敌人坦克消失
*/
package com.fanghua4; import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Vector; import javax.swing.*; public class MyTankGame1_5 extends JFrame { Mypanel1_2 mp = null; public static void main(String[] args) {
new MyTankGame1_5();
} // 构造函数
public MyTankGame1_5() {
mp = new Mypanel1_2(); // 启动mp线程
Thread t = new Thread(mp);
t.start(); this.add(mp);
// 注册监听
this.addKeyListener(mp); this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 我的面板,拓宽思路:Panel本身就是一个刷新体
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable { // 定义我的坦克
Hero1_2 hero = null;
// 定义敌人的坦克(不止一辆,线程安全,集合)
Vector<EnemyTank> ets = new Vector<EnemyTank>();
int enSize = 3;// 敌人坦克保持三个 // 构造函数
public Mypanel1_2() {
hero = new Hero1_2(10, 10);
for (int i = 0; i < enSize; i++) { // 创建一辆敌人的坦克
EnemyTank et = new EnemyTank((i + 1) * 50, 0);
et.setColor(0);
// 坦克默认反向是0(向上),这里改一下
et.setDirect(2);
// 加入
ets.add(et); }
} // 重写paint函数
public void paint(Graphics g) {
// 一定要调用
super.paint(g);
g.fillRect(0, 0, 400, 300);
// 画出自己的坦克(将方向填进去)
this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1); // 从ss中取出每一颗子弹,并画出
for (int i = 0; i < hero.ss.size(); i++) { Shot myShot = hero.ss.get(i);
if (myShot != null && myShot.isLive == true) {
g.draw3DRect(myShot.x, myShot.y, 1, 1, false); /*
* 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
* &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
* 1, 1,false); }
*/
}
if (myShot.isLive == false) {
// 从ss(向量)中删除该子弹
// hero.ss.remove(i);会报异常。
hero.ss.remove(myShot);
}
} // 画出敌人的坦克
for (int i = 0; i < enSize; i++) {
EnemyTank et = ets.get(i);
if (et.isLive) {
this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);
}
}
} // 写一个函数 专门判断是否击中敌人坦克
public void hitTank(Shot s, EnemyTank et) {
// 判断该坦克的方向
switch (et.direct) {
// 敌人坦克的方向是0或2,一致
case 0:
case 2:
if (s.x > et.x && s.x < et.x + 20 && s.y > et.y && s.y < et.y + 30) {
// 击中(子弹死亡,敌人四万)
s.isLive = false;
et.isLive = false;
}
break;
case 1:
case 3:
if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 20) {
// 击中(子弹死亡,敌人四万)
s.isLive = false;
et.isLive = false;
}
break;
}
} // 画出坦克的函数
public void drawTank(int x, int y, Graphics g, int direct, int type) {
// 坦克类型
switch (type) {
case 0:
g.setColor(Color.green);
break;
case 1:
g.setColor(Color.yellow);
break;
}
// 方向设置
switch (direct) {
// 向上
case 0:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y);
break;
// 向右
case 1:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x + 30, y + 10);
break;
// 向下
case 2:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y + 30);
break;
// 向左
case 3:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x, y + 10);
break;
} } @Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// 已更正为顺时针
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
this.hero.moveUp();
this.hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT
|| e.getKeyCode() == KeyEvent.VK_D) {
this.hero.setDirect(1);
this.hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN
|| e.getKeyCode() == KeyEvent.VK_S) {
this.hero.moveDown();
this.hero.setDirect(2);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT
|| e.getKeyCode() == KeyEvent.VK_A) {
this.hero.moveLeft();
this.hero.setDirect(3);
} else if (e.getKeyCode() == KeyEvent.VK_J) {
// 将J键设置为发出子弹
// 子弹连发,J被按几下,发几颗:this.hero.shotEnemy();
// this.repaint();在run函数里,不应该设计在这里
if (this.hero.ss.size() <= 4) {
this.hero.shotEnemy();
} } } @Override
public void run() {
// TODO Auto-generated method stub
// 每隔100毫秒去重绘
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法)
// 每一颗子弹都要和每个坦克进行匹配
for (int i = 0; i < hero.ss.size(); i++) {
// 取出子弹
Shot myShot = hero.ss.get(i);
// 判断子弹是否有效
if (myShot.isLive) {
// 取出每个坦克,与它判断
for (int j = 0; j < ets.size(); j++) {
// 取出坦克
EnemyTank et = ets.get(j); if (et.isLive) {
this.hitTank(myShot, et);
}
}
}
} // 重绘
this.repaint();
}
} @Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub } }

2.Menbers类:

package com.fanghua4;

import java.util.Vector;

//子弹类
class Shot implements Runnable {
int x;
int y;
int direct;
// 设置子弹的消亡(默认活着的)
boolean isLive = true;
// speed要给个初始值1,之前给0,按J键,子弹没有动
int speed = 1; public Shot(int x, int y, int direct) {
super();
this.x = x;
this.y = y;
this.direct = direct; } @Override
public void run() {
// TODO Auto-generated method stub while (true) {
// 设置子弹休息50毫秒 try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} switch (direct) {
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 > 400 || y < 0 || y > 300) {
this.isLive = false;
break;
}
}
}
} // 坦克类
class Tank1_2 { int x = 0;
int y = 0; // 坦克方向:0表示上,1表示右,2表示下,3表示左
int direct = 0;
int speed = 1;
// 坦克的颜色
int color; public int getColor() {
return color;
} public void setColor(int color) {
this.color = color;
} public int getSpeed() {
return speed;
} public void setSpeed(int speed) {
this.speed = speed;
} public int getDirect() {
return direct;
} public void setDirect(int direct) {
this.direct = direct;
} 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 Tank1_2(int x, int y) {
this.x = x;
this.y = y; } } // 敌人的坦克
class EnemyTank extends Tank1_2 { boolean isLive = true; public EnemyTank(int x, int y) {
super(x, y);
// TODO Auto-generated constructor stub
}
} // 我的坦克
class Hero1_2 extends Tank1_2 {
// 多个子弹,用向量创建
Vector<Shot> ss = new Vector<Shot>();
// 子弹
Shot s = null; public Hero1_2(int x, int y) {
super(x, y);
} // 坦克开火
public void shotEnemy() { switch (this.direct) {
case 0:
s = new Shot(x + 10, y, 0);
// 把子弹加入向量
ss.add(s);
break; case 1:
s = new Shot(x + 30, y + 10, 1);
// 把子弹加入向量
ss.add(s);
break; case 2:
s = new Shot(x + 10, y + 30, 2);
// 把子弹加入向量
ss.add(s);
break; case 3:
s = new Shot(x, y + 10, 3);
// 把子弹加入向量
ss.add(s);
break;
}
// 启动子弹线程
Thread t = new Thread(s);
t.start();
} public void moveUp() {
y -= speed;
} public void moveRight() {
x += speed;
} public void moveDown() {
y += speed;
} public void moveLeft() {
x -= speed;
}
}

坦克大战(1.6版本)

1.MyTankGame类

/*
* 功能:
* 1.实现爆炸效果
* 2.敌人坦克可移动,可以连发子弹
* 3.敌人击中我的坦克,我爆炸
* 4.击中第一个坦克爆炸的效果不明显
*/
package com.fanghua5; import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Vector;
import javax.swing.*; public class MyTankGame1_6 extends JFrame { Mypanel1_2 mp = null; public static void main(String[] args) {
new MyTankGame1_6();
} // 构造函数
public MyTankGame1_6() {
mp = new Mypanel1_2(); // 启动mp线程
Thread t = new Thread(mp);
t.start(); this.add(mp);
// 注册监听
this.addKeyListener(mp); this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 我的面板,拓宽思路:Panel本身就是一个刷新体
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable { // 定义我的坦克
Hero1_2 hero = null;
// 定义敌人的坦克(不止一辆,线程安全,集合)
Vector<EnemyTank> ets = new Vector<EnemyTank>(); // 定义炸弹集合
Vector<Bomb> bombs = new Vector<Bomb>(); int enSize = 4;// 敌人坦克保持四个 // 定义三张图片(三张图片才能组成一颗炸弹)
Image image1 = null;
Image image2 = null;
Image image3 = null; // 构造函数
public Mypanel1_2() {
hero = new Hero1_2(10, 10);
for (int i = 0; i < enSize; i++) { // 创建一辆敌人的坦克
EnemyTank et = new EnemyTank((i + 1) * 50, 0);
et.setColor(0);
// 坦克默认反向是0(向上),这里改一下
et.setDirect(2);
// 加入
ets.add(et); // 启动敌人的坦克
Thread t = new Thread(et);
t.start();
// 给敌人坦克添加一颗子弹
Shot s = new Shot(et.x + 10, et.y + 30, 2);
// 加入给敌人的坦克
et.ss.add(s); Thread t2 = new Thread(s);
t2.start();
ets.add(et); }
// 初始话图片,这样做击中第一个坦克,爆炸的效果不明显。下面优化
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")); // 引包:import javax.imageio.ImagesssIO;
// try {
// image1=ImageIO.read(new File("/bomsb_1.gif"));
// image2=ImageIO.read(new File("/bomb_2.gif"));
// image3=ImageIO.read(new File("/bomb_3.gif"));
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
} // 重写paint函数
public void paint(Graphics g) {
// 一定要调用
super.paint(g);
g.fillRect(0, 0, 400, 350);
// 画出自己的坦克(将方向填进去)
if (hero.isLive == true) {
this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
}
// 从ss中取出每一颗子弹,并画出
for (int i = 0; i < hero.ss.size(); i++) { Shot myShot = hero.ss.get(i);
if (myShot != null && myShot.isLive == true) {
g.draw3DRect(myShot.x, myShot.y, 1, 1, false); /*
* 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
* &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
* 1, 1,false); }
*/
}
if (myShot.isLive == false) {
// 从ss(向量)中删除该子弹
// hero.ss.remove(i);会报异常。
hero.ss.remove(myShot);
}
} // 画出炸弹
for (int i = 0; i < bombs.size(); i++) {
// 取出炸弹
Bomb b = bombs.get(i);
if (b.life > 6) {
g.drawImage(image1, b.x, b.y, 30, 30, this);
} else if (b.life > 4) {
g.drawImage(image2, b.x, b.y, 30, 30, this);
} else {
g.drawImage(image3, b.x, b.y, 30, 30, this);
}
// 让b的生命值减小
b.lifeDown();
// 如果炸弹生命值为零,就把该炸弹从bombs向量中去掉
if (b.life == 0) {
bombs.remove(b);
} } // 画出敌人的坦克
for (int i = 0; i < ets.size(); i++) {
EnemyTank et = ets.get(i);
if (et.isLive) {
this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0); // 画出敌人的子弹
for (int j = 0; j < et.ss.size(); j++) {
// 取出子弹
Shot enemyShot = et.ss.get(j);
if (enemyShot != null && enemyShot.isLive == true) {
g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
}
if (enemyShot.isLive == false) {
// 如果敌人的坦克死亡了,就从Vector中删除
et.ss.remove(enemyShot);
}
}
}
}
} // 判断敌人的子弹是否击中我
public void hitMe() {
// 取出每一个敌人的坦克
for (int i = 0; i < this.ets.size(); i++) {
// 取出坦克
EnemyTank et = ets.get(i);
// 取出每一颗子弹
for (int j = 0; j < et.ss.size(); j++) {
// 取出子弹
Shot enemyShot = et.ss.get(j); this.hitTank(enemyShot, hero);
} }
} // 判断我是否击中敌人的坦克
public void hitEnemyTank() {
// 判断是否被击中敌人的坦克
for (int i = 0; i < hero.ss.size(); i++) {
// 取出我的子弹与敌人坦克匹配
Shot myShot = hero.ss.get(i);
// 判断子弹是否有效
if (myShot.isLive) {
// 取出每个坦克,与它判断
for (int j = 0; j < ets.size(); j++) {
// 取出坦克
EnemyTank et = ets.get(j);
if (et.isLive) {
this.hitTank(myShot, et);
}
}
}
}
} // 写一个函数 专门判断是否击中敌人坦克(原来第二参数: EnemyTank et)
public void hitTank(Shot s, Tank1_2 et) {
// 判断该坦克的方向
switch (et.direct) {
// 敌人坦克的方向是0或2,一致
case 0:
case 2:
if (s.x >= et.x && s.x <= et.x + 20 && s.y >= et.y
&& s.y <= et.y + 30) {
// 击中(子弹死亡,敌人死亡)
s.isLive = false;
et.isLive = false; // 创建一颗炸弹,放入Vector中
Bomb b = new Bomb(et.x, et.y);
// 放入
bombs.add(b);
}
break;
case 1:
case 3:
if (s.x >= et.x && s.x <= et.x + 30 && s.y >= et.y
&& s.y <= et.y + 20) {
// 击中(子弹死亡,敌人死亡)
s.isLive = false;
et.isLive = false;
// 创建一颗炸弹,放入Vector中
Bomb b = new Bomb(et.x, et.y);
// 放入
bombs.add(b);
}
break;
}
} // 画出坦克的函数
public void drawTank(int x, int y, Graphics g, int direct, int type) {
// 坦克类型
switch (type) {
case 0:
g.setColor(Color.green);
break;
case 1:
g.setColor(Color.yellow);
break;
}
// 方向设置
switch (direct) {
// 向上
case 0:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y);
break;
// 向右
case 1:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x + 30, y + 10);
break;
// 向下
case 2:
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
g.fill3DRect(x + 5, y + 5, 10, 20, false);
g.fillOval(x + 5, y + 10, 10, 10);
g.drawLine(x + 10, y + 15, x + 10, y + 30);
break;
// 向左
case 3:
g.fill3DRect(x, y, 30, 5, false);
g.fill3DRect(x, y + 15, 30, 5, false);
g.fill3DRect(x + 5, y + 5, 20, 10, false);
g.fillOval(x + 10, y + 5, 10, 10);
g.drawLine(x + 15, y + 10, x, y + 10);
break;
} } @Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// 已更正为顺时针
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
this.hero.moveUp();
this.hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT
|| e.getKeyCode() == KeyEvent.VK_D) {
this.hero.setDirect(1);
this.hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN
|| e.getKeyCode() == KeyEvent.VK_S) {
this.hero.moveDown();
this.hero.setDirect(2);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT
|| e.getKeyCode() == KeyEvent.VK_A) {
this.hero.moveLeft();
this.hero.setDirect(3);
} else if (e.getKeyCode() == KeyEvent.VK_J) {
// 将J键设置为发出子弹
// 子弹连发,J被按几下,发几颗:this.hero.shotEnemy();
// this.repaint();在run函数里,不应该设计在这里
if (this.hero.ss.size() <= 4) {
this.hero.shotEnemy();
} } } @Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void run() {
// TODO Auto-generated method stub
// 每隔100毫秒去重绘
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法)
// 每一颗子弹都要和每个坦克进行匹配
for (int i = 0; i < hero.ss.size(); i++) {
// 取出子弹
Shot myShot = hero.ss.get(i);
// 判断子弹是否有效
if (myShot.isLive) {
// 取出每个坦克,与它判断
for (int j = 0; j < ets.size(); j++) {
// 取出坦克
EnemyTank et = ets.get(j); if (et.isLive) {
this.hitTank(myShot, et);
}
}
}
}
this.hitEnemyTank(); this.hitMe(); // 重绘
this.repaint();
}
}
}

2.Menbers类:

package com.fanghua5;

import java.util.Vector;

//炸弹类(没必要定义为线程,因为它不会移动,没有坐标改变)
class Bomb {
// 定义炸弹的坐标
int x, y;
int life = 9;// 炸弹的生命(三张图片)
// 可以看出isLive很有用,它可以决定类(或者对象)要不要展现在面板上
boolean isLive = true; public Bomb(int x, int y) {
this.x = x;
this.y = y;
} // 炸弹减少生命值
public void lifeDown() {
if (life > 0) {
life--;
} else {
this.isLive = false;
}
} } // 子弹类
class Shot implements Runnable {
int x;
int y;
int direct;
// 设置子弹的消亡(默认活着的)
boolean isLive = true;
// speed要给个初始值1,之前给0,按J键,子弹没有动
int speed = 1; public Shot(int x, int y, int direct) {
super();
this.x = x;
this.y = y;
this.direct = direct; } @Override
public void run() {
// TODO Auto-generated method stub while (true) {
// 设置子弹休息50毫秒 try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} switch (direct) {
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 > 400 || y < 0 || y > 300) {
this.isLive = false;
break;
}
}
}
} // 坦克类
class Tank1_2 { int x = 0;
int y = 0;
boolean isLive=true; // 坦克方向:0表示上,1表示右,2表示下,3表示左
int direct = 0;
int speed = 1;
// 坦克的颜色
int color; public int getColor() {
return color;
} public void setColor(int color) {
this.color = color;
} public int getSpeed() {
return speed;
} public void setSpeed(int speed) {
this.speed = speed;
} public int getDirect() {
return direct;
} public void setDirect(int direct) {
this.direct = direct;
} 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 Tank1_2(int x, int y) {
this.x = x;
this.y = y; } } // 敌人的坦克(做成线程,会移动)
class EnemyTank extends Tank1_2 implements Runnable { //从父类继承了,去掉:boolean isLive = true;
int times = 0;// 让time累积
// 定义向量,可以存放敌人的子弹
Vector<Shot> ss = new Vector<Shot>(); // 敌人添加子弹,应该刚刚创建坦克和敌人子弹死亡后 public EnemyTank(int x, int y) {
super(x, y);
} @Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
// 设置坦克休息一会
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
switch (this.direct) {
case 0:
// 说明坦克正在向上运动(继续往上走,符合实际)
// y -= speed;设置坦克平滑移动的效果
for (int i = 0; i < 30; i++) {
if (y > 0) {
y -= speed;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case 1:
for (int i = 0; i < 30; i++) {
// 这里注意坐标起点问题不是(400x300)
if (x < 350) {
x += speed;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case 2:
for (int i = 0; i < 30; i++) {
if (y < 250) {
y += speed;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case 3:
for (int i = 0; i < 30; i++) {
if (x > 0) {
x -= speed;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
}
this.times++;
// 设置3秒发一颗子弹
if (times % 2 == 0) {
if (isLive) {
if (ss.size() < 5) {
Shot s = null;
// 没有子弹,添加
switch (direct) {
case 0:
s = new Shot(x + 10, y, 0);
ss.add(s);
break;
case 1:
s = new Shot(x + 30, y + 10, 1);
ss.add(s);
break;
case 2:
s = new Shot(x + 10, y + 30, 2);
ss.add(s);
break;
case 3:
s = new Shot(x, y + 10, 3);
ss.add(s);
break;
}
// 启动子弹线程
Thread t = new Thread(s);
t.start();
}
}
}
// 让坦克随机产生一个新的方向
this.direct = (int) (Math.random() * 4);
// 判断敌人坦克是否死亡了(双等号)
if (this.isLive == false) {
// 让坦克死亡,后退出线程
return;
} }
}
} // 我的坦克
class Hero1_2 extends Tank1_2 {
// 多个子弹,用向量创建
Vector<Shot> ss = new Vector<Shot>();
// 子弹
Shot s = null; public Hero1_2(int x, int y) {
super(x, y);
} // 坦克开火
public void shotEnemy() { switch (this.direct) {
case 0:
s = new Shot(x + 10, y, 0);
// 把子弹加入向量
ss.add(s);
break; case 1:
s = new Shot(x + 30, y + 10, 1);
// 把子弹加入向量
ss.add(s);
break; case 2:
s = new Shot(x + 10, y + 30, 2);
// 把子弹加入向量
ss.add(s);
break; case 3:
s = new Shot(x, y + 10, 3);
// 把子弹加入向量
ss.add(s);
break;
}
// 启动子弹线程(创建线程,赶紧传参,我在这里吃了大亏!)
Thread t = new Thread(s);
t.start();
} public void moveUp() {
y -= speed;
} public void moveRight() {
x += speed;
} public void moveDown() {
y += speed;
} public void moveLeft() {
x -= speed;
}
}

1.6版本(图:基本功能都已经实现)

Java坦克大战(三)

之后,我还会继续写一篇博客,来记录该坦克大战的最终版本(2.0),这个坦克大战的项目利用Java图形界面来实现坦克的绘制,画质比较粗糙,部分的坐标没有那么精确。