java小游戏-飞翔的小鸟

java小游戏-ava小游戏-飞翔的小鸟

  • 1 游戏窗口的显示
  • 2 游戏背景添加
  • 3 背景颜色的添加
  • 4 屏幕中绘制小鸟
  • 5 实现小鸟上下移动
  • 6 解决屏幕闪烁问题
  • 7 云彩的添加与移动
  • 8 云彩的自动生成与销毁
  • 9 绘制从上向下的障碍物
  • 10 绘制从下往上的障碍物
  • 11 障碍物的自动生成
  • 12 障碍物对象池
  • 13 障碍物归还对象池
  • 14 判断小鸟与障碍物发生碰撞
  • 15 小鸟与碰撞物碰撞后处理
  • 16 计时器
  • 17 添加障碍物
  • 18 按下空格键查询开始游戏
  • 19 记录持久化
  • 20 游戏优化

连接视频


1 游戏窗口的显示

创建Constant类

/**
 * 常量
 */
public class Constant {
    //窗口的大小
    public static final int FRAME_WIDTH = 600;
    public static final int FRAME_HEIGHT = 500;

    //窗口的标题
    public static final String FRAME_TITLE = "飞翔的小鸟";

    //窗口的初始化位置
    public static final int FRAME_X = 200;
    public static final int FRAME_Y = 200;

}

创建GameFrame类

/**
 * 游戏的主窗口,所有的关于游戏中绘制的内容都在此类中完成。
 * 游戏开发:基本都是底层界面的绘制,而不是用jdk通过的各种组件
 */
public class GameFrame extends Frame {

    //构造方法中初始化一些参数
    public GameFrame() {
        //窗口是否可见
        setVisible(true);
        //窗口大小
        setSize(FRAME_WIDTH, FRAME_HEIGHT);
        //窗口标题
        setTitle(FRAME_TITLE);
        //窗口的初始化位置
        setLocation(FRAME_X, FRAME_Y);
        //窗口的大小不可变
        setResizable(false);

        //窗口的关闭事件
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);//结束程序
            }
        });
    }
    
}

创建GameApp类

public class GameApp {
    public static void main(String[] args) {
        new GameFrame();
    }
}

2 游戏背景添加

先把准备的图片放入项目中

在Constant类添加常量

//图片路径
public static final String BK_IMG_PATH = "birdimg/ground.png";

创建GameUtil类

/**
 * 工具类
 */
