圆圈不动的问题

Circle not moving problems

基本上我正在制作一个圆圈将向四个方向移动的游戏。当按一次“S”或“RIGHT”键时,圆圈将移动直到到达窗格的maxX。当我按下“A”键或“LEFT”时,圆圈将移动直到它到达窗格的 minX。 “UP”或“W”和“DOWN”或“Z”键也遵循类似的逻辑。如果它到达窗格的 maxY,它会停止,直到按下另一个键,反之亦然。

这是控制器的代码class

    @FXML
    private Pane board;

    private BooleanProperty wPressed = new SimpleBooleanProperty();
    private BooleanProperty aPressed = new SimpleBooleanProperty();
    private BooleanProperty zPressed = new SimpleBooleanProperty();
    private BooleanProperty sPressed = new SimpleBooleanProperty();

    private BooleanBinding keyPressed = wPressed.or(aPressed).or(zPressed).or(sPressed);

    


    private Circle circle = new Circle(20,40,20);




    private Rectangle[][] grid;
    private int size = 960;
    private int spots = 16;
    private int squareSize = size / spots;


    @FXML
    void handleB(ActionEvent event) {

    }

    AnimationTimer timer = new AnimationTimer() {

        double deltaX = 2;
        double deltaY = 2;
        
        @Override
        public void handle(long timestamp) {
            double rectX = circle.getLayoutX();
            Bounds bounds = board.getBoundsInLocal();


           

            double maxX = bounds.getMaxX();
            double maxY = bounds.getMaxY();
            double minX = bounds.getMinX();
            double minY = bounds.getMinY();

           

            if (circle.getLayoutX() >= ( maxX- circle.getRadius())) {
                deltaX = 0;
                //System.out.println(rect.getLayoutX());
            }
            if (circle.getLayoutY() >= (maxY - circle.getRadius())) {
                deltaY = 0;
            }


            if (circle.getLayoutX() <= ( minX + circle.getRadius())) {
                deltaX = 0;
                //System.out.println(rect.getLayoutX());
            }
            if (circle.getLayoutY() <= ( minY + circle.getRadius())) {
                deltaY = 0;
            }

            if(wPressed.get()) {
                circle.setLayoutY(circle.getLayoutY() - deltaY);
            }

            if(zPressed.get()){
                circle.setLayoutY(circle.getLayoutY() + deltaY);
            }

            if(aPressed.get()){
                circle.setLayoutX(circle.getLayoutX() - deltaX);
            }

            if(sPressed.get()){
                circle.setLayoutX(circle.getLayoutX() + deltaX);
            }



        }
    };


    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {

        
        grid = new Rectangle[spots][spots];
        for (int i = 0; i < size; i += squareSize) {
            for (int j = 0; j < size; j += squareSize) {
                Rectangle r = new Rectangle(i, j, squareSize, squareSize);
                grid[i / squareSize][j / squareSize] = r;
                // Filling each grid with the cell image
                r.setFill(Color.GRAY);
                r.setStroke(Color.BLACK);
                board.getChildren().add(r);
            }
        }

        board.getChildren().addAll(circle);


        movementSetup();

        keyPressed.addListener(((observableValue, aBoolean, t1) -> {
            if(!aBoolean){
                timer.start();
            } else {
                timer.stop();
            }
        }));




    }




    private void movementSetup() {
        board.setOnKeyPressed(e -> {
            if(e.getCode() == KeyCode.UP || e.getCode() == KeyCode.W ) {
                zPressed.set(false);
                sPressed.set(false);
                aPressed.set(false);
                wPressed.set(true);

            }

            if(e.getCode() == KeyCode.A || e.getCode() == KeyCode.LEFT) {
                zPressed.set(false);
                sPressed.set(false);
                wPressed.set(false);
                aPressed.set(true);
            }

            if(e.getCode() == KeyCode.Z || e.getCode() == KeyCode.DOWN) {
                wPressed.set(false);
                aPressed.set(false);
                sPressed.set(false);
                zPressed.set(true);
            }

            if(e.getCode() == KeyCode.S || e.getCode() == KeyCode.RIGHT) {
                wPressed.set(false);
                aPressed.set(false);
                zPressed.set(false);
                sPressed.set(true);
            }
        });


    }


}

** 我在 scenebuilder 中做了窗格,我也将它插入锚窗格**

fxml 文件如下 (ui.fxml)


<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>

