JavaFX Circle必须跟随光标 [英] JavaFX Circle must follow cursor
问题描述
我正在尝试使用JavaFX自己构建游戏.它具有一个必须跟随我的光标的圆(使用平滑的平移动画,因此它不会直接移到我的光标所在的位置)
I am trying to build a game myself using JavaFX. It features a circle that must follow my cursor (using a smooth translation animation, so it will not go directly to the location of my cursor)
到目前为止,我已经编写了这段代码
For now I have written this piece of code
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(..)只是一个标签,用于查看程序是否识别坐标.实际上,它们是:对于我的光标,每个像素移动都会立即更新这些数字.
The location.setText(..) is just a label to see whether the coords are recognized by the program. And in fact they are: for each pixel my cursor moves it updated these numbers instantly.
但是,我的圈子只会在其不动时移动到光标所在的位置.我希望形状也能随行随动,但不会.
However, my circle will only go to the location of my cursor when it does not move. I want the shape to follow my cursor on the go as well but it just won't.
所以我的问题是这样的:即使它在移动,如何使我的圈子跟随我的鼠标呢?
So my problem is this: how can I make my circle follow my mouse, even when it is moving?
推荐答案
使用 AnimationTimer 进行移动.您可能还想查看 Mike的博客中的用法示例.
Use an AnimationTimer for the movement. You may also want to check Mike's Blog about a usage example.
请阅读Daniel Shiffman的代码的本质,尤其是向量,1.10加速交互.该网页上有一个正在运行的示例,可以轻松转换为JavaFX.
Read The Nature of Code by Daniel Shiffman, especially the Chapter Vectors, 1.10 Interactivity with Acceleration. The webpage has a running example, easily to convert to JavaFX.
这是用JavaFX实现的书中的代码:
Here's the code from the book implemented in JavaFX:
Walker.java
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
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
Settings.java
public class Settings {
public static double SCENE_WIDTH = 800;
public static double SCENE_HEIGHT = 600;
}
PVector.java(您可以从处理"源代码中获取完整源代码)
PVector.java (you can get the full source from the Processing source code)
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;
}
}
这篇关于JavaFX Circle必须跟随光标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!