Animation Javafx使用鼠标拖动来加速连续旋转对象
我有一个项目,我正试图开发控制。我需要能够从一个单一的鼠标点击,拖动和释放连续旋转的对象。释放后,我希望该对象继续从其初始点旋转到我释放鼠标的位置。(前提是该对象尚未到达此位置。)我以前见过以这种方式工作的应用程序,我似乎无法在网上找到任何代码来显示如何实现。在将鼠标控件添加到我的项目之前,我正在使用下面的代码测试它们。它已经包含了简单的拖动和释放机制。不过,对于如何添加连续旋转,我将不胜感激。我希望鼠标能够控制对象沿任意轴旋转的速度。当我设置它时,它会沿着任意轴旋转。但我希望通过拖动而不是旋转对象,使对象以与鼠标拖动距离成比例的速度旋转(递归旋转)。这将随着距离的增加而增加速度。如果我将同一方向拖动两倍于同一距离,速度应该加倍,然后物体旋转速度加倍Animation Javafx使用鼠标拖动来加速连续旋转对象,animation,javafx,3d,rotation,javafx-8,Animation,Javafx,3d,Rotation,Javafx 8,我有一个项目,我正试图开发控制。我需要能够从一个单一的鼠标点击,拖动和释放连续旋转的对象。释放后,我希望该对象继续从其初始点旋转到我释放鼠标的位置。(前提是该对象尚未到达此位置。)我以前见过以这种方式工作的应用程序,我似乎无法在网上找到任何代码来显示如何实现。在将鼠标控件添加到我的项目之前,我正在使用下面的代码测试它们。它已经包含了简单的拖动和释放机制。不过,对于如何添加连续旋转,我将不胜感激。我希望鼠标能够控制对象沿任意轴旋转的速度。当我设置它时,它会沿着任意轴旋转。但我希望通过拖动而不是旋转
package javafxapplication3;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.geometry.Point3D;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class trafo extends Application {
final Group root = new Group();
final XformWorld world = new XformWorld();
final PerspectiveCamera camera = new PerspectiveCamera(true);
final XformCamera cameraXform = new XformCamera();
private static final double CAMERA_INITIAL_DISTANCE = -1000;
private static final double CAMERA_NEAR_CLIP = 0.1;
private static final double CAMERA_FAR_CLIP = 10000.0;
double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY;
double mouseFactorX, mouseFactorY;
@Override
public void start(Stage primaryStage) {
root.getChildren().add(world);
root.setDepthTest(DepthTest.ENABLE);
buildCamera();
buildBodySystem();
Scene scene = new Scene(root, 800, 600, true);
scene.setFill(Color.GREY);
handleMouse(scene);
primaryStage.setTitle("TrafoTest");
primaryStage.setScene(scene);
primaryStage.show();
scene.setCamera(camera);
mouseFactorX = 180.0 / scene.getWidth();
mouseFactorY = 180.0 / scene.getHeight();
}
private void buildCamera() {
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
camera.setNearClip(CAMERA_NEAR_CLIP);
camera.setFarClip(CAMERA_FAR_CLIP);
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
}
private void buildBodySystem() {
PhongMaterial whiteMaterial = new PhongMaterial();
whiteMaterial.setDiffuseColor(Color.WHITE);
whiteMaterial.setSpecularColor(Color.LIGHTBLUE);
Box box = new Box(400, 200, 100);
box.setMaterial(whiteMaterial);
PhongMaterial redMaterial = new PhongMaterial();
redMaterial.setDiffuseColor(Color.DARKRED);
redMaterial.setSpecularColor(Color.RED);
Sphere sphere = new Sphere(5);
sphere.setMaterial(redMaterial);
sphere.setTranslateX(200.0);
sphere.setTranslateY(-100.0);
sphere.setTranslateZ(-50.0);
world.getChildren().addAll(box);
world.getChildren().addAll(sphere);
}
private void handleMouse(Scene scene) {
scene.setOnMousePressed((MouseEvent me) -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
});
scene.setOnMouseDragged((MouseEvent me) -> {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseDeltaX = (mousePosX - mouseOldX);
mouseDeltaY = (mousePosY - mouseOldY);
if (me.isPrimaryButtonDown()) {
cameraXform.ry(mouseDeltaX * 180.0 / scene.getWidth());
cameraXform.rx(-mouseDeltaY * 180.0 / scene.getHeight());
} else if (me.isSecondaryButtonDown()) {
camera.setTranslateZ(camera.getTranslateZ() + mouseDeltaY);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
class XformWorld extends Group {
final Translate t = new Translate(0.0, 0.0, 0.0);
final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS);
final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS);
final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS);
public XformWorld() {
super();
this.getTransforms().addAll(t, rx, ry, rz);
}
}
class XformCamera extends Group {
Point3D px = new Point3D(1.0, 0.0, 0.0);
Point3D py = new Point3D(0.0, 1.0, 0.0);
Rotate r;
Transform t = new Rotate();
public XformCamera() {
super();
}
public void rx(double angle) {
r = new Rotate(angle, px);
this.t = t.createConcatenation(r);
this.getTransforms().clear();
this.getTransforms().addAll(t);
}
public void ry(double angle) {
r = new Rotate(angle, py);
this.t = t.createConcatenation(r);
this.getTransforms().clear();
this.getTransforms().addAll(t);
}
}
在我看来,你需要计算从你想要旋转的物体中间拖动的弧线,然后旋转,每当这个物体没有正确旋转,它就会以恒定的速度旋转,直到达到所需的旋转。我从来没有做过这样的事情,所以我不知道我的答案是否真的有效,但我至少可以尝试一下,因为我想我知道答案。现在,下面的代码可能工作,也可能不工作,请告诉我,如果有任何不正确的地方,我将尝试修复它
public class RotationNode extends Pane {
double startMouseAngle, goalAngle = 0.0, angleBeforeRotation;
boolean currentlyRotating = false;
public RotationNode(double angle) {
//Parameter angle is to give this Pane a start angle if you want to
super();
//This can all change to whatever you want it to be
setTranslateX(400.0);
setTranslateY(200.0);
setPrefSize(100.0, 100.0);
setRotationAxis(new Point3D(0.0, 0.0, 360.0));
//This is just to show something is actually rotating
Rectangle r = new Rectangle(0, 0, 100, 100);
r.setFill(Color.BLUE);
getChildren().add(r);
setRotate(angle);
angleBeforeRotation = 0.0;
addEventHandler(MouseEvent.MOUSE_PRESSED, ov -> {
if(ov.getButton() == MouseButton.PRIMARY) {
double x = ov.getX();
double y = ov.getY();
startMouseAngle = Math.toDegrees(Math.atan2(x, y));
angleBeforeRotation = currentlyRotating ? goalAngle : getRotate();
ov.consume();
}
});
addEventHandler(MouseEvent.MOUSE_DRAGGED, ov -> {
if(ov.getButton() == MouseButton.PRIMARY) {
double x = ov.getX();
double y = ov.getY();
double a = Math.toDegrees(Math.atan2(x, y));
double deltaAngle = startMouseAngle - a;
goalAngle = angleBeforeRotation + deltaAngle;
if(!currentlyRotating) {
new changeRotation();
}
ov.consume();
}
});
}
private class changeRotation {
private final long TIME_STEP = 25;
private final double ANGLE_PER_SECOND = 90;
public changeRotation() {
final ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
Runnable changeWidthCmd = () -> {
double rotationDelta = ANGLE_PER_SECOND / (1000.0 / TIME_STEP);
rotationDelta *= getRotate() > goalAngle ? -1 : 1;
setRotate(getRotate() + rotationDelta);
if(getRotate() - goalAngle < ANGLE_PER_SECOND / (1000.0 / TIME_STEP) && getRotate() - goalAngle > -ANGLE_PER_SECOND / (1000.0 / TIME_STEP)) {
setRotate(goalAngle);
currentlyRotating = false;
service.shutdown();
}
};
currentlyRotating = true;
service.scheduleAtFixedRate(changeWidthCmd, 0, TIME_STEP, TimeUnit.MILLISECONDS);
}
}
}
公共类旋转节点扩展窗格{
双星移动角度,goalAngle=0.0,旋转前角度;
布尔currentlyRotating=false;
公共旋转节点(双角度){
//参数“角度”用于在需要时为该窗格提供一个起始角度
超级();
//这一切都可以改变成你想要的样子
setTranslateX(400.0);
setTranslateY(200.0);
setPrefSize(100.0,100.0);
设置旋转轴(新点3D(0.0,0.0,360.0));
//这仅仅是为了表明某些东西在旋转
矩形r=新矩形(0,0,100,100);
r、 设置填充(颜色:蓝色);
getChildren().add(r);
设置旋转(角度);
旋转前角度=0.0;
addEventHandler(MouseeEvent.MOUSE_按下,ov->{
if(ov.getButton()==MouseButton.PRIMARY){
double x=ov.getX();
双y=ov.getY();
startMouseAngle=数学到角度(数学到角度2(x,y));
旋转前角度=当前旋转?目标:getRotate();
ov.consume();
}
});
addEventHandler(MouseEvent.MOUSE_,ov->{
if(ov.getButton()==MouseButton.PRIMARY){
double x=ov.getX();
双y=ov.getY();
双a=数学toDegrees(数学atan2(x,y));
双三角角=起始移动角度-a;
goalAngle=旋转前角度+三角洲角度;
如果(!currentlyRotating){
新的changeRotation();
}
ov.consume();
}
});
}
私有类交换{
私人最终长时间_步=25;
私人最终双角度每秒=90;
公营机构{
final ScheduledExecutorService=Executors.newSingleThreadScheduledExecutor();
可运行的changeWidthCmd=()->{
双旋转增量=角度/秒/(1000.0/时间步长);
rotationDelta*=getRotate()>goalAngle?-1:1;
setRotate(getRotate()+rotationDelta);
如果(getRotate()-goalAngle<角度/秒/(1000.0/时间步长)和&getRotate()-goalAngle>-角度/秒/(1000.0/时间步长)){
设置旋转(goalAngle);
currentlyrotting=false;
service.shutdown();
}
};
currentlyRotating=true;
scheduleAtFixedRate(changeWidthCmd,0,时间步长,时间单位为毫秒);
}
}
}
我希望这对你有帮助
勒纳吉
编辑:更新了代码,现在可以正常工作了。基于鼠标拖动的旋转是有效的,但是中心点很奇怪,而且效果不太好。我将尝试改进这一点并更新此答案 重要编辑:
我忘了提到这个答案包含使用外部库的代码。要添加它,请将其添加到项目pom文件:
<dependencies>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.1.14</version>
</dependency>
</dependencies>
io.reactivex.rxjava2
并将该jar添加到项目依赖项中。“释放后,我希望对象继续从其初始点旋转到我释放鼠标的位置。”这是什么意思?举个例子吧。为了澄清,我想要一个类似于谷歌地球的旋转:google.com/earth。我只想让旋转以我放开鼠标时的速度继续。我想我的意思是,我想要一个旋转速度。也许这就像响应鼠标释放的事件启动对my rotate_x和rotate_y函数的递归调用一样简单?我需要计算旋转速度。这应该是基于我拖动的速度,以及我放开鼠标的即时性。因此图像没有赶上@user1803551“我需要计算旋转速度。这应该基于我拖动的速度,以及我放开鼠标的即时性。”这是什么计算?我们不能告诉你你想要什么。你必须具体说明你希望它如何工作。你的问题