レベル2

目次

レベル-1
入門以前の知識の紹介。
レベル0
コンポーネントの使用。
レベル1
とことんShowMessage。
レベル2
じゃんけん。
レベル3
キャラの表示と十字移動。
レベル4
敵をつくってみよう。
レベル5
DelphiXを利用してみよう。
発展
発展的入門知識(矛盾?)。
ショートカットキー
ショートカットキーの紹介。
テクニック
さまざまなテクニックの紹介。

「早くゲーム作らせろ!」って思ってる人、いるかもしれませんが、基本をおさえるまでゲームには入りません。次の章まで待ちましょう。

今回は、「じゃんけん」を作ります。

TLabel

いままで文字を表示する方法はShowMessageしかやってませんでした。しかし、タイトルロゴとかを表示するのにShowMessageとかを使うのはどうなのって感じですよね?そこで、わざわざメッセージダイアログを表示させずにFormに直接文字を表示させる方法としてTLabelを使うというのがあります。

「じゃんけんゲーム」と表示させるためにTLabelを使ってみましょう。

まず、TButtonの三つ左の「A」と書かれたコンポーネントをクリックして、Tbuttonと同じ要領で貼り付けてください。これでTLabelが使えるようになりました。

最初は小さな文字で「Label1」と表示されてるだけだと思いますので、Captionプロパティを「じゃんけん」とでもしてください。次に、文字の大きさを変更するためにFontプロパティのところをダブルクリックして文字の大きさの設定をしてください。

グー・チョキ・パー

ボタンを三個用意して、Captionをそれぞれ「グー」「チョキ」「パー」にしてください。また、判りやすくするためにNameプロパティを「guu」「tyoki」「paa」にしてください。

次に、イベントの処理になります。じゃんけんにはいわゆる「三竦み」(さんすくみ)があり、相手との勝敗をif文で判定しなければならないのですが、とりあえずまず「ShowMessage('貴方の勝ちです')」と表示させるようにしてください。やり方はわかりますね?

とりあえず実行してみるわけですが、絶対勝ってしまうためじゃんけんになっていません。勝敗の判定はどうすればいいのでしょうか?とりあえず構想を練ってみると

///じゃんけん構想…これは実行できません。
//グーを出した時
procedure TForm1.guuClick(Sender: TObject);
begin
  if <相手> = <グー> then ShowMessage('あいこです');
  if <相手> = <チョキ> then ShowMessage('貴方の勝ちです');
  if <相手> = <パー> then ShowMessage('貴方の負けです');
end;

