Java小项目之飞翔的小鸟

视频 教程:00_【尚学堂】飞翔的小鸟_游戏介绍_哔哩哔哩_bilibili

源码:百度网盘 请输入提取码

涉及的知识点:

  • JavaSE的变量、数据类型、判断语句、循环结构、数组、集合、简单窗口创建、图形图片绘制、双缓存技术、事件-键盘事件、物体的碰撞检测、File。。。

一、窗口的绘制

Constant

package com.study.util;

public class Constant {
    //窗口大小
    public static final int FRAM_WIDTH=600;
    public static final int FRAM_HEIGHT=500;

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

    //窗口初始化位置
    public static final int FRAM_X=200;
    public static final int FRAM_Y=200;

}

GameApp

package com.study.app;

import com.study.main.GameFrame;

public class GameApp {
    public static void main(String[] args) {//游戏的入口
        new GameFrame();
    }
}

GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能

    public GameFrame(){
        setVisible(true);//窗口是否可见
        setSize(FRAM_WIDTH,FRAM_HEIGHT);//窗口大小
        setTitle(FRAM_TITLE);//标题
        setLocation(FRAM_X,FRAM_Y);//窗口的位置
        setResizable(false);//窗口大小不可改变
        addWindowListener(new WindowAdapter() {//窗口关闭事件
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);//结束程序
            }
        });
    }
}

运行结果:

二、添加游戏背景

Constant

package com.study.util;

import java.awt.*;

public class Constant {
    //图片路径
    public static final String BK_IMG_PATH="imgs/bird_bk.png";

}

GameBackGround

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 游戏背景类
 */
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 width=bkimg.getWidth();//图片宽度
        int count=Constant.FRAM_WIDTH/width+1;//循环次数
        for(int i=0;i<count;i++){
            g.drawImage(bkimg,width*i,Constant.FRAM_HEIGHT-height,null);//把图片画入窗口
        }
    }
}

GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {

    private GameBackGround 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);//每33毫秒刷新一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void update(Graphics g){
        gameBackGround.draw(g);
    }
}

GameUtil

package com.study.util;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 工具类
 */
public class GameUtil {

    //装载图片
    public static BufferedImage loadBufferedImage(String imgPath){

        try {
            return ImageIO.read(new FileInputStream(imgPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

运行结果:

三、添加背景颜色

Constant

package com.study.util;

import java.awt.*;

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

GameBackGround

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 游戏背景类
 */
public class GameBackGround {
    //绘制图片
    public void draw(Graphics g){
        //填充背景色
        g.setColor(BK_COLOR);
        g.fillRect(0,0,FRAM_WIDTH,FRAM_HEIGHT);
        g.setColor(Color.black);
    }
}

 运行结果:

四、绘制小鸟

Bird

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.BIRD_IMG;

/**
 * 小鸟类
 */
public class Bird {
    private BufferedImage[] images;//存放小鸟图片
    public static final int BIRD_IMG_COUNT=3;//小鸟图片数量
    //鸟的状态
    private int state;
    public static final int STATE_NORMAL=0;//平着飞
    public static final int STATE_UP=1;//向下飞
    public 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);
    }
}

Constant

package com.study.util;

import java.awt.*;

public class Constant {
    //小鸟的图片
    public static final String[] BIRD_IMG=
            {"imgs/bird_normal.png","imgs/bird_up.png","imgs/bird_down.png"};//上下摆翅膀
}

 GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    private Bird bird;//实例化Bird类
    //对游戏对象的初始化
    public void initGamg(){
        bird=new Bird();
    }
    public void update(Graphics g){
        bird.draw(g);
    }
}

运行结果:

五、实现小鸟的移动

Bird

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.BIRD_IMG;

/**
 * 小鸟类
 */
public class Bird {
    //小鸟的位置
    private int x=200,y=200;
    //小鸟的移动方向
    private boolean up=false,down=false;
    //小鸟的移动速度
    private int speed=4;

    //绘制小鸟
    public void draw(Graphics g){
        flyLogic();
    }

    //控制小鸟移动方向
    public void flyLogic(){
        if(up){
            y-=speed;//向上飞
            if(y<30){//控制小鸟不飞出窗口的上边界
                y=30;
            }
        }
        if(!up){
            y+=speed;//自由落体
            if(y>475){//控制小鸟不飞出窗口的下边界
                y=475;
            }
        }
    }
    public void fly(int fly){
        switch (fly){
            case 1:
                state=1;
                up=true;
                break;
            case 5:
                state=2;
                up=false;
                break;
        }
    }
}

GameFrame 

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    //在构造方法中初始化一些参数
    public GameFrame(){
        //添加按键监听
        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);//每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;
        }
    }
}

 运行结果:

