AnimationClock を使ってアニメーション動画を作る(1)

トップページへ

 AnimationClock を使用したアニメーションの紹介

  1.DoubleAnimationUsingKeyFrames を使用したアニメーション(2D) (このページ)
  2.Transform を使った円のアニメーション(2D)
  3.指定された経路上で円を運動させるアニメーション(2D)
  4.TileMode で描画された画像のアニメーション(2D)
  5.自公転する立方体のアニメーション(3D)
  6.立方体の表示にタイムラグを設けるアニメーション(3D)
  7.ClockGroup を使ったアニメーション−基本編(2D)
  8.ClockGroup を使ったアニメーション−応用編(2D)
  9.残像を形成するアニメーション(2D)

なお、これらの動画は、「ソフト関連Trial−No.109」で紹介しています。

 DoubleAnimationUsingKeyFrames を使用したアニメーション動画の作成方法(2D)

すでに「ソフト関連Trial−No.108」で、DoubleAnimation を使ったアニメーション動画の作成方法を紹介しているので、ここでは DoubleAnimationUsingKeyFrames を使用した動画作成例を紹介します。

1.作成するアニメーションの内容
このアニメーションは以下のように構成されています。
 (1)Canvas の左端に配置された Rectangle を 2 秒間で右方向に 450 の位置まで移動させます。
 (2)次の5 秒間で Rectangle を左方向に 50 の位置まで移動させる。
 (3)次の1 秒間で Rectangle を右方向に 200 の位置まで移動させる。
 (4)次の2 秒間で Rectangle を左側の端まで移動させる。
このようなアニメーションは単純な DoubleAnimation では作成できないために、 DoubleAnimetionUsingKeyFrames を使用してアニメーションを生成します。

アニメーション作成の画面は以下のようになります。


2.使用した開発環境
以下の開発環境を使用しました。
開発環境:Visual Studio 2010 Professional Edition
.NET Framework:.NET Framework 4 Client Profile
古いバージョンを使いましたが、最新の開発環境でも問題なく使用できると思います。

3.XAMLコード
XAMLコードでは、Canvas と ボタン類を配置します。
なお、ボタンのサイズ、位置、フォントなどを設定する記述は省略しています。

<Window x:Class="Example01_DoubleAnimationUKF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="530" Height="360"
    WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
 <Grid>
  <Grid.RowDefinitions>
   <RowDefinition Height="280"/>
   <RowDefinition Height="*"/>
  </Grid.RowDefinitions>
  <Canvas Name="cvs1" Grid.Row="0" Background="White" />
  <StackPanel Grid.Row="1" Orientation="Horizontal" Background="LightGray">
   <Button Name="btnStart" Content="開 始" Click="btnStart_Click" />
   <Button Name="btnStop" Content="停 止" Click="btnStop_Click" />
   <Button Name="btnAvi" Content="Avi" Click="btnAvi_Click" />
  </StackPanel>
 </Grid>
</Window>

