【问题标题】:Call dispatchKeyEvent to perform shape translation调用 dispatchKeyEvent 进行形状转换
【发布时间】:2017-03-22 09:31:45
【问题描述】:

我正在使用 JavaFX 开发一个简单的 Pong 克隆,但我很难移动桨。我想为此使用KeyEventDispatcher,并在AnimationTimer 循环期间检查按键。

我的Main 班级:

public class Main extends Application {

    private Player m_pUser;

    @Override
    public void start(Stage primaryStage) throws Exception{

        Group root = new Group();
        Scene scene = new Scene(root, 500, 300);
        ObservableList list = root.getChildren();

        KeyPressedChecker kpc = new KeyPressedChecker();

        m_pUser = new Player(kpc);

        list.add(m_pUser.getPaddleDrawable());

        GamePlayLoop gameLoop = new GamePlayLoop(m_pUser);
        gameLoop.start();

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

我的GamePlayLoop 班级:

public class GamePlayLoop extends AnimationTimer {

    Player m_pUser;

    public GamePlayLoop(Player p) {
        m_pUser = p;
    }

    public void handle(long now) {
        m_pUser.update();
    }
}

我的KeyPressedChecker 班级:

public class KeyPressedChecker implements KeyEventDispatcher {

    private static boolean downPressed = false;

    @Override
    public boolean dispatchKeyEvent(KeyEvent ke) {
        synchronized (KeyPressedChecker.class) {
            switch (ke.getID()) {

                case KeyEvent.KEY_PRESSED:
                    if (ke.getKeyCode() == KeyEvent.VK_DOWN)
                        downPressed = true;
                break;
                case KeyEvent.KEY_RELEASED:
                    if (ke.getKeyCode() == KeyEvent.VK_DOWN)
                        downPressed = false;
                    break;
            }

            return false;
        }
    }

    public static boolean isDownPressed() {
        synchronized (KeyPressedChecker.class) {
            return downPressed;
        }
    }
}

我的Player 班级:

public class Player {

    private Paddle m_paddle;
    private KeyPressedChecker m_kpc;

    public Player(KeyPressedChecker kpc) {
        m_paddle = new Paddle();
    }

    public Rectangle getPaddleDrawable() {
        return m_paddle.getDrawable();
    }

    public void update() {
        if (m_kpc.isDownPressed())
            m_paddle.moveDown();
        m_paddle.update();
    }
}

最后是我的Paddle 班级:

public class Paddle {

    private Rectangle m_rect;
    private double m_nPosY;

    public Paddle() {
        m_rect = new Rectangle(10, 60);
    }

    public void moveDown() {
        m_nPosY += 5;
    }

    public Rectangle getDrawable() {
        return m_rect;
    }

    public void update() {
        m_rect.setTranslateY(m_nPosY);
    }
}

我的问题是桨在场景中没有平移。事实上,dispatchKeyEvent 根本没有被调用。这是为什么呢?

【问题讨论】:

    标签: java javafx timer keyboard-events


    【解决方案1】:

    KeyEventDispatcher 是 AWT 的一部分,它是一个完全独立于 JavaFX 的工具包。 (即使它是 JavaFX 的一部分,您也只需实例化您的实现类,但永远不要对它做任何事情......)。

    在 JavaFX 中执行此操作的方法是在场景中注册 KeyEvent.KEY_PRESSED 事件的事件处理程序。

    所以使用你当前的设计(大约)你会这样做

    public class KeyPressedChecker implements EventHandler<KeyEvent> {
    
        private boolean downPressed = false;
    
        @Override
        public void handle(KeyEvent ke) {
            if (ke.getEventType() == KeyEvent.KEY_PRESSED) {
                downPressed = true ;
            } else if (ke.getEventType() == KeyEvent.KEY_RELEASED) {
                downPressed = false ;
            }   
        }
    
        public boolean isDownPressed() {
            return downPressed;
        }
    
    }
    

    在您的 Player 类中(我重命名字段以匹配正确的 naming conventions

    public class Player {
    
        private Paddle paddle;
        private KeyPressedChecker kpc;
    
        public Player(KeyPressedChecker kpc) {
            this.paddle = new Paddle();
            this.kpc = kpc ;
        }
    
        public Rectangle getPaddleDrawable() {
            return paddle.getDrawable();
        }
    
        public void update() {
            if (kpc.isDownPressed())
                paddle.moveDown();
            paddle.update();
        }
    }
    

    然后一切都链接在一起

    public class Main extends Application {
    
        private Player pUser;
    
        @Override
        public void start(Stage primaryStage) throws Exception{
    
            Group root = new Group();
            Scene scene = new Scene(root, 500, 300);
            ObservableList list = root.getChildren();
    
            KeyPressedChecker kpc = new KeyPressedChecker();
    
            scene.addEventHandler(KeyEvent.ANY, kpc);
    
            pUser = new Player(kpc);
    
            list.add(pUser.getPaddleDrawable());
    
            GamePlayLoop gameLoop = new GamePlayLoop(pUser);
            gameLoop.start();
    
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 这对我很有帮助,解决了我的问题,非常感谢!我理解重命名类变量 - 我命名它们的理由,例如m_pUser 表示一个成员变量(结合匈牙利符号)以避免必须确保我写 this 以避免名称冲突,因为局部变量不会在名称中包含这个“m”。希望我能正确解释自己。
    • @petehallw 我理解在其他语言中使用的约定,但我强烈建议您在编写 Java 时遵循 Java 约定(其他语言也类似)。这将使其他程序员更容易阅读您的代码。就个人而言,FWIW,我讨厌m_pUser,因为不可能在内部发声。 (如果解决了问题,请将答案标记为正确。)
    • 可以理解,以后会考虑的。标记为正确,谢谢。只是出于兴趣,您所说的“内部发声”是什么意思?
    • @petehallw 当我阅读时,我会在脑海中听到这些话(这就是我所说的“内部发声”:也许这不是一个好的描述)。这对于代码和阅读普通散文一样正确。如果变量名称不是我可以轻松“说出”的名称,那么我发现很难阅读(并因此理解)代码。 m_pUser 在阅读时比 pUser 更难“说”出来。显然这完全是主观的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-14
    • 1970-01-01
    • 2011-12-28
    • 1970-01-01
    相关资源
    最近更新 更多