简体   繁体   中英

Repaint() not called

I'm developing a game for a school project, a Bomberman-like game.

I'm using swing and I was using Canvas to draw my graphics but the KeyListener was not working, so I quitted using Canvas and started using paintComponent(Graphics g) . The KeyListener is responding now, but my graphics don't refresh when my while loop calls the repaint() methods.

My code:

    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);

            }
        });

Then:

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);
            }
        }
    }
}
}

And :

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 {
}

I hope you understand my problem, and will be able to help me, thank you :)

  1. You are creating different instances of your class direction , hence the issue you are seeing
  2. You should not use static like this. It goes against good OO-programming
  3. Use Swing key-bindings instead of using KeyListener
  4. Follow java naming conventions (your code is really hard to read for now): Classes start with an Upper case letter, methods and variables with a lower-case letter. Use CamelCase to concatenate words.
  5. Don't extend when not needed ( JFrame , Thread , etc...)
  6. Try to separate the various concepts of your program (one part should be responsible for the display (displaying the board, the enemies, the player), another one to react on user input (left-key pressed, right-key pressed, etc...) and a third one to handle the logic of your game (player location, enemies location, the board, etc...)).

Here is a very lame attempt to explain those various advices:

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);
                }
            }
        });

    }

}

Please note that the display and the logic of the games are here completely intertwined, so I don't quite follow advice nr 6.

The direction you assign to the frame/ board is not the same you a trying to paint to. You create a new reference in your main loop

I'd also suggest you use key bindings over key listeners

Updated

You construct a initial direction and then add that to the screen. This is actually what will be rendered.

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

But in your threadLoop you create a new (disconnected) direction and start trying to update it...

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

...this will never paint as it has no connection to the screen.

You also create a third reference in board ...

g = new direction();

All these disconnected direction classes have no one to paint or communicate with each and are unnecessary.

I would create a single reference in board , add it to the frame and pass that reference to the threadLoop

Updated

You could take a look at this . It's a basic example demonstrating a simple threaded animation engine and key bindings for the movement of a game asset

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM