两个线程调用相同的keyEvents方法

时间:2017-12-02 22:35:32

标签: java multithreading javafx netbeans thread-safety

我有一个适用于player1 keyEvents的线程,但是当我为player2 keyevents添加另一个线程时,只注册了player2按键。这是线程问题还是keyEvents()方法的问题?我不知道接下来要去哪里。

    //keyEvents thread for player 1
    AnimationTimer player1_timer = new AnimationTimer(){
        @Override
        public void handle(long now){
            keyEvents(player1, 1);
        }
    };
    player1_timer.start();

    if(true){ //if I set this to false, player1 keyEvents are registered again.
        //keyEvents thread for player 2
        AnimationTimer player2_timer = new AnimationTimer(){
            @Override
            public void handle(long now){
                keyEvents(player2, 2);
            }
        };
        player2_timer.start();
    }

private void keyEvents(Unit player, int playerNumber){
    map.setOnKeyPressed((KeyEvent e) -> {
        if(playerNumber == 1){
            if(null != e.getCode())switch (e.getCode()) {
                case LEFT:
                    player1.rotateLeft();
                    break;
                default:
                    break;
            }
        }
        if(playerNumber == 2){
            if(null != e.getCode())switch (e.getCode()) {
                case A:
                    player2.rotateLeft();
                    break;
                default:
                    break;
            }
        }
    });
}

更新代码:

//keyEvents thread for players
    AnimationTimer playerTimer = new AnimationTimer(){
        @Override
        public void handle(long now){
            keyEvents();
        }
    };
    playerTimer.start();
private void keyEvents(){
        Bullet bullet = new Bullet();
        map.setOnKeyPressed((KeyEvent e) -> {
            if(null != e.getCode())switch (e.getCode()) {
                case A:
                    player2.rotateLeft();
                    break;
                case LEFT:
                    player1.rotateLeft();
                    break;
                default:
                    break;
            }
        });
    }

1 个答案:

答案 0 :(得分:1)

首先,这就像我的第二个JavaFX程序,所以我确信可以做出一些改进。

你必须认识到你仍然只处理单个线程,JavaFX的事件调度线程。

AnimationTimerEventHandler都在此线程的上下文中被调用,因此添加更多这些内容并不会为您提供任何额外的好处,并且实际上可能是部门的。< / p>

相反,您想为keyPressedkeyReleased添加一个处理程序。在这些处理程序中,您希望为给定的玩家设置给定方向的状态。

执行此操作的最简单方法之一是Set,您可以addremove一个“关键”对象,它代表给定玩家的方向。< / p>

然后,您将使用单个AnimationTimer作为“主循环”,并根据Set的状态确定播放器对象应移动的方向

这是游戏开发中非常常见的概念,它很简单,但它也将逻辑与状态分离,因此可以通过任何方式(鼠标/操纵杆/ AI /网络)设置状态,逻辑不会在意。

import java.util.Set;
import java.util.TreeSet;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import static javafx.scene.input.KeyCode.DOWN;
import static javafx.scene.input.KeyCode.SHIFT;
import static javafx.scene.input.KeyCode.UP;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Test extends Application {

    enum Direction {
        UP, DOWN, LEFT, RIGHT;
    }

    private static final double W = 600, H = 400;

    private Image playerOneImage;
    private Node playerOneNode;

    private Image playerTwoImage;
    private Node playerTwoNode;

    private Set<Direction> playerOneDirection = new TreeSet<>();
    private Set<Direction> playerTwoDirection = new TreeSet<>();

    boolean running;

    @Override
    public void start(Stage stage) throws Exception {
        playerOneImage = makePlayerOne();
        playerOneNode = new ImageView(playerOneImage);

        playerTwoImage = makePlayerTwo();
        playerTwoNode = new ImageView(playerTwoImage);

        Group dungeon = new Group(playerOneNode, playerTwoNode);

        movePlayerTo(playerOneNode, 0, 0);
        movePlayerTo(playerTwoNode, W - 12.5, H - 12.5);

        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:
                        playerOneDirection.add(Direction.UP);
                        break;
                    case DOWN:
                        playerOneDirection.add(Direction.DOWN);
                        break;
                    case LEFT:
                        playerOneDirection.add(Direction.LEFT);
                        break;
                    case RIGHT:
                        playerOneDirection.add(Direction.RIGHT);
                        break;
                    case W:
                        playerTwoDirection.add(Direction.UP);
                        break;
                    case S:
                        playerTwoDirection.add(Direction.DOWN);
                        break;
                    case A:
                        playerTwoDirection.add(Direction.LEFT);
                        break;
                    case D:
                        playerTwoDirection.add(Direction.RIGHT);
                        break;
                }
            }
        });

        scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                switch (event.getCode()) {
                    case UP:
                        playerOneDirection.remove(Direction.UP);
                        break;
                    case DOWN:
                        playerOneDirection.remove(Direction.DOWN);
                        break;
                    case LEFT:
                        playerOneDirection.remove(Direction.LEFT);
                        break;
                    case RIGHT:
                        playerOneDirection.remove(Direction.RIGHT);
                        break;
                    case W:
                        playerTwoDirection.remove(Direction.UP);
                        break;
                    case S:
                        playerTwoDirection.remove(Direction.DOWN);
                        break;
                    case A:
                        playerTwoDirection.remove(Direction.LEFT);
                        break;
                    case D:
                        playerTwoDirection.remove(Direction.RIGHT);
                        break;
                }
            }
        });

        stage.setScene(scene);
        stage.show();

        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                movePlayer(playerOneNode, playerOneDirection);
                movePlayer(playerTwoNode, playerTwoDirection);
            }
        };
        timer.start();
    }

    private void movePlayer(Node playerNode, Set<Direction> direction) {
        int dx = 0;
        int dy = 0;
        if (direction.contains(Direction.UP)) {
            dy -= 1;
        }
        if (direction.contains(Direction.DOWN)) {
            dy += 1;
        }
        if (direction.contains(Direction.RIGHT)) {
            dx += 1;
        }
        if (direction.contains(Direction.LEFT)) {
            dx -= 1;
        }
        if (running) {
            dx *= 3;
            dy *= 3;
        }
        if (dx == 0 && dy == 0) {
            return;
        }

        final double cx = playerNode.getBoundsInLocal().getWidth() / 2;
        final double cy = playerNode.getBoundsInLocal().getHeight() / 2;

        double x = cx + playerNode.getLayoutX() + dx;
        double y = cy + playerNode.getLayoutY() + dy;

        movePlayerTo(playerNode, x, y);
    }

    private void movePlayerTo(Node playerNode, double x, double y) {
        final double cx = playerNode.getBoundsInLocal().getWidth() / 2;
        final double cy = playerNode.getBoundsInLocal().getHeight() / 2;

        if (x - cx >= 0
                        && x + cx <= W
                        && y - cy >= 0
                        && y + cy <= H) {
            playerNode.relocate(x - cx, y - cy);
        }
    }

    protected Image makePlayerOne() {
        return makePlayer(Color.RED);
    }

    protected Image makePlayerTwo() {
        return makePlayer(Color.BLUE);
    }

    protected Image makePlayer(Color color) {
        WritableImage image = new WritableImage(25, 25);
        PixelWriter writer = image.getPixelWriter();
        for (int y = 0; y < 25; y++) {
            for (int x = 0; x < 25; x++) {
                writer.setColor(x, y, color);
            }
        }
        return image;
    }

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