基于java的坦克大战实例
来源:互联网 发布:东华软件邮箱 编辑:程序博客网 时间:2024/05/22 17:45
原创性声明
此博文的出处 为 http://blog.csdn.net/zhujunxxxxx/article/details/40460931如果进行转载请注明出处。本文作者原创,邮箱zhujunxxxxx@163.com,如有问题请联系作者
前言
很久没碰java了,今天突然找出了大二时期写的一个坦克大战游戏的源码,然后运行了一下,竟然依然如此的亲切,突然想到了以前大二的时候的点点时光。好了不废话了,先给出一张图。
这个就是整个游戏的界面了,界面全是用的java画的,不是很好看。如果想要好看的得做成图片版本的
原理
游戏的基本原理就是,一开始创建N个敌人的实例,多线程在界面中移动(移动使用的是重写paint函数来实现的),然后随机移动和发射子弹。
还有就是使用了简单的碰撞检测方法来实现子弹击中别人和碰到障碍物
双缓冲技术,消除频闪
坦克类
坦克类是这个游戏的主要对象,可以分为三种坦克 一种是自己的坦克,一种是普通坦克,而另一种是BOSS坦克(血多 伤害大),不过都是一个类来实现的
import java.awt.*;import java.awt.event.*;import java.util.*;public class Tank {public static final int XSPEED = 5;public static final int YSPEED = 5;public static final int WIDTH = 30;public static final int HEIGHT = 30;TankClient tc;private int x, y;//坦克的坐标,即位置private int oldX, oldY;//用来保存上一步的坐标,撞墙的时候调整方向用的private boolean bL=false, bU=false, bR=false, bD = false;//方向的标志变量enum Direction {L, LU, U, RU, R, RD, D, LD, STOP};//方向的枚举private Direction dir = Direction.STOP;//我方坦克,初始方向private Direction ptDir = Direction.D;//敌方坦克初始方向,向下private int step = r.nextInt(12) + 3;private boolean isSuper=false;public boolean isSuper(){return isSuper;}public void setSuper(boolean isSuper){this.isSuper = isSuper;}private static Random r = new Random();//随机数产生器private boolean good;//区分好坏的变量private boolean boss;public boolean isBoss(){return boss;}public boolean isGood(){return good;}public void setGood(boolean good){this.good = good;}private BloodBar bb=new BloodBar();//血条//坦克生命值的变量private int life=100;public int getLife(){return life;}public void setLife(int life){this.life = life;}//坦克生死的变量private boolean live=true;public boolean isLive(){return live;}public void setLive(boolean live){this.live = live;}//坦克的构造方法public Tank(int x, int y,boolean good) {this.x = x;this.y = y;this.oldX = x;this.oldY = y;this.good=good;}public Tank(int x, int y,boolean good,Direction dir, TankClient tc) {this(x, y,good);this.dir=dir;this.tc = tc;}public Tank(int x, int y,boolean good,boolean boss, Direction dir, TankClient tc) {this(x, y,good);this.dir=dir;this.boss=boss;this.tc = tc;}//画坦克的方法public void draw(Graphics g) {if(!live) return;//Tank死了就不在重画了Color c = g.getColor();if(good)//通过好坏设置颜色{g.setColor(Color.CYAN);}else if(boss){g.setColor(Color.RED);}else {g.setColor(Color.BLUE);}g.fillOval(x, y, WIDTH, HEIGHT);g.setColor(c);if(good) bb.draw(g);//我方坦克有血条if(boss) bb.draw(g);//boss有血条switch(ptDir) {//通过方位判断,画炮筒位置case L:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x, y + Tank.HEIGHT/2);break;case LU:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x, y);break;case U:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x + Tank.WIDTH/2, y);break;case RU:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x + Tank.WIDTH, y);break;case R:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x + Tank.WIDTH, y + Tank.HEIGHT/2);break;case RD:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x + Tank.WIDTH, y + Tank.HEIGHT);break;case D:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x + Tank.WIDTH/2, y + Tank.HEIGHT);break;case LD:g.drawLine(x + Tank.WIDTH/2, y + Tank.HEIGHT/2, x, y + Tank.HEIGHT);break;}move();//重画时,进行移动}//坦克的移动方法,在重画的时候,通过方向定位来进行移动void move() {this.oldX = x;this.oldY = y;switch(dir) {case L:x -= XSPEED;break;case LU:x -= XSPEED;y -= YSPEED;break;case U:y -= YSPEED;break;case RU:x += XSPEED;y -= YSPEED;break;case R:x += XSPEED;break;case RD:x += XSPEED;y += YSPEED;break;case D:y += YSPEED;break;case LD:x -= XSPEED;y += YSPEED;break;case STOP:break;}if(this.dir != Direction.STOP) {//炮筒位置的定位,和行动方向一致this.ptDir = this.dir;}//判断坦克是否出界,遇到边界则停止if(x < 0) x = 0;if(y < 30) y = 30;if(x + Tank.WIDTH > TankClient.GAME_WIDTH) x = TankClient.GAME_WIDTH - Tank.WIDTH;if(y + Tank.HEIGHT > TankClient.GAME_HEIGHT) y = TankClient.GAME_HEIGHT - Tank.HEIGHT;//坏蛋坦克的随机移动,以及发子弹的时间if(!good&&!boss) {Direction[] dirs = Direction.values();if(step == 0) {step = r.nextInt(12) + 3;int rn = r.nextInt(dirs.length);dir = dirs[rn];}step --;if(r.nextInt(40) > 38) this.fire();}//boss坦克的攻击方法if(!good&&boss){Direction[] dirs = Direction.values();if(step == 0) {step = r.nextInt(12) + 3;int rn = r.nextInt(dirs.length);dir = dirs[rn];}step --;if(r.nextInt(40) > 20)this.fire();}}//按下键时进行设置键位标志,用于方向定位判断public void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_CAPS_LOCK:this.setSuper(!this.isSuper());case KeyEvent.VK_F2 :if(!this.live) {this.live = true;this.life = 100;}case KeyEvent.VK_CONTROL:fire();break;case KeyEvent.VK_LEFT :bL = true;break;case KeyEvent.VK_UP :bU = true;break;case KeyEvent.VK_RIGHT :bR = true;break;case KeyEvent.VK_DOWN :bD = true;break;}locateDirection();//每次按键后就判断方向}//Tank的方向定位,通过按键后设置的标志进行判断void locateDirection() {if(bL && !bU && !bR && !bD) dir = Direction.L;else if(bL && bU && !bR && !bD) dir = Direction.LU;else if(!bL && bU && !bR && !bD) dir = Direction.U;else if(!bL && bU && bR && !bD) dir = Direction.RU;else if(!bL && !bU && bR && !bD) dir = Direction.R;else if(!bL && !bU && bR && bD) dir = Direction.RD;else if(!bL && !bU && !bR && bD) dir = Direction.D;else if(bL && !bU && !bR && bD) dir = Direction.LD;else if(!bL && !bU && !bR && !bD) dir = Direction.STOP;}//方向键抬起来时的,恢复键位标志,也进行方向判断public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_LEFT :bL = false;break;case KeyEvent.VK_UP :bU = false;break;case KeyEvent.VK_RIGHT :bR = false;break;case KeyEvent.VK_DOWN :bD = false;break;case KeyEvent.VK_A :superFire();break;}locateDirection();}//发出一发子弹的方法,向missiles里面添加子弹public Missile fire() {if(!live) return null;int x = this.x + Tank.WIDTH/2 - Missile.WIDTH/2;int y = this.y + Tank.HEIGHT/2 - Missile.HEIGHT/2;Missile m;if(good&&this.isSuper())//判断是不是超级炮弹{m = new Missile(x, y,good, ptDir,this.tc,true);}else {m = new Missile(x, y,good, ptDir,this.tc);}tc.missiles.add(m);return m;}//SuperFire向每个方向发子弹的方法public Missile fire(Direction Dir) {if(!live) return null;int x = this.x + Tank.WIDTH/2 - Missile.WIDTH/2;int y = this.y + Tank.HEIGHT/2 - Missile.HEIGHT/2;Missile m = new Missile(x, y,good, Dir,this.tc);tc.missiles.add(m);return m;}private void superFire(){Direction[] dirs = Direction.values();for(int i=0;i<8;i++){//tc.missiles.add(fire(dirs[i]));fire(dirs[i]);}}//判断相撞的方法所需的public Rectangle getRect() {return new Rectangle(x, y, WIDTH, HEIGHT);}//与坦克和墙相撞时停下来的方法private void stay() {x = oldX;y = oldY;}//判断坦克是否与墙相撞的方法public boolean collidesWithWall(Wall w) {if(this.live && this.getRect().intersects(w.getRect())) {this.stay();return true;}return false;}//判断坦克是否与坦克相撞的方法public boolean collidesWithTanks(java.util.List<Tank> tanks) {for(int i=0; i<tanks.size(); i++) {Tank t = tanks.get(i);if(this != t) {if(this.live && t.isLive() && this.getRect().intersects(t.getRect())) {this.stay();t.stay();return true;}}}return false;}//血条的内部类private class BloodBar {public void draw(Graphics g) {Color c = g.getColor();g.setColor(Color.orange);g.drawRect(x, y-10, WIDTH, 10);int w = WIDTH * life/100 ;g.fillRect(x, y-10, w, 10);g.setColor(c);}}//吃血块的方法public boolean eat(Blood b) {if(this.live && b.isLive() && this.getRect().intersects(b.getRect())) {this.life = 100;b.setLive(false);return true;}return false;}}
子弹类
子弹类就是分为敌方子弹和我方子弹,具有移动速度等属性,具有碰撞检测等功能。
import java.awt.*;import java.util.List;public class Missile {public static final int XSPEED = 10;//子弹速度的变量public static final int YSPEED = 10;public static int WIDTH = 10;//子弹大小public static int HEIGHT = 10;int x, y;private TankClient tc;Tank.Direction dir;//方向变量private boolean isSuper;private boolean live = true;//子弹的生死变量public boolean isLive() {return live;}private boolean good;//坦克的好坏之分变量public boolean isGood(){return good;}//Missile的两个构造方法public Missile(int x, int y, Tank.Direction dir) {this.x = x;this.y = y;this.dir = dir;}public Missile(int x, int y,boolean good, Tank.Direction dir, TankClient tc) {this(x, y, dir);this.tc = tc;this.good=good;}public Missile(int x, int y,boolean good, Tank.Direction dir, TankClient tc,boolean isSuper) {this(x, y, dir);this.tc = tc;this.isSuper=isSuper;this.good=good;}//画子弹的方法public void draw(Graphics g) {if(!live) {tc.missiles.remove(this);return;}Color c = g.getColor();if(good&&isSuper)//是超级炮弹就变大{g.setColor(Color.YELLOW);g.fillOval(x-5, y-5, 20, 20);}else if(good&&!isSuper) {g.setColor(Color.YELLOW);g.fillOval(x, y, WIDTH, HEIGHT);}else {g.setColor(Color.RED);g.fillOval(x, y, WIDTH, HEIGHT);}g.setColor(c);move();//画子弹的时候就要移动}//子弹的移动方法,与坦克方位有关private void move() {switch(dir) {//通过方位判断速度case L:x -= XSPEED;break;case LU:x -= XSPEED;y -= YSPEED;break;case U:y -= YSPEED;break;case RU:x += XSPEED;y -= YSPEED;break;case R:x += XSPEED;break;case RD:x += XSPEED;y += YSPEED;break;case D:y += YSPEED;break;case LD:x -= XSPEED;y += YSPEED;break;case STOP:break;}//子弹越界了就要死if(x < 0 || y < 0 || x > TankClient.GAME_WIDTH || y > TankClient.GAME_HEIGHT) {live = false;tc.missiles.remove(this);}}public Rectangle getRect() {return new Rectangle(x, y, WIDTH, HEIGHT);}//子弹与子弹相撞的方法,且子弹分好坏public boolean hitMissile(Missile m) {if(this.live && this.getRect().intersects(m.getRect()) && m.isLive() && this.good !=m.isGood() ){this.live=false;m.live=false;return true;}return false;}public boolean hitMissiles(List<Missile> missiles) {for(int i=0; i<missiles.size(); i++) {if(hitMissile(missiles.get(i))) {//调用了hitMissile方法missiles.remove(missiles.get(i));return true;}}return false;}public boolean hitTank(Tank t) {if(this.live && this.getRect().intersects(t.getRect()) && t.isLive() && this.good !=t.isGood() ){if(t.isGood())//自己被击中减血{t.setLife(t.getLife()-20);if(t.getLife()<=0)t.setLive(false);}else if(t.isBoss())//BOSS被击中{if(this.isSuper)//被超级炮弹击中{t.setLife(t.getLife()-33);if(t.getLife()<=0)t.setLive(false);}else {t.setLife(t.getLife()-5);if(t.getLife()<=0)t.setLive(false);}}else//坏人直接死t.setLive(false);//t.setLive(false);this.live = false;Explode e = new Explode(x, y, tc);tc.explodes.add(e);return true;}return false;}//子弹与坦克相撞,且子弹分好坏(打敌人坦克的方法)public boolean hitTanks(List<Tank> tanks) {for(int i=0; i<tanks.size(); i++) {if(hitTank(tanks.get(i))) {//调用了hitTank方法tanks.remove(tanks.get(i));return true;}}return false;}//子弹与墙相撞的方法public boolean hitWall(Wall w) {if(this.live && this.getRect().intersects(w.getRect())) {this.live = false;return true;}return false;}}
主程序类
主类主要是实现显示界面的功能,把在内存中的对象画出来,实现动画的效果。
import java.awt.*;import java.awt.event.*;import java.util.List;import java.util.ArrayList;import org.omg.CORBA.PUBLIC_MEMBER;public class TankClient extends Frame{public static int GAME_WIDTH = 800;public static int GAME_HEIGHT = 600;Tank myTank = new Tank(200, 300,true,Tank.Direction.STOP, this);Tank BossTank = new Tank(60, 50,false,true,Tank.Direction.D,this);List<Missile> missiles=new ArrayList<Missile>();//装子弹的容器List<Explode> explodes = new ArrayList<Explode>();//装爆炸的容器List<Tank> tanks = new ArrayList<Tank>();//装敌方坦克的容器Blood b = new Blood();//实例化一个血块//实例化两个墙Wall w1=new Wall(300, 200, 20,150, this);Wall w2=new Wall(200, 100, 20,150, this);//双缓冲技术,消除频闪Image offScreenImage = null;public void update(Graphics g) {if(offScreenImage == null) {offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);}Graphics gOffScreen = offScreenImage.getGraphics();Color c = gOffScreen.getColor();gOffScreen.setColor(Color.gray);gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);gOffScreen.setColor(c);paint(gOffScreen);g.drawImage(offScreenImage, 0, 0, null);}public void paint(Graphics g)//会自动调用这个方法{g.drawString("tanks count:" + tanks.size(), 10, 35);g.drawString("explodes count:" + explodes.size(), 10, 50);g.drawString("missiles count:" + missiles.size(), 10, 65);g.drawString("Tank life:" + myTank.getLife(), 10, 80);if(tanks.size() <= 0) {for(int i=0; i<5; i++) {tanks.add(new Tank(50 + 40*(i+1), 50, false, Tank.Direction.D, this));}}//把容器里面的子弹都画出来for(int i=0;i<missiles.size();i++){Missile m=missiles.get(i);m.hitTanks(tanks);//添加子弹打坦克的方法m.hitTank(myTank);m.hitTank(BossTank);m.hitWall(w1);m.hitWall(w2);m.hitMissiles(missiles);//调用子弹撞子弹方法m.draw(g);}//把容器里面的爆炸全部画出来for(int i=0; i<explodes.size(); i++) {Explode e = explodes.get(i);e.draw(g);//e.ExplodehitTanks(tanks);//e.ExplodehitTank(BossTank);}//把容器里面的坦克全部画出来for(int i=0; i<tanks.size(); i++) {Tank t = tanks.get(i);t.collidesWithWall(w1);t.collidesWithWall(w2);t.collidesWithTanks(tanks);t.draw(g);}b.draw(g);//血块画出来BossTank.draw(g);BossTank.collidesWithWall(w1);BossTank.collidesWithWall(w2);BossTank.collidesWithTanks(tanks);//我方坦克画出来并添加方法myTank.draw(g);myTank.eat(b);myTank.collidesWithWall(w1);myTank.collidesWithWall(w2);//画出墙来w1.draw(g);w2.draw(g);}//初始化游戏窗口的方法public void lauchFrame(){//初始化坦克,添加进容器for(int i=0;i<10;i++){tanks.add(new Tank(50+40*(i+1),50,false,Tank.Direction.D,this));}this.setLocation(300, 100);this.setSize(GAME_WIDTH,GAME_HEIGHT);this.setTitle("zz TankWar");this.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});this.setBackground(Color.GREEN);this.setResizable(false);this.addKeyListener(new KeyMonitor());this.setVisible(true);new Thread(new PaintThread()).start();}private class PaintThread implements Runnable{public void run(){while(true){repaint();try{Thread.sleep(50);}catch(InterruptedException e){e.printStackTrace();}}}}private class KeyMonitor extends KeyAdapter {//键盘监听public void keyReleased(KeyEvent e){myTank.keyReleased(e);}public void keyPressed(KeyEvent e) {myTank.keyPressed(e);}}public static void main(String[] args) {TankClient t=new TankClient();t.lauchFrame();}}
总结
其实坦克大战这种游戏很简单,只要懂一些基本的数据结构和碰撞检测,还有重绘的方法就能够打造属于自己的坦克大战,给自己童年一个华丽的蜕变。
2 1
- 基于java的坦克大战实例
- 基于java swing的坦克大战游戏
- 基于JAVA的简易坦克大战(一)
- 基于JAVA的简易坦克大战(二)
- 基于JAVA的简易坦克大战(三)
- 基于JAVA的简易坦克大战(四)
- 基于JAVA的简易坦克大战(五)
- 基于JAVA的简易坦克大战(六)
- 基于JAVA的简易坦克大战(七)
- 基于JAVA的简易坦克大战(八)
- Unity实例-坦克大战
- 用java实现的坦克大战
- java制作简单的坦克大战
- JAVA坦克大战TankBattle
- java版坦克大战
- Java Swing 坦克大战
- Java实战-坦克大战
- JAVA坦克大战
- 关于未来网站访问速度及后台查询速度的优化建议
- serveru odbc数据库配置
- 小小Python爬虫一
- hdu 5074 Hatsune Miku (鞍山现场赛E题)
- RSA加密算法的C语言实现
- 基于java的坦克大战实例
- 程序员的反省和总结:给IT新兵的15个建议
- jQuery([selector,[context]])
- Linux c 配置文件读取与修改
- Tutorial : apt-get install Qt4 on the Rasperry Pi
- 局域网远程,文件共享,问题排查
- 关于异步的一些思考
- hibernate注解之多对一注解(五)
- 【BZOJ】【P2298】【HAOI2011】【problem a】【题解】【dp+二分】