<AnchorPane maxHeight="1000.0" maxWidth="1200.0" minHeight="0.0" minWidth="0.0" prefHeight="1000.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fx.game.Controller">
   <children>
      <Pane fx:id="board" maxHeight="960.0" maxWidth="960.0" minHeight="0.0" minWidth="0.0" prefHeight="960.0" prefWidth="960.0">
         <children>
            <Button layoutX="367.0" layoutY="934.0" mnemonicParsing="false" onAction="#handleB" text="Button" />
         </children>
      </Pane>
   </children>
</AnchorPane>

最后是主要的class


package fx.game;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("ui.fxml"));
        stage.setTitle("Hello World");
        stage.setScene(new Scene(root));
        stage.show();
    }

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

我真的不擅长游戏开发 我可能做错了 任何能给我更好的解决方案的人将不胜感激

根据我有限的理解和测试,board.setOnKeyPressed 没有响应关键事件,我用 Scene 代替。您还应该考虑 onKeyReleased.

我不知道你为什么要启动和停止 timer,只需启动它并在每个上评估状态并进行所需的更改。

你的运动逻辑似乎也有问题。获取圆圈当前位置,根据需要对其应用任何移动,然后确定新位置是​​否在可接受范围之外,根据需要调整位置,然后更新圆圈位置。

我还发现 Boundsboard 会根据它的 children 的位置进行更新,这使得很难进行边界检查,相反,我计算了预期大小基于 squareSizespots

的数量

例如...

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class App extends Application {

    private BooleanProperty wPressed = new SimpleBooleanProperty();
    private BooleanProperty aPressed = new SimpleBooleanProperty();
    private BooleanProperty zPressed = new SimpleBooleanProperty();
    private BooleanProperty sPressed = new SimpleBooleanProperty();

    private BooleanBinding keyPressed = wPressed.or(aPressed).or(zPressed).or(sPressed);

    private Circle circle = new Circle(20, 20, 20);

    private Rectangle[][] grid;
    private int size = 960;
    private int spots = 16;
    private int squareSize = size / spots;
    AnimationTimer timer = new AnimationTimer() {

        double deltaX = 2;
        double deltaY = 2;

        @Override
        public void handle(long timestamp) {
            double rectX = circle.getLayoutX();
            Bounds bounds = board.getBoundsInLocal();

            double width = squareSize * spots;
            double height = squareSize * spots;

            double diameter = circle.getRadius() * 2;

            double x = circle.getLayoutX();
            double y = circle.getLayoutY();

            if (wPressed.get()) {
                y -= deltaY;
            }

            if (zPressed.get()) {
                y += deltaY;
            }

            if (aPressed.get()) {
                x -= deltaX;
            }

            if (sPressed.get()) {
                x += deltaX;
            }

            if (x >= (width - diameter)) {
                x = width - diameter;
            }
            if (x < 0) {
                x = 0;
            }

            if (y > (height - diameter)) {
                y = height - diameter;
            }
            if (y < 0) {
                y = 0;
            }

            circle.setLayoutX(x);
            circle.setLayoutY(y);

        }
    };

    private Pane board = new AnchorPane();

    @Override
    public void start(Stage stage) {
        stage.setTitle("Dice Game");

        setup();

        Scene scene = new Scene(board);
        movementSetup(scene);
        stage.setScene(scene);
        stage.sizeToScene();
        stage.show();
    }

    private void movementSetup(Scene scene) {

        scene.setOnKeyPressed(e -> {
            zPressed.set(false);
            sPressed.set(false);
            aPressed.set(false);
            wPressed.set(false);
            if (e.getCode() == KeyCode.UP || e.getCode() == KeyCode.W) {
                wPressed.set(true);
            } else if (e.getCode() == KeyCode.A || e.getCode() == KeyCode.LEFT) {
                aPressed.set(true);
            }else if (e.getCode() == KeyCode.Z || e.getCode() == KeyCode.DOWN) {
                zPressed.set(true);
            }else if (e.getCode() == KeyCode.S || e.getCode() == KeyCode.RIGHT) {
                sPressed.set(true);
            }
        });

    }

    protected void setup() {
        grid = new Rectangle[spots][spots];
        for (int i = 0; i < size; i += squareSize) {
            for (int j = 0; j < size; j += squareSize) {
                Rectangle r = new Rectangle(i, j, squareSize, squareSize);
                grid[i / squareSize][j / squareSize] = r;
                // Filling each grid with the cell image
                r.setFill(Color.GRAY);
                r.setStroke(Color.BLACK);
                board.getChildren().add(r);
            }
        }

        board.getChildren().addAll(circle);

        timer.start();
    }

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

}

nb:我是一个完全的 JavaFX 菜鸟,所以可能有更好的方法来解决这个问题,也许可以看看 Introduction to JavaFX for Game Development 之类的东西(或其他“javafx 游戏开发博客” " 可能会提供更好的想法