Java解决游戏界面闪屏

Posted YQS_Love

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java解决游戏界面闪屏相关的知识,希望对你有一定的参考价值。

一、问题描述

我们在做有关于图形绘制方面的问题非常之多。比如,有时我们用普通的方法去绘制图形,会产生闪屏的现象,导致我们所做的游戏或者是别的项目效果非常差,这完全不是我们想要的结果。那么,有没有一种技术,实现不闪屏的效果,特别是在多线程环境下。答案是有的,这就是Java的什么技术——双缓冲技术。

                    图1 双缓冲技术效果图

二、实现方法

1、首先,我们定义一个类继承JFrame,要自定义绘图,我们就要实现JFrame的paint()方法,如下:

@Override
public void paint(Graphics g) 

2、创建一个缓冲区画笔;

public BufferedImage(int width,
                     int height,
                     int imageType)
    width          缓冲区的宽度       
    height         缓冲区的高度
    imageType      缓冲图形模式
// 创建一个缓冲区
BufferedImage paint = new BufferedImage(width, height,
    BufferedImage.TYPE_3BYTE_BGR);
// 得到缓冲区的画笔
Graphics g2 = paint.getGraphics();

3、将你想要绘制的图形绘制在缓冲区内;

// 将想要绘制的图形绘制到缓冲区
g2.drawImage(GameImage.getInstance().game_main_bg, 0, 0, width, height,
        this);

4、将缓冲区的图形绘制到显示面板上;

g.drawImage(paint, 0, 0, this);

经过上面四步之后,我们就解决了闪屏的问题,现在放心大胆的去做你的游戏吧!

三、项目源码

由于项目过大,源码只给出了双缓冲技术得用法,具体的实现并没有做。如果想验证源码的,可以联系我要项目所用到的图片,也可以上网查找。

由于技术和能力有限,文中难免会有错误之处,还望指正,谢谢合作!

1、程序入口类Main.java

/**
 * 主函数入口
 * @author Admin
 *
 */
public class Main 

    public static void main(String[] args) 
        new MainGameFrame();
    


2、游戏主界面类MainGameFrame.java

/**
 * 游戏主面板
 * 
 * @author Admin
 *
 */
public class MainGameFrame extends JFrame implements Runnable 

    private int width = 1200;
    private int height = 600;

    private BufferedImage clickGame;

    private List<PlantAutoMoveInfo> allPlant;

    private boolean isRunnableStart;

    public MainGameFrame() 

        isRunnableStart = true;

        new Thread(this).start();

        init();

        newPlant();
    

    /**
     * 创造植物
     */
    private void newPlant() 
        allPlant = new ArrayList<PlantAutoMoveInfo>();

        //如果你想让所有的植物都不是相同的动作,
        //你可以在PlantAutoMoveInfo去控制它切换图片的时机

        // constructor sunflower
        PlantAutoMoveInfo plantObj = new PlantAutoMoveInfo(new Point(300, 100),
                Constants.SUNFLOWER, GameImage.getInstance().sunflower);
        allPlant.add(plantObj);
       plantObj = new PlantAutoMoveInfo(new Point(300, 250),
                Constants.SUNFLOWER, GameImage.getInstance().sunflower);
        allPlant.add(plantObj);

        // constructor pea
        plantObj = new PlantAutoMoveInfo(new Point(400, 100), Constants.PEA,
                GameImage.getInstance().pea);
        allPlant.add(plantObj);
        plantObj = new PlantAutoMoveInfo(new Point(400, 250), Constants.PEA,
                GameImage.getInstance().pea);
        allPlant.add(plantObj);

        // constructor nut
        plantObj = new PlantAutoMoveInfo(new Point(500, 100), Constants.NUT,
                GameImage.getInstance().nut);
        allPlant.add(plantObj);
        plantObj = new PlantAutoMoveInfo(new Point(500, 250), Constants.NUT,
                GameImage.getInstance().nut);
        allPlant.add(plantObj);
    

    /**
     * 绘制图像
     */
    @Override
    public void paint(Graphics g) 
        // 创建一个缓冲区
        BufferedImage paint = new BufferedImage(width, height,
                BufferedImage.TYPE_3BYTE_BGR);
        // 得到缓冲区的画笔
        Graphics g2 = paint.getGraphics();

        // 将想要绘制的图形绘制到缓冲区
        // draw background image
        g2.drawImage(GameImage.getInstance().game_main_bg, 0, 0, width, height,
                this);

        // 绘制植物
        for (PlantAutoMoveInfo obj : allPlant) 
            g2.drawImage(obj.getShowImage(), (int) obj.getPos().getX(),
                    (int) obj.getPos().getY(), this);
        

        // 将缓冲区的图形绘制到显示面板上
        g.drawImage(paint, 0, 0, this);
    

    private void init() 
        this.setTitle("植物大战僵尸");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        this.setLocation(200, 200);
        this.setSize(width, height);
        this.setVisible(true);
    

    /**
     * 当游戏界面图形变化时,我们要不断的刷新显示
     */
    @Override
    public void run() 
        while (isRunnableStart) 
            this.repaint();
            try 
                Thread.sleep(50);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

