我正在尝试使用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(..)只是一个标签,用于查看程序是否识别出坐标。事实上它们是:对于每个像素我的光标移动它立即更新这些数字。
但是,我的圆圈只会在光标不移动时转到我的光标位置。我希望形状也可以随时跟随光标,但它不会。
所以我的问题是这样的:即使它正在移动,我怎么能让我的圆圈跟着我的鼠标?
答案 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.