4.C#コード
C#コードで、Rectangle を Canvas上に配置して、左右に動かすアニメーションを記述します。

  // usingによって名前空間を参照するコードの部分は省略
  
  public partial class MainWindow : Window
  {
    // コンストラクター
    public MainWindow()
    {
      InitializeComponent();
      InitializeWindow();
    }

    private const int TIME = 10;      // アニメーションの所要時間
    private AnimationClock _clock;     // [InitializeWindow]で初期化

    // [Avi]ボタンクリックイベント
    private void btnAvi_Click(object sender, RoutedEventArgs e)
    {
      var filepath = GetAviFilePath();
      if (0 < filepath.Length)
      {
        SaveAsAvi(filepath);
        MessageBox.Show("OK");
      }
    }

    // [開始]ボタンクリックイベント
    private void btnStart_Click(object sender, RoutedEventArgs e)
    {
      _clock.Controller.Begin();
    }

    // [停止]ボタンクリックイベント
    private void btnStop_Click(object sender, RoutedEventArgs e)
    {
      _clock.Controller.Stop();
    }

    // アニメーション(DoubleAnimationUsingKeyFrames)の定義
    private DoubleAnimationUsingKeyFrames DaUKF()
    {
      var frames = new DoubleAnimationUsingKeyFrames();

      var lframe1 = new LinearDoubleKeyFrame
      {
        KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0)),
        Value = 0
      };
      var lframe2 = new LinearDoubleKeyFrame
      {
        KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 2)),
        Value = 450
      };
      var lframe3 = new LinearDoubleKeyFrame
      {
        KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 7)),
        Value = 50
      };
      var lframe4 = new LinearDoubleKeyFrame
      {
        KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 8)),
        Value = 200
      };
      var lframe5 = new LinearDoubleKeyFrame
      {
        KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 10)),
        Value = 0
      };

      frames.KeyFrames.Add(lframe1);
      frames.KeyFrames.Add(lframe2);
      frames.KeyFrames.Add(lframe3);
      frames.KeyFrames.Add(lframe4);
      frames.KeyFrames.Add(lframe5);
      frames.BeginTime = new TimeSpan(0, 0, 0);
      frames.Duration = new TimeSpan(0, 0, 10);
      frames.RepeatBehavior = RepeatBehavior.Forever;

      return frames;
    }

    // Aviファイル保存パス取得
    private string GetAviFilePath()
    {
      // 省略
    }

    // Rectangleの配置とRectangleへのアニメーションの適用
    private void InitializeWindow()
    {
      // Rectangleの生成と配置
      var rect1 = new Rectangle();
      rect1.Width = 50;
      rect1.Height = 50;
      Canvas.SetLeft(rect1, 0);
      Canvas.SetTop(rect1, 100);
      rect1.Fill = Brushes.Blue;
      cvs1.Children.Add(rect1);

      // アニメーション生成とRectangleへの適用
      var animation = DaUKF();
      _clock = animation.CreateClock();
      rect1.ApplyAnimationClock(Canvas.LeftProperty, _clock);
      _clock.Controller.Stop();
    }

    // Aviファイル作成
    private void SaveAsAvi(string filepath)
    {
      var fps = 48;              // フレームレート
      var totalFrames = fps * TIME;   // 全フレーム数
      var secs = Enumerable.Range(0, totalFrames).Select(t => (((double)t) / fps));
      var aviManager = new AviFile.AviManager(filepath, false);
      AviFile.VideoStream aviStream = null;
      var tempFile = "frame.png";

      foreach (var sec in secs)
      {
        _clock.Controller.SeekAlignedToLastTick(TimeSpan.FromSeconds(sec),
                            TimeSeekOrigin.BeginTime);
        cvs1.UpdateLayout();
        cvs1.SaveImage(tempFile);      // cvs1の画像をファイルに保存する
        var bmp = new System.Drawing.Bitmap(tempFile);
        if (aviStream == null)
          aviStream = aviManager.AddVideoStream(true, fps, bmp);
        else
          aviStream.AddFrame(bmp);
        bmp.Dispose();
      }
      aviManager.Close();
      _clock.Controller.Stop();
      System.IO.File.Delete(tempFile);
    }
  }

アニメーションの生成などは[InitializeWindow]メソッド内の以下のコードで行います。
  var animation = DaUKF();        // アニメーションの生成
  _clock = animation.CreateClock();   // AnimationClockへの割り当て
  rect1.ApplyAnimationClock(Canvas.LeftProperty, _clock); // RectangleのCanvas.LeftPropertyへの割り当て
  _clock.Controller.Stop();       // AnimationClockの一時停止

アニメーションの開始は、[開始]ボタンクリックイベントの以下のコードで行います。
  _clock.Controller.Begin();

アニメーションの停止は、[停止]ボタンクリックイベントの以下のコードで行います。
  _clock.Controller.Stop();

Aviファイル作成のためにフレーム画像を取り出す操作は、[SaveAsAvi]メソッド中の以下のコードで行います。
  _clock.Controller.SeekAlignedToLastTick(TimeSpan.FromSeconds(sec),
                      TimeSeekOrigin.BeginTime);

Aviファイルを作成する[SaveAsAvi]メソッドの中間付近にある以下のコードは、Canvas の画像をファイルに保存する拡張メソッドです。
  cvs1.SaveImage(tempFile);
この拡張メソッドのコードは、こちら で参照してください。

 ダウンロード

ここで紹介したアニメーションを作成するプロジェクトファイルは、以下のリンクからダウンロードすることができます。
「Example01_DoubleAnimationUKF」プロジェクトファイルのダウンロード
なお、このプロジェクトでは、AVIファイル化用クラスライブラリとして、Code Project の「 A Simple C# Wrapper for the AviFile Library 」からダウンロードして入手した[AviFile.dll]を使用しています。

ダウンロードしたファイルの利用は、全て利用される方の責任で行っていただきます。
作者は十分な注意を払って本ファイルを作成していますが、もし万一、本ファイルの内容に誤りがあっても、 またその利用によって使用パソコンに問題が発生しても、作者は一切責任を負いません。

 公開・更新履歴

 2017/09/01 ページを公開しました。

 ご質問・ご意見・ご感想

ご質問、ご意見、ご感想等の連絡は、 こちらへ

トップページへ