坦克大战(上)

赋料扬雄敌,诗看子建亲。这篇文章主要讲述坦克大战(上)相关的知识,希望能为你提供帮助。
项目建设

坦克大战(上)

文章图片

在IDEA下新建一个项目TankGame文件,文件下新建TankGame类和MyPanel类
TankGame类主要用于游戏入口和窗口的相关配置
MyPanel类主要用于绘画坦克、子弹、移动、爆炸效果等
背景显示TankGame继承JFrame并重写构造器,给(main)启动入口
import javax.swing.*; /** * @author 谢阳 * @version 1.8.0_131 */ public class TankGame extends JFrame { MyPanel mp = null; public TankGame() {//重写构造器 mp = new MyPanel(); //初始化属性 this.setSize(1100, 800); //设置界面大小 this.add(mp); //添加mp this.setVisible(true); //设置可见 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭窗口结束程序 }public static void main(String[] args) { TankGame tankGame = new TankGame(); //启动游戏入口 } }

MyPanel继承JPanel并重写paint()方法
import javax.swing.*; import java.awt.*; /** * @author 谢阳 * @version 1.8.0_131 */ public class MyPanel extends JPanel { @Override public void paint(Graphics g) { super.paint(g); g.fill3DRect(0, 0, 1000, 750, false); //设置背景大小 } }

测试结果
坦克大战(上)

文章图片

画出坦克模型在MyPanel添加drawTank( ) 方法
/** * @param x坦克的横坐标 * @param y坦克的纵坐标 * @param g画笔 * @param direct 坦克的方向 * @param type坦克的颜色 */ public void drawTank(int x, int y, int direct, int type, Graphics g) {//设置坦克模板switch (type) {//坦克颜色区分敌我坦克 case 0: g.setColor(Color.CYAN); break; case 1: g.setColor(Color.YELLOW); break; }switch (direct) {//坦克方向 case 0://上 g.fill3DRect(x, y, 10, 40, false); //坦克左轮 g.fill3DRect(x + 30, y, 10, 40, false); //坦克右轮 g.fill3DRect(x + 10, y + 5, 20, 30, false); //坦克身子 g.fillOval(x + 10, y + 10, 20, 20); //坦克盖子 g.fill3DRect(x + 18, y - 2, 4, 4, false); // g.drawLine(x + 20, y + 20, x + 20, y); //坦克炮膛 for (int i = 2; i < 40; i += 4) { g.drawLine(x + 1, y + i, x + 9, y + i); g.drawLine(x + 31, y + i, x + 39, y + i); } break; case 1://右 g.fill3DRect(x, y, 40, 10, false); g.fill3DRect(x, y + 30, 40, 10, false); g.fill3DRect(x + 5, y + 10, 30, 20, false); g.fillOval(x + 10, y + 10, 20, 20); g.fill3DRect(x + 38, y + 18, 4, 4, false); g.drawLine(x + 20, y + 20, x + 40, y + 20); for (int i = 2; i < 40; i += 4) { g.drawLine(x + i, y + 1, x + i, y + 9); g.drawLine(x + i, y + 31, x + i, y + 39); } break; case 2://下 g.fill3DRect(x, y, 10, 40, false); g.fill3DRect(x + 30, y, 10, 40, false); g.fill3DRect(x + 10, y + 5, 20, 30, false); g.fillOval(x + 10, y + 10, 20, 20); g.fill3DRect(x + 18, y + 38, 4, 4, false); g.drawLine(x + 20, y + 20, x + 20, y + 40); for (int i = 2; i < 40; i += 4) { g.drawLine(x + 1, y + i, x + 9, y + i); g.drawLine(x + 31, y + i, x + 39, y + i); } break; case 3://左 g.fill3DRect(x, y, 40, 10, false); g.fill3DRect(x, y + 30, 40, 10, false); g.fill3DRect(x + 5, y + 10, 30, 20, false); g.fillOval(x + 10, y + 10, 20, 20); //坦克盖子 g.fill3DRect(x - 2, y + 18, 4, 4, false); g.drawLine(x + 20, y + 20, x, y + 20); for (int i = 2; i < 40; i += 4) { g.drawLine(x + i, y + 1, x + i, y + 9); g.drawLine(x + i, y + 31, x + i, y + 39); } break; } }

在MyPanel的paint( )内传参测试
@Override public void paint(Graphics g) { super.paint(g); g.fill3DRect(0, 0, 1000, 750, false); //设置背景大小 drawTank(100, 100, 1, 0, g); //测试 }

测试结果
坦克大战(上)

文章图片

画出敌我坦克添加Tank类(父类)、Hero类(我方坦克继承Tank)、Enemy类(敌方坦克继承Tank)
Tank类:
/** * @author 谢阳 * @version 1.8.0_131 */ public class Tank { private int x; //x坐标 private int y; //有坐标 private int direct; //方向public Tank(int x, int y, int direct) { this.x = x; this.y = y; 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 int getDirect() { return direct; }public void setDirect(int direct) { this.direct = direct; } }

Hero类
/** * @author 谢阳 * @version 1.8.0_131 */ public class Hero extends Tank{ public Hero(int x, int y, int direct) { super(x, y, direct); } }

Enemy类
/** * @author 谢阳 * @version 1.8.0_131 */ public class Enemy extends Tank { public Enemy(int x, int y, int direct) { super(x, y, direct); } }

在MyPanel中添加敌我坦克属性,并添加构造器初始化敌我坦克
Hero hero = null; //创建hero属性 int enemyNum = 10; //创建敌方坦克数量 Vector< Enemy> enemies = new Vector< > (); //创建敌方坦克集合public MyPanel() {//创建无参构造器 hero = new Hero(500, 500, 0); //初始化我方坦克for (int i = 0; i < enemyNum; i++) {//初始化敌方坦克 Enemy enemy = new Enemy(100*(i+0),0,2); enemies.add(enemy); } }

在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 < enemies.size(); i++) {//遍历画出敌方坦克 Enemy enemy = enemies.get(i); drawTank(enemy.getX(),enemy.getY(),enemy.getDirect(),1,g); } }

测试结果
坦克大战(上)

文章图片

我方坦克改变方向让MyPanel类实现KeyListener并在其方法内监听WDSA键,对应键可以改变对应方向
注: this.repaint(); 每改变一次方向可以刷新一次,后面可以通过多线程自动刷新
public class MyPanel extends JPanel implements KeyListener {@Override public void keyTyped(KeyEvent e) {}@Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_W) {//上 hero.setDirect(0); } else if (e.getKeyCode() == KeyEvent.VK_D){//右 hero.setDirect(1); }else if (e.getKeyCode() == KeyEvent.VK_S){//下 hero.setDirect(2); }else if (e.getKeyCode() == KeyEvent.VK_A){//左 hero.setDirect(3); } this.repaint(); //刷新画布 }@Override public void keyReleased(KeyEvent e) {}

在TankGame的构造器内添加监听键盘方法
public TankGame() {//重写构造器 mp = new MyPanel(); //初始化属性 this.setSize(1100, 800); //设置界面大小 this.add(mp); //添加mp this.setVisible(true); //设置可见 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭窗口结束程序 this.addKeyListener(mp); //监听键盘输入 }

测试结果(我方坦克可以上下左右切换方向)
坦克大战(上)

文章图片

我方坦克可以移动【坦克大战(上)】在Tank类中添加速度speed属性 (给set和get方法) ,并添加上下左右移动方法
private int speed = 1; //速度public void moveUp() { y -= speed; }public void moveDown() { y += speed; }public void moveRight() { x += speed; }public void moveLeft() { x -= speed; }public int getSpeed() { return speed; }public void setSpeed(int speed) { this.speed = speed; }

在MyPanel的监听方法中给其WDSA对应的坦克(hero)的移动方法,并且可以在构造器中设置移动速度
@Override 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(); } this.repaint(); }public MyPanel() {//创建无参构造器 hero = new Hero(500, 500, 0); //初始化我方坦克 hero.setSpeed(5); //设置我方移动速度for (int i = 0; i < enemyNum; i++) {//初始化敌方坦克 Enemy enemy = new Enemy(100*(i+0),0,2); enemies.add(enemy); } }

测试结果
坦克大战(上)

文章图片

敌方坦克向下移动Enemy类实现Runnable接口,并重写run方法
public class Enemy extends Tank implements Runnable { public Enemy(int x, int y, int direct) { super(x, y, direct); }@Override public void run() {//重写run方法 while (true) { moveDown(); //可以向下移动 try {//捕获异常 Thread.sleep(20); //休眠20ms } catch (InterruptedException e) { e.printStackTrace(); }} } }

在MyPanel的构造器中启动enemy线程
public MyPanel() {//创建无参构造器 hero = new Hero(500, 500, 0); //初始化我方坦克 hero.setSpeed(5); //设置我方移动速度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类实现Runnable接口,重写run()方法添加repaint使其自动刷新画板
public void run() { while(true) {this.repaint(); //刷新画板 try { Thread.sleep(15); //每15ms刷新一次 } catch (InterruptedException e) { e.printStackTrace(); } } }

在TankGame的构造器中启动MyPanel的线程
public TankGame() {//重写构造器 mp = new MyPanel(); //初始化属性 new Thread(mp).start(); //启动Mypanel的线程 this.setSize(1100, 800); //设置界面大小 this.add(mp); //添加mp this.setVisible(true); //设置可见 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭窗口结束程序 this.addKeyListener(mp); //监听键盘输入 }

验证结果
坦克大战(上)

文章图片

敌方坦克随机移动在Enemyl类中重写run方法,补充一点细节即可
@Override public void run() {//重写run方法 while (true) { 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)); //设置随机方向 } }

验证结果
坦克大战(上)

文章图片


    推荐阅读