第 7 课:创建动画对象

来源:互联网 发布:炫浪网络社区打不开 编辑:程序博客网 时间:2024/06/05 07:57

 第 7 课:创建动画对象

JavaFX 库提供了对创建动画的内置支持。本课向您展示如何构建图形对象并使用线性插值为其设置动画(JavaFX 库支持的一种关键帧动画)。本课中的示例使用 JavaFX Script 语言的声明性语法以及数据绑定、图形和特定于节点的功能,因此可能有助于您熟悉学习 JavaFX Script 编程语言在图形场景中显示 UI 对象创建图形对象
 

目录


创建应用程序窗口
创建图形场景
添加背景图像
绘制一片云
创建水平运动
控制时间线周期
添加垂直运动
 

本课介绍向简单应用程序添加动画的逐步操作过程。考虑创建一片云,在晴空中飘浮,碰到窗口边界时反弹,如以下窗口所示。

 
在窗口内反弹的云
图 1:在窗口内反弹的云
 


要评估和测试您的动画应用程序,请创建一个扩展名为 .fx 的文件,例如 cloud.fx

您可以在任意时间使用以下命令编译您的代码:

javafxc cloud.fx


您可以使用以下命令运行编译的代码:

javafx cloud


创建应用程序窗口

使用 Stage 类创建一个窗口:

  1. javafx.stage.Stage 类添加 import 语句。
  2. Stage 对象字面值添加到代码中。
创建图形场景

正如您在在图形场景中显示 UI 对象中所了解到的那样,UI 组件、形状、文本和图像被当作是图形场景中的对象分层结构。这些图形对象的动画也在场景中进行,因此下一步是创建一个场景。

  1. SceneColor 类添加 import 语句。
  2. Scene 对象字面值添加到 Stage类的 scene 实例变量中。
  3. 使用 Scene 类的 fill 变量定义场景的颜色。

    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;

    Stage{
    title: "Cloud"
    visible: true
    scene:
    Scene{
    fill: Color.WHITE
    }//Scene
    }//Stage
     

有关 JavaFX Script 编程语言中采用的声明性语法的更多信息,请参阅“使用声明性语法”。

添加背景图像

在 JavaFX SDK 中,图像是使用 javafx.scene.image.Image 类创建的,图像位置在 url 实例变量中指定。请注意,只能将一个 Node 对象添加到场景内容中,因此,您需要使用一个名为 ImageView 的适配器类。有关场景和节点的更多详细信息,请参见在图形场景中显示 UI 对象

  1. ImageImageView 类添加两个新的导入。
  2. 设置一个图像,用作飘浮的云的背景。您可以使用位于 java.sun.com 中的日照图像:/javafx/1/tutorials/ui/animation/weather-sun.png

这些更改将反映在修改后的代码中,如下所示:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
content:[
ImageView{image:
Image{url: "http://java.sun.com/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
}
]
}//Scene
}//Stage


编译和运行之后,此修改后的代码将生成以下窗口。

 
具有背景图像的画帧
图 2:使用背景图像的窗口
 



注意:由于没有指定窗口的宽度和高度,因此图像刚好填满窗口。
绘制一片云

通过绘制 5 个首尾相接的弧来创建实际的云。第一个弧的终点是第二个弧的起点。下图对此进行了说明。

 
形成云的弧的端点
图 3:形成云的弧的端点
 

 

