我的javaFX项目中有一辆汽车,当按下SPACE时,汽车(Node)的位置应该改变(汽车应该平稳地跳跃)。所以我使用了一个事件处理程序来调用名为moveUp()
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode())
{
case SPACE:
moveUp();
break;
}
}
});
这会创建一个新的线程,其中汽车的速度改变10次,间隔为75毫秒。
private void moveUp() {
new Thread(new Runnable() {
@Override
public void run() {
carSpeed = 10;
for(;carSpeed>=0;carSpeed--)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y-=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
for(carSpeed=0;carSpeed<=10;carSpeed++)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y+=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
}
}).start();
}
如果我不使用不同的线程,GUI线程将被冻结,如果我不使用Thread.sleep(),汽车将突然跳转(不顺利)。这段代码做得很好。但我了解到thread.start()
并不能保证线程的立即执行。我怎样才能保证立即执行?
答案 0 :(得分:1)
我建议留在FX应用程序主题并使用类AnimationTimer
。这是一个平滑跳跃的简短演示:
private void moveUp() {
new AnimationTimer() {
long startTime = -1;
double initCarPosition_Y;
@Override
public void handle(long now) {
if(startTime == -1){
startTime = now;
initCarPosition_Y = carPosition_Y;
carSpeedX = 3d;
carSpeedY = -15d;
}
double time = (now - startTime) / 1E9d;
carPosition_X += carSpeedX * time;
carPosition_Y += carSpeedY * time;
if(carSpeed > 0 && initCarPosition_Y <= carPosition_Y){
carPosition_Y = initCarPosition_Y;
stop();
}
carSpeedY += 0.8d * time; //gravity
car.relocate(carPosition_X, carPosition_Y);
}
}.start();
}
这种方法可让您全面直接控制每一帧中发生的事情。但是,javaFX还提供高级动画类,包括预定义的插值器和转换。适合替代方法的可以是以下类别:
PathTransition
:允许您定义给定节点动画的点和曲线。TimeLine
:允许您根据节点位置等属性定义任意动画关键帧。请注意,当您想为像汽车这样的用户控制的演员设置动画时,通常使用这些高级课程可能会变得具有挑战性。这些类都需要一段精确的持续时间才能使动画持续。例如,只要按下特定键就想要翻译节点,就不能事先知道动画的持续时间。