Java AWT Canvas中绘制点矩阵太慢

时间:2015-03-05 07:47:48

标签: java canvas awt

我正在尝试实施Conway's Game of Life来自学Java。来自C / C ++,它也是可以理解的。到目前为止,我已经相当成功了(我想)我差不多完成了。代码似乎有效,但有两件事仍然困扰着我。

  1. 我正在存储要在矩阵中绘制的点,并使用aGraphics.drawLine(i, j, i, j);方法在双Canvas::paint(Graphics aGraphics)内使用for-loop绘制它们。这里的问题是画布的构建从左到右可见。我确定问题是drawLine()方法的重复调用,因为当我切换嵌套for-loops的顺序时,构建是自上而下的。将点存储在图像中可能会更好吗?

  2. 另一个问题是游戏本身运行得太快了。如何在不停止中间油漆的情况下暂停程序的计算会有什么好主意?

  3. 这是我的Canvas类:

    class GOLCanvas extends Canvas {
    private int m_iWidth;
    private int m_iHeight;
    private int[][] m_iPoints;
    private int[][] m_iNeighbours;
    private double m_dSeed;
    private Random m_cRnd;
    
    GOLCanvas(int aWidth, int aHeight, double aSeed) {
        m_iWidth = aWidth;
        m_iHeight = aHeight;
        m_dSeed = aSeed;
        m_cRnd = new Random();
        m_cRnd.setSeed(m_cRnd.nextLong());
        m_iPoints = new int[m_iHeight][m_iWidth];
        m_iNeighbours = new int[m_iHeight][m_iWidth];   
    }
    
    public void init() {
        // init Points randomly
    }
    
    private int getRandomInt(double aProbability) {
        return (m_cRnd.nextDouble() < m_dSeed) ? 1 : 0;
    }
    
    public void countNeighbours () {
        // ditto name   
    }
    
    public void calcNextStep () {
        // ditto name
    }
    @Override
    public void paint(Graphics aGraphics) {
        // **ANY IDEAS TO SPEED UP THIS PART HERE?**
        for(int i = 0; i < m_iHeight; i++) {
            for(int j = 0; j < m_iWidth; j++) {
                if (m_iPoints[i][j] == 1){
                    aGraphics.drawLine(i, j, i, j);
                }
            }
        }
    }
    

2 个答案:

答案 0 :(得分:2)

查看代码我建议将设计更改为动态呈现Canvasrepaint未实现多重缓冲并可能导致闪烁。此外,关于您的游戏正在快速运行,您需要在自己的Thread(而不是主线程)中运行游戏,然后实施update方法并将其同步到N次,每次{{1 }}

设计可以是:

Thread.sleep

用法:

public class Game extends Canvas implements Runnable {

    // resolution
    public static final int     WIDTH         = 640;
    public static final int     HEIGHT        = 480;

    // window title
    private static final String TITLE         = "Title";

    /**
     * Number of logical/physical updates per real second
     */
    private static final int    UPDATE_RATE   = 60;

    /**
     * Number of rendering buffers
     */
    private static final int    BUFFERS_COUNT = 3;

    /**
     * Value of a second in NanoSeconds DO NOT CHANGE!
     */
    private static final long   NANOS_IN_SEC  = 1000000000L;

    /**
     * Update interval in double precision NanoSeconds DO NOT CHANGE!
     */
    private static final double UPDATE_SCALE  = (double) NANOS_IN_SEC / UPDATE_RATE;

    private JFrame              window;
    private Thread              gameThread;
    private boolean             running;

    // temp values 
    int                         x             = 0;
    int                         y             = 0;

    ////////////////

    public Game(JFrame window) {
        this.window = window;
        this.running = false;

        setPreferredSize(new Dimension(WIDTH, HEIGHT));

        this.window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        // properly ends the game by calling stop when window is closed
        this.window.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                stop();
                super.windowClosing(e);
                System.exit(0);
            }
        });

        this.window.getContentPane().add(this);
        this.window.setResizable(false);
        this.window.pack();
        this.window.setLocationRelativeTo(null);
        this.window.setVisible(true);
    }

    // starts the game
    public synchronized void start() {
        if (running)
            return;

        running = true;
        gameThread = new Thread(this);
        gameThread.start();
        System.out.println("Game thread started");
        System.out.println("UPDATE_RATE: " + UPDATE_RATE);
    }

    // ends the game
    public synchronized void stop() {
        if (!running)
            return;

        running = false;
        boolean retry = true;
        while (retry) {
            try {
                gameThread.join();
                retry = false;
                System.out.println("Game thread stoped");
            } catch (InterruptedException e) {
                System.out.println("Failed sopping game thread, retry in 1 second");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private void update() {
        // this will run UPDATE_RATE times a second
        x++;
        y++;
    }

    private void render() {
        BufferStrategy bs = getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(BUFFERS_COUNT);
            return;
        }

        Graphics2D g2d = (Graphics2D) bs.getDrawGraphics().create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        clear(g2d, 0);

        // render here
        g2d.setColor(Color.red);
        g2d.fillRect(x, y, 50, 50);
        //////////////

        g2d.dispose();

        bs.show();
    }

    private void clear(Graphics2D g2d, int shade) {
        g2d.setColor(new Color(shade, shade, shade));
        g2d.fillRect(0, 0, WIDTH, HEIGHT);
    }

    // game loop thread
    public void run() {
        long startTime = System.currentTimeMillis();
        long tick = 1000;

        int upd = 0;
        int fps = 0;

        double updDelta = 0;

        long lastTime = System.nanoTime();

        while (running) {
            long now = System.nanoTime();
            updDelta += (now - lastTime) / UPDATE_SCALE;
            lastTime = now;

            while (updDelta > 1) {
                update();
                upd++;
                updDelta--;
            }
            render();
            fps++;

            if (System.currentTimeMillis() - startTime > tick) {
                window.setTitle(TITLE + " || Upd: " + upd + " | Fps: " + fps);
                upd = 0;
                fps = 0;
                tick += 1000;
            }

            try {
                Thread.sleep(5); // always a good idea to let is breath a bit
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

显然,这只是实现此目的的一种方式(还有很多其他方式),请随意调整以满足您的需求。 我花了大约20分钟写了所以我希望它不是徒劳的,这也有帮助,如果你发现代码中有任何错误你不能解决让我知道(我有点写它而不检查它是否有效)。 / p>

答案 1 :(得分:0)

我会查看this linkthis one

基本上归结为使用BufferedImages。至于减慢程序的一部分,你可以使用Thread.sleep(1000),其中1000等于1秒。