六、解决屏幕闪烁问题

GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    //画布
    private BufferedImage buffimg=new BufferedImage(FRAM_WIDTH,FRAM_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);

    //在此方法内绘制所有需要绘制的内容
    public void update(Graphics g){
        //得到画笔
        Graphics graphics=buffimg.getGraphics();
        gameBackGround.draw(graphics);
        bird.draw(graphics);
        g.drawImage(buffimg,0,0,null);//把画布传入窗口
    }
}

运行结果:

七、云彩的添加与移动

Cloud

package com.study.main;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 云彩类
 */
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);
    }
}

 GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    private GameFrontGround gameFrontGround;
    //对游戏对象的初始化
    public void initGamg(){
        gameFrontGround=new GameFrontGround();
    }

    //在此方法内绘制所有需要绘制的内容
    public void update(Graphics g){
        gameFrontGround.draw(graphics);
    }

}

GameFrontGround

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

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

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

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

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

 运行结果:

八、云彩的自动生成与销毁 

Cloud

package com.study.main;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 云彩类
 */
public class Cloud {
    /**
     * 用于判断云彩是否飞出屏幕以外,飞出后把云彩从容器中移除
     */
    public boolean isOutFrame(){
        if(x<-100){
            return true;
        }
        return false;
    }
}

GameFrontGround

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏的前景类
 */
public class GameFrontGround {

    //构造器初始化数据
    public GameFrontGround(){
        random=new Random();
    }

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

    /**
     * 用于云彩的个数控制
     */
    private void logic(){
        if((int)(500*Math.random())<5){//产生0到1的随机整数,再乘以500,即产生从0到500的随机整数
            //在窗口上方0到150的区域随机生成云
            Cloud cloud=new Cloud(img[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(i);
            if(cloud.isOutFrame()){
                clouds.remove(i);
                i--;
                System.out.println("云被移除了"+cloud);
            }
        }
    }
}

运行结果:

九、绘制障碍物

Barrier

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

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

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

    private static BufferedImage[] imgs;

    static{
        final int COUNT=3;
        //类加载时初始化图片
        imgs=new BufferedImage[COUNT];
        for (int i=0;i<COUNT;i++){
            imgs[i]= GameUtil.loadBufferedImage(Constant.BARRIER_IMG_PATH[i]);
        }
    }
    //位置
    private int x,y;
    //宽度和高度
    private int width,height;
    //障碍物的类型
    private int type;
    public static final int TYPE_TOP_NORMAL=0;
    public static final int TYPE_BOTTOM_NORMAL=2;
    public static final int TYPE_HOVER_NORMAL=4;

    //获取障碍物的宽度和高度
    public static final int BARRIER_WIDTH=imgs[0].getWidth();//悬浮在中间的障碍物
    public static final int BARRIER_HEIGHT=imgs[0].getHeight();
    public static final int BARRIRE_HEAD_WIDTH = imgs[1].getWidth();
    public static final int BARRIRE_HEAD_HEIGHT = imgs[1].getHeight();

    public Barrier(){}

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

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

    //绘制从上往下的障碍物
    private void drawTopNormal(Graphics g){

        //求出所需要的障碍物块数
        //窗口的高度减去头的高度,再除以中间块的高度
        int count=(height-BARRIRE_HEAD_HEIGHT )/BARRIER_HEIGHT+1;
        //绘制障碍物
        for(int i=0;i<count;i++){
            g.drawImage(imgs[0],x,y+i*BARRIER_HEIGHT,null);
        }
        //绘制头
        int y=height-BARRIER_DOWN_HEIGHT;
        g.drawImage(imgs[2],x-(BARRIRE_HEAD_WIDTH-BARRIER_WIDTH)/2,y,null);
        x-=speed;
    }

    //绘制从下往上的障碍物
    private void drawBottomNormal(Graphics g){

        //求出所需要的障碍物块数
        int count=height/BARRIRE_HEIGHT +1;
        //绘制障碍物
        for(int i=0;i<count;i++){
            g.drawImage(imgs[0],x,Constant.FRAM_HEIGHT-i*BARRIER_HEIGHT,null);
        }
        //绘制头
        int y=Constant.FRAM_HEIGHT-height;
        g.drawImage(imgs[1],x-(BARRIRE_HEAD_WIDTH-BARRIER_WIDTH)/2,y,null);
        x-=speed;
    }

}

 Constant

package com.study.util;

import java.awt.*;

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

GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 游戏中障碍物层
 */
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);
        Barrier barrier1=new Barrier(300,0,300,2);
        barriers.add(barrier1);
        barriers.get(1).draw(g);
    }
}

GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    private GameBarrierLayer gameBarrierLayer;//实例化

    //对游戏对象的初始化
    public void initGamg(){
        gameBarrierLayer=new GameBarrierLayer();
    }
    //在此方法内绘制所有需要绘制的内容
    public void update(Graphics g){
        gameBarrierLayer.draw(graphics);
    }


}

 运行结果:

十、障碍物自动生成

Barrier

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

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

GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class 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();
    }

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

    public void logic(){
        if(barriers.size()==0){
            run();
            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()){
                run();
                Barrier top=new Barrier(600, 0, numberTop, 0);
                barriers.add(top);
                Barrier down=new Barrier(600, 500-numberDown, numberDown, 2);
                barriers.add(down);
            }
        }
    }

}

  运行结果:

十一、障碍物对象池

Barrier

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

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

    //障碍物的状态
    private boolean visible;
    //绘制从上往下的障碍物
    private void drawTopNormal(Graphics g){
        if(x<-50){//障碍物出框了
            visible=false;
        }
    }

    //绘制从下往上的障碍物
    private void drawBottomNormal(Graphics g){
        if(x<-50){//障碍物出框了
            visible=false;
        }
    }

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

    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;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }
}

BarrierPool

package com.study.main;

import java.util.ArrayList;
import java.util.List;

/**
 * 为了避免反复地创建和销毁对象,使用对象池来提前创建好对象
 * 反复使用
 */
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("归还对象");
        }
    }
}

 GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class 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();
    }


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

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

运行结果:

十二、判断小鸟与障碍物发生碰撞

Barrier

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

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

    //矩形参数
    private Rectangle rect;

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

    //绘制从上往下的障碍物
    private void drawTopNormal(Graphics g){
        rect(g);
    }

    //绘制从下往上的障碍物
    private void drawBottomNormal(Graphics g){
        rect(g);
    }

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

    /**
     * 绘制障碍物碰撞矩形参数
     * @return
     */
    public void setRectangle(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;
    }
}

Bird

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.BIRD_IMG;

/**
 * 小鸟类
 */
public class Bird {

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

    //小鸟的生命
    public boolean life=true;//默认存活

    //在构造方法中对资源初始化
    public Bird(){
        int w=images[0].getWidth();
        int h=images[0].getHeight();
        rect=new Rectangle(w,h);
    }

    //绘制小鸟
    public void draw(Graphics g){

        //绘制小鸟的矩形
        g.drawRect(x,y,(int)rect.getWidth(),rect.height);
        rect.x=this.x;
        rect.y=this.y;
    }

    public Rectangle getRect() {
        return rect;
    }
}

 GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class GameBarrierLayer {

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

    /**
     * 判断障碍物和小鸟发生碰撞
     */
    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

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能

    //在此方法内绘制所有需要绘制的内容
    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);
        }

    }

}

 运行结果:

十三、计时功能

GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class GameBarrierLayer {

    private GameTime gameTime;

    public GameBarrierLayer(){
        gameTime=new GameTime();
    }


    public void logic(Graphics g){
        if(barriers.size()==0){
            run();
            gameTime.begin();
        }else{
            //画计时数字
            g.setColor(Color.white);
            long differ = gameTime.differ();
            g.setFont(new Font("微软雅黑",1,20));
            g.drawString("坚持了: "+differ+"秒",30,70);
        }
    }

}

GameTime

package com.study.main;

/**
 * 游戏计时器
 */
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;
    }
}

 运行结果:

十四、添加悬浮障碍物

Barrier

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class GameBarrierLayer {

    public void logic(Graphics g){
        if(barriers.size()==0){
        }else{
            if(last.isInFrame()) {
                run();
                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);
                }
            }
        }
    }


}

GameBarrierLayer

package com.study.main;

import com.study.util.Constant;
import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 障碍物类
 */
public class Barrier {
    //障碍物的状态
    private boolean mob=true;

    //障碍物的类型
    public static final int TYPE_HOVER_NORMAL=4;
    public static final int TYPE_MOBILE=6;

