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

时间:2018-06-22 02:29:12

标签: java animation javafx event-handling

我是初学者。我正在使用Javafx制作一个简单的配色2D游戏,其中一个圆会穿过矩形的障碍。
圆必须穿过具有相同颜色的矩形。
通过后,圆形的颜色和矩形的颜色顺序将发生变化。
我已经完成了以下代码。现在我不知道如何在每个时间轴周期内更改矩形障碍物的颜色顺序和圆圈的颜色。
另外,我该如何检测圆形和障碍物的颜色是否匹配...需要快速帮助

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);

    }
}

2 个答案:

答案 0 :(得分:0)

KeyFrame具有可以接受事件处理程序的构造函数。 要更改颜色,请向(最后一个)KeyFrame中添加事件处理程序:

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

并添加处理颜色变化的方法:

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

答案 1 :(得分:0)

更接近游戏循环。触发EventHandler,以更频繁地更新场景,并使用它来检查圆形和矩形之间的交集。当矩形到达底部时,将其重置为顶部并更改颜色。

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();
}