3、图片获取类GameImage.java

/**
 * 获取图片
 * @author Admin
 *
 */
public class GameImage 

    //plant
    public static List<BufferedImage> sunflower;
    public static List<BufferedImage> nut;
    public static List<BufferedImage> pea;

    //game main bg
    public static BufferedImage game_main_bg;

    private static GameImage instance = null;

    /**
     * 提供对外接口,并加上同步锁
     * @return
     */
    public static GameImage getInstance() 
        if(instance == null)
            synchronized(GameImage.class)
                if(instance == null)
                    instance = new GameImage();
                
            
        
        return instance;
    


    private  GameImage()
        sunflower = new ArrayList<BufferedImage>();
        nut = new ArrayList<BufferedImage>();
        pea = new ArrayList<BufferedImage>();

        try 
            game_main_bg = ImageIO.read(new File("image\\\\bk1.jpg"));

            //plant
            for(int i=1;i<=11;i++)     
                nut.add(ImageIO.read(new File("image\\\\plant\\\\p_3_0"+i+".png")));
                if(i <= 8)
                    sunflower.add(ImageIO.read(new File("image\\\\plant\\\\p_1_0"+i+".png")));
                    pea .add(ImageIO.read(new File("image\\\\plant\\\\p_2_0"+i+".png")));
                
            
         catch (IOException e) 
            e.printStackTrace();
        
    

4、植物信息保存类PlantAutoMoveInfo.java

/**
 * 植物信息业务类
 * @author Admin
 *
 */
public class PlantAutoMoveInfo implements Runnable

    //植物对象的坐标
    private Point pos;
    //线程执行标识
    private boolean isStart;
    //将要显示的图片
    private BufferedImage showImage;
    //显示图片索引值
    private int index;
    //构造植物对象的类型
    private int type;
    //阳光每隔多少秒产生
    private int SUNTIME;
    //阳光产生剩余时间
    private int tempTime;
    //判断是否可以生产阳光
    private boolean isProduction;
    //产生植物动画的所有图片
    private List<BufferedImage> plantImage;

    public PlantAutoMoveInfo(Point pos,int type,List<BufferedImage> gameImage) 
        this.pos = pos;
        this.plantImage = gameImage;

        SUNTIME = Constants.PRODUCTION_SUNNING_TIME;
        index = 0;
        tempTime = 0;
        showImage = plantImage.get(index);
        this.type = type;
        isStart = true; 
        isProduction = false;
        new Thread(this).start();
    


    public PlantAutoMoveInfo() 
    

    public void stopSunflowerThread(boolean bool)
        isStart = bool;
    

    public boolean isProduction() 
        return isProduction;
    


    public int getType() 
        return type;
    


    public void setType(int type) 
        this.type = type;
    


    public void setProduction(boolean isProduction) 
        this.isProduction = isProduction;
    

    public Point getPos() 
        return pos;
    

    public void setPos(Point pos) 
        this.pos = pos;
    

    public boolean isStart() 
        return isStart;
    

    public void setStart(boolean isStart) 
        this.isStart = isStart;
    

    public BufferedImage getShowImage() 
        return showImage;
    

    public void setShowImage(BufferedImage showImage) 
        this.showImage = showImage;
    


    public int getTempTime() 
        return tempTime;
    


    public void setTempTime(int tempTime) 
        this.tempTime = tempTime;
    

    @Override
    public void run() 
        while(isStart)
            index++;
            showImage = plantImage.get(index % plantImage.size());
            try 
                Thread.sleep(150);
             catch (InterruptedException e) 
                e.printStackTrace();
            
            if(type == Constants.SUNFLOWER && !isProduction)
                tempTime++;
                if((tempTime * 150) >= SUNTIME * 1000)
                    isProduction = true;
                
            
        
    

6、常量类Constants.java

/**
 * 常量类
 * @author Admin
 *
 */
public class Constants 

    public final static int SUNFLOWER = 0x0002;
    public final static int PEA = 0x0004;
    public final static int NUT = 0x0008;

    public final static int PRODUCTION_SUNNING_TIME = 0;

以上是关于Java解决游戏界面闪屏的主要内容,如果未能解决你的问题,请参考以下文章

APP开发----启动闪屏的解决办法

WPF 切换窗口 闪屏

经典BugAndroid-初始化闪屏不消失

Blender源码分析之闪屏窗口显示流程

Blender源码分析之闪屏窗口显示流程

Alien Swarm进不去,丛STEAM一打开游戏 然后进游戏 还没到菜单 就闪屏弹出来了!