    //根据不同类型绘制障碍物
    public void draw(Graphics g){
        switch (type){
            case TYPE_HOVER_NORMAL:
                drawHoverNormal(g);
                break;
            case TYPE_MOBILE:
                drawMobile(g);
                break;
            default:
        }
    }
    //绘制中间悬浮的障碍物
    private void drawHoverNormal(Graphics g){

        //求出所需要的障碍物块数
        int count=(height-BARRIER_HEAD_HEIGHT)/BARRIER_HEIGHT;
        //绘制上头
        g.drawImage(imgs[1],x,y,null);
        //绘制障碍物
        for(int i=0;i<count;i++){
            g.drawImage(imgs[0],x,y+BARRIER_HEAD_HEIGHT+i*BARRIER_HEIGHT,null);
        }
        rect(g);
        //绘制下头
        int y11=y+height-BARRIER_HEAD_HEIGHT;
        g.drawImage(imgs[2],x,y11,null);
        x-=speed;
        if(x<-50){//障碍物出框了
            visible=false;
        }
    }
    //绘制中间可自由移动的障碍物
    private void drawMobile(Graphics g){

        //求出所需要的障碍物块数
        int count=(height-BARRIER_HEAD_HEIGHT)/BARRIER_HEIGHT;
        //绘制上头
        g.drawImage(imgs[1],x,y,null);
        //绘制障碍物
        for(int i=0;i<count;i++){
            g.drawImage(imgs[0],x,y+BARRIER_HEAD_HEIGHT+i*BARRIER_HEIGHT,null);
        }
        rect(g);
        //绘制下头
        int y11=y+height-BARRIER_HEAD_HEIGHT;
        g.drawImage(imgs[2],x,y11,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;//往下移
            }
        }
    }
}

 运行结果:

十五、按下空格重新开始游戏

Bird

package com.study.main;

import com.study.util.GameUtil;

import java.awt.*;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.BIRD_IMG;

/**
 * 小鸟类
 */
public class Bird {
    /**
     * 游戏重新开始,重新绘制小鸟的位置
     */
    public void restartDraw(){
        life=true;
        x=200;
        y=200;
    }
}

GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class GameBarrierLayer {
    /**
     * 清空障碍物对象池,重新开始游戏
     */
    public void restart(){
        barriers.clear();
    }
}

 GameFrame

package com.study.main;

import javax.swing.*;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

import static com.study.util.Constant.*;

/**
 * 绘制游戏的主窗口
 */
public class GameFrame extends Frame {//继续Frame后,该类就有了创建窗口的功能
    //在此方法内绘制所有需要绘制的内容
    public void update(Graphics g){
        if(bird.life){
        }else{
            String reset="Space Reset Game";
            g.drawString(reset,25,350);
        }
    }

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

    /**
     * 重置游戏
     */
    public void restart(){
        gameBarrierLayer.restart();//清空缓存
        bird.restartDraw();//复活小鸟
    }
}

运行结果:

十六、记录的持久化

GameBarrierLayer

package com.study.main;

import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 游戏中障碍物层
 */
public class GameBarrierLayer {
    public void logic(Graphics g){
        if(barriers.size()==0){
        }else{
            txt=getTxt();
            if(differ<=txt){
                g.drawString("最高成绩: "+txt,200,70);
            }else{
                setTxt(String.valueOf(differ));
                g.drawString("最高成绩: "+getTxt(),200,70);
            }     
        }
    }

    File file=new File("D:\\java-idea-2023\\bird\\game.txt");
    /**
     * 得到文件中的数据
     */
    public int getTxt(){
        BufferedReader in= null;//字符流
        try {
            in = new BufferedReader(new FileReader(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        int read= 0;
        try {
            read = Integer.parseInt(in.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return read;
    }
    /**
     * 储存数据
     */
    public void setTxt(String str){
        FileWriter fileWriter= null;
        try {
            fileWriter = new FileWriter(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fileWriter.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

运行结果:

当然可以!以下是一个简单的Java小游戏飞翔小鸟的代码示例: ```java import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class BirdGame extends JFrame implements KeyListener { private int birdY = 250; // 小鸟的初始位置 private int speed = 0; // 小鸟的初始速度 public BirdGame() { setTitle("飞翔小鸟"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); setVisible(true); addKeyListener(this); } public void paint(Graphics g) { super.paint(g); g.fillRect(100, birdY, 20, 20); // 绘制小鸟 } public void keyTyped(KeyEvent e) {} public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { speed = -10; // 按下空格键,小鸟向上飞行 } } public void keyReleased(KeyEvent e) {} public void birdMove() { birdY += speed; // 更新小鸟的位置 speed += 1; // 更新小鸟的速度 if (birdY >= 530) { birdY = 530; // 小鸟触底时停止下落 } repaint(); // 重绘界面 } public static void main(String[] args) { BirdGame game = new BirdGame(); while (true) { game.birdMove(); try { Thread.sleep(20); // 控制小鸟的速度 } catch (InterruptedException e) { e.printStackTrace(); } } } } ``` 这个代码示例实现了一个简单的飞翔小鸟游戏。通过按下空格键,小鸟会向上飞行,松开空格键后小鸟会自由下落。小鸟的位置和速度会不断更新,并通过重绘界面来实现动画效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

戏拈秃笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值