坦克大战2.0——基本达到坦克可以战斗的效果
2019-01-17 12:15
56 查看
参考数目: 韩顺平《java从入门到精通》 源代码在末尾
从坦克大战1.0后,通过几天的学习做出了坦克大战2.0版,其中增添了地方坦克可以移动,并可以发射子弹并且能够被消灭,以及自己可以被敌人消灭。
重点在于如何让敌方坦克动起来
class EnemyTank extends Tank implements Runnable { boolean isLive = true;//判断地方坦克是否存活 // 定义一个向量,可以存放敌人的子弹 Vector<Shot> ss = new Vector<Shot>(); Random rand =new Random();//生成一个随机数对象 public EnemyTank(int x, int y) { super(x, y); } @Override public void run() { while (true) { //生成一个5以内的随机数,如果它的余数为0,即在某一时刻它有0.4的概率开火 if (rand.nextInt(5)%2 == 0) { if (this.isLive) {//如果此坦克存在并且当前子弹数小于二则开火 if (ss.size() < 2) { 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(); } } } switch (this.direct) { case 0: // 说明坦克正在向上移动,并且生成一个随机数决定坦克移动多久 for (int i = 0; i < rand.nextInt(3000); i++) { if (y > 0) { y -= speed; } //如果到了边界则直接改变方向 if(y==0)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 1: // 向右 for (int i = 0; i < rand.nextInt(3000); i++) { if (x < 400) { x += speed; } if(x==400)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 2: // 向下 for (int i = 0; i < rand.nextInt(3000); i++) { if (y < 300) { y += speed; } if(y==300)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 3: // 向左 for (int i = 0; i < rand.nextInt(3000); i++) { if (x > 0) { x -= speed; } if(x==0) break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; } // 让坦克随机产生一个新的方向 this.direct = (int) (Math.random() * 4); // 判断敌人坦克是否死亡 if (this.isLive == false) { // 让坦克死亡后推出线程 break; } } } }
以及MyPanel里的对当前子弹的判断
public void run() { //每隔100毫秒去重绘 while(true){ try { Thread.sleep(100); } catch (InterruptedException e) { 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<enemy.size();j++){ //取出坦克 EnemyTank et=enemy.get(j); if(et.isLive){ this.hitTank(myShot, et); } } } } //判断是否被击中 for(int i=0;i<enemy.size();i++){ EnemyTank et=enemy.get(i); //取出子弹 for(int j=0;j<et.ss.size();j++){ Shot enemyShot=et.ss.get(j); //判断子弹是否有效 if(enemyShot.isLive){ //取出每个敌人坦克,与它判断 //取出坦克 if(hero.isLive){ hitMyTank(enemyShot, hero); } } } } //重绘 this.repaint(); }} }
public void hitTank(Shot s,EnemyTank et){ //判断该坦克的方向 switch(et.direct%2){ //如果敌人坦克的方向是上活着是下 case 0: 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); //放入vector bombs.add(b); } case 1: 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); //放入vector bombs.add(b); } } }
然后是判断是否击中的函数
public void hitMyTank(Shot s,Hero hero){ //判断该坦克的方向 switch(hero.direct%2){ //如果敌军坦克是竖着的 case 0: if(s.x>hero.x && s.x<hero.x+20 && s.y>hero.y && s.y<hero.y+30){ //击中 //子弹死亡 s.isLive=false; //敌人坦克死亡 hero.isLive=false; //创建一颗炸弹,放入vector Bomb b=new Bomb(hero.x,hero.y); //放入vector bombs.add(b); } //如果敌军坦克是横着的 case 1: if(s.x>hero.x && s.x<hero.x+30 && s.y>hero.y && s.y<hero.y+20){ //击中 s.isLive=false; //敌人坦克死亡 hero.isLive=false; //创建一颗炸弹,放入vector Bomb b=new Bomb(hero.x, hero.y); //放入vector bombs.add(b); } } }
大致2.0版本就是增加了这些功能,这样,一个坦克大战的初步版本就完成了。
源代码
package tank4; import java.util.*; import java.awt.event.*; import javax.swing.*; import java.awt.*; import java.util.Random; @SuppressWarnings("unused") public class MyGame3 extends JFrame { MyPanel mp = null; public static void main(String[] args) { MyGame3 mtg = new MyGame3(); } // 构造函数 public MyGame3() { mp = new MyPanel(); //启动mp线程 Thread t=new Thread(mp); t.start(); this.add(mp); // 注册监听 this.addKeyListener(mp); this.setSize(400, 300); this.setVisible(true); } } // 我的面板 class MyPanel extends JPanel implements KeyListener,Runnable{ // 定义一个我的坦克 Hero hero = null; //定义敌人的坦克组 Vector<EnemyTank> enemy=new Vector<EnemyTank>(); //定义炸弹集合 Vector<Bomb> bombs=new Vector<Bomb>(); //定义敌人坦克的数量 int enSize=3; //定义三张图片,三张图片才能组成一颗炸弹 Image image1=null; Image image2=null; Image image3=null; // 构造函数 public MyPanel() { hero = new Hero(100, 100, 20); //初始化敌人的坦克 for(int i=0;i<enSize;i++){ //创建一辆敌人的坦克对象 EnemyTank et=new EnemyTank((i+1)*50,0); et.setColor(0); et.setDirect(2); //启动敌人的坦克 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(); //加入到vector集合中 enemy.add(et); } //初始化图片 //image1=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb1.gif")); // image2=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb2.gif")); //=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb3.gif")); } // 重写paint public void paint(Graphics g) { super.paint(g); g.fillRect(0, 0, 400, 300); g.setColor(Color.CYAN); // 画出自己的坦克 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); } if(myShot.isLive==false){ //从ss中删除掉该子弹 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>3){ g.drawImage(image2, b.x, b.y, 30, 30,this); }else{ g.drawImage(image3, b.x, b.y, 30, 30,this); } //让b的生命值减小 b.lifeDown(); //如果炸弹生命值为0,就把该炸弹bombs向量去掉 if(b.life==0){ bombs.remove(b); } } //画出敌人的坦克 for(int i=0;i<enemy.size();i++){ EnemyTank et=enemy.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.isLive){ g.draw3DRect(enemyShot.x,enemyShot.y,1,1,false); }else{ //如果敌人的坦克死亡了,就从vector中去掉 et.ss.remove(enemyShot); } } } } } //写一个函数专门判断子弹是否击中敌人坦克 public void hitTank(Shot s,EnemyTank et){ //判断该坦克的方向 switch(et.direct%2){ //如果敌人坦克的方向是上活着是下 case 0: 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); //放入vector bombs.add(b); } case 1: 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); //放入vector bombs.add(b); } } } public void hitMyTank(Shot s,Hero hero){ //判断该坦克的方向 switch(hero.direct%2){ //如果敌人坦克的方向是上活着是下 case 0: if(s.x>hero.x && s.x<hero.x+20 && s.y>hero.y && s.y<hero.y+30){ //击中 //子弹死亡 s.isLive=false; //敌人坦克死亡 hero.isLive=false; //创建一颗炸弹,放入vector Bomb b=new Bomb(hero.x,hero.y); //放入vector bombs.add(b); } case 1: if(s.x>hero.x && s.x<hero.x+30 && s.y>hero.y && s.y<hero.y+20){ //击中 s.isLive=false; //敌人坦克死亡 hero.isLive=false; //创建一颗炸弹,放入vector Bomb b=new Bomb(hero.x, hero.y); //放入vector bombs.add(b); } } } // 画出坦克的函数 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; } // 判断方向 switch (direct) { // 向上 case 0: // 画出我的坦克 // 1.画出左边的矩形 g.fill3DRect(x, y, 5, 30, false); // 2.画出右边的矩形 g.fill3DRect(x + 15, y, 5, 30, false); // 3.画出中间矩形 g.fill3DRect(x + 5, y + 5, 10, 20, false); // 4.画出圆形 g.fillOval(x + 5, y + 10, 10, 10); // 5.画出线 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: // 炮筒向下 // 1.画出左边的矩形 g.fill3DRect(x, y, 5, 30, false); // 2.画出右边的矩形 g.fill3DRect(x + 15, y, 5, 30, false); // 3.画出中间矩形 g.fill3DRect(x + 5, y + 5, 10, 20, false); // 4.画出圆形 g.fillOval(x + 5, y + 10, 10, 10); // 5.画出线 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); } } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } // 键按下处理 a d w s @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_W) { // 设置我的坦克的方向 // 向上 this.hero.setDirect(0); this.hero.moveUp(); // this.repaint(); } if (e.getKeyCode() == KeyEvent.VK_D) { // 向右 this.hero.setDirect(1); this.hero.moveRight(); } if (e.getKeyCode() == KeyEvent.VK_S) { // 向下 this.hero.setDirect(2); this.hero.moveDown(); // this.repaint(); } if (e.getKeyCode() == KeyEvent.VK_A) { // 向左 this.hero.setDirect(3); this.hero.moveLeft(); } //判断玩家是否按下J if(e.getKeyCode()==KeyEvent.VK_J){ //开火 if(this.hero.ss.size()<=1){ this.hero.shotEnemy(); } } // 必须重绘panel this.repaint(); } @Override public void keyReleased(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_W||e.getKeyCode()==KeyEvent.VK_D||e.getKeyCode()==KeyEvent.VK_A||e.getKeyCode()==KeyEvent.VK_S) { } } @Override public void run() { //每隔100毫秒去重绘 while(true){ try { Thread.sleep(100); } catch (InterruptedException e) { 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<enemy.size();j++){ //取出坦克 EnemyTank et=enemy.get(j); if(et.isLive){ this.hitTank(myShot, et); } } } } for(int i=0;i<enemy.size();i++){ EnemyTank et=enemy.get(i); //取出子弹 for(int j=0;j<et.ss.size();j++){ Shot enemyShot=et.ss.get(j); //判断子弹是否有效 if(enemyShot.isLive){ //取出每个敌人坦克,与它判断 //取出坦克 if(hero.isLive){ hitMyTank(enemyShot, hero); } } } } //重绘 this.repaint(); }} } //坦克类,父类 class Tank { // 表示坦克的横坐标 int x = 0; // 坦克的纵坐标 int y = 0; // 坦克方向 // 0表示上 1表示右 2表示下 3表示左 int direct = 0; int color; // 坦克的速度 int speed = 1; 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 Tank(int x, int y) { this.x = x; this.y = y; } public Tank(int x, int y, int speed) { this.x = x; this.y = y; this.speed = speed; } 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; } } // 敌人的坦克,把敌人的坦克做成线程类 class EnemyTank extends Tank implements Runnable { boolean isLive = true; int times = 0; // 定义一个向量,可以存放敌人的子弹 Vector<Shot> ss = new Vector<Shot>(); Random rand =new Random(); // 敌人添加子弹,应当在刚刚创建坦克和敌人的坦克子弹死亡过后 public EnemyTank(int x, int y) { super(x, y); } @Override public void run() { while (true) { if (rand.nextInt(5)%2 == 0) { if (this.isLive) { if (ss.size() < 2) { // 没有子弹 // 添加 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(); } } } switch (this.direct) { case 0: // 说明坦克正在向上移动 for (int i = 0; i < rand.nextInt(3000); i++) { if (y > 0) { y -= speed; } if(y==0)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 1: // 向右 for (int i = 0; i < rand.nextInt(3000); i++) { if (x < 400) { x += speed; } if(x==400)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 2: // 向下 for (int i = 0; i < rand.nextInt(3000); i++) { if (y < 300) { y += speed; } if(y==300)break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; case 3: // 向左 for (int i = 0; i < rand.nextInt(3000); i++) { if (x > 0) { x -= speed; } if(x==0) break; try { Thread.sleep(50); } catch (Exception e) { e.printStackTrace(); } } break; } // 让坦克随机产生一个新的方向 this.direct = (int) (Math.random() * 4); // 判断敌人坦克是否死亡 if (this.isLive == false) { // 让坦克死亡后推出线程 break; } } } } // 炸弹类 class Bomb { // 定义炸弹的坐标 int x, y; // 炸弹的生命 int life = 9; 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; int speed = 5; // 是否还活着 boolean isLive = true; public Shot(int x, int y, int direct) { this.x = x; this.y = y; this.direct = direct; } @Override public void run() { while (true) { try { Thread.sleep(50); } catch (Exception e) { // TODO: handle exception } 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 > 400 || y < 0 || y > 300) { this.isLive = false; break; } } } } // 我的坦克 class Hero extends Tank { public boolean isLive=true; // 子弹 // Shot s=null; Vector<Shot> ss = new Vector<Shot>(); Shot s = null; public Hero(int x, int y, int speed) { super(x, y, speed); this.speed=1; } // 开火 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() { if(y>0) y -= speed; } // 向右移动 public void moveRight() { if(x<360) this.x += speed; } // 向下移动 public void moveDown() { if(y<260) this.y += this.speed; } // 向左移动 public void moveLeft() { if(x>0) x -= speed; } }
相关文章推荐
- 不间断滚动JS打包类,基本可以实现所有的滚动效果,太强了
- Android中的多点触摸交互处理,可以达到缩放图片的效果
- [贴图不说话]MapInfo可以达到的效果
- 两种方法可以达到背景图不缩放的效果
- Android 通过伪3D变换可以基本实现coverflow的效果
- 09-html5游戏坦克大战第五战(自己的坦克可以发射单颗子弹)
- 不间断滚动JS打包类,基本可以实现所有的滚动效果,太强了
- SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook 和 Path 2.0 滑动式菜单都可以实现(android页面布局效果)
- 10-html5游戏坦克大战第六战(自己的坦克可以连续发射子弹)
- 只写一个表单,可以达到两个表单的效果
- 纯白帽seo技术也可以达到快速排名上首页效果
- web项目在服务器IIS7上的部署:达到内部网可以通过输入网页直接访问的效果
- 短信防刷(开发时遇到的大问题,一天几万的钱都被刷了,至今未找到十全十美的方法,只是加入了极验图形验证,但是2.0极验基本已被破解,不知道3.0的效果怎么样)
- 利用CAShapeLayer可以制作出任意的几何图形,把它作为UIImageView的遮罩,达到把图片做成圆形效果。
- SlidingMenu和ActionBarSherlock结合做出出色的App布局,Facebook 和 Path 2.0 滑动式菜单都可以实现(android页面布局效果)
- 在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?(QQ 为什么采用 UDP 协议,而不采用 TCP 协议实现?)
- 解决20%的问题,调优效果就可以达到80%
- 可以达到去掉标题栏的效果
- css使背景变半透明,和js结合在一起可以达到使背景动态半透明弹出对话框的效果
- Android 通过伪3D变换可以基本实现coverflow的效果