インデックスに戻る ←前のチャプター →次のチャプター

3.避けゲーを創る on Delphi

このチャプターを始める前に

前のチャプターで、1秒間に約60回画面を描画する、STGのソースコードのひな形ともいうべき物ができました。
あとは、キャラクターを任意の座標に表示させていくだけです。
が、具体的な作業を始める前に、このゲームをどのようなものにするか設計しておきましょう。
暫定的なものでも、目標ははっきりさせておいた方が、何が必要かがわかって有効です。

STGに出てくる自機と敵弾に必要そうな変数と関数を挙げてみましょう。

・変数
自機の座標、当たり判定、状態(これはレコード型を作って、それに格納する)
敵弾の座標、当たり判定、状態、絵の大きさ(これも同様にレコード型を作る)
得点、現在のフレーム数(これらはすぐには必要なさそう?)

・関数
当たり判定をする
弾を撃つ

同様にプログラムの流れも考えましょう。

・キー入力を受け取り自機の座標を計算する
・敵弾を出す
・敵弾を動かす
・当たり判定をする
・描画する

普段からゲームをやっていれば理解できると思います。プログラムの具体的な流れと必要な変数や関数はあとで同時に考えましょう。
足りないものがあったら後から追加すればいいんだから気楽に。

1.自機を創る

今回のチャプターの内容を取り入れて完成したソースとバイナリです。ダウンロードはこちらから。ただし、最初は以下の説明に沿って前回のソースに、コードを追加していって下さい。

自機を創る

自機を表示する

まず、自機となる画像を作ってください。ここでは64×64としましょう。
面倒だったら、同梱の画像ファイルを使ってもらっても構いません。
dg.bmpとしてソースファイルのあるフォルダに保存しておきましょう。
ここで注意するべきはbmpファイルは減色しようなどとせず、普通にフルカラーで保存して下さい。
理由は詳しくは述べませんが、減色したbmpファイルはこの講座に限っては、トラブルの原因になると思って下さい。

今回は下の画像を自機として使用します。
dg.bmp画像

自機用レコード型を作る

Delphiにおけるレコード型というのは、C言語における構造体のような物で、複数の変数(メンバ変数)を一つの変数にまとめて持つ事が出来ます。
今回、TPlayerというレコード型を作り、下のように座標と画像データをもつ変数を持たせます。

(Interface部でTPlayer型のレコード型を宣言。)


  //自機のレコード型。とりあえず現段階では座標だけ
  TPlayer = record
    x:integer;//x座標
    y:integer;//y座標
    Texture:TDGTexture;//主人公機画像入れ
  end;

Seventh Delphiの旧 Delphi 入門を一通り読んだ方ならわかると思いますが、
上記のようにTPlayerというレコード型を作っておいて、
実際TPlayer型変数として使いたいところで、
player:TPlayer;
のように変数を作るわけです。
今回は、TForm1のメンバーとしてplayerを宣言しておきます。

座標等の変数を宣言したら、最初にどこかで呼ばれるまでに
player.x:=320
のように、何らかの値を入れてやらないといけません。
これが変数の初期化という奴です。
今回は、Form1のOnCreateイベントで初期化を行うことにします。

(以下をForm1のOnCreateイベントに追加する)


  player.x:=320;
  player.y:=240;

また、 今回から、少しですが、クラスの知識が必要になります。
上のTPlayer型レコードのメンバーとしてTDGTextureクラス型のTexture変数があるからです。
現段階で、クラスに関してはレコード型+αとだけ考えてください。
その+αの部分は、クラス型変数を初期化する場合には、

(以下をTForm1Createに追加する)


  player.Texture:=TDGTexture.Create(DG, DGFMT_ARGB);

のようにcreateを使う必要があると言うこと。
そして、クラスに入っているデータが不要になったら、
(Form1のOnDestroyイベントに追加する)


  player.free;

のように、freeを使う必要だとだけ覚えていてくれれば結構です。
ちなみに、Player.Textureをcreateしたら、続いて、Player.Textureの設定を行うために、以下のコードを追加して下さい。

(Form1のOncreateイベントで、player.Texture:=TDGTexture.Create(DG, DGFMT_ARGB);の後に追加する)


  Player.Texture.BorderColor:=$00000000;             //ボーダー色は透明・黒
  Player.Texture.LoadFromFile('dg.bmp');             //画像読み込み
  Player.Texture.SetColorKey//黒(=$000000)を透過色とする
    (
      Rect(0,0,Player.Texture.Width,Player.Texture.Height),
      D3DCOLOR_ARGB(0,0,0,0) //ここは$000000と書いても$00000000と書いても0と書いても一緒。$を付けると16進数となる。
    );

上記の意味は、ここまでに既に読んでいるはずのQuadruple DのDG-Caradのチュートリアル第一章に述べられているとおりです。

試しに自機を表示させてみる

実際に、自機を表示させてみましょう。
前のチャプターで作ったputsprite手続きを使います。
下記の赤く書かれている部分を追加した後、コンパイル、実行して下さい。
自機が表示されれば成功です。
x,yそれぞれ-32している理由は、自機のキャラの大きさの半分だけずらして、自機の座標に自機の真ん中が来るようにしているわけです。
こうしておくと、後であたり判定を付けるときに少し楽になります。


////////////////////
//
//スプライト配置処理
//
/////////////////////
procedure TForm1.makegraphic;
begin
//画面のクリア、色は黒で
  Scene.Clear(D3DCLEAR_TARGET, $000000, 1.0, 0);
  
//先に他のプログラムに処理を行う。
//今回のプログラムではこれを入れなくても正常に動作するようだが、
//60FPSの作り出し方次第では、
//下の行を入れないとちゃんと動かない(ボタン入力がうまくいかないとか)ので一応。
//こりゃなんだ、と思う方は、Google等で調べて下さい。
application.processmessages;

//ここに各スプライトの配置処理を書く

//自機の座標に自機スプライトの中心を置きましょう
//つまり、64の半分だけずらす。
  putsprite(player.Texture,player.x-32,player.y-32);
end;

キーボードの十字キーで自機を移動させる

キーボードの十字カーソルキーに対応して自機を移動させます。
下記の赤く記されている部分を追加して下さい。
これによって、DDIDEXコンポーネントを使って、キーボードによる上下左右移動が可能となります。


////////////////////
//
//スプライト配置処理
//
/////////////////////
procedure TForm1.makegraphic;
begin
//画面のクリア、色は黒で
  Scene.Clear(D3DCLEAR_TARGET, $000000, 1.0, 0);
  
//先に他のプログラムに処理を行う。
//今回のプログラムではこれを入れなくても正常に動作するようだが、
//60FPSの作り出し方次第では、
//下の行を入れないとちゃんと動かない(ボタン入力がうまくいかないとか)ので一応。
//こりゃなんだ、と思う方は、Google等で調べて下さい。
  application.processmessages;

//ここに各スプライトの配置処理を書く

////自機の座標決め


  DDIDEX1.Scan(DI_KEYB);//キー入力チェックをする

  //↑キーが入力されていれば、DDIDEX1.Stick.Y=-1
  //↓キーが入力されていれば、DDIDEX1.Stick.Y=1
  //←キーが入力されていれば、DDIDEX1.Stick.X=-1
  //→キーが入力されていれば、DDIDEX1.Stick.X=1
  //が入力されているので、以下のような条件分けが可能になる。
  //ここらへん、DDIDEXサマサマで、簡潔な記述が可能になってありがたい。

  if (DDIDEX1.Stick.X*DDIDEX1.Stick.Y=0) then//縦横どちらか入力されていない時
    begin
      player.x:=player.x+(DDIDEX1.Stick.X)*3;
      player.y:=player.y+(DDIDEX1.Stick.Y)*3;
    end
  else                 //縦横どちらも入力されている時は移動速度を遅くする。
    begin
      player.x:=player.x+(DDIDEX1.Stick.X)*2;
      player.y:=player.y+(DDIDEX1.Stick.Y)*2;
    end;


//画面の外に行っちゃったら戻す。
  if (player.x>form1.clientWidth) then player.x:=form1.clientWidth
    else if (player.x<0) then player.x:=0;
  if (player.y>form1.clientheight) then player.y:=form1.clientheight
    else if (player.y<0) then player.y:=0;
//

//自機の座標に自機スプライトの中心を置きましょう
//つまり、64の半分だけずらす。
  putsprite(player.Texture,player.x-32,player.y-32);
end;

以下にもう少しくだいて説明します。(DDIDEXの詳細は、Quadruple Dのマニュアルを参照してください。)

Scan手続きにより、キーボードのどのボタンが押されているかをチェックします。


  DDIDEX1.Scan(DI_KEYB);//キー入力チェックをする

キーボードの上下左右の入力により、DDIDEX1.Stick.XとDDIDEX1.Stick.Yの値が変化しています。
そのことを利用して、上下左右に移動させます。また、斜め移動の際は、スピードを遅くさせます。


  //↑キーが入力されていれば、DDIDEX1.Stick.Y=-1
  //↓キーが入力されていれば、DDIDEX1.Stick.Y=1
  //←キーが入力されていれば、DDIDEX1.Stick.X=-1
  //→キーが入力されていれば、DDIDEX1.Stick.X=1
  //が入力されているので、以下のような条件分けが可能になる。
  //ここらへん、DDIDEXサマサマで、簡潔な記述が可能になってありがたい。

  if (DDIDEX1.Stick.X*DDIDEX1.Stick.Y=0) then//縦横どちらか入力されていない時
    begin
      player.x:=player.x+(DDIDEX1.Stick.X)*3;
      player.y:=player.y+(DDIDEX1.Stick.Y)*3;
    end
  else                 //縦横どちらも入力されている時は移動速度を遅くする。
    begin
      player.x:=player.x+(DDIDEX1.Stick.X)*2;
      player.y:=player.y+(DDIDEX1.Stick.Y)*2;
    end;

これは、自機の座標が画面の外に行かないようにするための処理です。


//画面の外に行っちゃったら戻す。
  if (player.x>form1.clientWidth) then player.x:=form1.clientWidth
    else if (player.x<0) then player.x:=0;
  if (player.y>form1.clientheight) then player.y:=form1.clientheight
    else if (player.y<0) then player.y:=0;

プログラムの世界では、中高数学とは違って、y軸は下向きが正であることが多いです。
Quadruple Dでも2Dの世界では、下向きがy軸の正方向になります。一応念のため。


次はたくさんの敵弾を表示させます。
配列(いまは静的配列だけで結構です)はどんなものだか理解しておいて下さい。


インデックスに戻る ←前のチャプター →次のチャプター