Clutter学习(十一):动态效果设置ClutterBehaviour

来源:互联网 发布:java考试题 编辑:程序博客网 时间:2024/05/19 00:16

  根据教程,我们应学习ClutterAnimation,但是在这里我碰到了一些问题,我不确定是否是Clutter1.0的问题,从某种意义上看,Clutter0.9比Clutter1.0更为稳定。我们已经一而再地讨论了clutter的兼容,但是我想仍需要再三讨论这个问题。现在,我们学习类似的处理效果ClutterBehaviour,我认为所有ClutterAnmation均可以通过ClutterBehaviour来进行处理。消灭问题或者绕开问题,一直是中国传统哲学的一个特点。

  学习资料来源:Using BehaviourExample,以及clutter 1.0的联机文档。

  在ClutterTimeline中,可以根据new-frame触发来进行动态图像处理,但是new-frame的触发频率依赖于monitor,我们不能精确地控制动作发生的时间过程。而ClutterBehaviour提供一种在指定时间内完成某个动作的方式。

  下面是一个例子,我们去除了具体的动作效果,先讨论ClutterBehaviour如何工作。我们提供了两个动态效果,例如如果图像从大到小,那么另一个效果就是从小到大,已是的整个动作连贯。

#include <clutter/clutter.h>
#include <stdlib.h>

int main(int argc,char * argv[]){
    ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
    clutter_init (&argc, &argv);

    /* Get the stage and set its size and color: */
    ClutterActor *stage = clutter_stage_get_default ();
    clutter_actor_set_size (stage, 800, 600);
    clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

    /* Add a rectangle to the stage: */
    ClutterActor * rect  = clutter_texture_new_from_file("4.png",NULL);
    clutter_actor_set_position (rect, 200, 200);
    clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
    clutter_actor_show (rect);

    /* Show the stage: */
    clutter_actor_show (stage);

    /* 加两个顺序执行的timeline,周期均为10秒 */
    ClutterScore * score = clutter_score_new();
    clutter_score_set_loop(score,TRUE);
    ClutterTimeline *timeline1 = clutter_timeline_new(10000);
    ClutterTimeline *timeline2 = clutter_timeline_new(10000);
    clutter_score_append(score,NULL,timeline1);
    clutter_score_append(score,timeline1,timeline2);

    /* ClutterAlpha是个很有趣的参数,简单说他将某个运动的模式和timeline进行捆绑,例如我们定义在某个timeline的有效时间内,动态的效果是线性的。如果这个效果作用于一个移动的动作(在下面定义),则表示匀速运动,如果亮度的渐变方式,表示均速变化。Clutter提供了丰富的模式,详细可以参见联机文档:/usr/share/gtk-doc/html/clutter/clutter-Implicit-Animations.html#CLUTTER-LINEAR--CAPS。*/
    ClutterAlpha *alpha1 = clutter_alpha_new_full (timeline1, CLUTTER_LEANAR);
    ClutterAlpha *alpha2 = clutter_alpha_new_full (timeline2, CLUTTER_EASE_OUT_BOUNCE);
    g_object_unref (timeline1);
    g_object_unref (timeline2);

    /* … …,这里我们创建两个动作behaviour1和behaviour2,具体在后面讨论,先略去*/

    /* 将某个动作和具体的actor关联。这个actor将在timeline的有效时间内,根据运动模型,进行具体的动作*/
    clutter_behaviour_apply (behaviour1, rect);
    clutter_behaviour_apply (behaviour2, rect);
    clutter_score_start(score);

    clutter_main ();

    return EXIT_SUCCESS;
}

Clutter提供了六种的动作方式,具体的可以参见联机文档,我们在下面分别讨论:

这里给出两种动作,一种是椭圆运动方式。如果我们想使用逆时针旋转,方向设置为CLUTTER_ROTATE_CCW,但是初始角度要大于最后角度,应设置为……,CLUTTER_ROTATE_CCW,360.0,0);请注意角度是不能超过360度,如果需要连续旋转两周,可以设置两个timeline,分别旋转1周。后一种是Z轴的depth,但是在平面的图像中,我确实比较难理解Z的变化,从现在上看类似于Scale,而且不会小于图像本上大小。

