坦克大战(中)
Posted 爱学习的大鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了坦克大战(中)相关的知识,希望对你有一定的参考价值。
我方坦克发射子弹
添加Shot 类,让其实现多线程,添加相应属性及方法
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Shot implements Runnable {
private int x;//子弹x坐标
private int y;//子弹y坐标
private int speed = 6;//子弹速度
private int direct;//子弹方向
private boolean isLive = true;//子弹是否存活,用于后面判断可以消除子弹
public Shot(int x, int y, int direct) {//Shot的构造器
this.x = x;
this.y = y;
this.direct = direct;
}
@Override
public void run() {//根据移动方向设置子弹移动方向
while (true) {
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (direct) {
case 0:
y -= speed;
break;
case 1:
x += speed;
break;
case 2:
y += speed;
break;
case 3:
x -= speed;
break;
}
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750)) {//子弹超界退出循环
isLive = false;
break;
}
}
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
在Hero类中添加shotEnemy( )方法
import java.util.Vector;
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Hero extends Tank{
Vector<Shot> shots = new Vector<>();//创建子弹集合,后续限制子弹个数
private Shot shot = null;//子弹
public Hero(int x, int y, int direct) {//构造器
super(x, y, direct);
}
public void shotEnemy() {//根据方向设置子弹发射位置
switch (getDirect()) {
case 0:
shot = new Shot(getX() + 20, getY(), 0);
break;
case 1:
shot = new Shot(getX() + 40, getY() + 20, 1);
break;
case 2:
shot = new Shot(getX() + 20, getY() + 40, 2);
break;
case 3:
shot = new Shot(getX(), getY() + 20, 3);
break;
}
new Thread(shot).start();//启动子弹线程
shots.add(shot);//添加进子弹集合
}
}
在Mypanel的监听中设置按J键启动shotEnemy( )方法
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//上
hero.moveUp();
hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_D) {//右
hero.setDirect(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) {//下
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {//左
hero.setDirect(3);
hero.moveLeft();
}
if (e.getKeyCode() == KeyEvent.VK_J) {//按J发射子弹
hero.shotEnemy();
}
}
在Mypanel的paint( ) 中画出子弹
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);//设置背景大小
drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);//画出我方坦克
for (int i = 0; i < hero.shots.size(); i++) {//当子弹不为空时画出子弹
Shot shot = hero.shots.get(i);
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
}
for (int i = 0; i < enemies.size(); i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), enemy.getDirect(), 1, g);
}
}
验证结果
优化 :限制我方发射子弹数量,每次只能发射3颗子弹保证了游戏的公平性
在Hero类中shotEnemy()方法中添加限制条件
public void shotEnemy() {//根据方向设置子弹发射位置
if (shots.size() == 3) {//如果子弹数量等于3就不添加子弹
return;
}
switch (getDirect()) {
case 0:
shot = new Shot(getX() + 20, getY(), 0);
break;
case 1:
shot = new Shot(getX() + 40, getY() + 20, 1);
break;
case 2:
shot = new Shot(getX() + 20, getY() + 40, 2);
break;
case 3:
shot = new Shot(getX(), getY() + 20, 3);
break;
}
new Thread(shot).start();//启动子弹线程
shots.add(shot);//添加进子弹集合
}
在MyPanel的paint()方法中换子弹时判断
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);//设置背景大小
drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);//画出我方坦克
for (int i = 0; i < hero.shots.size(); i++) {//当子弹不为空时画出子弹
Shot shot = hero.shots.get(i);
if (shot.isLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);//画出子弹大小
} else {
hero.shots.remove(shot);//超界移除
}
}
for (int i = 0; i < enemies.size(); i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), enemy.getDirect(), 1, g);
}
}
验证结果
敌方坦克发射子弹
与我坦克坦克代码类似,Enemy是多线程,所以坦克可以通过run()方法自动发射子弹
Enemy的run( ) 中写出子弹代码
@Override
public void run() {//重写run方法
while (true) {
if (shots.size() < 2) {//设置敌方子弹个数为2
switch (getDirect()) {
case 0:
shot = new Shot(getX() + 20, getY(), 0);
break;
case 1:
shot = new Shot(getX() + 60, getY() + 20, 1);
break;
case 2:
shot = new Shot(getX() + 20, getY() + 60, 2);
break;
case 3:
shot = new Shot(getX(), getY() + 20, 3);
break;
}
new Thread(shot).start();//启动子弹线程
shots.add(shot);//添加进子弹集合
}
int random = (int) (Math.random() * 60);//获取随机移动距离
switch (getDirect()) {//获取方向
case 0://上
for (int i = 0; i < random; i++) {
moveUp();//向上移动random步
try {
Thread.sleep(50);//休眠50ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 1://右
for (int i = 0; i < random; i++) {
moveRight();//向右移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 2://下
for (int i = 0; i < random; i++) {
moveDown();//向下移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 3://左
for (int i = 0; i < random; i++) {
moveLeft();//向左移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
setDirect((int) (Math.random() * 4));//设置随机方向
}
}
同理,在在Mypanel的paint( ) 中画出敌人子弹
@Override
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);//设置背景大小
//我方坦克
drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);//画出我方坦克
for (int i = 0; i < hero.shots.size(); i++) {//当子弹不为空时画出子弹
Shot shot = hero.shots.get(i);
if (shot.isLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
hero.shots.remove(shot);//超界移除
}
}
//敌方坦克
for (int i = 0; i < enemies.size(); i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(), enemy.getY(), enemy.getDirect(), 1, g);
for (int j = 0; j < enemy.shots.size(); j++) {//当子弹不为空时画出子弹
Shot shot = enemy.shots.get(j);
if (shot.isLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
enemy.shots.remove(shot);//超界移除
}
}
}
}
验证结果
限制游戏移动区域
在Tank类中添加限制即可
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Tank {
private int x;//x坐标
private int y;//有坐标
private int direct;//方向
private int speed = 1;//速度
public void moveUp() {
if (y >= 3) {
y -= speed;
}
}
public void moveDown() {
if (y <= 707) {
y += speed;
}
}
public void moveRight() {
if (x <= 957) {
x += speed;
}
}
public void moveLeft() {
if (x >= 3 ) {
x -= speed;
}
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Tank(int x, int y, int direct) {
this.x = x;
this.y = y;
this.direct = direct;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
}
验证结果
我方坦克可以击中敌人
Tank类中添加isLive属性
public class Tank {
private int x;//x坐标
private int y;//有坐标
private int direct;//方向
private int speed = 1;//速度
boolean isLive = true;//坦克存活
MyPanel中添加hit方法,判断是否击中敌人
public void hit(Shot shot, Enemy tank) {//hit方法,判断是否击中敌人
int x = tank.getX();
int y = tank.getY();
if (shot.getX() > x && shot.getX() < x + 40 && shot.getY() > y && shot.getY() < y + 40){
tank.isLive = false;//设置为不存活
enemies.remove(tank);//击中就从敌方tank集合中移除
}
}
MyPanel的run()方法中遍历敌人和我方子弹并调用hit()方法
@Override
public void run() {
while (true) {
this.repaint();//刷新画板
try {
Thread.sleep(15);//每15ms刷新一次
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < enemies.size(); i++) {//遍历敌人坦克
Enemy enemy = enemies.get(i);//得到敌人
for (int j = 0; j < hero.shots.size(); j++) {//遍历我方子弹
Shot shot = hero.shots.get(j);//得到我方子弹
hit(shot,enemy);//调用方法判断
}
}
}
}
在MyPanel的paint()方法中画敌人坦克时判断
for (int i = 0; i < enemies.size(); i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
if (enemy.isLive) {//判断存活才画出坦克
drawTank(enemy.getX(), enemy.getY(), enemy.getDirect(), 1, g);
}
for (int j = 0; j < enemy.shots.size(); j++) {//当子弹不为空时画出子弹
Shot shot = enemy.shots.get(j);
if (shot.getIsLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
enemy.shots.remove(shot);//超界移除
}
}
}
验证结果
但子弹可以穿过敌人,可以优化一下,子弹击中敌人后消失
MyPanel类的hit()方法中涉资子弹击中敌人后状态
public void hit(Shot shot, Enemy tank) {//hit方法,判断是否击中敌人
int x = tank.getX();
int y = tank.getY();
if (shot.getX() > x && shot.getX() < x + 40 && shot.getY() > y && shot.getY() < y + 40){
tank.isLive = false;//击中坦克,坦克不存活
shot.setIsLive(false);//击中敌人,子弹不存活
enemies.remove(tank);//击中就从敌方tank集合中移除
}
}
Shot类中添加子弹判断条件,打中敌人可以提前退出循环
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {//子弹超界或则打中敌人退出循环
isLive = false;
break;
}
验证结果
敌方坦克可以击中我方坦克
MyPanel中添加我方坦克集合(后续有兴趣的可以添加两个坦克),删除原有tank,并在构造器中初始化我方坦克数据
public class MyPanel extends JPanel implements KeyListener, Runnable {
Vector<Hero> heroes = new Vector<>();//创建我方坦克集合
int enemyNum = 10;//创建敌方坦克数量
Vector<Enemy> enemies = new Vector<>();//创建敌方坦克集合
public MyPanel() {//创建无参构造器
Hero hero = new Hero(550, 500, 0);//初始化我方坦克
hero.setSpeed(5);//设置我方移动速度
heroes.add(hero);//添加我方坦克集合
for (int i = 0; i < enemyNum; i++) {//初始化敌方坦克
Enemy enemy = new Enemy(100 * (i + 0), 0, 2);
enemy.setSpeed(2);//设置敌人移动速度
enemies.add(enemy);//添加至敌人坦克集合
new Thread(enemy).start();//启动敌人坦克线程
}
}
MyPanel的paint()中修改我方绘画条件
//我方坦克
for (int i = 0; i < heroes.size(); i++) {//如果坦克数量为零则不画出
Hero hero = heroes.get(i);
drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);//画出我方坦克
for (int j = 0; j < hero.shots.size(); j++) {//当子弹不为空时画出子弹
Shot shot = hero.shots.get(j);
if (shot.getIsLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
hero.shots.remove(shot);//超界移除
}
}
}
MyPanel的监听中添加我方判断条件
@Override
public void keyPressed(KeyEvent e) {
for (int i = 0; i < heroes.size(); i++) {
Hero hero = heroes.get(i);
if (e.getKeyCode() == KeyEvent.VK_W) {//上
hero.moveUp();
hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_D) {//右
hero.setDirect(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) {//下
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {//左
hero.setDirect(3);
hero.moveLeft();
}
if (e.getKeyCode() == KeyEvent.VK_J) {//按J发射子弹
hero.shotEnemy();
}
}
}
MyPanel修改hit()方法,扩大其判断范围
public void hit(Shot shot, Tank tank) {//hit方法,判断是否击中坦克
int x = tank.getX();
int y = tank.getY();
if (shot.getX() > x && shot.getX() < x + 40 && shot.getY() > y && shot.getY() < y + 40) {
tank.isLive = false;//击中坦克,坦克不存活
shot.setIsLive(false);//击中坦克,子弹不存活
if (tank instanceof Enemy) {//判断是否为敌方坦克
enemies.remove(tank);//是敌方tank就从集合中移除
}
if (tank instanceof Hero) {//如果是我方坦克移除我方坦克
heroes.remove(tank);
}
}
}
MyPanel的run()方法中重新添加遍历条件并调用hit()方法
@Override
public void run() {
while (true) {
this.repaint();//刷新画板
try {
Thread.sleep(15);//每15ms刷新一次
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < enemies.size(); i++) {//遍历敌人坦克
Enemy enemy = enemies.get(i);//得到敌人
for (int j = 0; j < enemy.shots.size(); j++) {//遍历敌方子弹
Shot shot = enemy.shots.get(j);//得到敌方子弹
for (int k = 0; k < heroes.size(); k++) {
Hero hero = heroes.get(k);
hit(shot, hero);//调用方法判断
}
}
for (int k = 0; k < heroes.size(); k++) {//遍历我方坦克
Hero hero = heroes.get(k);//得到我方坦克
for (int j = 0; j < hero.shots.size(); j++) {//遍历我方子弹
Shot shot = hero.shots.get(j);//得到我方子弹
hit(shot, enemy);//调用方法判断
}
}
}
}
}
验证结果
显示游戏胜利失败
MyPane添加showInfo()方法
public void showInfo(Graphics g){//显示游戏信息
g.setColor(Color.BLACK);
Font font = new Font("宋体", Font.BOLD, 25);
g.setFont(font);
g.drawString("累计击毁敌方坦克", 1050, 30);
g.drawString( enemyNum -enemies.size() + "", 1110, 80);
drawTank(1050, 50, 0, 1, g);
if (enemies.size() == 0) {//胜利信息
g.setColor(Color.red);
Font font1 = new Font("宋体", Font.BOLD, 80);
g.setFont(font1);
g.drawString("YOU WIN", 350, 350);
}
if (heroes.size() == 0) {//失败信息
g.setColor(Color.red);
Font font2 = new Font("宋体", Font.BOLD, 80);
g.setFont(font2);
g.drawString("Game Over", 350, 350);
}
}
MyPanel的paint()中调用方法并传参
@Override
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);//设置背景大小
//我方坦克
for (int i = 0; i < heroes.size(); i++) {//如果坦克数量为零则不画出
Hero hero = heroes.get(i);
drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);//画出我方坦克
for (int j = 0; j < hero.shots.size(); j++) {//当子弹不为空时画出子弹
Shot shot = hero.shots.get(j);
if (shot.getIsLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
hero.shots.remove(shot);//超界移除
}
}
}
//敌方坦克
for (int i = 0; i < enemies.size(); i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
if (enemy.isLive) {//判断存活才画出坦克
drawTank(enemy.getX(), enemy.getY(), enemy.getDirect(), 1, g);
}
for (int j = 0; j < enemy.shots.size(); j++) {//当子弹不为空时画出子弹
Shot shot = enemy.shots.get(j);
if (shot.getIsLive()) {//判断子弹是否超界,未超界画出
g.fill3DRect(shot.getX() - 1, shot.getY() - 1, 3, 3, false);
} else {
enemy.shots.remove(shot);//超界移除
}
}
}
showInfo(g);//调用方法显示游戏信息
}
TankGame中修改构造器TankGame()中的界面大小
public TankGame() {//重写构造器
mp = new MyPanel();//初始化属性
new Thread(mp).start();//启动Mypanel的线程
this.setSize(1300, 800);//设置界面大小
this.add(mp);//添加mp
this.setVisible(true);//设置可见
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口结束程序
this.addKeyListener(mp);//监听键盘输入
}
显示结果
以上是关于坦克大战(中)的主要内容,如果未能解决你的问题,请参考以下文章