如何为 JavaFX 编写 KeyListener [英] How to write a KeyListener for JavaFX

查看:40
本文介绍了如何为 JavaFX 编写 KeyListener的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个小游戏,我可以使用 WASS 在 JavaFX 面板上移动球kbd>D 键.
我有一个 getPosX()setPosX() 但我不知道如何编写一个 KeyListener 它将例如计算 setPosX(getPosX()+1) 如果我按 D.

我该怎么办?

解决方案

来自 .

来自示例突破游戏的通用输入处理程序示例:

class InputHandler 实现 EventHandler{最终私有集activeKeys = new HashSet<>();@覆盖公共无效句柄(KeyEvent 事件){如果 (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {activeKeys.add(event.getCode());} else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {activeKeys.remove(event.getCode());}}公共集getActiveKeys() {返回 Collections.unmodifiableSet(activeKeys);}}

虽然具有适当设置更改侦听器的 ObservableSet 可用于活动键集,但我使用了一个访问器,该访问器返回一组不可修改的键,这些键在快照时处于活动状态,因为这是我在这里感兴趣的,而不是实时观察活动键集的变化.

示例通用输入处理程序用法:

Scene gameScene = createGameScene();//将输入处理程序注册到游戏场景.InputHandler inputHandler = new InputHandler();gameScene.setOnKeyPressed(inputHandler);gameScene.setOnKeyReleased(inputHandler);gameLoop = createGameLoop();//...私人动画计时器 createGameLoop() {返回新的 AnimationTimer() {公共无效句柄(现在很长时间){更新(现在,inputHandler.getActiveKeys());如果 (gameState.isGameOver()) {this.stop();}}};}公共无效更新(现在很长时间,设置 activeKeys){applyInputToPaddle(activeKeys);//...更新游戏状态和视图的其余逻辑.}//桨是精灵实现//一个内置的速度设置,用于//更新每一帧的位置.////在用户输入时,桨叶速度发生变化//指向正确的预定义方向.private void applyInputToPaddle(Set activeKeys) {Point2D paddleVelocity = Point2D.ZERO;如果(activeKeys.contains(KeyCode.LEFT)){paddleVelocity = paddleVelocity.add(paddleLeftVelocity);}如果(activeKeys.contains(KeyCode.RIGHT)){paddleVelocity = paddleVelocity.add(paddleRightVelocity);}gameState.getPaddle().setVelocity(paddleVelocity);}

I want to write a little game where I can move a ball on a JavaFX Panel using the W, A, S, D keys.
I have a getPosX() and setPosX() but I don't know how to write a KeyListener which will e.g. calculate setPosX(getPosX()+1) if I press D.

What do I have to do?

解决方案

From a JavaRanch Forum post.

Key press and release handlers are added on the scene and update movement state variables recorded in the application. An animation timer hooks into the JavaFX pulse mechanism (which by default will be capped to fire an event 60 times a second) - so that is a kind of game "loop". In the timer the movement state variables are checked and their delta actions applied to the character position - which in effect moves the character around the screen in response to key presses.

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
 
/**
 * Hold down an arrow key to have your hero move around the screen.
 * Hold down the shift key to have the hero run.
 */
public class Runner extends Application {
 
    private static final double W = 600, H = 400;
 
    private static final String HERO_IMAGE_LOC =
            "http://icons.iconarchive.com/icons/raindropmemory/legendora/64/Hero-icon.png";
 
    private Image heroImage;
    private Node  hero;
 
    boolean running, goNorth, goSouth, goEast, goWest;
 
