Java canvas 根本不更新

Java canvas doesn't update at all

我正在尝试制作一个 Brick Breaker 游戏,其中最初位于球拍上的球(在下面的代码中称为 BAR)以某个随机方向的速度(大约 100)发射,如果它击中屏幕上的任何砖块砖块消失,球相应地改变方向。

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.event.KeyEvent;
import java.awt.event.*;

public class Brick_Breaker extends Canvas implements KeyListener{
    
    int BRICK_WIDTH=60,BRICK_HEIGHT=30,X=0,Y=0;
    int BAR_X = 390,BAR_Y=560,BAR_WIDTH=120,BAR_HEIGHT=20,BAR_DX=10;
    int BALL_X=440,BALL_Y=540,BALL_SIZE=20,BALL_DX=0,BALL_DY=0;
    int LEFT_WALL=100,RIGHT_WALL=800,TOP_WALL=10;
    boolean GAME_STATE=false;
    int BAR_STATE=0;
    
    
    static int[][] y = new int[10][5];
    static int[][] x = new int[10][5];
    static int[][] status = new int[10][5];
    
    static Canvas canvas;
    static JFrame frame;
    @Override
    public void keyReleased(KeyEvent ke){}
    @Override
    public void keyTyped(KeyEvent ke){}
    
    public void STaRT(){
        frame = new JFrame("My Drawing");
        frame.addKeyListener(this);
        canvas = new Brick_Breaker();
        canvas.setSize(900, 600);
        frame.add(canvas);
        frame.pack();
        frame.setVisible(true);
    }
    
    
    @Override
    public void update(Graphics g){
        BALL_X += BALL_DX;
        BALL_Y += BALL_DY;
        for(int i=0;i<10;i++){
            for(int j=0;j<5;j++){
                if(BALL_X>x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y<=y[i][j]+BAR_HEIGHT+BALL_SIZE && BALL_Y>y[i][j]&&BALL_DY<0){
                    BALL_DY=-BALL_DY;
                    status[i][j]-=1;
                }else if(BALL_X>x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j]-BALL_SIZE && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY>0){
                    BALL_DY=-BALL_DY;
                    status[i][j]-=1;
                }else if(BALL_X+BALL_SIZE>=x[i][j]&&BALL_X<(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j] && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY<0){
                    BALL_DX=-BALL_DX;
                    status[i][j]-=1;
                }else if(BALL_X>x[i][j]&&BALL_X-BALL_SIZE<=(x[i][j]+BRICK_WIDTH)&&BALL_Y>=y[i][j] && BALL_Y<y[i][j]+BAR_HEIGHT&&BALL_DY<0){
                    BALL_DX=-BALL_DX;
                    status[i][j]-=1;
                }else if(BALL_X-BALL_SIZE<LEFT_WALL||BALL_X+BALL_SIZE>RIGHT_WALL){
                    BALL_DX=-BALL_DX;
                }else if(BALL_Y-BALL_SIZE<TOP_WALL){
                    BALL_DY=-BALL_DY;
                }
            }
        }
        BAR_X = BAR_X +BAR_STATE*BAR_DX;
        repaint();
    }
    public static void main(String[] args) {
       Brick_Breaker bb = new Brick_Breaker();
       bb.STaRT();
        for(int i=0;i<10;i++){
            for(int j=0;j<5;j++){
                x[i][j] = 300+60*j;
                y[i][j] = 50+30*i;
                status[i][j] = 1;
            }
        }
    }
    
    @Override
    public void keyPressed(KeyEvent ke){
        if(!GAME_STATE){
            BALL_DX = (int)(100*Math.random());
            BALL_DY = (int)(Math.sqrt(100*100-BALL_DX*BALL_DX));
            GAME_STATE = true;
        }else if(ke.getKeyCode() == KeyEvent.VK_LEFT){
            BAR_STATE=-1;
        }else if(ke.getKeyCode()==KeyEvent.VK_RIGHT){
            BAR_STATE=1;
        }
    }
    
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.white);
        g.drawLine(LEFT_WALL,600, LEFT_WALL, TOP_WALL);
        g.drawLine(RIGHT_WALL, 600, RIGHT_WALL, TOP_WALL);
        g.drawLine(LEFT_WALL,TOP_WALL,RIGHT_WALL,TOP_WALL);
        g.fillRect(BAR_X,BAR_Y,BAR_WIDTH,BAR_HEIGHT);
        g.setColor(Color.red);
        g.fillOval(BALL_X, BALL_Y, BALL_SIZE, BALL_SIZE);
        for(int i=0;i<10;i++){
            for(int j=0;j<5;j++){
                if(status[i][j]>0){
                    X = x[i][j];Y=y[i][j];
                    g.setColor(Color.white);
                    g.fillRect(X, Y, BRICK_WIDTH, BRICK_HEIGHT);
                    g.setColor(Color.red);
                    g.fillRect(X+3, Y+3, BRICK_WIDTH-6, BRICK_HEIGHT-6);
                }
            }
        }
        setBackground(Color.black);
    }
}

这里的update函数好像根本就没有update。 我不太确定该方法的工作原理。 任何帮助将不胜感激

Canvas 是一个非常低级的组件,只有在需要使用 BufferStrategy.

时我才会考虑使用它

