【问题标题】:Repaint() not called未调用重绘()
【发布时间】:2013-04-10 18:11:02
【问题描述】:

我正在为学校项目开发一款类似炸弹人的游戏。

我正在使用 swing,我正在使用 Canvas 绘制图形,但 KeyListener 无法正常工作,所以我退出使用 Canvas 并开始使用 paintComponent(Graphics g)。 KeyListener 现在正在响应,但是当我的 while 循环调用 repaint() 方法时,我的图形没有刷新。

我的代码:

    dispose();

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                board b = new board();
                b.setSize(630, 650);
                b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                b.setVisible(true);
                direction dessin = new direction();
                b.add(dessin);
                b.setVisible(true);
                dessin.setBackground(Color.BLACK);

            }
        });

然后:

package Bm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;

import javax.swing.JComponent;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class direction extends JPanel implements Runnable {

static float bmx = 35;
static float bmy = 35;
static float ex = 520;
static float ey = 520;
static float v = 0.03f;

static boolean gauche;
static boolean droite;
static boolean haut;
static boolean bas;

static void movEnnemi() {

    int r = 1 + (int) (Math.random() * ((4 - 1) + 1));
    Ennemi.droite = false;
    Ennemi.gauche = false;
    Ennemi.bas = false;
    Ennemi.haut = false;

    switch (r) {
    case 1:
        Ennemi.droite = true;
        break;
    case 2:
        Ennemi.gauche = true;
        break;
    case 3:
        Ennemi.bas = true;
        break;
    case 4:
        Ennemi.haut = true;
        break;
    }

    try {
        Thread.sleep(5);
    } catch (Exception e) {
    }
    ;

}

public direction() {
    super();
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    for (int ligne = 0; ligne < board.gridHauteur; ligne++) {
        for (int colonne = 0; colonne < board.gridLargeur; colonne++) {

            switch (board.plateau1[ligne][colonne]) {
            case 0:
                g.setColor(Color.lightGray);
                g.fillRect(30 * ligne, 30 * colonne, 30, 30);
                break;
            case 1:
                g.setColor(Color.black);
                g.fillRect(30 * ligne, 30 * colonne, 30, 30);
                board.plateau1[ligne][colonne] = board.BLOCKED;
                break;
            case 2:
                g.setColor(Color.darkGray);
                g.fillRect(30 * ligne, 30 * colonne, 30, 30);
                board.plateau1[ligne][colonne] = board.BLOCKED;
                break;
            }
        }
    }
    g.setColor(Color.blue);
    g.fillRect((int) ex, (int) ey, 20, 20);
    g.setColor(Color.red);
    g.fillRect((int) bmx, (int) bmy, 21, 21);
    g.dispose();
}

public void run() {

    long dernierTempsLoop = System.currentTimeMillis();

    while (true) {

        long delta = (System.currentTimeMillis() - dernierTempsLoop);
        dernierTempsLoop = System.currentTimeMillis();
        movEnnemi();

        for (int i = 0; i < delta / 5; i++) {
            logic(5);
            Ennemi.logic(5);
        }
        if ((delta % 5) != 0) {
            logic(delta % 5);
            Ennemi.logic(delta % 5);
        }

        System.out.println((int) (bmx / 30) + " - " + (int) (bmy / 30));

        try {
            Thread.sleep(20);
        } catch (Exception e) {
        }
        ;
        repaint(); // <== HERE
    }
}

public static void logic(long delta) {

    float dx = 0;
    float dy = 0;
    if (gauche) {
        dx--;
    }
    if (droite) {
        dx++;
    }
    if (haut) {
        dy--;
    }
    if (bas) {
        dy++;
    }
    if ((dx != 0) || (dy != 0)) {
        joueur.mouvement(dx * delta * v, dy * delta * v);
        if (joueur.mouvement((dx * delta * v), (dy * delta * v)) == false) {
            if (joueur.mouvement(0, dy * delta * v)) {
                joueur.mouvement(0, dy * delta * v);
            }
            if (joueur.mouvement(dx * delta * v, 0)) {

                joueur.mouvement(dx * delta * v, 0);
            }
        }
    }
}
}