ClutterBehaviour *behaviour1 = clutter_behaviour_ellipse_new( alpha1,
     300,               /* center x */
     200,               /* center y */
     400,               /* width */
     300,               /* height */
     CLUTTER_ROTATE_CW, /* direction */
     0.0,               /* initial angle */
     360.0);            /* final angle */

ClutterBehaviour *behaviour2 = clutter_behaviour_depth_new( alpha2,
200,
20
);

一个clutter的可能bug的处理如果我们不是要求马上进行动态运动,即我们不在main中调用clutter_score_start(),而是在程序的其他地方,例如某个回调函数,在检测到用户某个实现后触发,我们会发现actor并不在我们期待的位置。不在我们创建actor时指定的问题,也不在我们运动要求的初始位置。对于运动,clutter的默认初始位置为(0,0),如果是椭圆运动,默认运动中心为(0,0),根据我们运动范围和初始角度,将位置设置为(200,0),这显然不是我们所期待。在这种情况下,我们可以在clutter_behaviour_apply后面加上clutter_actor_set_position(rect,500,200)来修正我们的位置。我不实际了解depth动作的具体含义,这个不清除如何矫正。但是在这个例子中他的作用相当于scale,我们用scale的变化方式替代,scale是可以修正的。

下面是亮度渐变的方式。从暗到亮,在从亮到暗,循环进行。

ClutterBehaviour *behaviour1 = clutter_behaviour_opacity_new( alpha1,40,255);
ClutterBehaviour *behaviour2 = clutter_behaviour_opacity_new( alpha2,255,40);

路径移动,可以进行直线移动,也可以进行曲线移动。请注意clutter_path_add_move_to是非常重要的。如果不设置,初始位置为(0,0)。这是耗费了小时计算的时间才找到的解决方法。

ClutterPath * path1 = clutter_path_new();
clutter_path_add_move_to(path1,100,100);
clutter_path_add_line_to(path1,600,400);
ClutterBehaviour *behaviour1 = clutter_behaviour_path_new(alpha1,path1);
ClutterPath * path2 = clutter_path_new();
clutter_path_add_move_to(path2,600,400);
clutter_path_add_curve_to(path2,400,500,200,500,100,100);
ClutterBehaviour *behaviour2 = clutter_behaviour_path_new( alpha2,path2);

指定移动的路线,可以设置多个点,移动的方式是直线

ClutterKnot knot1[3],knot2[2];
  knot1[0].x = 50;
  knot1[0].y = 50;
  knot1[1].x = 100;
  knot1[1].y = 300;
  knot1[2].x= 600;
  knot1[2].y= 400;
  knot2[0].x = 600;
  knot2[0].y = 400;
  knot2[1].x= 50;
  knot2[1].y= 50;

ClutterBehaviour *behaviour1 = clutter_behaviour_path_new_with_knots( alpha1,knot1,3);
ClutterBehaviour *behaviour2 = clutter_behaviour_path_new_with_knots( alpha2,knot2,2);

旋转,同样如果需要反时针转动,设置为CLUTTER_ROTATE_CCW,并且初始角度大于最终角度。

ClutterBehaviour *behaviour1 = clutter_behaviour_rotate_new( alpha1,CLUTTER_Y_AXIS,CLUTTER_ROTATE_CW,0,360.0);
clutter_behaviour_rotate_set_center((ClutterBehaviourRotate *)behaviour1,20,0,50);
ClutterBehaviour *behaviour2 = clutter_behaviour_rotate_new( alpha2,CLUTTER_X_AXIS,CLUTTER_ROTATE_CW,0,360.0);

大小变化,这个比较简单。

ClutterBehaviour *behaviour1 = clutter_behaviour_scale_new(alpha1,0.5,0.5,3,2);
ClutterBehaviour *behaviour2 = clutter_behaviour_scale_new(alpha2,3,2,0.5,0.5);

关于动态效果

下面的这个图很好地表明的动态效果和时间轴的关系。

各类的动态效果,可以看下图,来自联机文档:

 

附:可能的一些bug

  ClutterBehavior初始位置的设定可能存在bug。例如clutter_behaviour_ellipse_new,这是个椭圆运动,无论我们如何设置椭圆的中心,clutter会按照中心为(0,0),根据范围,和初始角度设置初始位置。同样对于直线运动方式,初始会设置在(0,0),都需要修正。
  如果我们将动作变化在main函数中触发貌似正常,但是如果我们屏蔽了时间轴(或者时间轴集)的启动,就很清楚地看到clutterBehavior设置的初始位置,显然不是我们预计的。
  如果我们在callback函数中设置clutterBehavior或者启动时间轴,就会在触发的时候,在clutter自认为的初始位置中闪现,除非我们在clutter_behaviour_apply后面用set_position来进行修正。这等于需要我们重新计算位置。
  如果变化不是位置的变化,例如depth的变化,那么在我们apply的时候就设置为会初始化,而不是在时间轴启动的时候才进行。这会影响我们的实现,因为变化可能是ClutterScore非第一个时间轴,例如是第二个时间轴,他将会在score启动的时候,在其初始状态上进行闪现。这会严重影响我们的效果。因此需要避免相关情况。
  这是一个测试的例子:

#include <clutter/clutter.h>
#include <stdlib.h>

ClutterActor *rect = NULL;
ClutterBehaviour *behaviour1 = NULL , * behaviour2 = NULL;
ClutterScore * score = NULL;

void set_motion(){
        score = clutter_score_new();
        clutter_score_set_loop(score,TRUE);

        ClutterTimeline *timeline1 = clutter_timeline_new(10000);
        ClutterTimeline *timeline2 = clutter_timeline_new(10000);
        clutter_score_append(score,NULL,timeline1);
        //clutter_score_append(score,timeline1,timeline2);

        ClutterAlpha *alpha1 = clutter_alpha_new_full (timeline1,
         CLUTTER_EASE_IN_OUT_QUAD);//CLUTTER_EASE_IN_SINE);
        ClutterAlpha *alpha2 = clutter_alpha_new_full (timeline2,
         CLUTTER_EASE_OUT_BOUNCE);//CLUTTER_EASE_IN_SINE);
        g_object_unref (timeline1);
        //g_object_unref (timeline2);

        ClutterBehaviour *behaviour1 = clutter_behaviour_ellipse_new(
         alpha1,
         300,               /* center x */
         200,               /* center y */
         400,               /* width */
         300,               /* height */
         CLUTTER_ROTATE_CCW, /* direction */
         360.0,               /* initial angle */
         0.0);            /* final angle */

        ClutterBehaviour *behaviour2 = clutter_behaviour_depth_new(
         alpha2,
         200,
         20
         );
        clutter_behaviour_apply (behaviour1, rect);
        //clutter_behaviour_apply (behaviour2, rect);
        clutter_actor_set_position(rect,500,200);
        clutter_score_start(score);
}

static gboolean on_key_press(ClutterStage * stage ,
                ClutterEvent * event,
                gpointer *user_data){
        float x = 0;
        float y = 0;
        clutter_actor_get_position (rect, &x, &y);

        g_print ("rect  at (%f, %f)/n", x,y);
        set_motion();


        return TRUE;
}

int main(int argc,char * argv[]){
        ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
        //ClutterColor rect_color = { 0xff, 0xff, 0xff, 0x99 };

        clutter_init (&argc, &argv);

        /* Get the stage and set its size and color: */
        ClutterActor *stage = clutter_stage_get_default ();
        clutter_actor_set_size (stage, 800, 600);
        clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

        /* Add a rectangle to the stage: */
        //rect = clutter_rectangle_new_with_color (&rect_color);
        //clutter_actor_set_size (rect, 40, 40);
        rect  = clutter_texture_new_from_file("4.png",NULL);
        clutter_actor_set_position (rect, 500, 200);
        clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
        clutter_actor_show (rect);

        /* Show the stage: */
        clutter_actor_show (stage);


        g_signal_connect(stage,"key_press_event",G_CALLBACK(on_key_press),NULL);


        //set_motion();

        clutter_main ();

        return EXIT_SUCCESS;
}

相关链接:
我的Clutter相关博客

 

原创粉丝点击