Gjs で Clutter Actor に動きをつける

Clutter の Actor に動きをつける方法を調べてみた。 devhelp の ClutterActor の Animation に書かれているように、暗黙の指定と明示的な指定が可能らしい。しかし、明示的な指定で必要な ClutterInterval を利用するためには

let interval = new Clutter.Interval(GType);

しなければならないのだが、GType オブジェクトを生成する方法がわからなかったので、まもなく廃止される ClutterBehavior を使うことにする。

まずは、暗黙の指定のサンプル。

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

Clutter.init(null);

let stage = new Clutter.Stage({title:"Implicit"});
stage.set_background_color(Clutter.Color.get_static(Clutter.StaticColor.BLACK));
stage.connect('destroy', Clutter.main_quit);

let actor = new Clutter.Actor({reactive:true});
actor.set_background_color(Clutter.Color.get_static(Clutter.StaticColor.WHITE));
actor.set_position(100, 100);

let timeline = new Clutter.Timeline();
timeline.duration = 1000;
timeline.set_loop(true);
timeline.connect('completed', function (self, user_data) {
    actor.set_size(10, 10);
    actor.save_easing_state();
    actor.set_size(100, 100);
    actor.restore_easing_state();
});
timeline.start();

stage.add_actor(actor);
stage.show();

Clutter.main();

Clutter.Stage やClutter.Actor の生成は通常通り。Clutter.Timeline の使い方も以前書いたので省略。
今回のポイントは、

timeline.connect('completed', function (self, user_data) {
    actor.set_size(10, 10);
    actor.save_easing_state();
    actor.set_size(100, 100);
    actor.restore_easing_state();
});

の部分。complete シグナルが飛んでくるたびに、 actor のサイズを小さくして easing の状態を保存、その後で actor のサイズを大きくして easing の状態を復帰させるだけです。
こうすることで、大きくなる状態がアニメーションとして動作します。このように、save_easing_state() とrestore_easing_state() メソッドを使うと簡単にアニメーションができます。

次は、明示的なアニメーションです。

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

Clutter.init(null);

let stage = new Clutter.Stage({title:"Tween"});
stage.set_background_color(Clutter.Color.get_static(Clutter.StaticColor.BLACK));
stage.connect('destroy', Clutter.main_quit);

let actor = new Clutter.Actor({reactive:true});
actor.set_background_color(Clutter.Color.get_static(Clutter.StaticColor.WHITE));
actor.set_size(100, 100);
actor.set_position(100, 100);

let timeline = new Clutter.Timeline({duration:2000, loop:true, auto_reverse:true});

let alpha = new Clutter.Alpha({timeline:timeline,mode:Clutter.AnimationMode.EASE_IN_OUT_BOUNCE});

let behave = new Clutter.BehaviourScale({alpha:alpha, x_scale_start:1, y_scale_start:1, x_scale_end:0.1, y_scale_end:0.1});
behave.apply(actor);
timeline.start ();

stage.add_actor(actor);
stage.show();

Clutter.main();

Clutter.Timeline のコンストラクタで プロパティの初期値を JSON 形式で指定しています。それ以外は、一般的なコードです。

Clutter.Alpha とは、時間経過で値を計算してくれるクラスです。このクラスも廃止される運命なので、本来なら Clutter.Timeline の progress_mode プロパティを使うべきです(devhelp では progress-mode となっていますが、 mode をそのまま使えないので - ではなく _ を使って一つの単語として認識させるようにします)。モードは、派手派手な Clutter.AnimationMode.EASE_IN_OUT_BOUNCE にしてみました。モードの図解は、devhelp の ClutterAlpha を見てください。

Clutter.BehaviourScale は拡大縮小の動作を変更するクラスで、 Clutter.Behaviour を親クラスに持ちます。 Scale 以外にも Depth Ellipse Opacity Path Rotate などいろいろあるので試してみてください。

コンストラクタで Clutter.Alpha を指定しているので、わざわざ apply() メソッドは不要だと思うのですが、これがないと動作しないようです。

とりあえず、これでアニメーションはできるようです。Clutter.Interval クラスの使い方が判明したら、別途記事を書こうと思います。