昨天跳着看视频把飞翔小鸟做出来了,下面分享一下我的思路。
先放成品图
和上一篇飞机大战的思路相似:
1.先把窗体做出把背景图放在面板中
2.把游戏背景中地面移动实现
3.把柱子在面板中实现进场及移动
4.把小鸟放在面板中
5.鼠标监听控制小鸟飞行轨迹
6.写判断小鸟与柱子碰撞和与地面碰撞的方法
7.添加计分和游戏结束游戏开始的画面
上面步骤最难的是写判断碰撞的方法…
——————————————————————————————————————————
首先是窗体类:
public class GameFrame extends JFrame{public static void main(String[] args) {GameFrame frame=new GameFrame();GamePanel panel =new GamePanel();//显示窗体frame.setVisible(true);//向窗体内添加一块画板frame.add(panel); }public GameFrame() {setTitle("飞翔小鸟");// 设置标题setSize(432, 644);//窗体尺寸setLocationRelativeTo(null);// 相对于屏幕左上角居中setResizable(false);// 设置不允许玩家拖动界面setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置Logo图标 img/0.pngsetIconImage(ImageUtil.getImage("/img/0.png"));}
}
这是一个获取图片字节流的工具类:
public class ImageUtil {public static BufferedImage getImage(String path) {try {BufferedImage image = ImageIO.read(ImageUtil.class.getResource(path));return image;} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}return null;}
}
地面类:
public class Ground {/** 定义地方的x,y坐标和宽高*/int x;int y;int w;int h;BufferedImage img;//地面的构造器用来构建地面对象public Ground() {img=ImageUtil.getImage("/img/ground.png");h=img.getHeight();w=img.getWidth();x=0;y=644-h;}public void Move() {//让地面能够一直往左边移动if(x<=-(w-432)) {x=25; //初始化x为25 刷新时没有明显的断层}else {x--;}}
}
这个是柱子类:
public class Column {/** 定义地方的x,y坐标和宽高*/int x;int y;int w;int h;Random ran = new Random();BufferedImage img;// 安全间隙int gap;// 构造器初始化构造柱子对象(i表示第几根柱子)public Column(int i) {img = ImageUtil.getImage("/img/column.png");h = img.getHeight() / 2;w = img.getWidth() / 2;x = 320 + (i - 1) * 245;y = -ran.nextInt(h + 146 - 644 + 1);// 初始化安全间隙gap = 75;}// 柱子移动public void Move() {if (x <= -w) {x = 432 + w;y = -ran.nextInt(h + 146 - 644 + 1);} else {x--;}}}
这个是小鸟类(判断碰撞方法写在这里):
public class Bird {/** 定义地方的x,y坐标和宽高*/int x;int y;int w;int h;// 初速度double v0;// 时间间隔(往上移动的时间)double t;// 距离double s;// 重力double g;Random ran = new Random();BufferedImage img;List<BufferedImage> list;public Bird() {img = ImageUtil.getImage("/img/0.png");w = img.getWidth() / 2;h = img.getHeight() / 2;x = 100;y = 200;// 初始化初速度v0 = 2;// 时间t = 0.15;// 距离s = 0;// 重力g = 8;// 初始化装图片的容器list = new ArrayList<BufferedImage>();// 向容器中添加图片for (int i = 0; i < 8; i++) {list.add(ImageUtil.getImage("/img/" + i + ".png"));}}int index = 0;// 小鸟飞行时图片的切换效果public void fly() {if (index < 8) {img = list.get(index);index++;} else {index = 0;}}// 小鸟移动方法public void move() {// 计算小鸟上抛的距离s = v0 * t;// 得到小鸟上抛到最高点时的y坐标y = (int) (y - s);// 计算出小鸟到达最高点时的速度double v2 = v0 - g * t;// 最高点的速度就是小鸟下落时的初速度v0 = v2;}public void moveUp() {v0 = 15;}// 判断是否碰撞到天花板和地面public boolean hit() {if (y <= 0 || y >= 644 - 146 - h) {return true;}return false;}// 判断是否碰撞柱子public boolean hit(Column column) {if (x >= column.x - w && x <= column.x + column.w) {if (y > column.h / 2 + column.y - column.gap / 2 && y < column.h / 2 + column.y + column.gap / 2 - h) {return false;// 安全通过}return true;// 撞到了}return false;// 没撞到}}
最后是画板类:
public class GamePanel extends JPanel {BufferedImage bg;//背景图/** 声明地面和柱子的对象*/Ground ground;Column column1;Column column2;Bird bird;//声明小鸟对象/** 接收三个碰撞条件的变量*/boolean bool1 ;boolean bool2;boolean bool3;// 游戏准备状态boolean start;//是否startboolean GameOver;//是否Gameoverint socre;//分数public GamePanel() {bg = ImageUtil.getImage("/img/bg.png");ground = new Ground();column1 = new Column(1);column2 = new Column(2);bird = new Bird();// 监听鼠标MouseAdapter md = new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {// TODO 自动生成的方法存根super.mouseClicked(e);/** 当游戏为未开始时,点击鼠标为开始,执行start中的线程任务*/if (start == false) {start = true;start();} else if(GameOver){//当游戏结束时,点击鼠标为未开始,Gameover为否,并初始化画板中的各个对象start=false;GameOver=false;ground = new Ground();//初始化柱子对象column1 = new Column(1);//x = 300//初始化第二根柱子column2 = new Column(2);//x = 545//初始化鸟对象bird = new Bird();System.out.println("你的得分为 : "+socre);socre=0;repaint();}else{//游戏进行时,点击鼠标执行moveUp()方法bird.moveUp();}}};addMouseListener(md);addMouseMotionListener(md);}// 游戏开始的方法public void start() {MyThread mt = new MyThread();// 将线程所有执行的任务装入到线程对象中Thread t = new Thread(mt);// 将线程纳入线程调度t.start();// 告诉CPU可以给我这个线程分配时间片段了}@Overridepublic void paint(Graphics g) {super.paint(g);g.drawImage(bg, 0, 0, null);// 添加背景g.drawImage(column1.img, column1.x, column1.y, column1.w, column1.h, null);// 添加第一根柱子g.drawImage(column2.img, column2.x, column2.y, column2.w, column2.h, null);// 添加第二根柱子g.drawImage(ground.img, ground.x, ground.y, null);// 添加地面g.drawImage(bird.img, bird.x, bird.y, bird.w, bird.h, null);// 添加第二根柱子/** 当游戏为未开始时,把准备页面画上去*/if(start==false) {g.drawImage(ImageUtil.getImage("/img/start.png"), 0, 0, null);}/** 当游戏为结束时,把结束页面面画上去*/if(GameOver) {g.drawImage(ImageUtil.getImage("/img/gameover.png"), 0, 0, null);} //画板中字体设置Font f=new Font("宋体",Font.BOLD,18);g.setFont(f);g.setColor(Color.white);g.drawString("分数 :"+ socre, 20, 30);}//线程类class MyThread implements Runnable {//写在run()方法中,就可以用线程的方法同时进行判断@Overridepublic void run() {/** 用死循环方式不断运行对象的方法*/while (true) {ground.Move();column1.Move();column2.Move();bird.fly();bird.move();bool1 = bird.hit();bool2 = bird.hit(column1);bool3 = bird.hit(column2);if (bool1||bool2||bool3) {GameOver = true;// 窗体内的对象全部静止break;// 结束循环}if(bird.x==column1.x+column1.w||bird.x==column2.x+column2.w) {socre++;//分数加一}try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}repaint();//刷新画面}}}
}
需要问题可以留言哦