KeyListener 未在 JPanel 中实例化

KeyListener not instantiated in a JPanel

我正在创建一个简单的小游戏,我需要一些帮助来找出我正在犯的错误。这个想法是将一些面板存储在主框架内的 CardLayout 中,并在需要时在它们之间切换;我创建了一个自定义 JFrame (MainFrame) 和一堆自定义 JPanel,其中一个是 GamePanel,它已附加到自定义 KeyListener (MovementListener) 以捕获关键事件并根据需要移动玩家。问题是当我切换到 GamePanel 时,keyListener 似乎没有实例化。 要清楚,做了一堆测试,结果在 addKeyListener() 方法中,"new MovementListener()" 部分为空,但我不明白为什么。

这里是MovementListener class:

package controller.listeners;

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

import application.core.GameController;
import entities.Player;
import movement.Direction;

public class MovementListener implements KeyListener {

    private Player player;

    public MovementListener() {
        this.player=GameController.getInstance().getPlayer();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
        case KeyEvent.VK_W:
            player.move(Direction.NORTH);
            player.getAnimatedSprite().startMoving();
            break;
        case KeyEvent.VK_A:
            player.move(Direction.WEST);
            player.getAnimatedSprite().startMoving();
            break;
        case KeyEvent.VK_S:
            player.move(Direction.SOUTH);
            player.getAnimatedSprite().startMoving();
            break;
        case KeyEvent.VK_D:
            player.move(Direction.EAST);
            player.getAnimatedSprite().startMoving();
            break;
        default:
            break;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
        case KeyEvent.VK_W:
            player.getAnimatedSprite().stopMoving();
            break;
        case KeyEvent.VK_A:
            player.getAnimatedSprite().stopMoving();
            break;
        case KeyEvent.VK_S:
            player.getAnimatedSprite().stopMoving();
            break;
        case KeyEvent.VK_D:
            player.getAnimatedSprite().stopMoving();
            break;
        default:
            break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {}

}

游戏面板class:

package graphics.panels;

import java.awt.Component;
import java.awt.Graphics;

import javax.swing.JPanel;

import application.core.GameController;
import controller.listeners.MovementListener;
import entities.Entity;
import entities.Living;
import graphics.ConstantsCollector;
import graphics.sprites.AnimatedSprite;
import graphics.sprites.Tile;

@SuppressWarnings("serial")
public class GamePanel extends JPanel {

    public static final String NAME="Game";

    private static GamePanel instance=null;

    private Tile grassTile;
    private Entity[][] logicMap;

    private GamePanel() {
        super();

        logicMap = GameController.getInstance().logicMap;
        grassTile = new Tile(ConstantsCollector.GRASSTEXTURE);
        addKeyListener(new MovementListener());

        setAlignmentX(Component.CENTER_ALIGNMENT);
        setVisible(true);
        setFocusable(true);
        requestFocusInWindow();
        grabFocus();
    }

    @Override
    public void paintComponent(Graphics g) {
        drawFloorMap(g);
        drawObjects(g);
        drawEntities(g);
    }

    private void drawFloorMap(Graphics g) {
        for(int i = 0; i < ConstantsCollector.MAP_SIZE; i++)
            for(int j = 0; j < ConstantsCollector.MAP_SIZE; j++)
                g.drawImage(grassTile.getSprite(), Tile.calculateXPosition(i), Tile.calculateYPosition(j), Tile.calculateWidth(), Tile.calculateHeight(), null);
    }

    private void drawObjects(Graphics g) {
        for(int i = 0; i < ConstantsCollector.MAP_SIZE; i++)
            for(int j = 0; j < ConstantsCollector.MAP_SIZE; j++)
                if (logicMap[i][j]!=null && !(logicMap[i][j] instanceof Living))
                    g.drawImage(logicMap[i][j].getTile().getSprite(), logicMap[i][j].getTile().getWidth(), logicMap[i][j].getTile().getHeight(), null);
                else
                    g.drawImage(grassTile.getSprite(), Tile.calculateXPosition(i), Tile.calculateYPosition(j), Tile.calculateWidth(), Tile.calculateHeight(), null);
    }

    private void drawEntities(Graphics g)   {
        for(int i = 0; i < ConstantsCollector.MAP_SIZE; i++)
            for(int j = 0; j < ConstantsCollector.MAP_SIZE; j++)
                if (logicMap[i][j]!=null && (logicMap[i][j] instanceof Living))
                {
                    AnimatedSprite sprite=((Living)logicMap[i][j]).getAnimatedSprite();
                    g.drawImage(sprite.getCurrentImage(), sprite.getWidht(), sprite.getHeight(), null);
                }
    }

    public void update() {
        repaint();
    }

    public static GamePanel getInstance() {
        if (instance==null)
            instance=new GamePanel();
        return instance;
    }
}

KeyListener 在 JPanel 上不起作用,请使用 registerKeyboardAction 方法。我最好这样做

class Movement {
    Player player;

    public void move(Direction direction) {
        player.move(direction);
        player.getAnimatedSprite().startMoving();
    }
}

class GamePanel extends JPanel {
    Movement movement = new Movement();
    private GamePanel() {
        KeyStroke keystroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false); 
        registerKeyboardAction(movementListener(Direction.NORTH), keystroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
        // register other key strokes
    }
    ActionListener movementListener(final Direction direction) {
        return new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                movement.move(direction);
            }
        }
    }
}

ActionListener 可以在java8

中简化为 lambda