//チョキを出した時
procedure TForm1.tyokiClick(Sender: TObject);
begin
  if <相手> = <グー> then ShowMessage('貴方の負けです');
  if <相手> = <チョキ> then ShowMessage(あいこです');
  if <相手> = <パー> then ShowMessage('貴方の勝ちです');
end;

//パーを出した時
procedure TForm1.paaClick(Sender: TObject);
begin
  if <相手> = <グー> then ShowMessage('貴方の勝ちです');
  if <相手> = <チョキ> then ShowMessage('貴方の負けです');
  if <相手> = <パー> then ShowMessage('あいこです');
end;

まあ、大体こんなんだろうという構想は立てられます。

ところで今回いきなり「//グーを出した時」などといったものが出てきましたが、これはコメントです。行中で//を書くとコンパイラはその後の文字は無視してくれます。{}や、(**)で囲んでも同様です。(一部無視されない文字もあります)あとでみてもだれがみてもわかるプログラムにするために、コメントはまめに書きましょう。まあ書きすぎるのも問題ですが…

さて、これを作るに当たって一つの問題があります。それは「じゃんけんの時相手の手を記憶するコンポーネント、プロパティが存在しない」ということです。相手の出した手を記憶するものを自分で作る必要があります。そこで出てくるのが「変数」というものです。

変数について

変数

変数とは数字や文字を入れる箱のようなもので、いわゆる一時記憶の役割をします。

用途に沿って整数用、実数用、文字用などさまざまなタイプの変数が存在します。

このじゃんけんゲームでは相手の手を記憶するためにInteger型の変数を使います。

Integer
広い範囲の整数が入ります。恐らくもっとも使う場面が多い変数でしょう。使用バイト数は4バイトです。
「整数専用」ですので、負の数も入れる事ができます。小数や文字列をいれることはできません。マリオのHPは「ルイージ」だ!とか言われたら、コンピューターどころか人間でも混乱しますよね?
似たようなものにInt64Byte等が存在します。
Extended
広い範囲の実数が入ります。使用バイト数は10バイトです。
「実数専用」ですので、0.121のような小数も入れることができます。文字列を入れる事はできません。似たようなものにSingleDouble等が存在します。
String
文字列が入ります。使用バイト数は長さによって変わります。
「文字専用」ですので、整数などをそのまま入れることはできません。似たような物に1文字のみ入るCharが存在します。
Boolean
True(真)とFalse(偽)のみいれることができます。使用バイト数はたった1バイトです。

変数の宣言

変数を利用するには使う前にコンピューターに対して「この型をした、こんな名前の変数を使います」と宣言しなければなりません。

宣言は

Var 変数名,変数名:変数の型;

このように行います。(変数名の間にカンマを書けば複数の変数を同時に宣言することができます)

はじめのうちは{$R *.dfm}の下で宣言するのが良いでしょう。

使用例
{$R *.dfm}
  Var
    Mario_Hp,Mario_X,Mario_Y : integer;

ただ、procedureの後、beginの前にも書く事ができることを知っておいた方がいいです。(これをローカル変数といいます)主な用途は後で述べるFor文ですね。

これまた使用例
procedure TForm1(〜略〜)
  var
    Mario_Hp,Mario_X,Mario_Y : integer;
  begin (〜略〜)

変数のスコープ

スプーではありません。スコープです。

Wikipediaに結構わかりやすい説明が載ってたんで転載しときます。

プログラミングで、ある変数や関数が特定の名前で参照される範囲のこと。スコープ外にある名前は言語上存在しないのと同じ事である。このとき名前は「見えない」といわれる。プログラミングで予期しない誤作動を避けるためにも、必要のない名前はできるだけ参照されないことが望ましい(大域変数の危険性)。適切なスコープの判断は正しいプログラムを構成する上で重要である。

Delphiだと

var
  a:integer;
  
  implementation
  
{$R *.dfm}
var
  b:integer;
  
procedure TForm1.Button1Click(Sender: TObject);
var
  c:integer;
begin
end;

var
  d:integer;
  
procedure TForm1.Button2Click(Sender: TObject);
var
  e:integer;
begin
end;

aはこのユニットにリンクしてるユニットすべてで使えます。bはButton1ClickとButton2Click等で使えますが、cはButton1Clickでしか使えません。dはこれが宣言された後の場所…つまりButton2Click等でしかつかえません。eはButton2Clickだけです。

自分が作った変数を他人が間違えて使わないように、スコープには常に気をつける必要があります。

変数への代入(:=)…記憶するものに記憶をさせろ

右辺の計算結果を左辺の変数に代入します。右辺の計算結果を左辺の変数に対してに代入するためx+10:=152-51;などといったことはできません。

A:=100+A;

こうすればAにはA+100が代入され、結果的にAは100増えます。

代入をする時は、原則として同じ型同士のものでなければなりません(代入元の型が代入先の型に含まれる場合…小数型に整数を代入する場合等を除く)。

悪い例(Mario_Hpはinteger)
Mario_Hp:='ルイージ'
正しい例(Mario_Hpはinteger)
Mario_Hp:=0;

ちなみに、代入先が整数である場合、X:=X + 5;Inc(X,5);と書き換えができて、X:=X - 5;Dec(X,5);と書き換えられます。IncやDecを使った方がスマートになります。

算術演算子…+や-について

+
足し算。文字列を連結する事も可能です(例 name:='マリ'+'オ';)。
-
引き算。算数と大体同じ。
無駄知識かもしれませんが--とすると+になります。ホントに無駄知識ですね。
*
掛け算。算数の×、数学の・と大体同じです。
/
割り算。ちなみに5/0のように0で割るとエラーとなります。注意しましょう。
div
割った商。"整数 div 整数"と使います。(例 D:=15 div 7D=2となります。》)
mod
割った余り。これも"整数 mod 整数"と使います。(例 M:=15 mod 7D=1となります。》)

じゃんけんのおはなしにもどります

いきなりバーッって書いちゃいましたが大丈夫ですかね?じゃんけんの話にもどります。

まず、はじめのうちは{$R *.dfm}の下で宣言するのが良いでしょう。と書いたように、{$R *.dfm}の下に

{$R *.dfm}
 var
   Teki:integer;

と書いてください。これで「Teki」という名の変数ができました。練った構想を実際に書いてみましょう。

//0=グー、1=チョキ、2=パーとなっています。
//グーを出した時
procedure TForm1.guuClick(Sender: TObject);
begin
  if Teki = 0 then ShowMessage('あいこです');
  if Teki = 1 then ShowMessage('貴方の勝ちです');
  if Teki = 2 then ShowMessage('貴方の負けです');
end;

//チョキを出した時
procedure TForm1.tyokiClick(Sender: TObject);
begin
  if Teki = 0 then ShowMessage('貴方の負けです');
  if Teki = 1 then ShowMessage(あいこです');
  if Teki = 2 then ShowMessage('貴方の勝ちです');
end;

//パーを出した時
procedure TForm1.paaClick(Sender: TObject);
begin
  if Teki = 0 then ShowMessage('貴方の勝ちです');
  if Teki = 1 then ShowMessage('貴方の負けです');
  if Teki = 2 then ShowMessage('あいこです');
end;

このプログラムを実行してみましょう。うまく実行できたものの、毎回相手の手がグーになってしまったかと思います。

何故毎回グーになったのかというと、Tekiに一度も代入してないため、初期値の0になってしまっているのです。これを防ぐためには、ボタンを押すたびにTekiに適当なランダムな数字を代入する必要があります。

ランダムな数字を呼び出すためにはRandom関数を使います。Random関数にランダムを呼び出す範囲を指定すれば、0からその長さぶんの間の数の乱数が選ばれます。

Random関数を付け加えると

//0=グー、1=チョキ、2=パーとなっています。
//グーを出した時
procedure TForm1.guuClick(Sender: TObject);
begin
  Teki:=Random(3);///0から3の長さ…つまり0,1,2
  if Teki = 0 then ShowMessage('あいこです');
  if Teki = 1 then ShowMessage('貴方の勝ちです');
  if Teki = 2 then ShowMessage('貴方の負けです');
end;

//チョキを出した時
procedure TForm1.tyokiClick(Sender: TObject);
begin
  Teki:=Random(3);
  if Teki = 0 then ShowMessage('貴方の負けです');
  if Teki = 1 then ShowMessage('あいこです');
  if Teki = 2 then ShowMessage('貴方の勝ちです');
end;

//パーを出した時
procedure TForm1.paaClick(Sender: TObject);
begin
  Teki:=Random(3);
  if Teki = 0 then ShowMessage('貴方の勝ちです');
  if Teki = 1 then ShowMessage('貴方の負けです');
  if Teki = 2 then ShowMessage('あいこです');
end;

こうなります。これでじゃんけんが完成しました。

発展

Randomize

このプログラムを何度も実行すればわかるかと重いますが、起動してから相手が出すパターンが毎回同じです。これはコンピュータが命令されたとおりにしか動かないため「適当な数字をえらぶ」ということができず、呼び出した回数を元に数を選んでしまうため完全なランダムにならないのです。

この問題を解決するためにはForm1のOnCreateイベントに「Randomize;」と一行付け足すだけで解決できます。Randomizeは呼び出した時刻によって乱数を初期化するもので、コンピュータが時間を元に数字を選ぶ→起動ごとにちゃんと違った数が選び出される…となるのです。

case文で綺麗にまとめる

このプログラム、case文で次のようにまとめることができます。case文を使えばプログラムが読みやすくなるので、使える時は使った方が得です。跡で使わないといけない時も出てきます。

//グーを出した時
procedure TForm1.guuClick(Sender: TObject);
begin
  case Random(3) of
    0:ShowMessage('あいこです');
    1:ShowMessage('貴方の勝ちです');
    2:ShowMessage('貴方の負けです');
  end;
end;

//チョキを出した時
procedure TForm1.tyokiClick(Sender: TObject);
begin
  case Random(3) of
    0:ShowMessage('貴方の負けです');
    1:ShowMessage('あいこです');
    2:ShowMessage('貴方の勝ちです');
  end;
end;

//パーを出した時
procedure TForm1.paaClick(Sender: TObject);
begin
  case Random(3) of
    0:ShowMessage('貴方の勝ちです');
    1:ShowMessage('貴方の負けです');
    2:ShowMessage('あいこです');
  end;
end;