java实现坦克大战
代码总体上来说借鉴了尚学堂“手把手教你一小时写出坦克大战”(感谢),也从中加入了一些自己的想法(相对来说较少),子弹碰撞后消失,添加音效,随机生成地形等;话不多说,直接上思维导图(比较粗略)
目录
编辑
窗口初始化
准备工作
窗口初始化
游戏父类的编写
方向类
游戏父类
添加坦克类
Tank
四个方向的移动——玩家(键盘监听)、人机(随机移动)
射击——玩家(键盘监听)、人机(随机移动)
总
Player
键盘监听器
总
人机
总
初始化子弹类
玩家子弹
子弹射击
碰撞检测
总
人机子弹
击中玩家
总
添加围墙、基地
Base
Wall
Grass
Fe
优化
爆炸
音乐
重写GamePanel
游戏最终成品
窗口初始化
准备工作
首先创建一个TankWar项目,在scr相同路径下创建images、music文件夹,将需要使用的图片、音乐分别放在images、music中。创建一个com.tankwar(包),注意命名规范
窗口初始化
在com.tankwar中创建GamePanel类
import javax.swing.JFrame;
public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//窗口初始化public void launch() {//标题setTitle("坦克大战");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加关闭事件setDefaultCloseOperation(3);//用户不能调整setResizable(false);//使窗口可见setVisible(true);}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();}
}
运行结果
导入窗口图片与屏幕刷新
程序在运行时屏幕的每,对象的位置以及图像的每一次改变都需要屏幕的一次刷新,而屏幕的每一次刷新都需要重新绘制屏幕,所以会出现闪屏现象。如果想要解决这种问题,需要运用双缓存技术
(2条消息) Java双缓冲技术_kkvveeerer的博客-CSDN博客_java双缓冲
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;import javax.swing.JFrame;
public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//定义双缓存图片Image offScreenImage=null;//临时变量private int a=1;//游戏状态 0 未开始,1 开始,2 暂停,3 失败,4 胜利private int state=0;//游戏是否开始private boolean start=false;//窗口初始化public void launch() {//标题setTitle("坦克大战");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加关闭事件setDefaultCloseOperation(3);//用户不能调整setResizable(false);//使窗口可见setVisible(true);/** 控制屏幕刷新时间*/while(true) {repaint();try {Thread.sleep(25);//刷新休眠时间} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}public void paint(Graphics g) {//创建和容器一样大小的imageif(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//获得该图片的画布Graphics gImage=offScreenImage.getGraphics();//填充整个画布gImage.fillRect(0,0,width,height);if(state==0) {//游戏未开始gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);}else if(state==1) {//游戏开始}else if(state==2) {//游戏暂停}else if(state==3) {//游戏失败}else if(state==4) {//游戏胜利}g.drawImage(offScreenImage,0,0,null);}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();}
}
程序运行结果
添加鼠标监听器
在游戏中点击“PLAYER”方可进入游戏,需要加入鼠标监听器
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;import javax.swing.JFrame;
public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//定义双缓存图片Image offScreenImage=null;//临时变量private int a=1;//游戏状态 0 未开始,1 开始,2 暂停,3 失败,4 胜利private int state=0;//游戏是否开始private boolean start=false;//窗口初始化public void launch() {//标题setTitle("坦克大战");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加关闭事件setDefaultCloseOperation(3);//用户不能调整setResizable(false);//使窗口可见setVisible(true);/** 控制屏幕刷新时间*/while(true) {repaint();try {Thread.sleep(25);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}public void paint(Graphics g) {//创建和容器一样大小的imageif(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//获得该图片的画布Graphics gImage=offScreenImage.getGraphics();//填充整个画布gImage.fillRect(0,0,width,height);if(state==0) {//游戏未开始gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);//添加鼠标事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==1) {//游戏开始}else if(state==2) {//游戏暂停}else if(state==3) {//游戏失败}else if(state==4) {//游戏胜利}g.drawImage(offScreenImage,0,0,null);}/** 添加鼠标监听*/private class MouseMonitor extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent e) {Point p=new Point(e.getX(),e.getY());if(!start&&state==0) {if(p.x>450&&p.x<750&&p.y>400&&p.y<480) {//“PLAYER X,Y坐标范围”state=1;start=true;}}else if(state==3||state==4) {}}}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();}
}
游戏父类的编写
方向类
游戏中坦克需要运用到“方向”,可以单独创建一个枚举类,或者在坦克类中定义“方向”成员变量。
/** 首先枚举是一个特殊的class* 这个class相当于final static 修饰,不能被继承* 他的构造方法强制被私有化* 所有的枚举都继承自java.lang.Enum类。由于java不支持多继承,所以枚举对象不能再继承其他类*/
public enum Direction {//每个成员变量都是final static 修饰UP,LEFT,RIGHT,DOWN
}
游戏父类
游戏中的坦克、子弹、基地、墙体、爆炸图片等元素,在绘画到面板上的过程中,需要运用到坐标,大小、移动速度、主界面画板。将其抽取出来,创建游戏父类
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;public abstract class GameObject {//游戏元素图片Image img;//游戏元素的横纵坐标int x;int y;//游戏元素的宽,高int width;int height;//游戏元素的移动速度int speed;//游戏元素的移动方向Direction direction;//引入主界面GamePanel gamePanel;public GameObject() {}public GameObject(String img,int x,int y,GamePanel gamePanel) {this.img=Toolkit.getDefaultToolkit().getImage(img);this.x=x;this.y=y;this.gamePanel=gamePanel;}public Image getImag() {return img;}public void setImg(String img) {this.img=Toolkit.getDefaultToolkit().getImage(img);}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 getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public double getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public Direction getDirection() {return direction;}public void setDirection(Direction direction) {this.direction = direction;}public GamePanel getGamePanel() {return gamePanel;}public void setGamePanel(GamePanel gamepanel) {this.gamePanel = gamePanel;}//继承元素绘制自己的方法public abstract void paintSelf(Graphics g);//获取当前游戏元素的矩形,是为碰撞检测而写public abstract Rectangle getRec();
}
添加坦克类
Tank
注:蓝色字体的写在子类中
坦克具有哪些特有属性?
四个方向移动的图片
//向上移动时的图片private String upImage;//向下移动时的图片private String downImage;//向右移动时的图片private String rightImage;//向左移动时的图片private String leftImage;
四个方向的移动——玩家(键盘监听)、人机(随机移动)
1、墙体碰撞检测
2、边界碰撞检测
3、人机碰撞检测
4、移动
1、墙体碰撞检测
/** 坦克与墙碰撞检测*/public boolean hitWall(int x,int y) {//假设玩家坦克前进,下一个位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地图里所有的墙体List<Wall>walls=this.gamePanel.wallList;List<Fe>fes=this.gamePanel.feList;//判断两个矩形是否相交for(Wall w:walls) {if(w.getRec().intersects(next)) {return true;}}for(Fe f:fes) {if(f.getRec().intersects(next)) {return true;}}return false;}
2、边界碰撞检测
/** 边界与坦克碰撞检测*/public boolean moveToBorder(int x,int y) {if(x<10) {return true;}else if(x>this.gamePanel.getWidth()-width) {return true;}if(y<30) {return true;}else if(y>this.gamePanel.getHeight()-height) {return true;}return false;}
3、人机碰撞检测
/** 人机碰撞检测*/public boolean hitTank(int x,int y) {int a=0;//假设人机坦克前进,下一个位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地图里所有的人机List<Bot>bots=this.gamePanel.botList;//判断两个矩形是否相交for(Bot b:bots) {if(b.getRec().intersects(next)) {a++;if(a==2) {return true;}}}return false;}
4、移动
/** 坦克移动*/public void leftWard() {direction=Direction.LEFT;setImg(leftImage);if(!hitWall(x-speed,y)&&!moveToBorder(x-speed,y)&&alive&&!hitTank(x-speed,y)) {this.x-=speed;}}public void rightWard() {direction=Direction.RIGHT;setImg(rightImage);if(!hitWall(x+speed,y)&&!moveToBorder(x+speed,y)&&alive&&!hitTank(x+speed,y)) {this.x+=speed;}}public void upWard() {direction=Direction.UP;setImg(upImage);if(!hitWall(x,y-speed)&&!moveToBorder(x,y-speed)&&alive&&!hitTank(x,y-speed)) {this.y-=speed;}}public void downWard() {direction=Direction.DOWN;setImg(downImage);if(!hitWall(x,y+speed)&&!moveToBorder(x,y+speed)&&alive&&!hitTank(x-speed,y+speed)) {this.y+=speed;}}
射击——玩家(键盘监听)、人机(随机移动)
1、子弹射击方向应与坦克移动方向一致
2、射击子弹CD
3、射击
1、子弹射击方向应与坦克移动方向一致
坦克坐标点为坦克图片左上角,所以子弹初始坐标应该为坦克的坐标加上坦克高度或宽度的一半。
/** 根据方向确定头部位置,x和y是左上角的点*/public Point getHeadPoint() {switch(direction) {case UP:return new Point(x+width/2,y);case LEFT:return new Point(x,y+height/2);case DOWN:return new Point(x+width/2,y+height);case RIGHT:return new Point(x+width,y+height/2);default:return null;}}
2、射击子弹CD
/** 坦克射击cd*/public class AttackCD extends Thread{public void run() {attackCoolDown=false;try {//休眠1秒Thread.sleep(attackCoolDownTime);//attackCoolDownTime为定义的成员变量单位为ms}catch (InterruptedException e) {e.printStackTrace();}//将攻击功能解除冷却状态attackCoolDown=true;this.stop();//不是很理解}}
3、射击
/** 射击*/public void attack() {Point p=getHeadPoint();if(attackCoolDown&&alive) {Bullet bullet=new Bullet("images/bullet/bulletGreen.gif",p.x-10,p.y-10, direction, this.gamePanel);this.gamePanel.bulletList.add(bullet);//将子弹添加至子弹集合attackCoolDown=false;new AttackCD().start();}}
总
这里由于还未创建其他类所以会报错,在后续会添加上的(博主偷个懒直接把源码粘贴过来了)
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.List;public class Tank extends GameObject{//向上移动时的图片private String upImage;//向下移动时的图片private String downImage;//向右移动时的图片private String rightImage;//向左移动时的图片private String leftImage;//坦克sizeint width=54;int height=54;//坦克初始方向Direction direction=Direction.UP;//坦克速度private int speed=3;//攻击冷却private boolean attackCoolDown=true;//攻击冷却事件毫秒间隔1000ms发射子弹private int attackCoolDownTime=100;//坦克是否活着public boolean alive=true;/** 坦克坐标,方向,图片,方向,面板*/public Tank(String img,int x,int y,String upImage,String downImage,String leftImage,String rightImage,GamePanel gamePanel) {super(img,x,y,gamePanel);this.upImage=upImage;this.leftImage=leftImage;this.downImage=downImage;this.rightImage=rightImage; }/** 坦克移动*/public void leftWard() {direction=Direction.LEFT;setImg(leftImage);if(!hitWall(x-speed,y)&&!moveToBorder(x-speed,y)&&alive&&!hitTank(x-speed,y)) {this.x-=speed;}}public void rightWard() {direction=Direction.RIGHT;setImg(rightImage);if(!hitWall(x+speed,y)&&!moveToBorder(x+speed,y)&&alive&&!hitTank(x+speed,y)) {this.x+=speed;}}public void upWard() {direction=Direction.UP;setImg(upImage);if(!hitWall(x,y-speed)&&!moveToBorder(x,y-speed)&&alive&&!hitTank(x,y-speed)) {this.y-=speed;}}public void downWard() {direction=Direction.DOWN;setImg(downImage);if(!hitWall(x,y+speed)&&!moveToBorder(x,y+speed)&&alive&&!hitTank(x-speed,y+speed)) {this.y+=speed;}}/** 射击*/public void attack() {Point p=getHeadPoint();if(attackCoolDown&&alive) {Bullet bullet=new Bullet("images/bullet/bulletGreen.gif",p.x-10,p.y-10, direction, this.gamePanel);this.gamePanel.bulletList.add(bullet);//将子弹添加至子弹集合attackCoolDown=false;new AttackCD().start();}}/** 坦克射击cd*/public class AttackCD extends Thread{public void run() {attackCoolDown=false;try {//休眠1秒Thread.sleep(attackCoolDownTime);}catch (InterruptedException e) {e.printStackTrace();}//将攻击功能解除冷却状态attackCoolDown=true;this.stop();//不是很理解}}/** 根据方向确定头部位置,x和y是左上角的点*/public Point getHeadPoint() {switch(direction) {case UP:return new Point(x+width/2,y);case LEFT:return new Point(x,y+height/2);case DOWN:return new Point(x+width/2,y+height);case RIGHT:return new Point(x+width,y+height/2);default:return null;}}/** 坦克与墙碰撞检测*/public boolean hitWall(int x,int y) {//假设玩家坦克前进,下一个位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地图里所有的墙体List<Wall>walls=this.gamePanel.wallList;List<Fe>fes=this.gamePanel.feList;//判断两个矩形是否相交for(Wall w:walls) {if(w.getRec().intersects(next)) {return true;}}for(Fe f:fes) {if(f.getRec().intersects(next)) {return true;}}return false;}/** 人机碰撞检测*/public boolean hitTank(int x,int y) {int a=0;//假设人机坦克前进,下一个位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地图里所有的人机List<Bot>bots=this.gamePanel.botList;//判断两个矩形是否相交for(Bot b:bots) {if(b.getRec().intersects(next)) {a++;if(a==2) {return true;}}}return false;}/** 边界与坦克碰撞检测*/public boolean moveToBorder(int x,int y) {if(x<10) {return true;}else if(x>this.gamePanel.getWidth()-width) {return true;}if(y<30) {return true;}else if(y>this.gamePanel.getHeight()-height) {return true;}return false;}@Overridepublic Rectangle getRec(){return new Rectangle(x,y,width,height);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img, x, y, null);}
}
Player
玩家类继承坦克类,在父类的基础上只需要添加键盘监听器即可
键盘监听器
/** 按下键盘时坦克持续运动*/public void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_A:left=true;Music.playBackground();break;case KeyEvent.VK_D:right=true;Music.playBackground();break;case KeyEvent.VK_W:up=true;Music.playBackground();break;case KeyEvent.VK_S:down=true;Music.playBackground();break;case KeyEvent.VK_SPACE:Music.attackPlay();this.attack();break;default:break;} }/** 松开键盘时,坦克停止运动*/public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch (key){case KeyEvent.VK_A:left = false;Music.moveStop();break;case KeyEvent.VK_S:down = false;Music.moveStop();break;case KeyEvent.VK_D:right = false;Music.moveStop();break;case KeyEvent.VK_W:up = false;Music.moveStop();break;default:break;} }
总
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;public class PlayerOne extends Tank{private boolean up=false;private boolean down=false;private boolean left=false;private boolean right=false;public PlayerOne(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage,GamePanel gamePanel) {super(img, x, y, upImage, downImage, leftImage, rightImage, gamePanel);// TODO Auto-generated constructor stub}/** 按下键盘时坦克持续运动*/public void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_A:left=true;Music.playBackground();break;case KeyEvent.VK_D:right=true;Music.playBackground();break;case KeyEvent.VK_W:up=true;Music.playBackground();break;case KeyEvent.VK_S:down=true;Music.playBackground();break;case KeyEvent.VK_SPACE:Music.attackPlay();this.attack();break;default:break;} }/** 松开键盘时,坦克停止运动*/public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch (key){case KeyEvent.VK_A:left = false;Music.moveStop();break;case KeyEvent.VK_S:down = false;Music.moveStop();break;case KeyEvent.VK_D:right = false;Music.moveStop();break;case KeyEvent.VK_W:up = false;Music.moveStop();break;default:break;} }/** 坦克移动*/public void move() {if(left) {leftWard();}else if(right) {rightWard();}else if (up) {upWard();}else if (down) {downWard();}else {return;}}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);move();}public Rectangle getRec() {return new Rectangle(x,y,width,height);}}
人机
人机具有哪些属性呢?
随机、随机、随机还是随机!
1、随机移动
2、随机射击
1、随机移动
/** 人机移动*/public void go() {attack();if(moveTime>=20) {direction=randomDirection();moveTime=0;}else{moveTime+=1;}switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case RIGHT:rightWard();break;case LEFT:leftWard();break;}}/** 人机移动随机方向*/public Direction randomDirection() {Random r=new Random();int rnum=r.nextInt(4);switch(rnum) {case 0:return Direction.UP;case 1:return Direction.RIGHT;case 2:return Direction.LEFT;default:return Direction.DOWN;}}
2、随机射击
随机射击写在人机子弹类里
总
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Random;public class Bot extends Tank{//人机朝一个方向运动时间int moveTime=0;public Bot(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage,GamePanel gamePanel) {super(img, x, y, upImage, downImage, leftImage, rightImage, gamePanel);} /** 人机移动*/public void go() {attack();if(moveTime>=20) {direction=randomDirection();moveTime=0;}else{moveTime+=1;}switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case RIGHT:rightWard();break;case LEFT:leftWard();break;}}/** 人机移动随机方向*/public Direction randomDirection() {Random r=new Random();int rnum=r.nextInt(4);switch(rnum) {case 0:return Direction.UP;case 1:return Direction.RIGHT;case 2:return Direction.LEFT;default:return Direction.DOWN;}}/** 随机攻击*/public void attack() {Point p=getHeadPoint();Random r=new Random();int rnum=r.nextInt(100);if(rnum<2) {EnemyBullet enemyBullet=new EnemyBullet("images/bullet/bulletYellow.gif",p.x,p.y,direction,gamePanel);this.gamePanel.enemyBulletsList.add(enemyBullet);}}/** 绘制人机*/@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);go();}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}
初始化子弹类
玩家子弹
- 子弹射击
- 子弹碰撞检测
子弹射击
- 子弹运动方向与坦克一致
/** 子弹运动方向*/public void go() {switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case LEFT:leftWard();break;case RIGHT:rightWard();break;}}
/** 子弹运动坐标改变*/private void rightWard() {// TODO Auto-generated method stubx+=speed;}private void downWard() {// TODO Auto-generated method stuby+=speed;}private void leftWard() {// TODO Auto-generated method stubx-=speed;}private void upWard() {// TODO Auto-generated method stuby-=speed;}
碰撞检测
子弹与土墙
子弹与铁墙
子弹与基地
子弹与边界
子弹与子弹
1、子弹与土墙
/** 子弹和土墙碰撞*/public void hitWall() {Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.wallList.remove(w);this.gamePanel.removeList.add(this);break;}}}
2、子弹与铁墙
/** 子弹与Fe*/public void hitFe() {Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList.add(this);break;}}}
3、子弹与基地
/** 击中基地*/public void hitBase() {Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList.add(this);this.gamePanel.state=3;break;}}}
4、子弹与边界
/** 移动到边界*/public void moveToBorder() {if(x<0||x>this.gamePanel.getWidth()) {this.gamePanel.removeList.add(this);}if(y<0||y>this.gamePanel.getHeight()) {this.gamePanel.removeList.add(this);}}
5、子弹与子弹
/** 子弹与子弹碰撞检测*/public void hitEnemyBullet() {Rectangle next=this.getRec();List<EnemyBullet>enemyBullets=this.gamePanel.enemyBulletsList;for(EnemyBullet enemyBullet:enemyBullets) {if(enemyBullet.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList2.add(enemyBullet);this.gamePanel.removeList.add(this);break;}}}
总
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.List;public class Bullet extends GameObject{//长宽private int width=10;private int height=10;//速度private int speed=7;//方向Direction direction;//初始化子弹public Bullet(String img,int x,int y,Direction direction,GamePanel gamePanel) {super(img,x,y,gamePanel);this.direction=direction; }/** 子弹运动方向*/public void go() {switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case LEFT:leftWard();break;case RIGHT:rightWard();break;}}/** 子弹运动坐标改变*/private void rightWard() {// TODO Auto-generated method stubx+=speed;}private void downWard() {// TODO Auto-generated method stuby+=speed;}private void leftWard() {// TODO Auto-generated method stubx-=speed;}private void upWard() {// TODO Auto-generated method stuby-=speed;}/** 子弹与坦克碰撞检测*/public void hitBot() {//矩形类Rectangle next=this.getRec();List<Bot>bots=this.gamePanel.botList;//子弹和人机for(Bot bot:bots) {if(bot.getRec().intersects(next)) {Explode[]arr=new Explode[7];for(int i=0;i<7;i++) {Explode explode=new Explode("images/explode/"+(i+1)+".gif", x, y, this.gamePanel);this.gamePanel.explodeList.add(explode);}Music.explodePlay();this.gamePanel.botList.remove(bot);this.gamePanel.removeList.add(this);break;}}}/** 子弹与子弹碰撞检测*/public void hitEnemyBullet() {Rectangle next=this.getRec();List<EnemyBullet>enemyBullets=this.gamePanel.enemyBulletsList;for(EnemyBullet enemyBullet:enemyBullets) {if(enemyBullet.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList2.add(enemyBullet);this.gamePanel.removeList.add(this);break;}}}/** 子弹和土墙碰撞*/public void hitWall() {Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.wallList.remove(w);this.gamePanel.removeList.add(this);break;}}}/** 子弹与Fe*/public void hitFe() {Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList.add(this);break;}}}/** 移动到边界*/public void moveToBorder() {if(x<0||x>this.gamePanel.getWidth()) {this.gamePanel.removeList.add(this);}if(y<0||y>this.gamePanel.getHeight()) {this.gamePanel.removeList.add(this);}}/** 击中基地*/public void hitBase() {Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList.add(this);this.gamePanel.state=3;break;}}}@Overridepublic void paintSelf(Graphics g) {// TODO Auto-generated method stubg.drawImage(img,x,y,null);go();//碰撞检测hitBot();hitWall();hitBase();hitFe();hitEnemyBullet();}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}
人机子弹
人机与玩家的子弹有什么差别呢?
- 可以击中玩家,不能击中坦克
击中玩家
/** 击中玩家*/public void hitPlayer() {Rectangle next=this.getRec();List<Tank>tanks=this.gamePanel.tankList;//子弹和坦克for(Tank tank:tanks) {if(tank.getRec().intersects(next)) {tank.alive=false;this.gamePanel.tankList.remove(tank);this.gamePanel.removeList.add(this);break;}}}
总
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.List;
/** 人机子弹*/
public class EnemyBullet extends Bullet{public EnemyBullet(String img, int x, int y, Direction direction, GamePanel gamePanel) {super(img, x, y, direction, gamePanel);}public void hitPlayer() {//攻击到玩家,玩家死亡Rectangle next=this.getRec();List<Tank>tanks=this.gamePanel.tankList;//子弹和坦克for(Tank tank:tanks) {if(tank.getRec().intersects(next)) {tank.alive=false;this.gamePanel.tankList.remove(tank);this.gamePanel.removeList.add(this);break;}}}@Overridepublic void hitBase() {//攻击到基地,游戏结束Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList2.add(this);this.gamePanel.state=3;break;}}}public void hitWall() {//攻击到土墙,子弹与土均消失Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {this.gamePanel.wallList.remove(w);this.gamePanel.removeList2.add(this);break;}}}public void hitFe() {//攻击到铁墙,墙不变,子弹消失Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {this.gamePanel.removeList2.add(this);break;}}}public void paintSelf(Graphics g) {g.drawImage(img,x,y,null);go();hitBase();hitWall();hitFe();hitPlayer();}
}
添加围墙、基地
剩下的就是间的添加围墙、基地等对象了。
Base
import java.awt.Graphics;
import java.awt.Rectangle;public class Base extends GameObject{public int width=60;public int height=60;public Base(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);// TODO Auto-generated method stub}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}
}
Wall
import java.awt.Graphics;
import java.awt.Rectangle;public class Wall extends GameObject{private int width=60;private int height=60;public Wall(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() { return new Rectangle(x,y,width,height);}
}
Grass
import java.awt.Graphics;
import java.awt.Rectangle;public class Grass extends GameObject{public Grass(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() {return null;}}
Fe
import java.awt.Graphics;
import java.awt.Rectangle;public class Fe extends GameObject{private int width=60;private int height=60;public Fe(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}
优化
爆炸
import java.awt.Graphics;
import java.awt.Rectangle;public class Explode extends GameObject{public Explode(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x-25,y-30,null);//x,y为图片左上角的坐标,调整图片位置,使图片居中}@Overridepublic Rectangle getRec() {// TODO Auto-generated method stubreturn null;}
}
音乐
import java.io.File;import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;public class Music{private static Clip start;//刚进入游戏的音乐private static Clip move;//玩家移动音乐private static Clip attack;//玩家射击音乐private static Clip explode;//爆炸音效private static Clip wall;//击中墙体音效static {File bgMusicStartFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\bgm.wav");File bgMusicAttackFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\attack.wav");File bgMusicMoveFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\move.wav");File bgMusicExplodeFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\explode.wav");File bgMusicWallFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\wall.wav");try {AudioInputStream audioInputStreamStart = AudioSystem.getAudioInputStream(bgMusicStartFile);start = AudioSystem.getClip();start.open(audioInputStreamStart);AudioInputStream audioInputStreamAttack = AudioSystem.getAudioInputStream(bgMusicAttackFile);attack = AudioSystem.getClip();attack.open(audioInputStreamAttack);AudioInputStream audioInputStreamStartMove = AudioSystem.getAudioInputStream(bgMusicMoveFile);move = AudioSystem.getClip();move.open(audioInputStreamStartMove);AudioInputStream audioInputStreamStartExplode = AudioSystem.getAudioInputStream(bgMusicExplodeFile);explode = AudioSystem.getClip();explode.open(audioInputStreamStartExplode); AudioInputStream audioInputStreamStartWall = AudioSystem.getAudioInputStream(bgMusicWallFile);wall = AudioSystem.getClip();wall.open(audioInputStreamStartWall); } catch (Exception e) {e.printStackTrace();}}public static void playBackground(){//循环播放move.setFramePosition(0);move.loop(Clip.LOOP_CONTINUOUSLY); }public static void startPlay(){start.start();start.setFramePosition(0);}public static void attackPlay(){attack.start();//将进度条调为0attack.setFramePosition(0);}public static void movePlay(){move.start();move.setFramePosition(0);}public static void moveStop(){move.stop();}public static void explodePlay(){explode.start();explode.setFramePosition(0);}public static void wallPlay() {wall.start();wall.setFramePosition(0);}
}
重写GamePanel
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;import javax.swing.JFrame;public class GamePanel extends JFrame{boolean one=true;boolean run=true;//关卡private int level=1;//定义双缓存图片Image offScreenImage=null;/** //游戏状态* 0 未开始,1 单人模式,* 2 游戏暂停,3 游戏失败,4 游戏胜利*/public int state =0;//游戏是否开始private boolean start=false;//临时变量private int a=1;//窗口长宽private int width=1260;private int height=800;//指针初始纵坐标private int y=260;//基地private Base base=new Base("images/base.gif",660,740,this);//重绘次数public int count=0;//敌人数量private int enemyCount=0;///随机生成的墙体数量private int wallCount=100;private boolean d=true;private int[]xrr=new int[wallCount];private int[]yrr=new int[wallCount];//物体集合public List<Bullet>bulletList=new ArrayList<>();public List<Tank>tankList=new ArrayList<>();public List<Bot>botList=new ArrayList<>();public List<Bullet>removeList=new ArrayList<>();public List<Wall>wallList=new ArrayList<>();public List<Grass>grassList=new ArrayList<>();public List<Fe>feList=new ArrayList<>();public List<Base> baseList = new ArrayList<>();public List<EnemyBullet>enemyBulletsList=new ArrayList<>();public List<EnemyBullet>removeList2=new ArrayList<>();public List<Explode>explodeList=new ArrayList<>();//玩家private PlayerOne playerOne = new PlayerOne("images/player1/p1tankU.gif", 500, 700,"images/player1/p1tankU.gif","images/player1/p1tankD.gif","images/player1/p1tankL.gif","images/player1/p1tankR.gif", this);public void random() {Random r=new Random(); for(int i=0;i<wallCount;) {int x=r.nextInt(20);int y=r.nextInt(8)+3;if(i>0) {boolean repeat=false;for(int j=0;j<i;j++) {if(xrr[j]==x*60&&yrr[j]==y*60) {repeat=true;}}if(!repeat) {xrr[i]=x*60;yrr[i]=y*60;i++;}else {continue;}}else {xrr[i]=x*60;yrr[i]=y*60;i++;}}}/** 重置*/public void reset() {count=0;enemyCount=0;playerOne = new PlayerOne("images/player1/p1tankU.gif", 500, 700,"images/player1/p1tankU.gif","images/player1/p1tankD.gif","images/player1/p1tankL.gif","images/player1/p1tankR.gif", this);feList.clear();bulletList.clear();tankList.clear();botList.clear();removeList.clear();wallList.clear();grassList.clear();baseList.clear();enemyBulletsList.clear();removeList2.clear();explodeList.clear();}/** 添加墙,基地*/public void add() {random();//添加围墙for(int i=0;i<21;i++) {wallList.add(new Wall("images/walls.gif",i*60,120,this));}wallList.add(new Wall("images/walls.gif",600,740,this));wallList.add(new Wall("images/walls.gif",600,680,this));wallList.add(new Wall("images/walls.gif",660,680,this));wallList.add(new Wall("images/walls.gif",720,680,this));wallList.add(new Wall("images/walls.gif",720,740,this));for(int i=0;i<wallCount;i++) {Random a=new Random();int num=a.nextInt(4);if(num<2) {Wall wall=new Wall("images/walls.gif",xrr[i], yrr[i], null);wallList.add(wall);}else if(num<3){Grass g=new Grass("images/cao.gif",xrr[i], yrr[i], null);grassList.add(g);}else {Fe f=new Fe("images/fe.gif",xrr[i], yrr[i], null);feList.add(f);}}//添加基地baseList.add(base);}/** 窗口的启动方法*/public void launch() {//标题setTitle("坦克大战无尽版");//窗口初始化大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加关闭事件setDefaultCloseOperation(3);//用户不能调整大小setResizable(false);//使窗口可见setVisible(true);//初始化基地围墙;add();//添加键盘事件this.addKeyListener(new GamePanel.KeyMonitor());while(true) {if(botList.size()==0&&enemyCount==10) {state=4;}if(tankList.size()==0&&(state==1)) {state=3;}if(state==1) {if(count%50==1&&enemyCount<10) {boolean a=true;Random r=new Random();int rnum=r.nextInt(19)+1;if(enemyCount>0) {for(Bot b:botList) {if(Math.abs(rnum*60-b.getX())<60) {a=false;}}if(a) {botList.add(new Bot("images/enemy/enemy1U.gif", rnum*60, 60,"images/enemy/enemy1U.gif","images/enemy/enemy1D.gif","images/enemy/enemy1L.gif","images/enemy/enemy1R.gif", this));enemyCount++;}}else {botList.add(new Bot("images/enemy/enemy1U.gif", rnum*60, 60,"images/enemy/enemy1U.gif","images/enemy/enemy1D.gif","images/enemy/enemy1L.gif","images/enemy/enemy1R.gif", this));enemyCount++;}}if(count%2==1) {if(!explodeList.isEmpty()) {explodeList.remove(0);}}}if(run) {repaint();}try {Thread.sleep(25);}catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}@Overridepublic void paint(Graphics g) {//创建和容器一样大小的Image图片if(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//获得该图片的画布Graphics gImage=offScreenImage.getGraphics();//填充整个画布gImage.fillRect(0,0,width,height);if(state==0) {//添加图片gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);//添加鼠标事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==1) {//paint重绘游戏元素for(Tank player:tankList) {player.paintSelf(gImage);}for(Bullet bullet:bulletList) {bullet.paintSelf(gImage);}bulletList.removeAll(removeList);for(EnemyBullet enemyBullet:enemyBulletsList) {enemyBullet.paintSelf(gImage);}enemyBulletsList.removeAll(removeList2);for(Explode explode:explodeList) {explode.paintSelf(gImage);}for(Bot bot:botList) {bot.paintSelf(gImage);}for(Wall wall:wallList) {wall.paintSelf(gImage);}for(Fe fe:feList) {fe.paintSelf(gImage);}for(Grass grass:grassList) {grass.paintSelf(gImage);}for(Base base:baseList) {base.paintSelf(gImage);}//重绘次数+1count++;}else if(state==2) {}else if(state==3) {gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/shibai.png"),315,200,this);//添加鼠标事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==4) {gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/win.png"),(width-322)/2,(height-84)/2,this);this.addMouseListener(new GamePanel.MouseMonitor());}//将缓冲区绘制好的图形整个绘制到容器的画布中g.drawImage(offScreenImage,0,0,null);}/** 添加键盘监听*/private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_ENTER:if(!start) {tankList.add(playerOne);//将坦克添加至坦克集合state=a;start=true;}break;case KeyEvent.VK_P:if(state!=2) {a=state;state=2;run=false;}else {state=a;run=true;if(a==0) {a=1;}}break; default:playerOne.keyPressed(e);break;}}@Overridepublic void keyReleased(KeyEvent e) {playerOne.keyReleased(e);}}//添加鼠标监听private class MouseMonitor extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent e) {Point p=new Point(e.getX(),e.getY());if(!start&&state==0) {if(p.x>450&&p.x<750&&p.y>400&&p.y<480) {tankList.add(playerOne);state=1;start=true;Music.startPlay();}}else if(state==3||state==4) {reset();start=false;state=0;add();}}} public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();}
}
游戏最终成品
java实现坦克大战相关推荐
- 基于Java的坦克大战游戏的设计与实现(论文+PPT+源码)
幻灯片1 基于Java的坦克大战游戏的设计与实现 幻灯片2 CONTENTS 1 4 设计工具与相关技术 详细设计 2 5 系统分析 结论 3 总体设计 幻灯片3 PPT模板下载:http://www ...
- java小组坦克大战游戏开发文档开发日志_java实现坦克大战游戏
本文实例为大家分享了java实现坦克大战游戏的具体代码,供大家参考,具体内容如下 一.实现的功能 1.游戏玩法介绍 2.自定义游戏(选择游戏难度.关卡等) 3.自定义玩家姓名 4.数据的动态显示 二. ...
- Java实现坦克大战,单机版和联网版
Java实现坦克大战 源码获取途径 部分源代码 源码获取途径 百度网盘链接: 百度网盘地址 提取码:5r7i GitHub Github获取地址 部分源代码 public class TankClie ...
- 【JAVA程序设计】基于JAVA的坦克大战小游戏--入门级小游戏
基于JAVA的坦克大战小游戏--入门级小游戏 零.项目获取 一.项目简介 二.开发环境 三.游戏玩法 四.运行截图 零.项目获取 获取方式(点击下载):是云猿实战 项目经过多人测试运行,可以确保100 ...
- java坦克大战登录界面设计_基于JAVA的坦克大战设计和实现-代码.doc
JISHOU UNIVERSITY 本科生毕业设计 题 目:基于JAVA的坦克大战设计与实现作 者:学 号:所属学院:专业年级:指导教师:职 称:完成时间:2012年5月7日 吉首大学 基于JAVA的 ...
- Java版坦克大战游戏
技术:Java等 摘要: Java随着各种电子设备,其中尤其是移动通信设备的发展所诞生的一项新的开发技术.Java定位在各种电子设备产品的功能应用上,对电子产品的多样,智能化,提供了很大的帮助.本次设 ...
- java 坦克大战 教程_[Java教程]坦克大战(一)
[Java教程]坦克大战(一) 0 2016-09-16 08:00:05 坦克大战(一) 相信大家对坦克大战都不陌生,并且网上也有很多用java实现的小程序,最近用了几天时间将其使用javaScri ...
- java怎么连发子弹_【Java_项目篇1】--JAVA实现坦克大战游戏--子弹连发+爆炸效果(四)...
前期相关文章 [Java_项目篇<1>]–JAVA实现坦克大战游戏–画出坦克(一) [Java_项目篇<1>]–JAVA实现坦克大战游戏–坦克移动+添加敌方坦克(二) [Jav ...
- 【Java_项目篇1】--JAVA实现坦克大战游戏--坦克移动+添加敌方坦克(二)
前期文章: [Java_项目篇<1>]--JAVA实现坦克大战游戏--画出坦克(一) 控制小球移动 1.外部类 实现KeyListener监听接口写法 package com.test3; ...
- 【java版坦克大战---准备篇】 java 绘图
要写坦克大战当然要先画出坦克.java画图是基础. package com.game; import java.awt.*; import javax.swing.*; public class Pr ...
最新文章
- cloudera hbase集群简单思路
- springBoot 搭建web项目(前后端分离,附项目源代码地址)
- 网络营销之CPA、CPS、CPM、CPT、CPC 是什么
- docker 容器环境 检测方法
- IO多路复用 select、poll、epoll
- jmeter之ip欺骗
- SAP Commerce Cloud OAuth 实现介绍
- FLOAT或DOUBLE列与具有数值类型的数值进行比较 问题
- (Python)时序预测的七种方法
- 入门monkeyrunner7-monkeyrunner demo3 EasyMonkeyDevice+hierarchyviewer +monkeyrunner+截图对比
- 多线程调用生成主键流水号存储过程产生主键冲突问题解决方案
- 安装pattern出错mysql_config not found
- JS总结 循环 退出循环 函数
- IDEA切换使用的语言
- 1010 -- 青蛙的约会
- stm32f4 ov7670 屏幕一直显示,OV7670 ERR 且MID(PID) 读出来是65535(0xffff)的解决办法
- ES7和 ES8 一览
- TikTok与抖音有什么不同?为什么TikTok被称为“海外版抖音”?
- 荣耀60和荣耀x30max哪个好
- 2011, 完全用 GNU/Linux 工作