Java坦克大战
Posted 长河落日圆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java坦克大战相关的知识,希望对你有一定的参考价值。
关于这个坦克大战的项目是在学*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; // 坦以上是关于Java坦克大战的主要内容,如果未能解决你的问题,请参考以下文章