在javafx中移动屏幕上的对象
我是Javafx新手,我正在尝试用它制作一个游戏。 为此,我需要一些物体在屏幕上的流体运动。 我不确定,哪种方法最好。 我用一些矩形启动了一个测试文件。我希望矩形沿路径移动到单击位置。我可以通过设置位置使它出现在那里。所以我想我可以做更小的步,然后运动就会变得流畅。但它不是这样工作的。要么是因为移动太快,所以我需要让进程等待(我想使用线程),要么是因为java intepreter不是sequentiell,因此它只显示最终位置。也许两者都有,或者是我没想到的。 现在我想知道我对这个话题的想法是否正确,是否有更优雅的方式来实现我的目标。 我希望你能给我一些建议!在javafx中移动屏幕上的对象,javafx,motion,Javafx,Motion,我是Javafx新手,我正在尝试用它制作一个游戏。 为此,我需要一些物体在屏幕上的流体运动。 我不确定,哪种方法最好。 我用一些矩形启动了一个测试文件。我希望矩形沿路径移动到单击位置。我可以通过设置位置使它出现在那里。所以我想我可以做更小的步,然后运动就会变得流畅。但它不是这样工作的。要么是因为移动太快,所以我需要让进程等待(我想使用线程),要么是因为java intepreter不是sequentiell,因此它只显示最终位置。也许两者都有,或者是我没想到的。 现在我想知道我对这个话题的想法是
关于费利克斯,你需要做的是阅读丹尼尔·希夫曼的汽车游戏,尤其是 这本书很容易理解。您可以将代码应用于JavaFX。我将不详细介绍,您必须自己学习JavaFX。下面是代码: 您需要一个AnimationTimer,在其中应用力,根据力移动对象,并根据对象的位置在UI中显示JavaFX节点 Main.java
package application;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
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.stage.Stage;
public class Main extends Application {
static Random random = new Random();
Layer playfield;
List<Attractor> allAttractors = new ArrayList<>();
List<Vehicle> allVehicles = new ArrayList<>();
AnimationTimer gameLoop;
Vector2D mouseLocation = new Vector2D( 0, 0);
Scene scene;
MouseGestures mouseGestures = new MouseGestures();
@Override
public void start(Stage primaryStage) {
// create containers
BorderPane root = new BorderPane();
// playfield for our Sprites
playfield = new Layer( Settings.SCENE_WIDTH, Settings.SCENE_HEIGHT);
// entire game as layers
Pane layerPane = new Pane();
layerPane.getChildren().addAll(playfield);
root.setCenter(layerPane);
scene = new Scene(root, Settings.SCENE_WIDTH, Settings.SCENE_HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
// add content
prepareGame();
// add mouse location listener
addListeners();
// run animation loop
startGame();
}
private void prepareGame() {
// add vehicles
for( int i = 0; i < Settings.VEHICLE_COUNT; i++) {
addVehicles();
}
// add attractors
for( int i = 0; i < Settings.ATTRACTOR_COUNT; i++) {
addAttractors();
}
}
private void startGame() {
// start game
gameLoop = new AnimationTimer() {
@Override
public void handle(long now) {
// currently we have only 1 attractor
Attractor attractor = allAttractors.get(0);
// seek attractor location, apply force to get towards it
allVehicles.forEach(vehicle -> {
vehicle.seek( attractor.getLocation());
});
// move sprite
allVehicles.forEach(Sprite::move);
// update in fx scene
allVehicles.forEach(Sprite::display);
allAttractors.forEach(Sprite::display);
}
};
gameLoop.start();
}
/**
* Add single vehicle to list of vehicles and to the playfield
*/
private void addVehicles() {
Layer layer = playfield;
// random location
double x = random.nextDouble() * layer.getWidth();
double y = random.nextDouble() * layer.getHeight();
// dimensions
double width = 50;
double height = width / 2.0;
// create vehicle data
Vector2D location = new Vector2D( x,y);
Vector2D velocity = new Vector2D( 0,0);
Vector2D acceleration = new Vector2D( 0,0);
// create sprite and add to layer
Vehicle vehicle = new Vehicle( layer, location, velocity, acceleration, width, height);
// register vehicle
allVehicles.add(vehicle);
}
private void addAttractors() {
Layer layer = playfield;
// center attractor
double x = layer.getWidth() / 2;
double y = layer.getHeight() / 2;
// dimensions
double width = 100;
double height = 100;
// create attractor data
Vector2D location = new Vector2D( x,y);
Vector2D velocity = new Vector2D( 0,0);
Vector2D acceleration = new Vector2D( 0,0);
// create attractor and add to layer
Attractor attractor = new Attractor( layer, location, velocity, acceleration, width, height);
// register sprite
allAttractors.add(attractor);
}
private void addListeners() {
// capture mouse position
scene.addEventFilter(MouseEvent.ANY, e -> {
mouseLocation.set(e.getX(), e.getY());
});
// move attractors via mouse
for( Attractor attractor: allAttractors) {
mouseGestures.makeDraggable(attractor);
}
}
public static void main(String[] args) {
launch(args);
}
}
演示有一个吸引器,在您的例子中,只需单击鼠标即可。只需单击圆并拖动它。车辆将跟随它
package application;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class Attractor extends Sprite {
public Attractor(Layer layer, Vector2D location, Vector2D velocity, Vector2D acceleration, double width, double height) {
super(layer, location, velocity, acceleration, width, height);
}
@Override
public Node createView() {
double radius = width / 2;
Circle circle = new Circle( radius);
circle.setCenterX(radius);
circle.setCenterY(radius);
circle.setStroke(Color.GREEN);
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.3));
return circle;
}
}
以下是用于拖动的代码:
MouseGestures.java
package application;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
public class MouseGestures {
final DragContext dragContext = new DragContext();
public void makeDraggable(final Sprite sprite) {
sprite.setOnMousePressed(onMousePressedEventHandler);
sprite.setOnMouseDragged(onMouseDraggedEventHandler);
sprite.setOnMouseReleased(onMouseReleasedEventHandler);
}
EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
dragContext.x = event.getSceneX();
dragContext.y = event.getSceneY();
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
Sprite sprite = (Sprite) event.getSource();
double offsetX = event.getSceneX() - dragContext.x;
double offsetY = event.getSceneY() - dragContext.y;
sprite.setLocationOffset(offsetX, offsetY);
dragContext.x = event.getSceneX();
dragContext.y = event.getSceneY();
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
}
};
class DragContext {
double x;
double y;
}
}
然后你需要一些课程设置
Settings.java
package application;
public class Settings {
public static double SCENE_WIDTH = 1280;
public static double SCENE_HEIGHT = 720;
public static int ATTRACTOR_COUNT = 1;
public static int VEHICLE_COUNT = 10;
public static double SPRITE_MAX_SPEED = 2;
public static double SPRITE_MAX_FORCE = 0.1;
// distance at which the sprite moves slower towards the target
public static double SPRITE_SLOW_DOWN_DISTANCE = 100;
}
实用程序类用于创建箭头图像和映射值:
Utils.java
package application;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
public class Utils {
public static double map(double value, double currentRangeStart, double currentRangeStop, double targetRangeStart, double targetRangeStop) {
return targetRangeStart + (targetRangeStop - targetRangeStart) * ((value - currentRangeStart) / (currentRangeStop - currentRangeStart));
}
/**
* Create an imageview of a right facing arrow.
* @param size The width. The height is calculated as width / 2.0.
* @param height
* @return
*/
public static ImageView createArrowImageView( double size) {
return createArrowImageView(size, size / 2.0, Color.BLUE, Color.BLUE.deriveColor(1, 1, 1, 0.3), 1);
}
/**
* Create an imageview of a right facing arrow.
* @param width
* @param height
* @return
*/
public static ImageView createArrowImageView( double width, double height, Paint stroke, Paint fill, double strokeWidth) {
return new ImageView( createArrowImage(width, height, stroke, fill, strokeWidth));
}
/**
* Create an image of a right facing arrow.
* @param width
* @param height
* @return
*/
public static Image createArrowImage( double width, double height, Paint stroke, Paint fill, double strokeWidth) {
WritableImage wi;
double arrowWidth = width - strokeWidth * 2;
double arrowHeight = height - strokeWidth * 2;
Polygon arrow = new Polygon( 0, 0, arrowWidth, arrowHeight / 2, 0, arrowHeight); // left/right lines of the arrow
arrow.setStrokeLineJoin(StrokeLineJoin.MITER);
arrow.setStrokeLineCap(StrokeLineCap.SQUARE);
arrow.setStroke(stroke);
arrow.setFill(fill);
arrow.setStrokeWidth(strokeWidth);
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
int imageWidth = (int) width;
int imageHeight = (int) height;
wi = new WritableImage( imageWidth, imageHeight);
arrow.snapshot(parameters, wi);
return wi;
}
}
当然还有向量计算课
Vector2D.java
package application;
public class Vector2D {
public double x;
public double y;
public Vector2D(double x, double y) {
this.x = x;
this.y = y;
}
public void set(double x, double y) {
this.x = x;
this.y = y;
}
public double magnitude() {
return (double) Math.sqrt(x * x + y * y);
}
public void add(Vector2D v) {
x += v.x;
y += v.y;
}
public void add(double x, double y) {
this.x += x;
this.y += y;
}
public void multiply(double n) {
x *= n;
y *= n;
}
public void div(double n) {
x /= n;
y /= n;
}
public void normalize() {
double m = magnitude();
if (m != 0 && m != 1) {
div(m);
}
}
public void limit(double max) {
if (magnitude() > max) {
normalize();
multiply(max);
}
}
static public Vector2D subtract(Vector2D v1, Vector2D v2) {
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public double heading2D() {
return Math.atan2(y, x);
}
}
下面是它的样子
三角形(车辆)将跟随圆圈(吸引子)并在接近圆圈时减速,然后停止。你的问题有点宽泛,因为关于你要做什么的信息确实不够。如果您只是沿着一条路径移动一个矩形,a就会这样做,一般来说,a就足够了。对于更复杂的游戏和模拟,您可能需要一个Hey thanx作为答案。我会尽量做到更准确:我的目标是进行一场赛车比赛。通过舔橡胶,你可以给你的汽车一个方向和一些不会立即施加的加速度。按下按钮后将执行移动。我试过你建议的方法。我在screne上工作得很好,但是如果我试图得到矩形的位置,它只显示0,0。我需要进一步计算的位置,例如,如果汽车仍在轨道上,当然还有下一个运动。接下来我将检查动画API和AnimationTimer。再次感谢你!哇,罗兰,代码链接的本质是我见过的最好的资源之一。非常感谢…@jewelsea:是的,他解释得很好。我马上就买了。代码可以很容易地映射到JavaFX。他还解释了他频道中关于维米奥的每一章,e。G我在回答中提到的答案。嗨,罗兰,这是一个惊人的答案,肯定会派上用场:)我会坚持这本书。我正在使用MVC模式,所以我将把带有转向力的运动放在modell包中。我想使用绑定将模型汽车与其相应的视图对象连接起来,并为此调整了vector类。不幸的是,每次执行移动时,我都必须绑定。我更愿意将绑定设置为全局绑定,但这到目前为止还不起作用,因为我的initialize方法和move方法是分开的操作。你对此有什么想法吗?我将提出一个关于装订的新问题。还有更多的不起作用。但是谢谢你的帮助!太棒了!不要调整vector类以支持绑定。你需要执行所有的矢量运算,然后移动汽车。如果您真的想使用绑定,您可以做的是创建x和y双重属性,并在display方法i中设置值。E在这里我调用了重定位方法。原因是你想要施加力,然后移动,然后你想要e。G检查目的地是否在屏幕之外。但这一切都必须在汽车在屏幕上移动之前发生。
package application;
public class Settings {
public static double SCENE_WIDTH = 1280;
public static double SCENE_HEIGHT = 720;
public static int ATTRACTOR_COUNT = 1;
public static int VEHICLE_COUNT = 10;
public static double SPRITE_MAX_SPEED = 2;
public static double SPRITE_MAX_FORCE = 0.1;
// distance at which the sprite moves slower towards the target
public static double SPRITE_SLOW_DOWN_DISTANCE = 100;
}
package application;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
public class Utils {
public static double map(double value, double currentRangeStart, double currentRangeStop, double targetRangeStart, double targetRangeStop) {
return targetRangeStart + (targetRangeStop - targetRangeStart) * ((value - currentRangeStart) / (currentRangeStop - currentRangeStart));
}
/**
* Create an imageview of a right facing arrow.
* @param size The width. The height is calculated as width / 2.0.
* @param height
* @return
*/
public static ImageView createArrowImageView( double size) {
return createArrowImageView(size, size / 2.0, Color.BLUE, Color.BLUE.deriveColor(1, 1, 1, 0.3), 1);
}
/**
* Create an imageview of a right facing arrow.
* @param width
* @param height
* @return
*/
public static ImageView createArrowImageView( double width, double height, Paint stroke, Paint fill, double strokeWidth) {
return new ImageView( createArrowImage(width, height, stroke, fill, strokeWidth));
}
/**
* Create an image of a right facing arrow.
* @param width
* @param height
* @return
*/
public static Image createArrowImage( double width, double height, Paint stroke, Paint fill, double strokeWidth) {
WritableImage wi;
double arrowWidth = width - strokeWidth * 2;
double arrowHeight = height - strokeWidth * 2;
Polygon arrow = new Polygon( 0, 0, arrowWidth, arrowHeight / 2, 0, arrowHeight); // left/right lines of the arrow
arrow.setStrokeLineJoin(StrokeLineJoin.MITER);
arrow.setStrokeLineCap(StrokeLineCap.SQUARE);
arrow.setStroke(stroke);
arrow.setFill(fill);
arrow.setStrokeWidth(strokeWidth);
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
int imageWidth = (int) width;
int imageHeight = (int) height;
wi = new WritableImage( imageWidth, imageHeight);
arrow.snapshot(parameters, wi);
return wi;
}
}
package application;
public class Vector2D {
public double x;
public double y;
public Vector2D(double x, double y) {
this.x = x;
this.y = y;
}
public void set(double x, double y) {
this.x = x;
this.y = y;
}
public double magnitude() {
return (double) Math.sqrt(x * x + y * y);
}
public void add(Vector2D v) {
x += v.x;
y += v.y;
}
public void add(double x, double y) {
this.x += x;
this.y += y;
}
public void multiply(double n) {
x *= n;
y *= n;
}
public void div(double n) {
x /= n;
y /= n;
}
public void normalize() {
double m = magnitude();
if (m != 0 && m != 1) {
div(m);
}
}
public void limit(double max) {
if (magnitude() > max) {
normalize();
multiply(max);
}
}
static public Vector2D subtract(Vector2D v1, Vector2D v2) {
return new Vector2D(v1.x - v2.x, v1.y - v2.y);
}
public double heading2D() {
return Math.atan2(y, x);
}
}