JAVA简易版坦克大战的二次开发
本文将对该简易版坦克大战的功能进行添加,该程序运用Java编写,玩家可以在该程序窗口中对玩家坦克进行简单的移动和射击操作,本文将对该程序添加一个记录已击毁敌方坦克数量的功能。
点击查看代码
import javax.swing.*;
import java.util.Vector;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class TankFram extends JFrame {
MyPanel myPanel = new MyPanel();
public static void main(String[] args) {
TankFram tankFram = new TankFram();
}
public TankFram() {
myPanel = new MyPanel();
this.add(myPanel);
this.setSize(1000, 750);
new Thread(myPanel).start();
this.addKeyListener(myPanel);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
public class Tank {
private int x;
private int y;
private int derection;
private int speed = 5;
boolean isLive = true;
Vector<Shot> shots = new Vector<>();
//坦克射击方法
public void tankShot(){
Shot shot = null;
//根据射击方向发射子弹
switch (this.derection){
case 0:
shot = new Shot(x + 20, y, 0);
shots.add(shot);
new Thread(shot).start();
break;
case 1:
shot = new Shot(x + 60, y + 20, 1);
shots.add(shot);
new Thread(shot).start();
break;
case 2:
shot = new Shot(x + 20, y + 60, 2);
shots.add(shot);
new Thread(shot).start();
break;
case 3:
shot = new Shot(x, y + 20, 3);
shots.add(shot);
new Thread(shot).start();
break;
}
System.out.println("发射子弹");
}
//坦克移动
public void moveUp () {
y-=speed;
}
public void moveDown () {
y+=speed;
}
public void moveRight () {
x+=speed;
}
public void moveLeft () {
x-=speed;
}
public Tank(int x, int y) {
this.x = x;
this.y = y;
}
//Getter 和 Setter
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getDerection() {
return derection;
}
public void setDerection(int derection) {
this.derection = derection;
}
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 class EnemyTank extends Tank implements Runnable{
RandomNum randomNum1 = new RandomNum(2);
public EnemyTank(int x, int y) {
super(x, y);
}
public void returnDirection(){
switch (getDerection()){
case 0: //若该坦克向上,仅需判断往上是否越界
if (getY() <= 50) {
randomNum1.randomNum = 1;
}
else return;
break;
case 1: //若该坦克向右,仅需判断往右是否越界
if (getX() + 60 >= 700) {
randomNum1.randomNum = 9;
}
else return;
break;
case 2: //若该坦克向下,仅需判断往下是否越界
if (getY() + 60 >= 350) {
randomNum1.randomNum = 7;
}
else return;
break;
case 3: //若该坦克向左,仅需判断往左是否越界
if (getX() <= 150) {
randomNum1.randomNum = 2;
}
else return;
break;
}
}
@Override
public void run() {
while (isLive){
returnDirection(); // 若移动超出指定范围则掉头
if(shots.size() == 0){ //若子弹已经消失,则其shots集合为0,令其重新发射
this.tankShot();
}
switch (randomNum1.randomNum){ // 135往下 246往右 78往上 9、10往左
case 7,8:
setDerection(0); //设置坦克方向为上
setY(getY() - getSpeed());
break;
case 2,4,6:
setDerection(1); //设置坦克方向为右
setX(getX() + getSpeed());
break;
case 1,3,5:
setDerection(2); //设置坦克方向为下
setY(getY() + getSpeed());
break;
case 9,10:
setDerection(3); //设置坦克方向为左
setX(getX() - getSpeed());
break;
}
try {
Thread.sleep(1000); //敌方坦克每秒移动一次
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Hero extends Tank {
public Hero(int x, int y) {
super(x, y);
}
}
public class Shot implements Runnable{
int x;
int y;
int direction;
int speed = 10;
boolean isLive = true;
public Shot(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
@Override
public void run() {
while (this.isLive){
switch (this.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 + " " + y);
if(!(x >= 0 && x <= 1000 && y >= 0 && y <=750)) {
this.isLive = false;
System.out.println("该子弹线程结束");
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class RandomNum implements Runnable{
int randomNum = 2;
public void varnum(){
randomNum = (int)((Math.random()) * 10 + 1); //randomNum获取一个1-10的随机整数
}
public RandomNum(int randomNum) {
this.randomNum = randomNum;
}
public int getRandomNum() {
return randomNum;
}
public void setRandomNum(int randomNum) {
this.randomNum = randomNum;
}
@Override
public void run() {
while (true){
varnum();
try {
Thread.sleep(10000); //每5秒改变一次随机数,即让敌方坦克改变移动方向
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//坦克大战的绘图区域
public class MyPanel extends JPanel implements KeyListener,Runnable {
private Hero hero = null; //己方坦克只有一辆
private int enemtSize = 3; //敌方坦克默认是3辆
Vector<EnemyTank> enemyTanks = new Vector<>(3); //敌方坦克有多辆选择集合,并考虑多线程选择Vector
Vector<Bomb> bombs = new Vector<>(); //初始化爆炸集合用以存放Bomb对象以画出图片
//初始化三张爆炸图片
Image image1 = Toolkit.getDefaultToolkit().getImage("D:\\java代码\\TankGame\\out\\production\\TankGame\\bomb1.jpg");
Image image2 = Toolkit.getDefaultToolkit().getImage("D:\\java代码\\TankGame\\out\\production\\TankGame\\bomb2.jpg");
Image image3 = Toolkit.getDefaultToolkit().getImage("D:\\java代码\\TankGame\\out\\production\\TankGame\\bomb3.jpg");
public MyPanel() {
//初始化己方坦克
hero = new Hero(300, 500);
//初始化敌方坦克
for(int i = 1; i <= enemtSize; i++){
EnemyTank enemyTank = new EnemyTank((200 * i), 100);
enemyTank.setDerection(2);
enemyTanks.add(enemyTank);
new Thread(enemyTank.randomNum1).start(); //每创建一辆敌方坦克就启动该敌方坦克的随机数线程
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDerection());
enemyTank.shots.add(shot); //每创建一个坦克对象就发射一颗子弹
new Thread(shot).start(); //立即启动该子弹线程
new Thread(enemyTank).start(); //启动该敌方坦克线程以使敌方坦克移动
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);
g.setColor(Color.red);
g.draw3DRect(150, 50, 550, 300, false);
//画出己方坦克
if (hero.isLive == true) {
drawTank(hero.getX(), hero.getY(), g, hero.getDerection(), 0);
}
//画出敌方坦克
for(int i = 0; i < enemyTanks.size(); i++){ //遍历敌方坦克
EnemyTank enemyTank = enemyTanks.get(i);
if (enemyTank.isLive == true) { //若存活则重绘
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDerection(), 1);
}
else enemyTanks.remove(enemyTank); //非存活则移出集合
}
//画出己方坦克子弹
g.setColor(Color.cyan);
for (int i = 0; i < hero.shots.size(); i++){ //遍历己方坦克子弹集合
if (hero.shots.get(i).isLive == true) {
g.drawOval(hero.shots.get(i).x, hero.shots.get(i).y, 3, 3);
for (int j = 0; j < enemyTanks.size(); j++){ //每颗己方子弹遍历敌方坦克集合
tankRemove(hero.shots.get(i), enemyTanks.get(j)); //若己方坦克子弹击中则销毁
}
}
else {
hero.shots.remove(i); //若子弹非存活则移出集合
}
}
//画出敌方坦克子弹
g.setColor(Color.yellow);
for(int i = 0; i < enemyTanks.size(); i++){ //遍历敌方坦克集合
EnemyTank enemyTank = enemyTanks.get(i);
if(enemyTank.shots != null){
for (int j = 0; j < enemyTank.shots.size(); j++){
Shot shot = enemyTank.shots.get(j);
if(shot.isLive == true){ //若该子弹存活则重绘
g.drawOval(shot.x, shot.y, 3, 3);
tankRemove(shot, hero); // 若敌方子弹击中己方则销毁
}
else enemyTank.shots.remove(shot); //若该子弹非存活则移出集合
}
}
}
// 画爆炸效果
if(bombs != null){
for(int i = 0; i < bombs.size(); i++) {
Bomb bomb = bombs.get(i);
if(bomb.life > 12){
g.drawImage(image1, bomb.x, bomb.y, 40, 40, this);
bomb.lifeDown();
} else if (bomb.life > 7) {
g.drawImage(image2, bomb.x, bomb.y, 40, 40, this);
bomb.lifeDown();
} else if (bomb.life > 1) {
g.drawImage(image3, bomb.x, bomb.y, 40, 40, this);
bomb.lifeDown();
}
else {
bomb.isLive = false;
if(bomb.isLive == false){
bombs.remove(bomb);
}
}
}
}
}
/**
* @param x 坦克的左上角x坐标
* @param y 坦克的左上角y坐标
* @param g 画笔
* @param direct 坦克方向
* @param type 坦克类型
*/
public void drawTank(int x, int y, Graphics g, int direct, int type) { //画出坦克
switch (type) {
case 0: //己方坦克
g.setColor(Color.cyan);
break;
case 1: //敌方坦克
g.setColor(Color.yellow);
break;
}
//根据坦克方向绘制坦克(0上1右2下3左)
switch (direct) {
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;
}
}
public void tankRemove(Shot shot, Tank tank){
switch (tank.getDerection()){
case 0,2:
if(shot.x >= tank.getX() && shot.x < tank.getX() + 40
&& shot.y >= tank.getY() && shot.y < tank.getY() + 60){
shot.isLive = false;
tank.isLive = false;
bombs.add(new Bomb(tank.getX(), tank.getY())); //若击中则bombs集合添加一个对象
}
break;
case 1,3:
if(shot.x >= tank.getX() && shot.x < tank.getX() + 60
&& shot.y >= tank.getY() && shot.y < tank.getY() + 40){
shot.isLive = false;
tank.isLive = false;
bombs.add(new Bomb(tank.getX(), tank.getY())); //若击中则bombs集合添加一个对象
}
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){ //按下W键既向上
hero.setDerection(0);
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_D) { //按下D键既向右
hero.setDerection(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) { //按下S键即向下
hero.setDerection(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) { //按下A键既向左
hero.setDerection(3);
hero.moveLeft();
} else if (e.getKeyCode() == KeyEvent.VK_J) { //按下J键射击
hero.tankShot();
}
this.repaint(); //面板重绘
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {
while (true) {
this.repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Bomb {
int x;
int y;
int life = 20;
boolean isLive = true;
public Bomb(int x, int y) {
this.x = x;
this.y = y;
}
public void lifeDown(){
life--;
}
}
该程序原有以下类:
我方坦克类Hero与敌方坦克类EnemyTank均从父类Tank继承,此外还有射击类Shot表示敌我双方坦克发射的子弹,随机数类RandomNum表示敌方坦克的随即移动,Bomb类表示敌方坦克被击中后的爆炸效果,
MyPanel类用于绘制。
该程序使用集合来储存敌方坦克和敌我双方子弹的对象实例,通过多线程来描绘每辆坦克以及每颗子弹实例,并启动MyPanel类的线程使其不断重绘。
通过使用一个变量记录子弹命中敌方坦克数并将其绘制即可记录我方击毁的敌方坦克数量
(1)绘制显示成绩的区域:
public void showInfo(Graphics g) {
//画出玩家击毁的坦克数量
g.setColor(Color.BLACK);
Font font = new Font("宋体", Font.BOLD, 25);
g.setFont(font);
g.drawString("已击毁敌方坦克数量:", 1020, 30);
drawTank(1020, 60, g, 0, 0);
g.setColor(Color.BLACK);
g.drawString(Integer.toString(hero.shotenemyTankNum), 1080, 100);
}
(2)在我方坦克类Hero中增加一个int属性shotenemyTankNum用于记录击毁的敌方坦克数量
(3)在MyPanel类中的tankRemove方法中当我方子弹击中敌方坦克时使我方坦克hero的shotenemyTankNum变量增加
(4)在showInfo方法中添加绘制成绩的代码:
g.drawString(Integer.toString(hero.shotenemyTankNum), 1080, 100);
最终效果如图:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理