Java canvas根本不更新

问题描述

我正在尝试制作打砖块游戏,其中最初在桨上的球(在下面的代码中称为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,RIGHT_WALL,TOP_WALL);
        g.drawLine(LEFT_WALL,TOP_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);
    }
}

这里,更新功能似乎根本没有更新。 我不确定该方法的工作原理。 任何帮助将不胜感激

解决方法

Canvas是一个相当低级的组件,只有在需要使用BufferStrategy时才考虑使用。

update被称为绘制阶段的一部分,因为您没有调用super实现就覆盖了它,所以您中断了绘制工作流程。

AWT和Swing通常使用被动渲染系统,这意味着更新仅在系统确定需要进行时才发生,因此以update的方式覆盖您的做法并没有实际意义,也不会继续为您提供帮助。

一个更好的起点是JPanel,主要原因是它具有双重缓冲,并且省去了试图消除闪烁的麻烦。

Performing Custom PaintingPainting 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,"right");

            ActionMap am = getActionMap();
            am.put("left",new KeyAction(this,-1));
            am.put("right",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,RIGHT_WALL,TOP_WALL);
            g2d.drawLine(LEFT_WALL,TOP_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;
            }

        }
    }
}

我搞砸了增量值,因为球和杠很快就消失了

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...