JavaFX Circle必须遵循游标

时间:2015-06-29 11:23:40

标签: java javafx

我正在尝试使用JavaFX自己构建游戏。它有一个必须跟随我的光标的圆圈(使用平滑的平移动画,因此它不会直接转到我的光标位置)

现在我写了这段代码

    root.setOnMouseMoved(event -> {
        TranslateTransition tt = new TranslateTransition(Duration.millis(2000), circle);

        x[0] = event.getSceneX();
        y[0] = event.getSceneY();

        location.setText(x[0] + ", " + y[0]);

        if (x[0] != oldX[0] || y[0] != oldY[0]) {
            tt.stop();
            tt.setToX(event.getSceneX());
            tt.setToY(event.getSceneY());

            oldX[0] = x[0];
            oldY[0] = y[0];
        }

        tt.play();
    });

location.setText(..)只是一个标签,用于查看程序是否识别出坐标。事实上它们是:对于每个像素我的光标移动它立即更新这些数字。

但是,我的圆圈只会在光标不移动时转到我的光标位置。我希望形状也可以随时跟随光标,但它不会。

所以我的问题是这样的:即使它正在移动,我怎么能让我的圆圈跟着我的鼠标?

2 个答案:

答案 0 :(得分:1)

使用AnimationTimer进行移动。您可能还想查看Mike's Blog about a usage example

阅读Daniel Shiffman的The Nature of Code,特别是章节Vectors,1.10与加速的互动。该网页有一个运行示例,可以轻松转换为JavaFX。

这里是JavaFX中实现的书中的代码:

Walker.java

import java.util.Random;

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

public class Walker extends Pane {

    private static Random random = new Random();

    PVector location;
    PVector velocity;
    PVector acceleration;
    float topspeed;

    double width = 30;
    double height = width;
    double centerX = width / 2.0;
    double centerY = height / 2.0;
    double radius = width / 2.0;

    Circle circle;

    public Walker() {

        location = new PVector(random.nextDouble() * width, random.nextDouble() * height, 0);
        velocity = new PVector(0, 0, 0);
        topspeed = 4;

        circle = new Circle(radius);
        circle.setCenterX(radius);
        circle.setCenterY(radius);

        circle.setStroke(Color.BLUE);
        circle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.3));

        getChildren().add(circle);

    }

    public void step(PVector mouse) {

        PVector dir = PVector.sub(mouse, location);
        dir.normalize();
        dir.mult(0.5);
        acceleration = dir;
        velocity.add(acceleration);
        velocity.limit(topspeed);
        location.add(velocity);

    }

    public void checkBoundaries() {

        if (location.x > Settings.SCENE_WIDTH) {
            location.x = 0;
        } else if (location.x < 0) {
            location.x = Settings.SCENE_WIDTH;
        }

        if (location.y > Settings.SCENE_HEIGHT) {
            location.y = 0;
        } else if (location.y < 0) {
            location.y = Settings.SCENE_HEIGHT;
        }
    }

    public void display() {
        relocate(location.x - centerX, location.y - centerY);
    }
}

Main.java

import java.util.ArrayList;
import java.util.List;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    Pane playfield;

    List<Walker> allWalkers = new ArrayList<>();

    PVector mouse = new PVector(0,0,0);

    @Override
    public void start(Stage primaryStage) {

        // create containers
        BorderPane root = new BorderPane();

        StackPane layerPane = new StackPane();

        // playfield for our walkers
        playfield = new Pane();

        layerPane.getChildren().addAll(playfield);

        root.setCenter(layerPane);

        Scene scene = new Scene(root, Settings.SCENE_WIDTH, Settings.SCENE_HEIGHT);
        primaryStage.setScene(scene);
        primaryStage.show();

        // add 1 walker
        addWalker();

        // capture mouse position
        scene.addEventFilter(MouseEvent.ANY, e -> {
            mouse.set(e.getX(), e.getY(), 0);
        });

        // process all walkers
        AnimationTimer loop = new AnimationTimer() {

            @Override
            public void handle(long now) {

                // move
                allWalkers.forEach((walker) -> walker.step(mouse));

                // check border
                allWalkers.forEach(Walker::checkBoundaries);

                // update in fx scene
                allWalkers.forEach(Walker::display);

            }
        };

        loop.start();

    }

    /**
     * Add single walker to list of walkers and to the playfield
     */
    private void addWalker() {

        Walker walker = new Walker();

        allWalkers.add(walker);

        playfield.getChildren().add(walker);

    }

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

Settings.java

public class Settings {

    public static double SCENE_WIDTH = 800;
    public static double SCENE_HEIGHT = 600;

}

PVector.java(您可以从Processing源代码中获取完整的源代码)

public class PVector {

    public double x;
    public double y;
    public double z;

    public PVector(double x, double y, double z) {
        super();
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public void normalize() {
        double m = mag(); 
        if (m != 0 && m != 1) { 
          div(m); 
        } 
    }

    public void div(double value) {
        x /= value;
        y /= value;
        z /= value;
    }

    public void mult(double value) {
        x *= value;
        y *= value;
        z *= value;
    }

    public void add(PVector v) {
        x += v.x;
        y += v.y;
        z += v.z;
    }

    public void sub(PVector v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
    }

    public void limit(float max) {
        if (mag() > max) {
            normalize();
            mult(max);
        }
    }

    public double mag() {
        return Math.sqrt(x * x + y * y + z * z);
    }

    public static PVector sub(PVector v1, PVector v2) {
        return sub(v1, v2, null);
    }

    public static PVector sub(PVector v1, PVector v2, PVector target) {
        if (target == null) {
            target = new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
        } else {
            target.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
        }
        return target;
    }

    public void set(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

答案 1 :(得分:0)

所以使用Roland给我的提示我已经创建了这段代码,它的工作方式与我想要的一样(就像我在我的问题中描述的那样)

   AnimationTimer timer = new AnimationTimer() {
        @Override
        public void handle(long now) {
            TranslateTransition tt = new TranslateTransition(Duration.millis(250), circle);
            Point mouse = MouseInfo.getPointerInfo().getLocation();

            x[0] = mouse.getX();
            y[0] = mouse.getY();

            location.setText(x[0] + ", " + y[0]);

            tt.setToX(x[0]);
            tt.setToY(y[0]);

            tt.play();
        }
    };

    timer.start();

主要变化是使用AnimationTimer而不是事件。这导致我改变了检索鼠标位置的方式,现在我使用awt.MouseInfo来获取光标的X和Y.