还有:

package Bm;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;

import javax.swing.*;

@SuppressWarnings("serial")
class board extends JFrame implements KeyListener {

static JPanel p;
public Timer fpstimer;
public direction g;
static final int BLOCKED = 1;
static int gridLargeur = 21;
static int gridHauteur = 21;
int fenLargeur = 630;
int fenHauteur = 650;
public static int plateau1[][] = {
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1 },
        { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };

public board() {
    super("Bomberman");
    g = new direction();
    addKeyListener(this);
    threadLoop p = new threadLoop("loop");
    p.start();
}

public static boolean blocked(double d, double e) {

    return plateau1[(int) d][(int) e] == BLOCKED;

}

public void keyPressed(KeyEvent e) {

    if (e.getKeyCode() == KeyEvent.VK_LEFT) {
        direction.gauche = true;
    }
    if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
        direction.droite = true;
    }
    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
        direction.bas = true;
    }
    if (e.getKeyCode() == KeyEvent.VK_UP) {
        direction.haut = true;
    }
    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
        System.exit(0);
    }
}

public void keyReleased(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_LEFT) {
        direction.gauche = false;
    }
    if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
        direction.droite = false;
    }
    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
        direction.bas = false;
    }
    if (e.getKeyCode() == KeyEvent.VK_UP) {
        direction.haut = false;
    }
}

public void keyTyped(KeyEvent e) {
}
}

class threadLoop extends Thread {

public direction g;

threadLoop(String name) {
    super(name);
}

public void run() {
    g = new direction();
    g.run();

}

}

public class Jouer {
}

希望你能理解我的问题,并能帮助我,谢谢:)

【问题讨论】:

  • 顺便说一句:((4 - 1) + 1) 与简单写4 相同

标签: java swing jpanel repaint


【解决方案1】:
  1. 您正在创建您的班级 direction 的不同实例,因此您遇到了问题
  2. 你不应该像这样使用static。这违背了良好的 OO 编程
  3. 使用 Swing 键绑定而不是使用 KeyListener
  4. 遵循 java 命名约定(您的代码现在真的很难阅读):类以大写字母开头,方法和变量以小写字母开头。使用 CamelCase 连接单词。
  5. 不要在不需要时extendJFrameThread 等...)
  6. 尝试将程序的各种概念分开(一部分应该负责显示(显示棋盘、敌人、玩家),另一部分负责对用户输入做出反应(左键按下、右键按下)等...)和第三个处理游戏逻辑(玩家位置、敌人位置、棋盘等...))。

