ClutterTimeline を使う

タイマーを利用してアニメーションを実施するために、 ClutterTimeline を使ってみます。はじめは C です。

#include <clutter/clutter.h>

void
on_completed (ClutterTimeline *timeline, gpointer user_data) 
{
    ClutterActor *actor;
    gfloat x, y;
    
    actor = * (ClutterActor**)user_data;
    clutter_actor_get_position (actor, &x, &y);
    if (x > 100)
    {
        clutter_actor_set_position (actor, 100, 100);
    }
    else
    {
        clutter_actor_set_position (actor, 200, 200);
    }
}

int
main (int argc, char *argv[])
{
    ClutterStage *stage;
    ClutterActor *actor;
    ClutterTimeline *timeline;
    
    if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
        return 1;
    stage = (ClutterStage*) clutter_stage_new ();
    g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);

    actor = clutter_actor_new ();
    clutter_actor_set_background_color (actor, clutter_color_get_static (CLUTTER_COLOR_RED));
    clutter_actor_set_size (actor, 100, 100);
    clutter_actor_set_position (actor, 100, 100);
    
    timeline = clutter_timeline_new (2000);
    clutter_timeline_set_repeat_count (timeline, -1);
    g_signal_connect (timeline, "completed", G_CALLBACK (on_completed), &actor);
    clutter_timeline_start (timeline);

    clutter_actor_add_child ((ClutterActor*) stage, actor);
    clutter_actor_show ((ClutterActor*) stage);
    clutter_main ();
    return 0;
}

ClutterTimeline の completed シグナルを使って on_completed() を呼び出しています。 clutter_actor_position() を利用して (100, 100) と (200, 200) を交互に 2 秒間隔で動かしています。
ClutterTimeline の使い方は簡単で、 clutter_timeline_new() で duration (タイマー設定:ミリ秒単位)で作成し、clutter_timeline_set_repeat_count() で繰り返し回数を指定 (-1 は無限) します。繰り返しを無限に繰り返すにために、以前はclutter_timeline_set_loop() を使っていましたが、これは廃止される予定です。
後は、 g_signal_connect() でシグナルを登録し、 clutter_timeline_start() でタイマーを開始させます。

GJS では以下のようになります。

#! /usr/bin/env gjs
const Clutter = imports.gi.Clutter;

function on_completed (timeline) 
{
    let [x, y] = actor.get_position();
    if (x > 100) {
        actor.set_position(100, 100);
    } else {
        actor.set_position(200, 200);
    }
}

Clutter.init(null);
let stage = new Clutter.Stage();
stage.connect('destroy', Clutter.main_quit);

let actor = new Clutter.Actor();
actor.set_background_color(Clutter.Color.get_static (Clutter.StaticColor.RED));
actor.set_size(100, 100);
actor.set_position(100, 100);

let timeline = new Clutter.Timeline({duration:2000});
timeline.set_repeat_count(-1);
timeline.connect('completed', on_completed);
timeline.start();

stage.add_child(actor);
stage.show();
Clutter.main();

Gjs のシグナルでは user_data 引数が使えません。ま、 let でactor を作っているので、グローバル変数としてそのまま利用できるのでよしとします。