    @Override
    public void start(Stage stage) throws Exception {
        heroImage = new Image(HERO_IMAGE_LOC);
        hero = new ImageView(heroImage);
 
        Group dungeon = new Group(hero);
 
        moveHeroTo(W / 2, H / 2);
 
        Scene scene = new Scene(dungeon, W, H, Color.FORESTGREEN);
 
        scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                switch (event.getCode()) {
                    case UP:    goNorth = true; break;
                    case DOWN:  goSouth = true; break;
                    case LEFT:  goWest  = true; break;
                    case RIGHT: goEast  = true; break;
                    case SHIFT: running = true; break;
                }
            }
        });
 
        scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                switch (event.getCode()) {
                    case UP:    goNorth = false; break;
                    case DOWN:  goSouth = false; break;
                    case LEFT:  goWest  = false; break;
                    case RIGHT: goEast  = false; break;
                    case SHIFT: running = false; break;
                }
            }
        });
 
        stage.setScene(scene);
        stage.show();
 
        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                int dx = 0, dy = 0;
 
                if (goNorth) dy -= 1;
                if (goSouth) dy += 1;
                if (goEast)  dx += 1;
                if (goWest)  dx -= 1;
                if (running) { dx *= 3; dy *= 3; }
 
                moveHeroBy(dx, dy);
            }
        };
        timer.start();
    }
 
    private void moveHeroBy(int dx, int dy) {
        if (dx == 0 && dy == 0) return;
 
        final double cx = hero.getBoundsInLocal().getWidth()  / 2;
        final double cy = hero.getBoundsInLocal().getHeight() / 2;
 
        double x = cx + hero.getLayoutX() + dx;
        double y = cy + hero.getLayoutY() + dy;
 
        moveHeroTo(x, y);
    }
 
    private void moveHeroTo(double x, double y) {
        final double cx = hero.getBoundsInLocal().getWidth()  / 2;
        final double cy = hero.getBoundsInLocal().getHeight() / 2;
 
        if (x - cx >= 0 &&
            x + cx <= W &&
            y - cy >= 0 &&
            y + cy <= H) {
            hero.relocate(x - cx, y - cy);
        }
    }
 
    public static void main(String[] args) { launch(args); }
}


Please ignore the rest of this answer if the information already provided is sufficient for your purposes.

While the above solution is sufficient to answer this question, if interested, a more sophisticated input handler (with a more general and separated, input and update handling logic), can be found in this demo breakout game:

Example generic input handler from the sample breakout game:

class InputHandler implements EventHandler<KeyEvent> {
    final private Set<KeyCode> activeKeys = new HashSet<>();

    @Override
    public void handle(KeyEvent event) {
        if (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
            activeKeys.add(event.getCode());
        } else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
            activeKeys.remove(event.getCode());
        }
    }

    public Set<KeyCode> getActiveKeys() {
        return Collections.unmodifiableSet(activeKeys);
    }
}

While an ObservableSet with an appropriate set change listener could be used for the set of active keys, I have used an accessor which returns an unmodifiable set of keys which were active at a snapshot in time, because that is what I was interested in here rather than observing changes to the set of active keys in real-time.

Example generic input handler usage:

Scene gameScene = createGameScene();

// register the input handler to the game scene.
InputHandler inputHandler = new InputHandler();
gameScene.setOnKeyPressed(inputHandler);
gameScene.setOnKeyReleased(inputHandler);

gameLoop = createGameLoop();

// . . .

private AnimationTimer createGameLoop() {
    return new AnimationTimer() {
        public void handle(long now) {
            update(now, inputHandler.getActiveKeys());
            if (gameState.isGameOver()) {
                this.stop();
            }
        }
    };
}

public void update(long now, Set<KeyCode> activeKeys) {
    applyInputToPaddle(activeKeys);
    // . . . rest of logic to update game state and view.
}

// The paddle is sprite implementation with
// an in-built velocity setting that is used to
// update its position for each frame.
//
// on user input, The paddle velocity changes 
// to point in the correct predefined direction.
private void applyInputToPaddle(Set<KeyCode> activeKeys) {
    Point2D paddleVelocity = Point2D.ZERO;

    if (activeKeys.contains(KeyCode.LEFT)) {
        paddleVelocity = paddleVelocity.add(paddleLeftVelocity);
    }

    if (activeKeys.contains(KeyCode.RIGHT)) {
        paddleVelocity = paddleVelocity.add(paddleRightVelocity);
    }

    gameState.getPaddle().setVelocity(paddleVelocity);
}

这篇关于如何为 JavaFX 编写 KeyListener的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