这是一个非常蹩脚的尝试来解释这些不同的建议:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class Game {

    private static final String ICON_URL = "http://images2.wikia.nocookie.net/__cb20100515002803/fanon/images/a/a2/Bomberman_sprite.png";

    private static final int GRID_SIZE = 24;
    private static final int SQUARE_SIZE = 30;

    private JFrame frame;

    private Board board;

    private static class Board extends JPanel {

        private int[][] grid;

        private int playerX;
        private int playerY;

        private ImageIcon playerIcon;

        public Board() throws MalformedURLException {
            // Some code to generate a random pseudo-board
            Random random = new Random();
            grid = new int[GRID_SIZE][];
            for (int i = 0; i < GRID_SIZE; i++) {
                grid[i] = new int[GRID_SIZE];
                for (int j = 0; j < GRID_SIZE; j++) {
                    int r = random.nextInt(10);
                    grid[i][j] = r > 8 ? 2 : r > 6 ? 1 : 0;
                }
            }
            playerIcon = new ImageIcon(new URL(ICON_URL));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(GRID_SIZE * SQUARE_SIZE, GRID_SIZE * SQUARE_SIZE);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // pseudo-board painting
            for (int i = 0; i < grid.length; i++) {
                for (int j = 0; j < grid[i].length; j++) {
                    switch (grid[i][j]) {
                    case 1:
                        g.setColor(Color.GREEN);
                        g.fillRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE);
                        break;
                    case 2:
                        g.setColor(Color.RED);
                        g.fillRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE);
                        break;

                    default:
                        break;
                    }
                }
            }
            // Player painting
            int x = playerX * SQUARE_SIZE + (SQUARE_SIZE - playerIcon.getIconWidth()) / 2;
            int y = playerY * SQUARE_SIZE + (SQUARE_SIZE - playerIcon.getIconHeight()) / 2;
            g.drawImage(playerIcon.getImage(), x, y, this);
        }

        public int getPlayerX() {
            return playerX;
        }

        public int getPlayerY() {
            return playerY;
        }

        public void setPlayerX(int playerX) {
            if (playerX >= 0 && playerX < GRID_SIZE && grid[playerX][playerY] == 0) {
                this.playerX = playerX;
                repaint();
            }
        }

        public void setPlayerY(int playerY) {
            if (playerY >= 0 && playerY < GRID_SIZE && grid[playerX][playerY] == 0) {
                this.playerY = playerY;
                repaint();
            }
        }
    }

    private class MoveLeftAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            board.setPlayerX(board.getPlayerX() - 1);
        }

    }

    private class MoveRightAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            board.setPlayerX(board.getPlayerX() + 1);
        }

    }

    private class MoveUpAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            board.setPlayerY(board.getPlayerY() - 1);
        }

    }

    private class MoveDownAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            board.setPlayerY(board.getPlayerY() + 1);
        }

    }

    private class ExitAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            int i = JOptionPane.showConfirmDialog(board, "Are you sure you want to exit?");
            if (i == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }

    }

    protected void initUI() throws MalformedURLException {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        board = new Board();
        board.setBackground(Color.BLACK);
        board.registerKeyboardAction(new MoveLeftAction(), KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), JComponent.WHEN_FOCUSED);
        board.registerKeyboardAction(new MoveRightAction(), KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), JComponent.WHEN_FOCUSED);
        board.registerKeyboardAction(new MoveUpAction(), KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), JComponent.WHEN_FOCUSED);
        board.registerKeyboardAction(new MoveDownAction(), KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), JComponent.WHEN_FOCUSED);
        board.registerKeyboardAction(new ExitAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
        frame.add(board);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new Game().initUI();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Could not load icon from Internet", "Unable to start", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

    }

}

请注意,游戏的显示和逻辑在这里是完全交织在一起的,所以我不太听从第 6 条的建议。

【讨论】:

    【解决方案2】:

    您分配给框架的direction/board 与您尝试绘制的不同。您在主循环中创建一个新引用

    我还建议您在关键侦听器上使用 key bindings

    更新

    您构造一个初始的direction,然后将其添加到屏幕上。这实际上就是要渲染的内容。

    direction dessin = new direction();
    b.add(dessin);
    

    但是在您的 threadLoop 中,您创建一个新的(断开连接的)direction 并开始尝试更新它...

    public void run() {
        g = new direction();
        g.run();
    }
    

    ...这将永远不会绘制,因为它与屏幕没有连接。

    您还可以在board...中创建第三个引用...

    g = new direction();
    

    所有这些断开连接的direction 类都没有人可以绘制或与每个类进行通信,并且是不必要的。

    我会在board 中创建一个引用,将其添加到框架中并将该引用传递给threadLoop

    更新

    您可以查看this。这是一个基本示例,展示了一个简单的线程动画引擎和用于游戏资产移动的键绑定

    【讨论】:

    • 我不太确定你的意思,我正在等待我的程序正确运行以使用键绑定:)
    • 在您的 threadLoop 类中,您创建了一个新方向。这不会添加到任何 tat 可以实际绘制的内容中,但您将其用作渲染的基础。它永远无法渲染,它与屏幕没有连接
    • 如果我删除它,我会收到此错误“Bm.threadLoop.run(Jouer.java:105) 处的线程“循环”java.lang.NullPointerException 中的异常”我做错了什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多