Java解決遊戲介面閃屏
阿新 • • 發佈:2019-01-10
一、問題描述
我們在做有關於圖形繪製方面的問題非常之多。比如,有時我們用普通的方法去繪製圖形,會產生閃屏的現象,導致我們所做的遊戲或者是別的專案效果非常差,這完全不是我們想要的結果。那麼,有沒有一種技術,實現不閃屏的效果,特別是在多執行緒環境下。答案是有的,這就是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;
}