矢印キーで画像を移動する

C# DirectX で矢印キーの操作で画像を移動します。

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

プロジェクトの設定

  1. 次のファイルを格納して下さい。
    /***************************************/
    /*★ 矢印キーで画像を移動    前田 稔 ★*/
    /***************************************/
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using Microsoft.DirectX;
    using Microsoft.DirectX.DirectDraw;
    
    namespace DXDraw
    {
        public class DXDraw : Form
        {
            String      ImgFile = "C:\\Data\\Test\\emiko_s.bmp";
            Device      draw = null;        // DrawDevice object.
            Surface     primary = null;     // primary destination surface.
            Surface     image = null;       // Image surface.
            Surface     offscreen = null;   // offscreen surface
            Rectangle   dest,sou;           // 受取側と送り側の矩形領域
            int         xp=10, yp= 48;      // 描画座標
            int         width, height;      // Image Size
            bool        flg= true;
    
            public DXDraw()
            {
                ClientSize = new System.Drawing.Size(640, 480);
                Text = "DXDraw";
                this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyEvent);
                //Image File をロードしてサイズを取得
                Bitmap bmp = new Bitmap(ImgFile);
                width = bmp.Width;
                height = bmp.Height;
                bmp.Dispose();
                CreateSurfaces();
            }
    
            // This function Draws the offscreen bitmap surface to the primary visible surface.
            private void Draw()
            {
                if (null == primary)    return;
                if (FormWindowState.Minimized == WindowState)   return;
                if (flg == false) return;
                flg = false;
                Height = Height < 50 ? 50 : Height;
                dest = new Rectangle(PointToScreen(new Point(0, 0)), ClientSize);
    
                try
                {
                    primary.Draw(dest, offscreen, DrawFlags.Wait);
                }
                catch(SurfaceLostException)
                {
                    CreateSurfaces();       // Surface was lost. Recreate them.
                }
            }
    
            // This function is where the surfaces and clipper object are created.
            private void CreateSurfaces()
            {
                // Create new DrawDevice.  coop level normal windowed mode.
                draw = new Device();
                draw.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);
                // Create primary surface.
                SurfaceDescription description = new SurfaceDescription();
                description.SurfaceCaps.PrimarySurface = true;
                primary = new Surface(description, draw);
                // Create image surface.
                description.Clear();
                image = new Surface(ImgFile, description, draw);
                // Create offscreen surface.
                description.Clear();
                description.SurfaceCaps.OffScreenPlain = true;
                description.Width = this.Width;
                description.Height = this.Height;
                offscreen = new Surface(description, draw);
                offscreen.ColorFill(Color.White);
                dest = new Rectangle(xp, yp, width, height);
                offscreen.Draw(dest, image, DrawFlags.Wait);
            }
    
            //protected override void OnKeyDown(KeyEventArgs e)
            private void OnKeyEvent(object sender, System.Windows.Forms.KeyEventArgs e)
            {
                switch(e.KeyCode)
                {   case Keys.Escape:
                        Application.Exit();
                        break;
                    case Keys.Left:
                        xp--;
                        break;
                    case Keys.Right:
                        xp++;
                        break;
                    case Keys.Up:
                        yp--;
                        break;
                    case Keys.Down:
                        yp++;
                        break;
                    default:
                        return;
                }
                offscreen.ColorFill(Color.White);
                dest = new Rectangle(xp, yp, width, height);
                sou = new Rectangle(0, 0, width, height);
                if (xp < 0)
                {
                    dest.Width += xp; dest.X = 0;
                    sou.Width += xp; sou.X = 0 - xp;
                }
                if (yp < 0)
                {
                    dest.Height += yp; dest.Y = 0;
                    sou.Height += yp; sou.Y = 0 - yp;
                }
                offscreen.Draw(dest, image, sou, DrawFlags.Wait);
                flg= true;
            }
    
            //☆ Main() メソッド
            static void Main()
            {
                // using で資源の解放を確実に行う
                using (DXDraw frm = new DXDraw())
                {
                    frm.CreateSurfaces();      // Create Draw Surfaces
                    frm.Show();
    
                    // メッセージループ
                    while(frm.Created)
                    {
                        frm.Draw();
                        Application.DoEvents();
                    }
                }
            }
        }
    }
    
  2. ImgFile は描画する画像ファイルの名前です。
    image は画像ファイルを入力してイメージを生成する領域です。
    offscreen は primary と同じサイズで、座標(xp,yp)からイメージを描画して primary に一括転送する領域です。
    dest, sou は受取側と送り側の矩形領域です。
    xp, yp は画像を描画する座標です。
    width, height は画像の幅と高さを格納する領域です。
    flg が矢印キーが押されて画像が移動したことを記憶するフラグです。
            String      ImgFile = "C:\\Data\\Test\\emiko_s.bmp";
            Device      draw = null;        // DrawDevice object.
            Surface     primary = null;     // primary destination surface.
            Surface     image = null;       // Image surface.
            Surface     offscreen = null;   // offscreen surface
            Rectangle   dest,sou;           // 受取側と送り側の矩形領域
            int         xp=10, yp= 48;      // 描画座標
            int         width, height;      // Image Size
            bool        flg= true;
        
  3. OnKeyEvent はキー入力を処理するイベントハンドラです。
    new Bitmap() で ImgFile を調べて画像の幅と高さを格納します。
            public DXDraw()
            {
                ClientSize = new System.Drawing.Size(640, 480);
                Text = "DXDraw";
                this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnKeyEvent);
                //Image File をロードしてサイズを取得
                Bitmap bmp = new Bitmap(ImgFile);
                width = bmp.Width;
                height = bmp.Height;
                bmp.Dispose();
                CreateSurfaces();
            }
        
  4. surface を取得する CreateSurfaces です。
    primary surface を取得します。
    画像を入力して image surface を生成します。
    primary surface と同じサイズの offscreen surface を生成します。
    offscreen surface に最初に描画するイメージを描画します。
        private void CreateSurfaces()
        {
            // Create new DrawDevice.  coop level normal windowed mode.
            draw = new Device();
            draw.SetCooperativeLevel(this, CooperativeLevelFlags.Normal);
            // Create primary surface.
            SurfaceDescription description = new SurfaceDescription();
            description.SurfaceCaps.PrimarySurface = true;
            primary = new Surface(description, draw);
            // Create image surface.
            description.Clear();
            image = new Surface(ImgFile, description, draw);
            // Create offscreen surface.
            description.Clear();
            description.SurfaceCaps.OffScreenPlain = true;
            description.Width = this.Width;
            description.Height = this.Height;
            offscreen = new Surface(description, draw);
            offscreen.ColorFill(Color.White);
            dest = new Rectangle(xp, yp, width, height);
            offscreen.Draw(dest, image, DrawFlags.Wait);
        }
        
  5. 矢印キーを検出する OnKeyEvent メソッドです。
    Escape キーがタイプされるとプログラムを終了します。
    上下左右の矢印キーで、描画する座標(xp,yp)を更新します。
    座標が更新されたとき、offscreen をクリアして新しい座標からイメージを描画します。
    このとき xp,yp が offscreen の領域からはみ出すとエラーで中断してしまいます。
    xp,yp が負になったとき、画像がどのように描画されるか考えて下さい。
    offscreen に新しいイメージが描画されると flg を true に設定して画面を更新します。
        private void OnKeyEvent(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            switch(e.KeyCode)
            {   case Keys.Escape:
                    Application.Exit();
                    break;
                case Keys.Left:
                    xp--;
                    break;
                case Keys.Right:
                    xp++;
                    break;
                case Keys.Up:
                    yp--;
                    break;
                case Keys.Down:
                    yp++;
                    break;
                default:
                    return;
            }
            offscreen.ColorFill(Color.White);
            dest = new Rectangle(xp, yp, width, height);
            sou = new Rectangle(0, 0, width, height);
            if (xp < 0)
            {
                dest.Width += xp; dest.X = 0;
                sou.Width += xp; sou.X = 0 - xp;
            }
            if (yp < 0)
            {
                dest.Height += yp; dest.Y = 0;
                sou.Height += yp; sou.Y = 0 - yp;
            }
            offscreen.Draw(dest, image, sou, DrawFlags.Wait);
            flg= true;
        }
        
  6. メッセージループから呼び出される Draw() メソッドでが flg が true のときに primary に描画します。
    new DXDraw() で Form を生成して frm.CreateSurfaces() で surface を取得します。
            private void Draw()
            {
                if (null == primary)    return;
                if (FormWindowState.Minimized == WindowState)   return;
                if (flg == false) return;
                flg = false;
                Height = Height < 50 ? 50 : Height;
                dest = new Rectangle(PointToScreen(new Point(0, 0)), ClientSize);
    
                try
                {
                    primary.Draw(dest, offscreen, DrawFlags.Wait);
                }
                catch(SurfaceLostException)
                {
                    CreateSurfaces();       // Surface was lost. Recreate them.
                }
            }
        }
        

【演習】

  1. xp, yp が offscreen の領域からはみ出すとエラーで中断してしまいます。
    このプログラムでは xp, yp が負になったとき、画像がどのように描画されるか考えて下さい。
  2. xp, yp が負の場合しかプログラムされていませんが、大きくなったときも同様の処理が必要です。
    負の場合に準じて、大きい場合もプログラムして下さい。

超初心者のプログラム入門(C# Frame Work)