要在代码中绘制此云,您需要执行以下步骤:

  1. 使用 javafx.scene.shape 软件包中的 MoveToArcToPath 类,如以下代码片段所示。

    Path {
    fill: Color.WHITE
    stroke: Color.LIGHTBLUE
    strokeWidth: 2
    effect: Lighting{light: DistantLight{azimuth: 90}}
    elements: [
    MoveTo { x: 15 y: 15 },
    ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
    ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
    ]
    }//Path
     
    MoveTo 类用于指示此形状的起点,ArcTo 类用于创建弧段。使用 Path 类(表示一个简单的形状)将所有弧段组合成一个形状,然后启用基本的几何路径构造。如果需要创建一个自己的形状,使其不同于 javafx.scene.shape 软件包中提供的基本图形形状,则 Path 类很有用。Path 类扩展了 Node 类,并继承了后者的所有实例变量和函数。


    注意:sweepFlag 实例变量已设置为 true,因此按顺时针方向(“正”角度)绘制弧。如果按逆时针方向绘制弧,这些弧将不能正确弯曲。
  2. 应用以下代码创建照明效果,使云具有浮雕感。

    effect: Lighting{light: DistantLight{azimuth: 90}}
     
    这种效果模拟使用一个远距光源照亮对象。azimuth 实例变量用于定义光源的角度。
  3. MoveToArcToPathLightingDistantLight 类添加 import 语句。

    有关形状和视觉效果的更多信息,请参阅创建图形对象。以下修改后的代码包含图形场景、图像和云:

    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.shape.ArcTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.effect.Lighting;
    import javafx.scene.effect.light.DistantLight;

    Stage{
    title: "Cloud"
    visible: true
    scene:
    Scene{
    fill: Color.WHITE
    content:[
    ImageView{image:
    Image{url: "/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
    },

    Path {
    fill: Color.WHITE
    stroke: Color.LIGHTBLUE
    strokeWidth: 2
    effect: Lighting{light: DistantLight{azimuth: 90}}
    elements: [
    MoveTo { x: 15 y: 15 },
    ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
    ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
    ]
    }//Path
    ]
    }//Scene

    }//Stage
     
    编译和运行之后,此修改后的代码将生成以下窗口。

     
    具有一个图像和一个看上去像云的形状的帧
    图 4:具有一个图像和一个看上去像云的形状的窗口
     
     
创建水平运动

下一步是为云设置动画。JavaFX Script 语言支持关键帧动画概念。这意味着,图形场景的动画状态过渡是通过场景在某些时间点的状态的起始快照和结束快照(关键帧)声明的。给定这两个状态后,系统就可以自动执行动画。一经请求,它就可以停止、暂停、继续、反向或重复运动。

首先,通过设置云的水平动画(没有垂直运动)来简化任务。然后,再添加垂直运动。要设置云的水平动画,请更改 Path 对象的 translateX 实例变量,并保持 translateY 实例变量不变。请执行以下步骤:

  1. Path 对象的 translateY 变量设置为 15。
  2. 为起始点 (0, 15) 和结束点 (387, 15) 定义关键帧。要计算这些值,请考虑图像大小 (470x119) 和形状大小 (83x64)。下图说明了这些尺寸。

     
    关键帧
    图 5:关键帧
     
     
    动画沿着由 javafx.animation.Timeline 对象表示的时间线进行。每条时间线包含由 javafx.animation.KeyFrame 对象表示的两个或多个关键帧。
  3. 创建具有两个关键帧的时间线来执行云的水平运动,并在启动应用程序时开始此运动。起始点和结束点之间的位置是使用线性插值计算的。

    import javafx.animation.Timeline;
    import javafx.animation.KeyFrame;
    import javafx.animation.Interpolator;

    var x: Number;

    Timeline {
    keyFrames: [
    KeyFrame{
    time: 0s
    values: x => 0.0
    },

    KeyFrame{
    time: 7s
    values: x => 387.0 tween Interpolator.LINEAR
    }
    ]
    }.play();
     
    time 实例变量用来定义所经过的时间,在这段时间里,将在单个 Timeline 对象周期内设置关联值。timejavafx.lang.Duration 类的变量,它具有一个 Number 值,后跟 "s" 或 "ms"(分别表示秒和毫秒)。=> 运算符为关键值列表提供了一个字面值构造函数。tween 运算符是插值的字面值构造函数。因此,在 7 秒钟内,云从像素 0 开始移到位置 387。

    尽管 KeyFrame 动画是典型的 JavaFX 对象,但 JavaFX 提供了一种特殊的语法,与标准的对象字面值语法相比,使用这种语法表示动画更简单。使用 trigger 子句可将任意回调与关键帧相关联。由 at 指定的时间是相对于时间线的起点的。此功能可简化代码,如下所示:

    import javafx.animation.Timeline;
    import javafx.animation.KeyFrame;
    import javafx.animation.Interpolator;

    var x: Number;

    Timeline {
    keyFrames: [
    at (0s) {x => 0.0},
    at (7s) {x => 387.0 tween Interpolator.LINEAR}
    ]
    }.play();
     
  4. Path 对象的 translateX 实例变量绑定到 x 变量,如以下代码片段所示:

    Path{
    ...
    translateX: bind x
    ...
    }
     
    x 变量发生变化时,Path 对象的 translateX 对象也随之发生变化。有关数据绑定机制的更多详细信息,请参见对 UI 对象应用数据绑定
控制时间线周期

您可以使用 Timeline 类的实例变量来控制时间线周期。

  1. repeatCount 实例变量设置为 Timeline.INDEFINITE 可以循环动画。
  2. autoReverse 实例变量设置为 true 可以启用双向运动。

以下代码可完成这些任务:

import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;

var x: Number;

Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {x => 0.0},
at (7s) {x => 387.0 tween Interpolator.LINEAR}
]
}.play();


