简体   繁体   English

如何在Javafx中使用时间轴实现游戏循环?

[英]How do I implement game-loop using timeline in Javafx?

I am a beginner. 我是初学者。 I am making a simple color matching 2D game using Javafx where a circle will pass through obstacles of rectangles. 我正在使用Javafx制作一个简单的配色2D游戏,其中一个圆会穿过矩形的障碍。
The circle must pass through the rectangle which has the same color. 圆必须穿过具有相同颜色的矩形。
After passing, the color of the circle and the sequence of colors of rectangles will change. 通过后,圆形的颜色和矩形的颜色顺序将发生变化。
I have done the following code. 我已经完成了以下代码。 Now I don't have any clue how can I change sequence of colors of the rectangle obstacles and the color of the circle for each cycle of timeline. 现在我不知道如何在每个时间轴周期内更改矩形障碍物的颜色顺序和圆圈的颜色。
Also how can I detect if the color of the circle and obstacle has matched or not... need help quickly 另外我该如何检测圆形和障碍物的颜色是否匹配...需要快速帮助

import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.input.*;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class ColorRun extends Application {

    private static final int KEYBOARD_MOVEMENT_DELTA = 20;
    private static final Duration TRANSLATE_DURATION = Duration.seconds(0.25);

    @Override
    public void start(Stage primaryStage) {

        for (int i = 0; i < 12; i++) {
        Circle circle = new Circle();
        circle.setCenterX(650);
        circle.setCenterY(500);
        circle.setRadius(40);
        circle.setFill(Color.RED);

        Rectangle rectangle1 = new Rectangle(0, 0, 200, 70);
        rectangle1.setFill(Color.RED);
        rectangle1.setStroke(Color.BLACK);
        rectangle1.setArcWidth(10);
        rectangle1.setArcHeight(10);

        Rectangle rectangle2 = new Rectangle(200, 0, 200, 70);
        rectangle2.setFill(Color.GREEN);
        rectangle2.setStroke(Color.BLACK);
        rectangle2.setArcWidth(10);
        rectangle2.setArcHeight(10);

        Rectangle rectangle3 = new Rectangle(400, 0, 200, 70);
        rectangle3.setFill(Color.BLUE);
        rectangle3.setStroke(Color.BLACK);
        rectangle3.setArcWidth(10);
        rectangle3.setArcHeight(10);

        Rectangle rectangle4 = new Rectangle(600, 0, 200, 70);
        rectangle4.setFill(Color.YELLOW);
        rectangle4.setStroke(Color.BLACK);
        rectangle4.setArcWidth(10);
        rectangle4.setArcHeight(10);

        Pane root = new Pane();
        root.getChildren().addAll(circle, rectangle1, rectangle2, rectangle3, rectangle4);
        final Scene scene = new Scene(root, 800, 800, Color.GREY);
        primaryStage.setTitle("Color Run");
        primaryStage.setScene(scene);
        moveCircleOnKeyPress(scene, circle);

            Timeline timeline1 = new Timeline();
            timeline1.setCycleCount(Timeline.INDEFINITE);
            timeline1.setAutoReverse(false);
            final KeyValue kv1 = new KeyValue(rectangle1.yProperty(), 800);
            final KeyValue kv2 = new KeyValue(rectangle2.yProperty(), 800);
            final KeyValue kv3 = new KeyValue(rectangle3.yProperty(), 800);
            final KeyValue kv4 = new KeyValue(rectangle4.yProperty(), 800);
            final KeyFrame kf = new KeyFrame(Duration.millis(2000), kv1, kv2, kv3, kv4);
            timeline1.getKeyFrames().add(kf);
            timeline1.play();


        primaryStage.show();
        }
    }

    public void moveCircleOnKeyPress(Scene scene, Circle circle) {
        scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                switch (event.getCode()) {

                    case RIGHT:
                        circle.setCenterX(circle.getCenterX() + KEYBOARD_MOVEMENT_DELTA);
                        break;
                    case LEFT:
                        circle.setCenterX(circle.getCenterX() - KEYBOARD_MOVEMENT_DELTA);
                        break;
                }
            }
        });
    }

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

    }
}

KeyFrame has a constructor that can accept event handler. KeyFrame具有可以接受事件处理程序的构造函数。 To change colors add a event handler to the (last) KeyFrame : 要更改颜色,请将事件处理程序添加到(最后一个) KeyFrame

final KeyFrame kf = new KeyFrame(Duration.millis(2000),(evt -> changeColors()), kv1, kv2, kv3, kv4);

And add a method to handle color changes: 并添加处理颜色变化的方法:

private void changeColors() {
    //todo handle color change
    System.out.println("timeline cycle finished");
}           

