在Java AWT画布中绘制点矩阵太慢

在Java AWT画布中绘制点矩阵太慢,java,canvas,awt,Java,Canvas,Awt,我正在尝试实现教自己Java。来自C/C++也是可以理解的。到目前为止,我已经相当成功,(我认为)我几乎完成了。代码似乎很有效,但有两件事仍然困扰着我 我将要绘制的点存储在一个矩阵中,并使用aGraphics.drawLine(I,j,I,j)绘制它们。这里的问题是画布的构建是从左到右可见的。我确信问题在于反复调用drawLine()方法,因为当我切换嵌套for循环的顺序时,构建是自上而下的。将点存储在图像中是否更好 另一个问题是游戏本身运行太快。暂停程序的计算而不停止中间绘制是什么好主意 这是

我正在尝试实现教自己Java。来自C/C++也是可以理解的。到目前为止,我已经相当成功,(我认为)我几乎完成了。代码似乎很有效,但有两件事仍然困扰着我

  • 我将要绘制的点存储在一个矩阵中,并使用aGraphics.drawLine(I,j,I,j)绘制它们for循环中的
    Canvas::paint(Graphics aGraphics)
    方法中的code>。这里的问题是画布的构建是从左到右可见的。我确信问题在于反复调用
    drawLine()
    方法,因为当我切换嵌套
    for循环的顺序时,构建是自上而下的。将点存储在图像中是否更好

  • 另一个问题是游戏本身运行太快。暂停程序的计算而不停止中间绘制是什么好主意

  • 这是我的画布课程:

    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);
                }
            }
        }
    }
    
    class GOLCanvas扩展画布{
    米乌伊维兹私人酒店;
    私人国际机场;
    私人int[]m_i点;
    私人整数[][]米/小时;
    私人双种子;
    私有随机m_cRnd;
    GOLCanvas(内宽、内高、双aSeed){
    m_iWidth=宽度;
    m_iHeight=ahheight;
    m_dSeed=aSeed;
    m_cRnd=新随机数();
    m_cRnd.setSeed(m_cRnd.nextLong());
    m_iPoints=新整数[m_iHeight][m_iWidth];
    m_iNeighbours=新整数[m_iHeight][m_iWidth];
    }
    公共void init(){
    //初始点随机
    }
    私有int getRandomInt(双概率){
    返回值(m_cRnd.nextDouble()
    我会退房


    基本上可以归结为使用BuffereImage。为了降低程序的一部分速度,您可以使用
    Thread.sleep(1000)
    其中1000等于1秒。

    查看您的代码,我建议将设计更改为动态渲染的
    画布
    重新绘制
    没有实现多缓冲,可能会导致闪烁。另外,考虑到您的游戏运行速度太快,您需要在自己的
    线程
    中运行游戏(不是主线程)然后实现一个
    update
    方法,并使用
    Thread.sleep将其同步到每秒N次

    设计可以类似于:

    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();
                }
    
            }
    
        }
    }
    
    用法:

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        EventQueue.invokeLater(() -> {
            new Game(new JFrame()).start();
        });
    }
    
    显然,这只是一种方法(还有很多其他方法),请根据您的需要随意调整。
    我花了大约20分钟来写,所以我希望这不是徒劳的,这也有帮助,如果你发现代码中有任何错误,你不能修复,让我知道(我写它时没有检查它是否有效).

    @DavidWright坏主意。不要将主
    线程置于睡眠状态。Dima是正确的,您应该只使用线程。在非主线程的线程上睡眠您可能应该重新设计此线程,使用游戏循环运行
    线程,创建更新方法(使用所有逻辑)并且每秒同步N次。另外,我建议使用
    BufferingStrategy
    创建一个自定义渲染方法,它将使游戏看起来更漂亮(删除闪烁…等等)非常感谢您的努力。我将尝试调用您的更改。我需要稍微调整一下,因为我使用了一个类,该类继承自包含游戏画布类对象的框架,该框架的对象为
    按钮
    文本字段
    WindowAdapter
    等。我仅将画布用于计算和输出。Bu这应该不是问题。这有点离题,但我看到你使用swing类(JFrame)而不是awt,既然我对这一点很陌生,你介意告诉我你更喜欢swing类而不是awt吗?@DavidWright我就放在这里。你可以自己判断自己。