在JavaFX中,当对象(如节点或图形)的运动方向发生变化时,可以通过监听位置或速度属性的变化来触发事件。这通常涉及到:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class DirectionChangeDemo extends Application {
private double prevX = 0;
private double prevY = 0;
private Direction prevDirection = Direction.NONE;
enum Direction {
UP, DOWN, LEFT, RIGHT, NONE
}
@Override
public void start(Stage primaryStage) {
Circle circle = new Circle(15);
circle.setLayoutX(100);
circle.setLayoutY(100);
Pane root = new Pane(circle);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Direction Change Demo");
primaryStage.show();
// 动画计时器,模拟运动
new AnimationTimer() {
private long lastTime = 0;
private double velocityX = 2;
private double velocityY = 1;
@Override
public void handle(long now) {
if (lastTime == 0) {
lastTime = now;
return;
}
double elapsedSeconds = (now - lastTime) / 1_000_000_000.0;
lastTime = now;
// 边界检测和方向反转
if (circle.getLayoutX() <= 0 || circle.getLayoutX() >= scene.getWidth()) {
velocityX *= -1;
fireDirectionChangeEvent(circle);
}
if (circle.getLayoutY() <= 0 || circle.getLayoutY() >= scene.getHeight()) {
velocityY *= -1;
fireDirectionChangeEvent(circle);
}
// 更新位置
double newX = circle.getLayoutX() + velocityX * elapsedSeconds * 60;
double newY = circle.getLayoutY() + velocityY * elapsedSeconds * 60;
// 检测方向变化
detectDirectionChange(circle.getLayoutX(), circle.getLayoutY(), newX, newY);
circle.setLayoutX(newX);
circle.setLayoutY(newY);
}
}.start();
}
private void detectDirectionChange(double oldX, double oldY, double newX, double newY) {
double deltaX = newX - oldX;
double deltaY = newY - oldY;
Direction currentDirection = Direction.NONE;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
currentDirection = deltaX > 0 ? Direction.RIGHT : Direction.LEFT;
} else if (Math.abs(deltaY) > Math.abs(deltaX)) {
currentDirection = deltaY > 0 ? Direction.DOWN : Direction.UP;
}
if (currentDirection != prevDirection && currentDirection != Direction.NONE) {
System.out.println("方向改变: " + prevDirection + " -> " + currentDirection);
prevDirection = currentDirection;
}
}
private void fireDirectionChangeEvent(Circle circle) {
System.out.println("在位置 (" + circle.getLayoutX() + ", " + circle.getLayoutY() + ") 方向改变");
// 这里可以触发自定义事件或调用回调方法
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
public class DirectionChangeWithProperties {
private DoubleProperty xVelocity = new SimpleDoubleProperty();
private DoubleProperty yVelocity = new SimpleDoubleProperty();
private Direction currentDirection = Direction.NONE;
enum Direction {
UP, DOWN, LEFT, RIGHT, NONE
}
public DirectionChangeWithProperties() {
// 监听速度变化来检测方向改变
xVelocity.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> obs, Number oldVal, Number newVal) {
checkDirectionChange();
}
});
yVelocity.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> obs, Number oldVal, Number newVal) {
checkDirectionChange();
}
});
}
private void checkDirectionChange() {
double vx = xVelocity.get();
double vy = yVelocity.get();
Direction newDirection = Direction.NONE;
if (Math.abs(vx) > Math.abs(vy)) {
newDirection = vx > 0 ? Direction.RIGHT : Direction.LEFT;
} else if (Math.abs(vy) > Math.abs(vx)) {
newDirection = vy > 0 ? Direction.DOWN : Direction.UP;
}
if (newDirection != currentDirection) {
System.out.println("方向改变: " + currentDirection + " -> " + newDirection);
currentDirection = newDirection;
// 触发方向改变事件
onDirectionChanged(newDirection);
}
}
protected void onDirectionChanged(Direction newDirection) {
// 子类可以重写这个方法处理方向改变事件
}
// Getter和Setter方法
public DoubleProperty xVelocityProperty() { return xVelocity; }
public DoubleProperty yVelocityProperty() { return yVelocity; }
}
原因:由于浮点数计算的精度问题,微小的位置变化可能导致方向频繁切换
解决方案:
// 在detectDirectionChange方法中添加阈值检查
private void detectDirectionChange(double oldX, double oldY, double newX, double newY) {
double deltaX = newX - oldX;
double deltaY = newY - oldY;
// 设置最小移动阈值
if (Math.abs(deltaX) < 0.5 && Math.abs(deltaY) < 0.5) {
return;
}
// 其余逻辑...
}
原因:频繁的位置监听和计算可能影响性能
解决方案:
原因:简单的方向枚举无法描述复杂运动(如曲线运动)
解决方案:
private void detectDirectionWithAngle(double oldX, double oldY, double newX, double newY) {
double deltaX = newX - oldX;
double deltaY = newY - oldY;
if (Math.abs(deltaX) < 0.5 && Math.abs(deltaY) < 0.5) {
return;
}
double angle = Math.toDegrees(Math.atan2(deltaY, deltaX));
angle = (angle + 360) % 360; // 标准化到0-360度
// 8方向检测
if (angle >= 337.5 || angle < 22.5) {
updateDirection(Direction.RIGHT);
} else if (angle >= 22.5 && angle < 67.5) {
updateDirection(Direction.DOWN_RIGHT);
} // 其他方向...
}
在JavaFX中检测运动方向变化并触发事件,核心是跟踪位置或速度属性的变化,并通过比较前后状态来确定方向是否改变。可以根据应用需求选择简单方向枚举或更精确的向量角度方法,同时注意处理性能问题和边界情况。