Go closer to a game loop. 更加接近游戏循环。 Trigger a EventHandler that updates the scene more frequently and use it to check for intersections between circle and rectangles. 触发EventHandler程序,该EventHandler程序会更频繁地更新场景,并使用它来检查圆形和矩形之间的交集。 When the rectangles reach the bottom, reset them to the top and change the colors. 当矩形到达底部时,将其重置为顶部并更改颜色。

private static final double KEYBOARD_MOVEMENT_DELTA = 5;
private static final double RECT_WIDTH = 200;
private static final double RECT_HEIGHT = 70;
private static final double RECT_MAX_Y = 800;

private static Rectangle createRectangle(double x) {
    Rectangle rect = new Rectangle(x, 0, RECT_WIDTH, RECT_HEIGHT);
    rect.setStroke(Color.BLACK);
    rect.setArcWidth(10);
    rect.setArcHeight(10);
    return rect;
}

private final Random random = new Random();

private void randomizeColors(Rectangle[] rects, Circle circle, List<Color> colors) {
    Collections.shuffle(colors, random);
    for (int i = 0; i < rects.length; i++) {
        rects[i].setFill(colors.get(i));
    }
    circle.setFill(colors.get(random.nextInt(colors.size())));
}

@Override
public void start(Stage primaryStage) {
    List<Color> colors = Arrays.asList(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW);

    Circle circle = new Circle(650, 500, 40);
    Rectangle[] rectangles = new Rectangle[4];
    for (int i = 0; i < rectangles.length; i++) {
        rectangles[i] = createRectangle(RECT_WIDTH * i);
    }

    Pane root = new Pane();
    root.setPrefHeight(RECT_MAX_Y);
    for (Rectangle rect : rectangles) {
        root.getChildren().add(rect);
    }
    root.getChildren().add(circle);

    final double frameDuration = 16;
    final double iterationDuration = 5000;
    final int framesPerIteration = (int) (iterationDuration / frameDuration + 1);
    randomizeColors(rectangles, circle, colors);

    Timeline timeline = new Timeline();

    class FrameHandler implements EventHandler<ActionEvent> {

        KeyCode code;
        private int frame = 1;

        @Override
        public void handle(ActionEvent event) {
            if (frame == 0) {
                randomizeColors(rectangles, circle, colors); // change colors when iteration is done
            }

            // move circle, if key is pressed
            if (code != null) {
                switch (code) {
                    case RIGHT:
                        circle.setCenterX(circle.getCenterX() + KEYBOARD_MOVEMENT_DELTA);
                        break;
                    case LEFT:
                        circle.setCenterX(circle.getCenterX() - KEYBOARD_MOVEMENT_DELTA);
                        break;
                }
            }

            // move rects & check intersection
            final Paint color = circle.getFill();
            final double cx = circle.getCenterX();
            final double cy = circle.getCenterY();
            final double r2 = circle.getRadius() * circle.getRadius();
            boolean lost = false;
            for (Rectangle rect : rectangles) {
                rect.setY(frame * RECT_MAX_Y / framesPerIteration);
                // check for intersections with rects of wrong color
                if (rect.getFill() != color) {

                    double dy = Math.min(Math.abs(rect.getY() - cy),
                            Math.abs(rect.getY() + rect.getHeight() - cy));
                    dy = dy * dy;

                    if (dy > r2) {
                        continue; // y-distance too great for intersection
                    }
                    if (cx >= rect.getX() && cx <= rect.getX() + rect.getWidth()) {
                        lost = true;
                    } else {
                        double dx = Math.min(Math.abs(rect.getX() - cx),
                                Math.abs(rect.getX() + rect.getWidth() - cx));
                        if (dx * dx + dy <= r2) {
                            lost = true;
                        }
                    }
                }
            }
            frame = (frame + 1) % framesPerIteration;
            if (lost) {
                timeline.stop();
            }

        }
    }

    FrameHandler frameHandler = new FrameHandler();

    Scene scene = new Scene(root);

    // keep track of the state of the arrow keys
    scene.setOnKeyPressed(evt -> {
        KeyCode code = evt.getCode();
        switch (code) {
            case RIGHT:
            case LEFT:
                frameHandler.code = code;
                break;
        }
    });
    scene.setOnKeyReleased(evt -> {
        KeyCode code = evt.getCode();
        if (frameHandler.code == code) {
            frameHandler.code = null;
        }
    });

    primaryStage.setScene(scene);

    timeline.getKeyFrames()
            .add(new KeyFrame(Duration.millis(frameDuration), frameHandler));
    timeline.setCycleCount(Timeline.INDEFINITE);

    timeline.play();

    primaryStage.show();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM