Demo 2

さて、Demo2 プログラムである。このデモでは新しく DGCImageLib Component を使用しているが、それ以外にもいくつか重要な点がある。それも含めて順番に見ていくことにしよう。

procedure TForm1.DGCScreen1Initialize(Sender: TObject);
begin
     //Draw stuff on the hidden surface
     DrawFrame;

     //Quickly fade palette to black
     DGCScreen1.FadePaletteOut(1);

     //Flip the hidden surface with the visible one so you can
     //see it on the screen - but you can't see it yet cause the
     //palette is still black???
     DGCScreen1.Flip;

     //Finally Smoothly fade the palette in
     DGCScreen1.FadePaletteIn(100);

     //Copy the Front surface to the back buffer so
     //both surfaces contain the same info
     DGCScreen1.Back.BltFast(0, 0, DGCScreen1.Front, DGCScreen1.Front.ClientRect, False);

     //Initialise the image attributes (for my crude bounce code)
     x := 150;
     y := 200;
     yvel := 1;
     xvel := 2;

     //Now Start the page flipping
     DGCScreen1.FlippingEnabled := True;
end;

OnInitialize イベントの中で一番最初に DrawFrame が呼び出されている。しかし何も新しいことはしていない。大事なのは、描き終わったら Canvas.Release を呼び出すことぐらいだろう。変化が無いので DrawFrame と OnKeyPress の説明は、今回はしない。

  DGCScreen1.Back.BltFast(0, 0, DGCScreen1.Front, DGCScreen1.Front.ClientRect, False);

このメソッドは、イメージのコピーを行うメソッドである。この場合は Front の画面全体を、Back の座標(0,0)へ転送している。最後のパラメーターが False になっているのは、「転送する際に透過しない」と言う意味である。なお、この一行の代わりに、

  DrawFrame;

と書いても結果は同じである。

次に、x,y,xvel,yvel の各変数の初期値を代入している。これらの変数は、Form の private で定義されているので、このユニット内からであれば自由に参照できる。ではこの変数を実際に何に使っているのかと言えば、今回のデモプログラムの主人公であるキャラクターの座標(x,y)及びそれらの変数の増分であるが、その話は後回しにする。

  //Now Start the page flipping
  DGCScreen1.FlippingEnabled := True;

ここで新しいプロパティが出てきた。FlippingEnabled って何?

Demo1 のプログラムで、Flip というメソッドが出てきたのを覚えていると思う。Flip は呼び出された時に画面を切り替える(もちろん、Front と Back)メソッドだったが、FlippingEnabled はこれを自動で切り替えるようにするかどうかを決めるプロパティである。こいつを True にしておくと、かってに切り替えを始めるのである。

ではいつ切り替えるのか? これは重要だが、ちゃんと考えられている。TApplication の OnIdle イベントで呼び出されるのだ。このイベントは、Windows がやることが無くて暇になった時に呼び出される。つまり、そのシステムで最適なタイミングで呼び出されるのである。これにより同じ時間でも、早いマシンではより多く、遅いマシンでは少ない回数の画面書き換えをすることになる。当然早いマシンの方が、画面がスムーズに動いて見えるので快適に遊ぶことが出来る。逆に遅いマシンでも、画面の切り替えが少なくてぎこちない動きをするかもしれないが、遊べないよりはマシということになる。

procedure TForm1.DGCScreen1Flip(Sender: TObject);
begin
     //Erase the area theat the sprite will bounce in
     DGCScreen1.Back.EraseRect(Rect(0, 200, 640, 468), 0);

     //Now Draw the Sprite
     DGCScreen1.Back.Draw(x, y, DGCScreen1.Images[0], False);

     //Update the Images X position
     Inc(x, xvel);
     if (x < 0) or (x > 500) then
        xvel := -xvel;

     //Update the y position using yvel
     Inc(y, yvel);

     //Uncrease the Velocity and make sure it is in a range
     Inc(yvel);
     if yvel > 18 then yvel := 18;
     if yvel < -18 then yvel := -18;

     //If the image has reached the bottom then reverse direction
     if y > 380 then
     begin
          y := 380;
          yvel := -yvel;
     end;
end;

FlippingEnabled が True のとき、実際に呼び出されるのはこの OnFlip イベントである。それでは、順番に見ていこう。最初は EraseRect を使って部分的に画面をクリアしている。このデモプログラムでは、画面の下の部分を使って、キャラクターを移動させているので、こうしておかないと動いた後に残像が残ってしまう。そういう効果を出したいこともあるので、一度この行をコメントにして実行してみると良い。

さて、問題は次の行である。ここで新しい DGSImageLib Component が登場する。どこに? と思うかもしれないが、まずは DGCScreen Component のプロパティを見てほしい。そこに、ImageLibrary というプロパティがあるはずだ。今回のデモプログラムでは、そこが DGCImageLib1 になっていると思う。DGCScreen1.Images[0] とは、「DGSImageLib Component の Images プロパティの一番目のイメージ」という意味になる。そのイメージを、Back に Draw しているわけだが、それだけ解っていても、実際に自分で使うとなると困ることになる。

それは、DGCImageLib Component にイメージを割り当てるには DGCImageLib Component の Images プロパティに「何か」を読み込ませるわけだが、その「何か」が DGC 専用のイメージライブラリだからである。なぜそうなっているかというと、標準の TImageList では、イメージのサイズが一定になってしまうからである。その他にも理由は考えられるが、それは次回以降で説明する。そしてイメージライブラリを作るには、イメージライブラリエディタを使う必要があるからである。

それでは、イメージライブラリエディタの使い方を簡単に説明しておこう。まずは DGC をインストールしたディレクトリの下にある、Tools ディレクトリを見てほしい。この中に ImgLib.exe があるはずなので、そいつを実行する。次に「Open Bitmap Image」でビットマップを読み込む。ツールバーにボタンがあるはずである。この時、256 色以外のビットマップは読み込めないので注意すること。( DGC 自体が、256 色にしか対応していないので、当たり前である)

読み込んだら、今度は左下にある「Add Current Image To Library」を押す。すると、リストボックスにイメージが追加されたのが解ると思う。いくつかイメージを読み込んで追加した後は、「Save Image Library」でセーブする。これがイメージライブラリである。使い方が分かったところで、デルファイの「ツール」メニューの追加しておくと良い。「ツール」−「ツールの設定」で出来る。この他にもいくつかツールがあるが、全て登録しておくと後が楽だ。

さて、イメージライブラリが出来たら、こいつを DGCImageLib Component に読み込ませる。DGCImageLib Component の Images プロパティであるが、今回のデモではすでに読み込まれているので、ここは変更しなくても良い。もちろん、自分の作った絵を動かしたいのであれば、やってみると良い。

本題のプログラムに戻ると、x の値に xvel を加え、x が範囲外に出たら跳ね返る処理をしている。当たり前の処理なので、これ以上の説明はしない。

次に y の値を更新しているが、重力の効果が加わっただけでほぼ x と同じである。このような計算はゲームの基本となるので、知らなかった人はここで覚えておくと良い。

procedure TForm1.DGCScreen1Paint(Sender: TObject);
begin
     //The paint event should only be called when surfaces are lost. This
     //can be caused when application switching with ALT+TAB.
     DrawFrame;
     DGCScreen1.Flip;
     DrawFrame;
end;

最後に OnPaint イベントである。前回に比べて DrawFrame が一つ増えているのは、FlippingEnabled が True になっているからである。こうしておかないと、OnPaint イベントが終わった瞬間に OnFlip が発生した時に、一瞬真っ暗な画面が表示される。これは Direct Draw が全画面で使用される時、もし画面を切り替えてしまうと、今まで画面用として使っていた領域を開放してしまい、切り替わる前の画面の内容を保証しないためである。本来ならここでゴミが写っているはずだが、おそらく DGCScreen が初期化しているのであろう。

これで Demo1 プログラムの説明は終わりである。ここまで理解できれば、自分で何か簡単なプログラムを作ることが出来るはずである。

もどる