update 作为绘制阶段的一部分被调用,因为你在没有调用它的 super 实现的情况下覆盖了它,你破坏了绘制工作流程。

AWT 和 Swing 通常采用被动渲染系统,这意味着更新仅在系统决定需要发生时发生,因此重写 update 您拥有的方式并没有真正意义,也不是'不会帮你的。

更好的起点是 JPanel,主要原因是它是双缓冲的,可以让您省去尝试找出如何消除闪烁的麻烦。

一个很好的起点是 Performing Custom Painting and Painting in AWT and Swing 以更好地了解绘画的工作原理(以及您应该如何使用它)。

KeyListener 对于输入监控来说也是一个糟糕的选择,说真的,只是在 SO 上搜索一下所有原因。

更好且通常问题较少的方法是也使用 key bindings

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        int BRICK_WIDTH = 60, BRICK_HEIGHT = 30, X = 0, Y = 0;
        int BAR_X = 390, BAR_Y = 560, BAR_WIDTH = 120, BAR_HEIGHT = 20, BAR_DX = 1;
        int BALL_X = 440, BALL_Y = 540, BALL_SIZE = 20, BALL_DX = 0, BALL_DY = 0;
        int LEFT_WALL = 100, RIGHT_WALL = 800, TOP_WALL = 10;
        boolean GAME_STATE = false;
        int BAR_STATE = 0;

        int[][] y = new int[10][5];
        int[][] x = new int[10][5];
        int[][] status = new int[10][5];

        private Timer timer;

        public TestPane() {
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 5; j++) {
                    x[i][j] = 300 + 60 * j;
                    y[i][j] = 50 + 30 * i;
                    status[i][j] = 1;
                }
            }
            BALL_DX = 0; //(int) (100 * Math.random());
            BALL_DY = -1;//(int) (Math.sqrt(100 * 100 - BALL_DX * BALL_DX));
            setBackground(Color.BLACK);

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");

            ActionMap am = getActionMap();
            am.put("left", new KeyAction(this, -1));
            am.put("right", new KeyAction(this, 1));
        }

        @Override
        public void addNotify() {
            super.addNotify(); //To change body of generated methods, choose Tools | Templates.
            if (timer == null) {
                timer = new Timer(5, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        tick();
                    }
                });
                timer.start();
            }
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            if (timer != null) {
                timer.stop();
                timer = null;
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(900, 600);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.white);
            g2d.drawLine(LEFT_WALL, 600, LEFT_WALL, TOP_WALL);
            g2d.drawLine(RIGHT_WALL, 600, RIGHT_WALL, TOP_WALL);
            g2d.drawLine(LEFT_WALL, TOP_WALL, RIGHT_WALL, TOP_WALL);
            g2d.fillRect(BAR_X, BAR_Y, BAR_WIDTH, BAR_HEIGHT);
            g2d.setColor(Color.red);
            g2d.fillOval(BALL_X, BALL_Y, BALL_SIZE, BALL_SIZE);
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 5; j++) {
                    if (status[i][j] > 0) {
                        X = x[i][j];
                        Y = y[i][j];
                        g2d.setColor(Color.white);
                        g2d.fillRect(X, Y, BRICK_WIDTH, BRICK_HEIGHT);
                        g2d.setColor(Color.red);
                        g2d.fillRect(X + 3, Y + 3, BRICK_WIDTH - 6, BRICK_HEIGHT - 6);
                    }
                }
            }

            g2d.dispose();
        }

        protected void tick() {
            BALL_X += BALL_DX;
            BALL_Y += BALL_DY;
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 5; j++) {
                    if (BALL_X > x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y <= y[i][j] + BAR_HEIGHT + BALL_SIZE && BALL_Y > y[i][j] && BALL_DY < 0) {
                        BALL_DY = -BALL_DY;
                        status[i][j] -= 1;
                    } else if (BALL_X > x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] - BALL_SIZE && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY > 0) {
                        BALL_DY = -BALL_DY;
                        status[i][j] -= 1;
                    } else if (BALL_X + BALL_SIZE >= x[i][j] && BALL_X < (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY < 0) {
                        BALL_DX = -BALL_DX;
                        status[i][j] -= 1;
                    } else if (BALL_X > x[i][j] && BALL_X - BALL_SIZE <= (x[i][j] + BRICK_WIDTH) && BALL_Y >= y[i][j] && BALL_Y < y[i][j] + BAR_HEIGHT && BALL_DY < 0) {
                        BALL_DX = -BALL_DX;
                        status[i][j] -= 1;
                    } else if (BALL_X - BALL_SIZE < LEFT_WALL || BALL_X + BALL_SIZE > RIGHT_WALL) {
                        BALL_DX = -BALL_DX;
                    } else if (BALL_Y - BALL_SIZE < TOP_WALL) {
                        BALL_DY = -BALL_DY;
                    }
                }
            }
            BAR_X = BAR_X + BAR_STATE * BAR_DX;
            repaint();
        }

        class KeyAction extends AbstractAction {

            private TestPane source;
            private int delta;

            public KeyAction(TestPane source, int delta) {
                this.source = source;
                this.delta = delta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                source.BAR_STATE = delta;
            }

        }
    }
}

我弄乱了 delta 值,因为球和条很快就消失了