JAVA - Graphics2D dispose()方法不处理填充对象

时间:2017-10-30 18:13:29

标签: java swing rendering graphics2d

我正在尝试学习Graphics2D库,同时构建2D汽车游戏,平台游戏等小型游戏......今天我决定制作一个基于太空的游戏,并在你需要的空间中进行虚拟游戏明星。所以我决定使用fillOval()绘制小圆圈,这将产生夜空效果。但是,每当我尝试移动星星或任何其他物体时,旧框架就会停留在那里并且一层又一层地绘制。我认为dipose()方法就够了......但似乎不是这样。

我有什么方法可以解决这个问题?
以下是我运行代码时的预览。

enter image description here

Main.java(过滤掉不相关的代码)

    package asteroids;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;


public class Main extends Canvas implements KeyListener {

    private boolean gameOver;
    private BufferStrategy backBuffer;  
    private Dimension dimension = new Dimension(Config.WINDOW_WH[0], Config.WINDOW_WH[1]);
    private List<Star> stars = new ArrayList<Star>();
    private HashMap<Integer,Boolean> keyDownMap = new HashMap<Integer, Boolean>();
    private Ship ship;


    public Main() {
        // Initialize Window
        initWindow();
        addKeyListener(this);

        this.createBufferStrategy(2);               
        backBuffer = this.getBufferStrategy();

        // init variables
        gameOver = false;

        // Generating stars
        generateStars();

        // Init spaceship
        ship = new Ship(25,36,"ship.png");

        // Init loop
        gameLoop();

    }

    public void initWindow(){
        JFrame window = new JFrame("Asteroids"); 
        setPreferredSize(dimension); 

        window.add(this);           
        window.pack();  
        window.setResizable(false);
        window.setVisible(true); 
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setBackground(new Color(54, 71, 99));


        window.requestFocus();

    }

    public void update() {

        if(keyDownMap.containsKey(KeyEvent.VK_ESCAPE)){
            gameOver = false;
            System.exit(0);
        }

        /*for(Star s: stars) {
            s.update(keyDownMap);
        }*/
        this.ship.update(keyDownMap);

    }


    public void render(){
        Graphics2D g = (Graphics2D) backBuffer.getDrawGraphics();

        // Stars
        for(Star s: stars) {
            g.fillOval(s.posx - (s.width/2), s.posy - (s.height/2), s.width, s.height);
        }

        // Spaceship
        g.drawImage(
                this.ship.getImage(), 
                this.ship.posx, this.ship.posy, 
                this.ship.width, this.ship.height, null);


        g.dispose();
        backBuffer.show();

    }

    public void generateStars() {
        for(int i = 0;i < 20;i++) {
            int starX = new Random().nextInt(Config.WINDOW_WH[0]-10)+5;
            int starY = new Random().nextInt(Config.WINDOW_WH[1]-10)+5;
            stars.add(new Star(starX, starY));
        }
    }


    public void gameLoop(){
        while(!gameOver){
            update();
            render();
            try{ Thread.sleep(20);}catch(Exception e){};
        }

    }

    public static void main(String[] args) {

        new Main();
    }


    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyPressed(KeyEvent e) {
        keyDownMap.put(e.getKeyCode(), true);

    }

    @Override
    public void keyReleased(KeyEvent e) {
        keyDownMap.remove(e.getKeyCode());

    }


}

Star.java

package asteroids;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.HashMap;
import java.util.Random;
public class Star {

    int width, height;
    int posx, posy;


    /** CONSTRUCTOR **/
    public Star(int x, int y) {
        int rand = new Random().nextInt(Config.STAR_SIZES.length);
        width = Config.STAR_SIZES[rand];
        height = Config.STAR_SIZES[rand];
        posx = x;
        posy = y;


    }

    public void update(HashMap keyDownMap) {
        if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
            this.posx += 1;

        if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
            this.posx -= 1;

        if(keyDownMap.containsKey(KeyEvent.VK_UP))
            this.posy += 1;

        if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
            this.posy -= 1;



    }


}

Ship.java

package asteroids;

import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.HashMap;

import javax.swing.ImageIcon;

public class Ship {

    public int posx, posy;
    public int width, height;
    private Image image;

    public Ship(int w, int h, String img) {
        this.posx = Config.WINDOW_WH[0]/2;
        this.posy = Config.WINDOW_WH[1]/2;
        this.width = w;
        this.height = h;
        this.image = new ImageIcon(getClass().getResource("/"+img)).getImage();
    }

    public Image getImage() {
        return this.image;
    }

    public void setPosx(int x) {posx = x;}
    public void setPosy(int y) {posy = y;}
    public void setImg(Image img) {
        this.image = img; 
    }

    public void update(HashMap keyDownMap) {
        if(keyDownMap.containsKey(KeyEvent.VK_LEFT))
            this.posx += 1;

        if(keyDownMap.containsKey(KeyEvent.VK_RIGHT))
            this.posx -= 1;

        if(keyDownMap.containsKey(KeyEvent.VK_UP))
            this.posy += 1;

        if(keyDownMap.containsKey(KeyEvent.VK_DOWN))
            this.posy -= 1;

    }

}

Config.java

import java.awt.Color;

public class Config {

    // MAIN CANVAS SETTINGS
    public static int[] WINDOW_WH = {500, 500};
    public static String WINDOW_BG_IMG = "";
    public static Color WINDOW_BG_CLR = new Color(40, 42, 45);

    // OBJECT SETTINGS
    public static int[] STAR_SIZES = {10,5,8,3,7};
}

编辑:

在我尝试在绘制星星和船之前添加背景图像g.drawImage(this.bg,0,0,Config.WINDOW_WH[0], Config.WINDOW_WH[1], null);后,它不会再发生了。但我想知道这是一个修复,还是一个不好的做法,以避免未清除帧。

1 个答案:

答案 0 :(得分:0)

  

但是,每当我试图移动星星或任何其他物体时,旧框架就会停留在那里并且一层又一层地被绘制。

是的,这就是绘画的作用。将Graphics上下文视为物理画布。每次在其上绘画时,您都会向其添加更多内容。 API不会为您清除它。

这样做的好处是,如果您正在执行添加绘画过程,您可能不希望在每次传递时刷新它,但在您的情况下,您每次都必须清除它。

  

我认为dipose()方法就够了......但它似乎不是

不,dispose释放上下文可能持有的所有内部资源,释放内存。话虽如此,您不应该处理您创建的上下文,因为它可能会阻止将来的操作被应用。

如果您查看example中的tutorials,则会清楚地显示Graphics背景已为每个框架明确/准备......

Graphics g = bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
    g.setColor(COLORS[i]);
    g.fillRect(0,0,bounds.width, bounds.height);
    bufferStrategy.show();
    g.dispose();
}

我还建议您查看JavaDocs中提供基本循环操作的示例