アニメーションクラス

高精度タイマでアニメーションを行うクラスを作成します。
C言語(Windows)でも シップが爆発するアニメーション を作成しています。
爆発アニメーションの画像は ANIME Class でアニメーション から取得して下さい。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. 高精度タイマを利用したアニメーションクラスを使って、プログラムを作成します。
    @"c:\data\test\Bomb.gif" は、爆発アニメーションの画像です。
    /***************************************/
    /*★ アニメーション Class    前田 稔 ★*/
    /***************************************/
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    public class MyForm : Form
    {
        [DllImport("User32.dll")]
        static extern short GetAsyncKeyState(int vKey);
    
        ANIME   App;
        private Timer timer1;
        private System.ComponentModel.IContainer components;
    
        // Constructor
        public MyForm()
        {
            // timer1
            components = new System.ComponentModel.Container();
            timer1 = new System.Windows.Forms.Timer(this.components);
            SuspendLayout();
            timer1.Interval = 15;
            timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // MyForm
            BackColor = SystemColors.AppWorkspace;
            this.Width = 640;
            this.Height = 480;
            SetStyle(ControlStyles.DoubleBuffer, true);
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            App = new ANIME(@"c:\data\test\Bomb.gif",128,128);
            Paint += new PaintEventHandler(MyHandler);
            timer1.Start();
        }
    
        // 画像を描画
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.Bmp == null) Application.Exit();
            App.View(g);
        }
    
        // タイマー割り込み
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (GetAsyncKeyState(0x1B)!=0)  Application.Exit();
            App.Next(1000000);
            if (GetAsyncKeyState(0x20)!=0)  App.Set(0,50,50);
            Invalidate();
        }
    }
    
    //☆ アニメーションクラス
    class ANIME
    {
        public  Bitmap  Bmp;
        public  Point   Size;   //Sprite の幅と高さ
        public  int     Wn;     //横の枚数
        public  int     Max;    //画像を切り分けた枚数
        public  int     Num;    //現在の Sprite 番号
        public  long    Vtim;   //Sprite を描画した時刻
        public  float   X, Y;   //Sprite の座標
        public  float   DX, DY; //Sprite の移動量
    
        // Constructor
        public ANIME(string file, int w, int h, int x, int y)
        {   Init(file, w, h, x, y);  }
        public ANIME(string file, int w, int h)
        {   Init(file, w, h, 0, 0);  }
    
        public void Init(string file, int w, int h, int x, int y)
        {
            try
            {   Bmp = new Bitmap(file);  }
            catch
            {
                MessageBox.Show("イメージが取得できません", "Error");
                return;
            }
            Size = new Point(w, h);
            X = x;
            Y = y;
            Wn = Bmp.Width / w;
            Max = (Bmp.Height/h) * Wn;
            Num = 99;
            Vtim = DateTime.Now.Ticks;
        }
    
        // 画像全体を描画
        public void View(Graphics g, int x, int y)
        {   if (Bmp!=null)  g.DrawImage(Bmp,x,y);   }
    
        // Sprite を描画
        public void View(Graphics g)
        {   View(g,Num,(int)X,(int)Y);  }
        public void View(Graphics g, int n, int x, int y)
        {
            if (Bmp==null || n>=Max)    return;
            Rectangle des = new Rectangle(x, y, Size.X, Size.Y);
            Rectangle sou = new Rectangle((n%Wn)*Size.X,(n/Wn)*Size.Y,Size.X,Size.Y);
            g.DrawImage(Bmp,des,sou,GraphicsUnit.Pixel);
        }
    
        // Sprite 番号と座標の設定
        public void Set(int num,float x,float y)
        {   Num= num;
            X = x;
            Y = y;
        }
        public void Set(int num,float x,float y,float dx,float dy)
        {   Num= num;
            X = x;
            Y = y;
            DX = dx;
            DY = dy;
        }
    
        // 次の画像に切り替える
        public void Next(long tim)
        {   if (Num<Max)
            {   long  nowTime = DateTime.Now.Ticks;
                if ((Vtim+tim) < nowTime)
                {
                    Vtim = nowTime;
                    Num++;
                }
            }
            else Num = 99;
        }
        public void Loop(long tim)
        {   if (Num<Max)
            {   long nowTime = DateTime.Now.Ticks;
                if (Vtim+tim < nowTime)
                {
                    Vtim = nowTime;
                    Num = (Num + 1) % Max;
                }
            }
            else Num = 99;
        }
    
        // 座標の更新(Rectangle を超えると削除)
        public void Update(Rectangle rect)
        {
            if (Num==99)  return;
            X += DX;
            Y += DY;
            if (X<rect.Left || X>rect.Right || Y<rect.Top  || Y>rect.Bottom)
            {   Num = 99;
                return;
            }
        }
    
        // 座標の更新(Rectangle でバウンドする)
        public void Bound(Rectangle rect)
        {
            if (Num==99)  return;
            X += DX;
            Y += DY;
            if (X<rect.Left || X>rect.Right)    DX = 0-DX;
            if (Y<rect.Top  || Y>rect.Bottom)   DY = 0-DY;
        }
    }
    
    class form01
    {
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  2. class ANIME が、アニメーションのクラスです。
    Bmp が、アニメーション用の画像領域です。
    Point Size; が、Sprite の幅と高さです。
    int Max; が、画像を切り分けた Sprite の枚数です。
    int Num; が、現在描画中の Sprite の番号です。
    long Vtim; は、画像を切り替えた時刻の領域で、long tim の時間が経過すると次の Sprite に切り替えます。
    float X, Y; は、アニメーション描画する座標です。
    float DX, DY; は描画座標の移動量で、座標を移動しながらアニメーションすることが出来ます。
    画像の切り分けとアニメーションの基礎は Sprite を切り替える を参照して下さい。
        public  Bitmap  Bmp;
        public  Point   Size;   //Sprite の幅と高さ
        public  int     Wn;     //横の枚数
        public  int     Max;    //画像を切り分けた枚数
        public  int     Num;    //現在の Sprite 番号
        public  long    Vtim;   //Sprite を描画した時刻
        public  float   X, Y;   //Sprite の座標
        public  float   DX, DY; //Sprite の移動量
        
  3. Constructor で画像と Sprite の情報を設定します。
    file が画像ファイルの名前で、w, h が Sprite の幅と高さで、x, y が描画する座標です。
        // Constructor
        public ANIME(string file, int w, int h, int x, int y)
        {   Init(file, w, h, x, y);  }
        public ANIME(string file, int w, int h)
        {   Init(file, w, h, 0, 0);  }
        
  4. Sprite を描画するメソッドです。
    番号 Num の Sprite を、座標 x,y から描画します。
        public void View(Graphics g)
        {   View(g,Num,(int)X,(int)Y);  }
        public void View(Graphics g, int n, int x, int y)
        {
            if (Bmp==null || n>=Max)    return;
            Rectangle des = new Rectangle(x, y, Size.X, Size.Y);
            Rectangle sou = new Rectangle((n%Wn)*Size.X,(n/Wn)*Size.Y,Size.X,Size.Y);
            g.DrawImage(Bmp,des,sou,GraphicsUnit.Pixel);
        }
        
  5. Sprite 番号と座標を設定するメソッドです。
    Sprite 番号は最初 99(描画しない)に設定されています。
    アニメーションを開始するときは、Set() メソッドで番号と座標を設定して下さい。
        public void Set(int num,float x,float y)
        {   Num= num;
            X = x;
            Y = y;
        }
        public void Set(int num,float x,float y,float dx,float dy)
        {   Num= num;
            X = x;
            Y = y;
            DX = dx;
            DY = dy;
        }
        
  6. 次の Sprite に切り替えるメソッドです。
    番号が Max(Sprite の枚数)になると 99 を設定してアニメーションを終了します。
        public void Next(long tim)
        {   if (Num<Max)
            {   long  nowTime = DateTime.Now.Ticks;
                if ((Vtim+tim) < nowTime)
                {
                    Vtim = nowTime;
                    Num++;
                }
            }
            else Num = 99;
        }
        
  7. アニメーションを繰り返すメソッドも用意しています。
    こちらは Max(Sprite の枚数)になると 0 に戻りアニメーションを繰り返します。
        public void Loop(long tim)
        {   if (Num<Max)
            {   long nowTime = DateTime.Now.Ticks;
                if (Vtim+tim < nowTime)
                {
                    Vtim = nowTime;
                    Num = (Num + 1) % Max;
                }
            }
            else Num = 99;
        }
        
  8. 描画座標を更新するメソッドです。
    Rectangle を超えると 99 を設定して停止します。
        // 座標の更新(Rectangle を超えると削除)
        public void Update(Rectangle rect)
        {
            if (Num==99)  return;
            X += DX;
            Y += DY;
            if (X<rect.Left || X>rect.Right || Y<rect.Top  || Y>rect.Bottom)
            {   Num = 99;
                return;
            }
        }
        
  9. 描画座標が Rectangle でバウンドするメソッドです。
        // 座標の更新(Rectangle でバウンドする)
        public void Bound(Rectangle rect)
        {
            if (Num==99)  return;
            X += DX;
            Y += DY;
            if (X<rect.Left || X>rect.Right)    DX = 0-DX;
            if (Y<rect.Top  || Y>rect.Bottom)   DY = 0-DY;
        }
        
  10. class ANIME を使ってアニメーションする MyForm クラスです。
    App に爆発画像(Bomb.gif)を設定します。
    MyHandler() メソッドでアニメーションを描画します。
    timer1_Tick() でスペースキー(0x20)を検出して、アニメーションを開始します。
    App.Next(1000000); で画像を切り替えます。
        ANIME   App;
        App = new ANIME(@"c:\data\test\Bomb.gif",128,128);
    
        // 画像を描画
        private void MyHandler(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (App.Bmp == null) Application.Exit();
            App.View(g);
        }
    
        // タイマー割り込み
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (GetAsyncKeyState(0x1B)!=0)  Application.Exit();
            App.Next(1000000);
            if (GetAsyncKeyState(0x20)!=0)  App.Set(0,50,50);
            Invalidate();
        }
        
  11. 少女の髪が風になびくアニメーションもテストしてみて下さい。
        App = new ANIME(@"c:\data\test\Girl.gif",128,216);
        App.View(g, 10, 10);
        App.Loop(2000000);
        

前田稔(Maeda Minoru)の超初心者のプログラム入門