클러터(Clutter) 사용하기 (4)

클러터 튜토리얼 계속 이어집니다.

타임라인 (Timelines)

ClutterTimeline 은 시간이 흐르는 동안 액터의 모양이나 위치를 자동으로 변경하는데 사용합니다. 다음에 설명할 효과(effect)나 움직임(behaviour)와 함께 사용할 수도 있지만 직접 사용할 수도 있습니다.

타임라인 객체는 지정한 초당 프레임 수를 기준으로 시간이 되면 각 프레임이 그려질 수 있도록 new-frame 시그널을 발생합니다. 그러면 시그널 핸들러에서 액터의 속성을 변경하면 됩니다. 물론 스테이지에 있는 여러 액터의 속성을 동시에 변경할 수도 있습니다. (물론 이외에도 몇 가지 시그널이 더 있습니다)

타임라인 객체를 만드는 clutter_timeline_new() 함수는 총 프레임 수(n_frames)와 초당 프레임 수(fps)를 인수로 받습니다. 따라서 이 값을 기준으로 전체 지속 시간을 예측할 수 있습니다. 타임라인은 clutter_timeline_start() 를 호출해야 비로소 시작합니다. clutter_timeline_stop() 을 호출하기 전까지 clutter_timeline_set_loop() 를 이용하여 무한히 반복하게 할 수도 있습니다.

여러 타임라인을 동시에 시작하거나 정지, 또는 순서대로 실행하려면 ClutterScore 객체를 사용합니다. 일종의 타임라인 제어기 역할을 하는 셈입니다. clutter_score_append() 는 두 개의 타임라인을 인수로 받는데, 첫번째는 부모(parent) 타임라인이고 두번째가 추가할 타임라인입니다. 추가되는 타임라인은 부모가 끝난 다음에 실행됩니다. 부모가 NULL인 타임라인은 clutter_timeline_start() 을 호출하면 바로 시작합니다.

예를 들어 다음 예제는 timeline1이 끝난 다음에 timeline2, timeline3가 동시에 시작합니다.

  ClutterTimeline *timeline1, *timeline2, *timeline3;
  ClutterScore *score;

  timeline1 = clutter_timeline_new_for_duration (1000);
  timeline2 = clutter_timeline_new_for_duration (500);
  timeline3 = clutter_timeline_new_for_duration (500);

  score = clutter_score_new ();

  clutter_score_append (score, NULL,       timeline1);
  clutter_score_append (score, timeline1, timeline2);
  clutter_score_append (score, timeline1, timeline3);

  clutter_score_start (score);

클러터 액터와 달리 타임라인 객체는 부동 참조(floating reference)가 없기 때문에 사용이 끝난 다음에는 g_object_unref()로 리소스를 해제해야 합니다. 사용이 끝나는 시점이 모호할 경우 completed 시그널에 핸들러를 등록해서 처리해도 됩니다.

다음 예제는 하나가 끝난 뒤 다른 하나가 시작하는 두 개의 타임라인을 포함하는 하나의 스코어 객체를 보여줍니다. 이 스코어 객체는 무한히 반복하고, 첫번째 타임라인은 사각형을 회전시키며 두번째 타임라인은 사각형을 수평을 이동시킵니다.

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

ClutterActor *rect = NULL;

gint rotation_angle = 0;
gint color_change_count = 0;

/* 사각형을 회전시키고 색상을 변경 */
void
on_timeline_rotation_new_frame (ClutterTimeline *timeline,
                                gint             frame_num,
                                gpointer         data)
{
  rotation_angle += 1;
  if(rotation_angle >= 360)
    rotation_angle = 0;

  /* X축을 기준으로 시계방향으로 회전시킵니다. */
  clutter_actor_set_rotation (rect, CLUTTER_X_AXIS,
    rotation_angle, 0, 0, 0);

  /* 색삭을 변경합니다.
   * (This is a silly example, making the rectangle flash):
   */
  ++color_change_count;
  if(color_change_count > 100)
    color_change_count = 0;

  if(color_change_count == 0)
  {
    ClutterColor rect_color = { 0xff, 0xff, 0xff, 0x99 };
    clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
  }
  else if (color_change_count == 50)
  {
    ClutterColor rect_color = { 0x10, 0x40, 0x90, 0xff };
    clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
  }
}

/* 사각형 움직이기 */
void
on_timeline_move_new_frame (ClutterTimeline *timeline,
                            gint             frame_num,
                            gpointer         data)
{
  gint x_position = clutter_actor_get_x (rect);

  x_position += 1;
  if (x_position >= 150)
    x_position = 0;

  clutter_actor_set_x (rect, x_position);
}

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

  clutter_init (&argc, &argv);

  /* 스테이지를 얻어 크기와 색상을 정합니다. */
  ClutterActor *stage = clutter_stage_get_default ();
  clutter_actor_set_size (stage, 200, 200);
  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);

  /* 스테이지에 사각형을 추가합니다. */
  rect = clutter_rectangle_new_with_color (&rect_color);
  clutter_actor_set_size (rect, 70, 70);
  clutter_actor_set_position (rect, 50, 100);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
  clutter_actor_show (rect);

  /* 스테이지를 보이게 합니다. */
  clutter_actor_show (stage);

  /* 스코어 객체를 하나 만들어 타임라인 객체 두개를 추가합니다.
   * 두번째 타임라인은 첫번째가 멈춘 뒤에 시작합니다. */
  ClutterScore *score = clutter_score_new ();
  clutter_score_set_loop (score, TRUE);

  ClutterTimeline *timeline_rotation =
    clutter_timeline_new (200 /* 총프레임수 */, 120 /* 초당프레임수(fps) */);
  g_signal_connect (timeline_rotation, "new-frame",
                    G_CALLBACK (on_timeline_rotation_new_frame), NULL);
  clutter_score_append (score, NULL, timeline_rotation);

  ClutterTimeline *timeline_move =
    clutter_timeline_new (200 /* 총프레임수 */, 120 /* 초당프레임수(fps) */);
  g_signal_connect (timeline_move, "new-frame",
                    G_CALLBACK (on_timeline_move_new_frame), NULL);
  clutter_score_append (score,  timeline_rotation, timeline_move);

  clutter_score_start (score);

  /* 메인 이벤트 루프를 시작합니다. */
  clutter_main ();

  g_object_unref (timeline_rotation);
  g_object_unref (timeline_move);
  g_object_unref (score);

  return EXIT_SUCCESS;
}

이제 클러터를 이용한 기본적인 애니메이션 원리를 알게 되었군요.

comments powered by Disqus

Related