public class GameUtil {
    //加载图片
    public static BufferedImage loadBufferedImage(String imgPath){
        try {
            return ImageIO.read(new FileInputStream(imgPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

创建GameBackGround类

/**
 * 游戏背景类
 */
public class GameBackGround {
    //背景需要的资源图片
    private BufferedImage bkimg;

    //构造器初始化资源
    public GameBackGround(){
        bkimg = GameUtil.loadBufferedImage(Constant.BK_IMG_PATH);
    }

    //绘制图片
    public void draw(Graphics g){
        //得到图片的高度和宽度
        int height = bkimg.getHeight();
        int wight = bkimg.getWidth();
        //循环次数
        int count = Constant.FRAME_WIDTH/wight + 1;
        for (int i = 0; i < count; i++) {
            g.drawImage(bkimg,wight*i,Constant.FRAME_HEIGHT-height,null);
        }
    }
}

在GameFrame类添加方法

public class GameFrame extends Frame {

    //实例化gameBackGround类
    private GameBackGround gameBackGround;

    //构造方法中初始化一些参数
    public GameFrame() {
        ...

		//初始化游戏对象
        initGamg();

        new run().start();
    }

    //对游戏中对象初始化
    public void initGamg(){
        gameBackGround = new GameBackGround();
    }

    //创建线程
    class run extends Thread{
        @Override
        public void run() {
            repaint();
            try {
                Thread.sleep(33);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

	 /**
     * 所有我们需要绘制的内容都在此方法中进行调用绘制
     */
    @Override
    public void update(Graphics g){
        gameBackGround.draw(g);
    }

}

3 背景颜色的添加

在Constant类添加常量

//游戏背景颜色
public static final Color BK_COLOR = new Color(0x4B4CF);

在GameBackGround类draw方法添加绘制

//绘制图片
public void draw(Graphics g){
    //填充背景色
    g.setColor(BK_COLOR);
    g.fillRect(0,0,FRAME_WIDTH,FRAME_HEIGHT);
    g.setColor(Color.black);

    //得到图片的高度和宽度
    ...
}

4 屏幕中绘制小鸟

在Constant类中添加常量

//小鸟的图片资源
public static final String[] BIRD_IMG =
        {"birdimg/00.png","birdimg/01.png","birdimg/02.png"};

创建Bird类

/**
 * 小鸟类
 */
public class Bird {
    //存放小鸟图片
    private BufferedImage[] images;
    private static final int BIRD_IMG_COUNT = 3;

    //鸟的状态
    private int state;
    private static final int STATE_NORMAR = 0;//平着飞
    private static final int STATE_UP = 1;//向上飞
    private static final int STATE_DOWN = 2;//向下飞

    //构造方法中对资源初始化
    public Bird(){
        images = new BufferedImage[BIRD_IMG_COUNT];
        for (int i = 0; i < BIRD_IMG_COUNT; i++) {
            images[i] = GameUtil.loadBufferedImage(BIRD_IMG[i]);
        }
    }

    //绘制小鸟
    public void draw(Graphics g){
        g.drawImage(images[state],200,200,null);
    }

}

在GameFrame类中添加bird对象

//实例化Bird类
private Bird bird;

//对游戏中对象初始化
public void initGamg(){
    gameBackGround = new GameBackGround();
    bird = new Bird();
}

/**
 * 所有我们需要绘制的内容都在此方法中进行调用绘制
 */
@Override
public void update(Graphics g){
    gameBackGround.draw(g);
    bird.draw(g);
}

5 实现小鸟上下移动

在Bird类添加小鸟移动参数

//小鸟的位置
private int x = 200, y = 200;

//小鸟移动方向 上下
private boolean up = false, down = false;

//小鸟移动速度
private int speed = 4;
//绘制小鸟
public void draw(Graphics g) {
   flyLogic();
   g.drawImage(images[state], x, y, null);
}

//控制小鸟移动方向
public void flyLogic() {
   if (up) {
       y -= speed;
       if (y < 20) {
           y = 20;
       }
   }
   if (!up) {
       y += speed;
       if (y > 470) {
           y = 470;
       }
   }
}

public void fly(int fly) {
   switch (fly) {
       case 1:
           state = 1;
           up = true;
           break;
       case 5:
           state = 2;
           up = false;
           break;
   }
}

在GameFrame类添加小鸟移动监听事件

//构造方法中初始化一些参数
public GameFrame() {
   	...
	//初始化游戏对象
    initGamg();

    new run().start();
    //添加按键监听事件
    addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            add(e);
        }

        @Override
        public void keyReleased(KeyEvent e) {
            minu(e);
        }
    });
}

//创建线程
class Run extends Thread {
    @Override
    public void run() {
        while (true) {
            repaint();
            try {
                Thread.sleep(33);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//按键
public void add(KeyEvent e){
    switch (e.getKeyCode()){
        case KeyEvent.VK_UP:
            bird.fly(1);
            break;
    }
}

//抬键
public void minu(KeyEvent e){
    switch (e.getKeyCode()){
        case KeyEvent.VK_UP:
            bird.fly(5);
            break;
    }
}

6 解决屏幕闪烁问题

在GameFrame类添加缓存图片对象

//存放屏幕图片
private BufferedImage buffimg = new BufferedImage(FRAME_WIDTH, FRAME_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);

/**
 * 所有我们需要绘制的内容都在此方法中进行调用绘制
 */
@Override
public void update(Graphics g) {
    //得到图片的画笔
    Graphics graphics = buffimg.getGraphics();

    gameBackGround.draw(graphics);
    bird.draw(graphics);

    //一次性的将图片绘制到屏幕中
    g.drawImage(buffimg, 0, 0, null);
}

7 云彩的添加与移动

创建Cloud类

/**
 * 云彩类
 */
public class Cloud {
    //云彩图片
    private BufferedImage img;
    //云彩的速度
    private int speed;
    //云彩的位置
    private int x,y;

    public Cloud(){
    }

    public Cloud(BufferedImage img, int speed, int x, int y) {
        this.img = img;
        this.speed = speed;
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g){
        x-=speed;
        g.drawImage(img,x,y,null);
    }
}

创建GameFrontGround类

/**
 * 游戏的前景类
 */
public class GameFrontGround {
    //云彩的个数
    private static final int CLOUD_COUNT = 2;
    //存放云彩的容器
    private List<Cloud> clouds;
    //云彩的飞行速度
    private static final int CLOUD_SPEED = 1;
    //使用到的图片资源资源
    private BufferedImage[] images;

    //构造器初始化数据
    public GameFrontGround(){
        clouds = new ArrayList<>();
        images = new BufferedImage[CLOUD_COUNT];

        //容器中添加云彩图片
        for (int i = 0; i < CLOUD_COUNT; i++) {
            images[i] = GameUtil.loadBufferedImage("birdimg/cloud" + i +".png");
        }
    }

    //绘制云彩
    public void draw(Graphics g){
        Cloud cloud = new Cloud(images[1], CLOUD_SPEED, 300, 100);
        clouds.add(cloud);

        clouds.get(0).draw(g);
    }
    
}

在GameFrame类绘制云彩

//实例化GameFrontGround类
private GameFrontGround gameFrontGround;

//对游戏中对象初始化
public void initGamg() {
    gameBackGround = new GameBackGround();
    bird = new Bird();
    gameFrontGround = new GameFrontGround();
}

@Override
public void update(Graphics g) {
    //得到图片的画笔
    Graphics graphics = buffimg.getGraphics();

    gameBackGround.draw(graphics);
    bird.draw(graphics);
    gameFrontGround.draw(graphics);

    //一次性的将图片绘制到屏幕中
    g.drawImage(buffimg, 0, 0, null);
}

8 云彩的自动生成与销毁

在GameFrontGround添加云彩随机数

//用于产生随机数
private Random random;
//构造器初始化数据
public GameFrontGround() {
    clouds = new ArrayList<>();
    images = new BufferedImage[CLOUD_COUNT];

    //容器中添加云彩图片
    for (int i = 0; i < CLOUD_COUNT; i++) {
        images[i] = GameUtil.loadBufferedImage("birdimg/cloud" + i + ".png");
    }

    random = new Random();
}

//绘制云彩
public void draw(Graphics g) {
    logic();
    for (int i = 0; i < clouds.size(); i++) {
        clouds.get(i).draw(g);
    }
}

//用于云彩个数控制
public void logic() {
    if ((500 * Math.random()) < 5) {
        Cloud cloud = new Cloud(images[random.nextInt(CLOUD_COUNT)],CLOUD_SPEED,600,random.nextInt(150));
        clouds.add(cloud);
    }
    for (int i = 0; i < clouds.size(); i++) {
        Cloud cloud = clouds.get(0);
        if (cloud.isOutFrame()) {
            clouds.remove(cloud);
            i--;
            System.out.println("云彩移除:" + cloud);
        }
    }
}

在Cloud类添加判断

//用于判断云彩是否飞出屏幕之外
public boolean isOutFrame(){
    if(x < -50){
        return true;
    }
    return false;
}

9 绘制从上向下的障碍物

在Constant类添加障碍物资源

//障碍物的图片资源
public static final String[] BARRIER_IMG_PATH =
        {"birdimg/barrier.png","birdimg/barrier_up.png","birdimg/barrier_down.png"};

创建Barrier类

/**
 * 障碍物类
 */
public class Barrier {

    //障碍物所需三个图片
    private static BufferedImage[] images;

    static {
        final int COUNT = 3;
        //类加载的时候将三个图片初始化
        images = new BufferedImage[COUNT];
        for (int i = 0; i < COUNT; i++) {
            images[i] = GameUtil.loadBufferedImage(Constant.BARRIER_IMG_PATH[i]);
        }
    }

    //位置
    private int x, y;
    //宽度和高度
    private int width, height;
    //障碍物的类型
    private int type;
    private static final int TYPE_TOP_NORMAL = 0;
    private static final int TYPE_BOTTOM_NORMAL = 2;
    private static final int TYPE_HOVER_NORMAL = 4;

    //获取障碍物的高度和宽度
    public static final int BARRIER_WIDTH = images[0].getWidth();
    public static final int BARRIER_HEIGHT = images[0].getHeight();
    public static final int BARRIER_HEAD_WIDTH = images[1].getWidth();
    public static final int BARRIER_HEAD_HEIGHT = images[1].getHeight();

    public Barrier() {
    }

    public Barrier(int x, int y, int height, int type) {
        this.x = x;
        this.y = y;
        this.width = BARRIER_WIDTH;
        this.height = height;
        this.type = type;
    }

    //根据不同的类型绘制障碍物
    public void draw(Graphics g) {
        drawToNormal(g);
    }

    //绘制从上向下障碍物
    private void drawToNormal(Graphics g) {
        //求出所需要的障碍物的块数
        int count = (height - BARRIER_HEAD_HEIGHT) / BARRIER_HEIGHT + 1;
        //for循环绘制障碍物
        for (int i = 0; i < count; i++) {
            g.drawImage(images[0], x, y + i * BARRIER_HEIGHT, null);
        }
        //绘制头
        int y = height - BARRIER_HEAD_HEIGHT;
        g.drawImage(images[2], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);
    }
}

创建GameBarrierLayer类

/**
 * 游戏中的障碍物层
 */
public class GameBarrierLayer {
    //存放障碍物
    private List<Barrier> barriers;

    public GameBarrierLayer(){
        barriers = new ArrayList<>();
    }

    //绘制障碍物
    public void draw(Graphics g){
        Barrier barrier = new Barrier(200, 0, 200, 0);
        barriers.add(barrier);
        barriers.get(0).draw(g);
    }
}

在GameFrame类创建GameBarrierLayer 对象

//实例化GameBarrierLayer类
private GameBarrierLayer gameBarrierLayer;

//对游戏中对象初始化
public void initGamg() {
    gameBackGround = new GameBackGround();
    bird = new Bird();
    gameFrontGround = new GameFrontGround();
    gameBarrierLayer = new GameBarrierLayer();
}

/**
 * 所有我们需要绘制的内容都在此方法中进行调用绘制
 */
@Override
public void update(Graphics g) {
    //得到图片的画笔
    Graphics graphics = buffimg.getGraphics();

    gameBackGround.draw(graphics);
    bird.draw(graphics);
    gameFrontGround.draw(graphics);
    gameBarrierLayer.draw(graphics);

    //一次性的将图片绘制到屏幕中
    g.drawImage(buffimg, 0, 0, null);
}

10 绘制从下往上的障碍物

在Barrier类添加方法

//根据不同的类型绘制障碍物
public void draw(Graphics g) {
    switch (type){
        case TYPE_TOP_NORMAL:
            drawToNormal(g);
            break;
        case TYPE_BOTTOM_NORMAL:
            drawNormalTop(g);
            break;
    }
}

//绘制从下向上的障碍物
public void drawNormalTop(Graphics g) {
    //求出所需要的障碍物的块数
    int count = height / BARRIER_HEIGHT + 1;
    //for循环绘制障碍物
    for (int i = 0; i < count; i++) {
        g.drawImage(images[0], x, Constant.FRAME_HEIGHT - i * BARRIER_HEIGHT, null);
    }
    //绘制头
    int y = Constant.FRAME_HEIGHT - height;
    g.drawImage(images[1], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);
}

在GameBarrierLayer类修改draw方法

//绘制障碍物
public void draw(Graphics g){
    Barrier barrier = new Barrier(200, 0, 200, 0);
    barriers.add(barrier);
    barriers.get(0).draw(g);
    Barrier barrier1 = new Barrier(300, 0, 300, 2);
    barriers.add(barrier1);
    barriers.get(1).draw(g);
}

11 障碍物的自动生成

在GameBarrierLayer添加障碍物的自动生成

private Random random = new Random();

//绘制障碍物
public void draw(Graphics g){
    for (int i = 0; i < barriers.size(); i++) {
        Barrier barrier = barriers.get(i);
        barrier.draw(g);
    }
    logic();
}

public void logic(){
    if(barriers.size() == 0){
        ran();
        Barrier top = new Barrier(600,0,numberTop,0);
        barriers.add(top);
        Barrier down = new Barrier(600,500-numberDown,numberDown,2);
        barriers.add(down);
    }else {
        //判断最后一个障碍物是否完全进入屏幕内
        Barrier last = barriers.get(barriers.size() - 1);
        if(last.isInFrame()){
            ran();
            Barrier top = new Barrier(600,0,numberTop,0);
            barriers.add(top);
            Barrier down = new Barrier(600,500-numberDown,numberDown,2);
            barriers.add(down);
        }
    }
}

//上方障碍物高度
private int numberTop;
//下方障碍物高度
private int numberDown;
//产生两个100-500之间的随机高度
public void ran(){
    numberTop = random.nextInt(400) + 100;
    numberDown = random.nextInt(400) + 100;
    //如果管道重合,则重新随机
    if(numberTop + numberDown > 450){
        ran();
    }

}

在Barrier类添加判断

//障碍物移动速度
private int speed = 3;

//绘制从上向下障碍物
private void drawToNormal(Graphics g) {
    //求出所需要的障碍物的块数
    int count = (height - BARRIER_HEAD_HEIGHT) / BARRIER_HEIGHT + 1;
    //for循环绘制障碍物
    for (int i = 0; i < count; i++) {
        g.drawImage(images[0], x, y + i * BARRIER_HEIGHT, null);
    }
    //绘制头
    int y = height - BARRIER_HEAD_HEIGHT;
    g.drawImage(images[2], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);
    x-=speed;
}

//绘制从下向上的障碍物
public void drawNormalTop(Graphics g) {
    //求出所需要的障碍物的块数
    int count = height / BARRIER_HEIGHT + 1;
    //for循环绘制障碍物
    for (int i = 0; i < count; i++) {
        g.drawImage(images[0], x, Constant.FRAME_HEIGHT - i * BARRIER_HEIGHT, null);
    }
    //绘制头
    int y = Constant.FRAME_HEIGHT - height;
    g.drawImage(images[1], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);
    x-=speed;
}

//判断什么时候绘制下一组障碍物
public boolean isInFrame(){
    return 600-x>150;
}

12 障碍物对象池

创建BarrierPool对象

/**
 * 为了避免反复创建和销毁对象,使用对象池来提前创建一些好的对象。
 * 使用的时候从池子中获取,使用完毕后,归还
 */
public class BarrierPool {
    //用于管理池中所有对象的容器
    private static List<Barrier> pool = new ArrayList<>();
    //池中初始化的对象个数
    public static final int initCount = 16;
    //对象池中最大数
    public static final int maxCount = 20;

    static {
        //初始化池中对象
        for (int i = 0; i < initCount; i++) {
            pool.add(new Barrier());
        }
    }

    //从池中获取一个对象
    public static Barrier getPool(){
        int size = pool.size();
        //如果池中有对象才可以拿
        if(size > 0){
            //移除数据
            System.out.println("拿走一个");
            return pool.remove(size-1);
        }else {
            //池中没有对象 只能new
            System.out.println("新的对象");
            return new Barrier();
        }
    }

    //将对象归还容器中
    public static void setPool(Barrier barrier){
        if(pool.size() < maxCount){
            pool.add(barrier);
            System.out.println("容器归还了");
        }
    }
}

在Barrier类添加get和set方法

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 getHeight() { return height; }
public void setHeight(int height) { this.height = height; }
public int getType() { return type; }
public void setType(int type) { this.type = type; }

在GameBarrierLayer类添加对象池方法

public void logic(){
   if(barriers.size() == 0){
       ran();
//            Barrier top = new Barrier(600,0,numberTop,0);
//            barriers.add(top);
//            Barrier down = new Barrier(600,500-numberDown,numberDown,2);
//            barriers.add(down);
       insert(600,0,numberTop,0);
       insert(600,500-numberDown,numberDown,2);
   }else {
       //判断最后一个障碍物是否完全进入屏幕内
       Barrier last = barriers.get(barriers.size() - 1);
       if(last.isInFrame()){
           ran();
//                Barrier top = new Barrier(600,0,numberTop,0);
//                barriers.add(top);
//                Barrier down = new Barrier(600,500-numberDown,numberDown,2);
//                barriers.add(down);
           insert(600,0,numberTop,0);
           insert(600,500-numberDown,numberDown,2);
       }
   }
}
    
//用于从池中获取对象,并把参数封装成barrier,存入barriers数组中
public void insert(int x,int y,int height,int type){
    Barrier pool = BarrierPool.getPool();
    pool.setX(x);
    pool.setY(y);
    pool.setHeight(height);
    pool.setType(type);
    barriers.add(pool);
}

13 障碍物归还对象池

在Barrier类添加存活判断

//障碍物存活状态
private boolean visible;

//绘制从上向下障碍物
private void drawToNormal(Graphics g) {
	....
    x-=speed;
    if(x < -50){
        visible = false;
    }
}

//绘制从下向上的障碍物
private void drawNormalTop(Graphics g) {
	....
    x-=speed;
    if(x < -50){
        visible = false;
    }
}
public boolean isVisible() { return visible; }
public void setVisible(boolean visible) { this.visible = visible; }

在GameBarrierLayer类设置存活状态

//绘制障碍物
public void draw(Graphics g){
    for (int i = 0; i < barriers.size(); i++) {
        Barrier barrier = barriers.get(i);
        if (barrier.isVisible()) {
            barrier.draw(g);
        }else {
            Barrier remove = barriers.remove(i);
            BarrierPool.setPool(remove);
            i--;
        }
    }
    logic();
}

//用于从池中获取对象,并把参数封装成barrier,存入barriers数组中
public void insert(int x,int y,int height,int type){
    Barrier pool = BarrierPool.getPool();
    pool.setX(x);
    pool.setY(y);
    pool.setHeight(height);
    pool.setType(type);
    pool.setVisible(true);
    barriers.add(pool);
}

14 判断小鸟与障碍物发生碰撞

在Bird类添加矩形对象

//小鸟矩形对象
private Rectangle rect;

//构造方法中对资源初始化
public Bird() {
    images = new BufferedImage[BIRD_IMG_COUNT];
    for (int i = 0; i < BIRD_IMG_COUNT; i++) {
        images[i] = GameUtil.loadBufferedImage(BIRD_IMG[i]);
    }
    int w = images[0].getWidth();
    int h = images[0].getHeight();
    rect = new Rectangle(w,h);
}

//绘制小鸟
public void draw(Graphics g) {
    flyLogic();
    g.drawImage(images[state], x, y, null);
    //绘制小鸟的矩形
    g.drawRect(x,y,(int)rect.getWidth(),(int)rect.getHeight());
    rect.x = this.x;
    rect.y = this.y;
}

public Rectangle getRect() {
    return rect;
}

在Barrier类添加矩形对象

//矩形参数
private Rectangle rect;

public Barrier() {
    rect = new Rectangle();
}

//绘制从上向下障碍物
private void drawToNormal(Graphics g) {
    ...
    rect(g);
}

//绘制从下向上的障碍物
public void drawNormalTop(Graphics g) {
   ...
    rect(g);
}

//绘制障碍物碰撞矩形
public void rect(Graphics g){
    int x1 = this.x;
    int y1 = this.y;
    int w1 = images[0].getWidth();
    g.setColor(Color.blue);
    g.drawRect(x1,y1,w1,height);
    setRecyangle(x1,y1,w1,height);
}

//障碍物的碰撞矩形参数
public void setRecyangle(int x,int y,int width,int height){
    rect.x = x;
    rect.y = y;
    rect.width = width;
    rect.height = height;
}

public Rectangle getRect() {
    return rect;
}

在GameBarrierLayer类添加碰撞判断

//绘制障碍物
public void draw(Graphics g,Bird bird){
    for (int i = 0; i < barriers.size(); i++) {
        Barrier barrier = barriers.get(i);
        if (barrier.isVisible()) {
            barrier.draw(g);
        }else {
            Barrier remove = barriers.remove(i);
            BarrierPool.setPool(remove);
            i--;
        }
    }
    collideBird(bird);
    logic();
}

//判断障碍物和小鸟发生碰撞
public boolean collideBird(Bird bird){
    for (int i = 0; i < barriers.size(); i++) {
        Barrier barrier = barriers.get(i);
        //判断是否相交
        if(barrier.getRect().intersects(bird.getRect())){
            System.out.println("碰撞上了");
        }
    }
    return false;
}

在GameFrame 类修改update方法

public void update(Graphics g) {
    //得到图片的画笔
    Graphics graphics = buffimg.getGraphics();

    gameBackGround.draw(graphics);
    bird.draw(graphics);
    gameFrontGround.draw(graphics);
    gameBarrierLayer.draw(graphics,bird);

    //一次性的将图片绘制到屏幕中
    g.drawImage(buffimg, 0, 0, null);
}

15 小鸟与碰撞物碰撞后处理

在Bird类添加小鸟状态

//小鸟的生命
public boolean life = true;

在GameBarrierLayer类修改collideBird方法

//判断障碍物和小鸟发生碰撞
public boolean collideBird(Bird bird){
    for (int i = 0; i < barriers.size(); i++) {
        Barrier barrier = barriers.get(i);
        //判断是否相交
        if(barrier.getRect().intersects(bird.getRect())){
            System.out.println("碰撞上了");
            bird.life = false;
        }
    }
    return false;
}

在GameFrame 类修改update方法

/**
 * 所有我们需要绘制的内容都在此方法中进行调用绘制
 */
@Override
public void update(Graphics g) {
    if (bird.life) {
        //得到图片的画笔
        Graphics graphics = buffimg.getGraphics();

        gameBackGround.draw(graphics);
        bird.draw(graphics);
        gameFrontGround.draw(graphics);
        gameBarrierLayer.draw(graphics,bird);

        //一次性的将图片绘制到屏幕中
        g.drawImage(buffimg, 0, 0, null);
    }else {
        String over = "游戏结束";
        g.setColor(Color.red);
        g.setFont(new Font("微软雅黑",1,60));
        g.drawString(over,300,250);
    }
}

16 计时器

创建GameTime类

/**
 * 游戏计时
 */
public class GameTime {
    //开始
    private long beginTime;
    //结束
    private long endTime;
    //时间差
    private long differ;

    public GameTime(){}

    //开始计时
    public void begin(){
        beginTime = System.currentTimeMillis();
    }

    //计算时间差
    public long differ(){
        endTime = System.currentTimeMillis();
        return differ = (endTime-beginTime) / 1000;
    }

}

在GameBarrierLayer类引用计时对象

private GameTime gameTime;

public GameBarrierLayer(){
    barriers = new ArrayList<>();
    gameTime = new GameTime();
}

 //绘制障碍物
public void draw(Graphics g,Bird bird){
    ....
    logic(g);
}

public void logic(Graphics g){
    if(barriers.size() == 0){
        ran();
        gameTime.begin();
        insert(600,0,numberTop,0);
        insert(600,500-numberDown,numberDown,2);
    }else {
        long differ = gameTime.differ();
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",1,20));
        g.drawString("您坚持了:" + differ+"秒",20,50);
        //判断最后一个障碍物是否完全进入屏幕内
        Barrier last = barriers.get(barriers.size() - 1);
        if(last.isInFrame()){
            ran();
            insert(600,0,numberTop,0);
            insert(600,500-numberDown,numberDown,2);
        }
    }
}

17 添加障碍物

在GameBarrierLayer添加中间障碍物

//中间障碍物
private int number;

public void ran(){
    number = random.nextInt(500);
    ...
}

public void logic(Graphics g){
    if(barriers.size() == 0){
        ran();
        gameTime.begin();
        insert(600,0,numberTop,0);
        insert(600,500-numberDown,numberDown,2);
    }else {
        long differ = gameTime.differ();
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",1,20));
        g.drawString("您坚持了:" + differ+"秒",20,50);
        //判断最后一个障碍物是否完全进入屏幕内
        Barrier last = barriers.get(barriers.size() - 1);
        if(last.isInFrame()){
            ran();
            if (number < 50) {
                insert(600,32,440,4);
            }else if (number > 450){
                insert(600,125,200,6);
            }else {
                insert(600,0,numberTop,0);
                insert(600,500-numberDown,numberDown,2);
            }
        }
    }
}

在Barrier类添加绘制中间障碍物和移动障碍物

private static final int TYPE_MOBILE = 6;

private boolean mob = true;

//根据不同的类型绘制障碍物
public void draw(Graphics g) {
    switch (type){
        case TYPE_TOP_NORMAL:
            drawToNormal(g);
            break;
        case TYPE_BOTTOM_NORMAL:
            drawNormalTop(g);
            break;
        case TYPE_HOVER_NORMAL:
            drawHoverNormal(g);
            break;
        case TYPE_MOBILE:
            drawMobile(g);
            break;
    }
}

//绘制中间的障碍物
public void drawHoverNormal(Graphics g) {
    //求出所需要的障碍物的块数
    int count = (height - BARRIER_HEAD_HEIGHT)/ BARRIER_HEIGHT;
    //绘制上头
    g.drawImage(images[1],x,y,null);
    //for循环绘制障碍物
    for (int i = 0; i < count; i++) {
        g.drawImage(images[0], x, y+BARRIER_HEAD_HEIGHT+i*BARRIER_HEIGHT, null);
    }
    rect(g);

    //绘制下头
    int y1 = y+height-BARRIER_HEAD_HEIGHT;
    g.drawImage(images[2], x, y1, null);

    x-=speed;
    if(x < -50){
        visible = false;
    }
}

//绘制移动的障碍物
public void drawMobile(Graphics g) {
    //求出所需要的障碍物的块数
    int count = (height - BARRIER_HEAD_HEIGHT)/ BARRIER_HEIGHT;
    //绘制上头
    g.drawImage(images[1],x,y,null);
    //for循环绘制障碍物
    for (int i = 0; i < count; i++) {
        g.drawImage(images[0], x, y+BARRIER_HEAD_HEIGHT+i*BARRIER_HEIGHT, null);
    }
    rect(g);

    //绘制下头
    int y1 = y+height-BARRIER_HEAD_HEIGHT;
    g.drawImage(images[2], x, y1, null);
    x-=speed;
    if(x < -50){
        visible = false;
    }

    if(mob){
        y+=5;
        if(y >= 250){
            mob = false;
        }
    }else if(!mob){
        y-=5;
        if(y <= 100){
            mob = true;
        }
    }
}

18 按下空格键查询开始游戏

在GameBarrierLayer类添加方法

//用于清空障碍物的池子
public void restant(){
    barriers.clear();
}

在Bird类添加方法

//重新绘制小鸟的位置
public void restartDraw(){
    life = true;
    x = 200;
    y = 200;
}

在GameFrame类添加按键事件

@Override
public void update(Graphics g) {
    if (bird.life) {
        //得到图片的画笔
        Graphics graphics = buffimg.getGraphics();

        gameBackGround.draw(graphics);
        bird.draw(graphics);
        gameFrontGround.draw(graphics);
        gameBarrierLayer.draw(graphics,bird);

        //一次性的将图片绘制到屏幕中
        g.drawImage(buffimg, 0, 0, null);
    }else {
        String over = "游戏结束";
        g.setColor(Color.red);
        g.setFont(new Font("微软雅黑",1,60));
        g.drawString(over,300,250);

        String reset = "Space Reset Game";
        g.drawString(reset,25,350);
    }
}

//按键
public void add(KeyEvent e) {
    switch (e.getKeyCode()) {
        case KeyEvent.VK_UP:
            bird.fly(1);
            break;
        case KeyEvent.VK_SPACE:
            if (bird.life == false) {
                restart();
            }
            break;
    }
}

//重置游戏
public void restart(){
    gameBarrierLayer.restant();
    bird.restartDraw();
}

19 记录持久化

先创建一个txt文件,然后写入一条数据

在GameBarrierLayer类创建文件对象

//存储飞行时间
private int txt;

File file = new File("birdimg/bird.txt");
//用于得到文件中数据
public int getTxt(){
    try {
        BufferedReader in = new BufferedReader(new FileReader(file));
        int read = Integer.parseInt(in.readLine());
        in.close();
        return read;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return 0;
}

//用于存储数据
public void setTxt(String str){
    try {
        FileWriter writer = new FileWriter(file);
        writer.write(str);
        writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void logic(Graphics g){
   if(barriers.size() == 0){
        ran();
        gameTime.begin();
        insert(600,0,numberTop,0);
        insert(600,500-numberDown,numberDown,2);
    }else {
        long differ = gameTime.differ();
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",1,20));
        g.drawString("您坚持了:" + differ+"秒",20,50);

        txt = getTxt();
        if(differ <= txt){
            g.drawString("最高成绩:" + txt,200,50);
        }else {
            setTxt(differ+"");
            g.drawString("最高成绩:" + getTxt(),200,50);
        }

        //判断最后一个障碍物是否完全进入屏幕内
        Barrier last = barriers.get(barriers.size() - 1);
        if(last.isInFrame()){
            ran();
            if (number < 50) {
                insert(600,32,440,4);
            }else if (number > 450){
                insert(600,125,200,6);
            }else {
                insert(600,0,numberTop,0);
                insert(600,500-numberDown,numberDown,2);
            }

        }
    }
}

20 游戏优化

在Bird类修改

//小鸟加速度
private int acceleration;

//绘制小鸟
public void draw(Graphics g) {
    flyLogic();
    g.drawImage(images[state], x, y, null);
    //绘制小鸟的矩形
   // g.drawRect(x,y,(int)rect.getWidth(),(int)rect.getHeight());
    rect.x = this.x;
    rect.y = this.y;
}

//控制小鸟移动方向
public void flyLogic() {
    if (up) {
        acceleration--;
        y+=acceleration;
        if(acceleration < -10){
            acceleration = -10;
        }
        if (y < 20) {
            y = 20;
            acceleration = 0;
        }
    }
    if (!up) {
        acceleration++;
        y+=acceleration;
        if(acceleration > 10){
            acceleration=10;
        }
        if (y > 470) {
            y = 470;
            acceleration = 0;
        }
    }
}

在Barrier类修改

//绘制障碍物碰撞矩形
public void rect(Graphics g){
    int x1 = this.x;
    int y1 = this.y;
    int w1 = images[0].getWidth();
//        g.setColor(Color.blue);
//        g.drawRect(x1,y1,w1,height);
    setRecyangle(x1,y1,w1,height);
}

你可能感兴趣的:(java小游戏,java,开发语言,jvm)