Java动画无法正确刷新并占用过多CPU

时间:2014-05-10 15:10:27

标签: java swing animation awt graphics2d

我现在正在创建一个简单的Java游戏。我希望一个圆点(一辆汽车)可以在游戏画面上移动,但是我可以在屏幕上看到的只有长长的蛇#34;由我移动的点创建:

Screenshot

其他问题是我的Mac上的活动管理器显示游戏使用了大量的CPU电量 - 我的笔记本电脑变得非常热。我怀疑我的游戏循环有问题,但从现在起我还没有找到任何解决方案:

BoardPanel.java:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.event.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class BoardPanel extends JPanel implements KeyListener, Runnable {
    public static final int WIDTH = 600;
    public static final int HEIGHT = 600;


    private Thread thread;
    private boolean running;

    private BufferedImage image;
    private Graphics2D g;

    private int FPS = 30;
    private int targetTime = 1000/FPS;

    private Map map;
    private Car car;

    public BoardPanel() {
        super();
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setFocusable(true);
        requestFocus();
    }

    public void addNotify() {
        super.addNotify();
        if(thread == null) {
            thread = new Thread(this);
            thread.start();
        }
        addKeyListener(this);
    }

    public void run() {
        init();

        long startTime;
        long reTime;
        long waitTime;

        while (running) {
            startTime = System.nanoTime();
            update();
            render();
            draw();

            reTime = System.nanoTime() - startTime;
            waitTime = targetTime - reTime;
            try {
                Thread.sleep(waitTime);
            }
            catch(Exception e) {

            }
        }
    }

    private void init() {
        running = true;
        image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        g = (Graphics2D) image.getGraphics();

        map = new Map();
        car = new Car(map);
        car.setxpos(50);
        car.setypos(50);

    }

    private void update() {
        map.update();
        car.update();

    }

    private void render() {
        map.draw(g);
        car.draw(g);
    }

    private void draw() {
        Graphics g2 = getGraphics();
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
    }

    public void keyTyped(KeyEvent key) {

    }

    public void keyPressed(KeyEvent key) {
        int code = key.getKeyCode();

        if(code == KeyEvent.VK_LEFT) {
            car.setLeft(true);
        }
        if(code == KeyEvent.VK_RIGHT) {
            car.setRight(true);
        }
        if(code == KeyEvent.VK_UP) {
            car.setUp(true);
        }
        if(code == KeyEvent.VK_DOWN) {
            car.setDown(true);
        }
    }

    public void keyReleased(KeyEvent key) {
        int code = key.getKeyCode();

        if(code == KeyEvent.VK_LEFT) {
            car.setLeft(false);
        }
        if(code == KeyEvent.VK_RIGHT) {
            car.setRight(false);
        }
        if(code == KeyEvent.VK_UP) {
            car.setUp(false);
        }
        if(code == KeyEvent.VK_DOWN) {
            car.setDown(false);
        }
    }
}

Car.java

import java.awt.*;

public class Car {
    private double xpos;
    private double ypos;

    //private int xsize;
    //private int ysize;

    private boolean left;
    private boolean right;
    private boolean up;
    private boolean down;

    private Map map;

    public Car(Map m) {
        map = m;
    }

    public void setxpos(int i) {
        xpos = i;
    }

    public void setypos(int i) {
        ypos = i;
    }

    public void setLeft (boolean b) {
        left = b;
    }

    public void setRight (boolean b) {
        right = b;
    }

    public void setUp (boolean b) {
        up = b;
    }

    public void setDown (boolean b) {
        down = b;
    }

    public void update() {
        if(left) {
            xpos--;
        }

        if(right) {
            xpos++;
        }
        if(up) {
            ypos--;
        }
        if(down) {
            ypos++;
        }
    }

    public void draw(Graphics2D g) {
        int mx = map.getx();
        int my = map.gety();

        g.setColor(Color.BLUE);
        g.fillOval((int)(mx+xpos-20/2), (int)(my+ypos-20/2), 20, 20);
    }
}

Map.java(我还没有创建地图,现在只想让点正确移动)

import java.awt.*;

public class Map {
    public int x;
    public int y;

    public int getx() {
        return x;
    }

    public int gety() {
        return y;
    }

    public void setx(int i) {
        x = i;
    }

    public void sety(int i ) {
        y = i;
    }

    public void update() {

    }

    public void draw(Graphics2D g) {

    }


}

RacerMain.java

import javax.swing.JFrame;


public class RacerMain {
    public static void main (String[]args) {
        //MainFrame mf = new MainFrame();
        JFrame mf = new JFrame("Racer");
        mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mf.setContentPane(new BoardPanel());;
        mf.pack();
        mf.setVisible(true);

    }

}

非常感谢你的帮助!!!

2 个答案:

答案 0 :(得分:2)

除了camickr所说的:小心使用Graphics。经验法则:

永远不要在组件上调用getGraphics

此外,您永远不会从Graphics处理您正在提取的BufferedImage。您正在处理从Component获得的Graphics,这可能比首先获取更糟糕!

我想知道为什么要覆盖addNotify方法。您不应该基于averriding此方法实现任何功能....

因此,您应该大致按照以下方式更改BoardPanel类的相应部分:

public class BoardPanel extends JPanel implements KeyListener, Runnable     {
    ...
    // private Graphics2D g; // Don't store this here

    public BoardPanel() {
        ...

        // Create the thread here instead of in the "addNotify" method!
        if(thread == null) {
            thread = new Thread(this);
            thread.start();
        }
        addKeyListener(this);
    }


    public void run() {
        ...
        while (running) {
            ...
            //draw(); // Don't call this method
            repaint(); // Trigger a repaint instead!
        }
    }


    private void render() {
        Graphics2D g = image.createGraphics();

        // Clear the background (see camickrs answer)
        g.setColor(Color.BLACK);
        g.fillRect(0,0,image.getWidth(),image.getHeight());

        try
        {
            map.draw(g);
            car.draw(g);
        }
        finally
        {
            g.dispose(); // Dispose the Graphics after it has been used
        }
    }

    /** Don't call "getGraphics" on a component!   
    private void draw() {
        Graphics g2 = getGraphics();
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
    }
    */

    // Override the paintComponent method instead:
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(image,0,0,null);
    }

答案 1 :(得分:1)

在draw()方法中,您需要在调用fillOval方法之前清除BufferedImages背景。类似的东西:

g.setColor( Color.BLACK );
g.fillRect(...);
g.setColor( Color.BLUE );
g.fillOval(...);

打印出你的" waitTime"确保你等待合理的时间。