此应用程序修改后的代码如下所示:

import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.light.DistantLight;

var x: Number;

Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) {x => 0.0},
at (7s) {x => 387.0 tween Interpolator.LINEAR}
]
}.play();

Stage{
title: "Cloud"
visible: true
scene:
Scene{
fill: Color.WHITE
content:[
ImageView{image:
Image{url: "/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
},
Path{
translateX: bind x
translateY: 15
fill: Color.WHITE
stroke: Color.LIGHTBLUE
strokeWidth: 2
effect: Lighting{light: DistantLight{azimuth: 90}}
elements: [
MoveTo { x: 15 y: 15 },
ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},

]
}//Path
]
}//Scene
onClose: function() {
java.lang.System.exit(0);
}//close action

}//Stage


编译和运行之后,此代码将生成以下窗口:

 
水平运动
图 6:水平运动
 


此动画应用程序使用可按均匀时间增量移动对象的线性插值。您可以尝试其他形式的插值。例如,如果您设置 Interpolator.EASEBOTH 类型,则在时间线周期的起点和终点,云的运动速度将稍微下降。

添加垂直运动

您可以通过创建最初所需的飘浮效果来改进应用程序。

  1. 为此形状的 y 坐标创建另一个时间线。
  2. translateY 实例变量绑定到 y 值,如以下代码片段所示:

    var y: Number;

    Timeline {
    repeatCount: Timeline.INDEFINITE
    autoReverse: true
    keyFrames: [
    at (0s) {y => 0.0},
    at (4s) {y => 55.0 tween Interpolator.LINEAR},
    ]
    }.play();
    ...

    Path{
    ...
    translateY: bind y
    ...
    }//Path
     

    注意:在四秒钟之后,y 变量达到其最大值位置,这比 x 变量要快。因此,translateY 值变化得比 translateX 快。这将产生漫游效果。

    以下是此示例的完整代码。

    import javafx.animation.Interpolator;
    import javafx.animation.Timeline;
    import javafx.stage.Stage;
    import javafx.scene.Scene;
    import javafx.scene.paint.Color;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.shape.ArcTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.effect.Lighting;
    import javafx.scene.effect.light.DistantLight;

    var x: Number;

    Timeline {
    repeatCount: Timeline.INDEFINITE
    autoReverse: true
    keyFrames: [
    at (0s) {x => 0.0},
    at (7s) {x => 387.0 tween Interpolator.LINEAR},
    ]
    }.play();

    var y: Number;

    Timeline {
    repeatCount: Timeline.INDEFINITE
    autoReverse: true
    keyFrames: [
    at (0s) {y => 0.0},
    at (4s) {y => 55.0 tween Interpolator.LINEAR},
    ]
    }.play();

    Stage{
    title: "Cloud"
    visible: true
    scene:
    Scene{
    fill: Color.WHITE
    content:[
    ImageView{image:
    Image{url: "/docs/books/tutorial/2d/basic2d/examples/images/weather-sun.png"}
    },
    Path {
    translateX: bind x
    translateY: bind y
    fill: Color.WHITE
    stroke: Color.LIGHTBLUE
    strokeWidth: 2
    effect: Lighting{light: DistantLight{azimuth: 90}}
    elements: [
    MoveTo { x: 15 y: 15 },
    ArcTo { x: 50 y: 10 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 70 y: 20 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 50 y: 60 radiusX: 20 radiusY: 20 sweepFlag: true},
    ArcTo { x: 20 y: 50 radiusX: 10 radiusY: 5 sweepFlag: true},
    ArcTo { x: 15 y: 15 radiusX: 10 radiusY: 10 sweepFlag: true},
    ]
    }//Path
    ]
    }//Scene
    onClose: function() {
    java.lang.System.exit(0);
    }//close action

    }//Stage
     
    编译和运行之后,此代码将生成以下窗口。

     
    在窗口内反弹的云
    图 7:在窗口内反弹的云
     
     
总结

本课介绍了如何创建动画对象,并对插值动画进行了分析。请尝试使用本课中提到的概念和技巧来探究 JavaFX SDK 的其他动画功能。

原创粉丝点击