#はじめに
もう、ご存じの方も多いと思います。
無料なのに、ほとんどの機能が使えてしまうDelphi Community Editionが発表されました。
おかげさまで、VCL一筋だった私も、ついにFireMonkeyに手を出してみました。なにぶんにも、はじめてなもので、突っ込みどころ満載かと思います。あれ? とお気づきの点がありましたら、ご指摘のほどよろしくお願いします。
プログラム初心者さん向けを心掛けて書きました。楽しくプログラムとDelphiに興味を持って頂けたら、幸いです。
##Androidで動く、じゃんけんゲームを作ります
お題です。
Delphi Community Editionを使い、ごく簡単なじゃんけんゲームを作ります。
じゃんけんが大好きな幽霊さんと5回戦するじゃんけんゲームです。
##用意したもの
1.Windows パソコン(windows10 64bit)
2.Delphi Community Edition
3.Clip Studio Paint Pro
4.Androidで動くスマホ (Android6.0.1 VPA051 VAIO® Phone A)
※Delphi Community Editionとは何かについては、@pik様のこちらの記事を参照ください。
Delphi Community Edition
##では、つくってみましょう
今回作るのは、こんな画面になります。
##材料を用意しましょう。
###じゃんけん幽霊さんのイラスト
じゃんけん幽霊さんの画像を張ってゆきます。Clip Studio Paint で描いたものを、背景を透過にしたPng形式のデータです。余談ですけど、ストリエさんでも、物語作成に使用可能なイラストデータとして公開しています。これらを右クリックして保存してください。
待機 (ImageList1.Images[0]に格納します)
ぐー (ImageList1.Images[1]に格納します)
ちょき (ImageList1.Images[2]に格納します)
ぱー (ImageList1.Images[3]に格納します)
幽霊さんが勝ちました (ImageList1.Images[4]に格納します)
幽霊さんが負けました (ImageList1.Images[5]に格納します)
###じゃんけん、ぐー、ちょき、ぱぁの画像
ぐー (ImageList2.Images[0]に格納します)
ちょき(ImageList2.Images[1]に格納します)
ぱぁ (ImageList2.Images[2]に格納します)
##最初にどんな風にじゃんけんを数値化しようかな? を決めます。
ぐー、ちょき、ぱぁのデータ構造とアルゴリズム
まず、ぐぅ、ちょき。ぱぁ を数値化するルールを決めます。
簡単に、ぐぅ = 1、ちょき = 2、ぱぁ = 3 とします。
したがい、乱数で生成した幽霊さんの「手」と、あなたがイラストをクリックして出した「手」が等しい時は、「あいこ」と判定します。勝ち負けも数値の比較で行います。
たとえば……
もしも、あなたの「手」が ぐぅ 1 のとき、
幽霊さんの「手」が ちょき 2 ならば、あなたの勝ち ぱぁ 3 ならば、あなたの負けとなります。
これをあとで、Delphiのプログラム言語であるObject Pascalで表現します。
##画面を作ります
Delphiは、画面のデザインとプログラムのコーディングが綺麗に分かれています。
画面の一番下端に「コード / デザイン / 履歴」と3つタブがあります。デザインのタブを選択してください。
つぎに、インストールしたそのままの画面配置だったら、右下に ツールパレットがあります。
Delphi には驚くほどに数多くのコンポーネントがあります。
このたくさんあるコンポーネントが、Rapid Application Development(ラピッド・アプリケーション・デベロップメント)ツールである、Delphiが誇る鬼の生産性を支える力です。でも、呆れるほどたくさんあるので、図のように検索窓を使い絞り込んでみましょう。
さあ、作っていきましょう。
マウスで、ツールパレットからフォームへコンポーネントをぺたぺた貼り付けて、プロパティを設定することでつくれます。まだ、コード書く必要はありません。
####実際にコンポーネントをぺたぺた貼って画面を作ります。
まず、FormのNameプロパティを変えます。ここでは、fmMainとしました。From1のまま、変えなくてもいいのですが、unitの名前をFormのnameプロパティに合わせたかったため、変えています。(fmMains と、Formの名前+Sにしてます)
それでは、Panelから始めていきましょう。
まず、Panelをふたつ選び、貼り付けます。ツールパレットでPanelを選択している状態で、デザイン画面のフォームをクリックします。大きさと位置合わせは、Alignプロパティを使います。
プロパティの設定は、画面左下のオブジェクトインスペクタを使用します。プロパティのタブを選択して、リストをスクロールしてAlignを探してください。アルファベット順に並んでいますので、Alignは上の方にあります。見つけたら、下図のようにクリックして選択。それだけで設定完了です。画面上では、Panelがみょ~んと広がって、画面下へ張り付いたと思います。
Alignの設定順序には、ちょっとコツがあります。Top(上に張り付き),Left(左寄せ),Right(右寄せ),Bottom(下へ張り付き)を先に設定して、残った画面真ん中をClientにしてください。Clientは残りの画面全部に広がるため、最初に設定すると、他のコンポーネントがClientにしたコンポーネントの下へ隠れてしまいます。
####Glyphを貼り付けます。
次に、Glyphをツールパレットから選択して、Panel1(上のパネル)に貼り付け Align をClient にしてください。この場合、Panel1の中なので、Panel1の全体にGlyphが広がります。(ちょっと見た目がわかりにくいけど)
さらに、Rectangleを3つ、今度は下のPanel2へ貼り付けます。Alignは3つともLeftにします。Width つまり横幅を120にしてください。ついでにPanel2も height 高さを120にします。
それから、Rectangle の tagプロパティを それぞれ Rectangle1 =1 Rectangle2 =2 Rectangle2 =2 に設定します。
####さらに、Rectangle,Glyph,Textを選び、貼り付けます。
ツールパレットから、下図のようにRectangle,Glyph,Textを選び、貼り付けてください。
####コンポーネントには親子関係があります
そろそろ慣れてきましたでしょうか?
実は、ペタっと貼り付けても、図のようには配置できなかった方もいらっしゃるかもしれません。
それは、FireMonkey のコンポーネントには親子関係があるんです。(私も最近知りました^^) )
構造は画面右上にあります。ここにコンポーネントの親子関係が表示されています。デザイン画面でコンポーネントをクリックして選択すると、この構造画面でも選択状態になるので、「えっと、同じコンポーネントがたくさんあるんだけど…… どれ?」って、なったときは、先にデザイン画面で目的のコンポーネントをクリックしてください。
Glyphの2,3,4はきっと変な場所にあるはずなので、マウスでつかんでぐりぐりドラックしてください。親のコンポーネントの名前に被せてから、離すようにすると上手く子供の位置に入ります。
####ProgressBarを貼り付けます。
次は、ProgressBarです。じゃんけんは5回勝負のため、最大値 Max を 5、 最小値 Min を 0 にします。現在の値を保持している Value は 5 に設定してください。
####イラストを表示できるように設定します。
ImageListを画面に貼り付けてください。このImageListは自分自身は表示されず、他のコンポーネントにデータを渡してあげる荷物持ち担当のコンポーネントです。だから、Alignはありません。そして、荷物はと言うと…… ImageListの場合は、画像データです。ImageListを右クリックしてください。デザイナでも構造でもかまいません。画像リストエディタというのが、右クリックしたメニューにありますから、選択してください。
先ほどのイラストを保存して、順番にイメージリストエディタで追加してください。先ほどのイラストにもImageListのIndex番号を書き添えてあります。
0:待機
1:ぐぅ
2:ちょき
3:ぱぁ
4:幽霊さんが勝ち! Bang!
5:あなたが勝ち Good
この順に画像データを追加します。追加した順番にIndexが設定されます。
つぎに幽霊さんを表示するGlyph1の Images というプロパティを探してください。ImageList1を選択します。さらに、そのひとつ上、にある ImageIndex の値も 0 選択してください。初期値は-1ですが、ImageListに画像が仕込んである状態でImageIndexを選択すると、小さくて見づらいけど、ちゃんと幽霊さんの絵がドロップダウンリストに表示されます。最初は、0 待機の絵を選んでください。
####幽霊さんのセリフを用意します。
最後です。ListBoxを貼り付けてください。
0:最初のセリフ
1:最初はグーじゃんけんぽん
2:あいこでしょ
3:勝ち!
4:負け!
5:5回戦負け
6:5回戦勝ち
7:あと1つで勝ち
8:あと1つで負け
勝ち負けは、幽霊さんの視点で書いてます。セリフはアレンジしてください。
ListBoxのプロパティには、Itemsという文字列データを格納する場所があります。図のように「...」をクリックすると、文字列リストの設定画面が開きます。
Delphiでは 〇〇Listという名前のコンポーネントやオブジェクトがときどき登場します。それらは、Indexで番号がついた何かのリストを保持する役割を持っています。先ほどのImageListは画像データにindexを割り振って保存しました。こんどはString つまり文字列データを保持するコンポーネントです。
ここへ、幽霊さんのセリフを保存します。図のように改行すると、上から順にItemIndexの値が割り当てられます。
仕上げに、ListBox1のVisibleプロパティをFalseに変更してください。ListBox1は、今回はセリフを仕舞っておく舞台裏倉庫の役目を担ってもらいます。
以上で画面の制作は、一応、完了です。
###保存しましょう。
ファイルメニューにも、保存メニューがありますが、このスピードボタンが一番手っ取り早いです。
押すと……
最初の一回目の保存なので
・プロジェクトに名前を付けて保存
・ユニットに名前を付けて保存
こんな感じにダイアログボックスが聞いてきます。
保存場所は初期値では、マイドキュメントのフォルダーの中のEmbarcadero\Studio\Projectsになります。
ここへ適当な名前でサブフォルダーを作って保存してください。
とりあえず
・フォルダー名を 000JKUrei
・プロジェクトの名を pJKUrei
・ユニットの名を fmMains
としてみましょう。
#プログラムしましょう。
##前置き、凄くかんたんなオブジェクト指向について
Delphiでは、Object Pascal(オブジェクトパスカル) を使ってプログラムを書きます。
前振りとして、すご~く大雑把ですけど、オブジェクトについてイメージを説明します。
簡単にまとめると……
・オブジェクトには、画面に表示される姿や形が予め設定されています。
・オブジェクトが持つ様々な機能や、姿や形はプロパティを読み書きすることで操作できます。
・プログラムは、オブジェクトのイベントハンドラに書き込みます。
すぐ使うのは以上の3つです。
ほかにできたら……
・オブジェクトの持つ内部データは、外から直接は触れません。プロパティを通して読み書きします。
・オブジェクトには、メソッドという便利機能も用意されています。
というのも覚えてください。
プロパティは画面を作る過程で色々と設定しました。
###プログラムを書くのはunitファイルの中です。
Delphiでプログラムコードを書いてゆくのは、ウインドウごとにある unitの名前.pasファイルの中です。
コードのタブを選ぶとプログラムの画面が出ます。もう、システムが自動でコードを用意してくれています。
このUnitのファイル、大ざまっばにこんな構造になっています。
一番先頭に、unit fmMains; とあるのがユニットの名前です。先ほど「名前を付けて保存」をした名前になっているはずです。
次が、interface。unitの中身は、interface(インターフェイスセクション)と、少し下にある implementation(インプリメイテーションセクション)にわかれます。
・interface(インターフェイスセクション)は、プログラムで使う色々な物を宣言する場所です。
ちょうと、お買い物リストみたいなものと考えるとわかりやすいかも知れません。
・uses句は、このユニットから、他のライブラリやユニットを呼び出して使うためにあります。でも、ツールパレットからコンポーネントを張り付けている限りは、システムが自動的に必要なものを見繕ってくれます。とりあえず、お任せでかまいません。
・その下にあるのが、このフォーム(ウインドウ)をコードで表したものです。
type
TfmMain = class(TForm)
private
{ private 宣言 }
public
{ public 宣言 }
end;
このうち、privateと、publicの場所には、グローバル変数や処理を担当するprocedureやfunctionの宣言を記述します。システムが自動で作ってくれるものもありますが、手入力が必要な内容もあります。
・implementation(インプリメイテーションセクション)に、プログラムの本体を記述します。Delphiでは、プログラムは……
・procedure(プロシージャ)つまり、手続き。戻り値のない処理手続きを記載します。
・function (ファンクション)戻り値(Result)のある処理手続きを記載します。
このふたつに分かれます。
また、イベントハンドラなどコンポーネントから直接に呼び出されるものの他、いわゆるサブルーチン的なprocedure functionも作れます。
プログラムで使う小道具は、
・procedure function プログラム
・変数、定数
このふたつです。このふたつには次の図のようにスコープ(見える範囲)の決まりがあります。
・グローバル
・public
他のユニットからも見える。読み書きできるし呼び出せる。
・private
このユニットの中ならば、どのprocedureやfunctionからも読み書きできる。
・ローカル
特定のprocedureやfunctionでしか使えない。
この3つに分かれます。
図にまとめると、こうなります。
###グローバル変数の宣言
先頭から探していくと、 { private 宣言 }と書かれている場所があると思います。ここへ
private
{ private 宣言 }
k2:integer; //前回何出しか覚えて重複を避ける。
//ヒトはじゃんけんでは無意識のうちにそんな戦略を取っているのです。
gfgRes:boolean; //決着したよフラグ
procedure KachiMake(sender:tobject; fg:boolean); //勝敗表示処理
と書き足してください。
詳しくはあとで説明を差しあげますが、このユニットの中で共通に使うグローバル変数や、手続きを宣言します。
###サブルーチンを書きます。
implementation
{$R *.fmx}
と、書いてある次に以下の内容を書き足してください。
procedure TfmMain.KachiMake(sender:tobject; fg:boolean); //勝ち負け表示サブルーチン
begin
if fg=true then
begin //幽霊さんが勝ち
Text1.Text:=ListBox1.Items[3]; //幽霊さんの勝ったセリフ
TRectangle(sender).fill.Color:=$FF111111; //rectangleを負け表示 黒色
PrBar_you.Value:=PrBar_you.Value-1; //ユーザーのprogressbarを-1する
end
else
begin //幽霊さんが負け
Text1.Text:=ListBox1.Items[4]; //幽霊さんが負けたセリフ
TRectangle(sender).fill.Color:=$FFF882F0; //rectangleを勝ち表示 朱色
PrBar_Urei.Value:=PrBar_Urei.Value-1; //幽霊さんのprogressbarを -1する
end;
end;
これはイベントとは直接に結び付いていないけど、イベントハンドラなどから呼び出されて共通の処理を下請けするお手伝いさんのようなものです。処理内容は、senderがユーザーが選んだ「手」を、fgに 幽霊さんが勝ち:True 幽霊さんが負け:False をそれぞれセットして呼び出すと、幽霊さんのセリフ、5回勝負のプログレスバーから負けを減らす処理、ユーザーの「手」を表すRectangleの色表示をしています。
###初期化処理を書きます
次は、初期化ルーチン。勝ち負け表示サブルーチンの下へ書きます。
先ほど宣言したグローバル変数を初期化します。FormCreateイベントは、名前のとおりFormつまりウインドウが生成されたときに呼び出されます。ここで、初期値を入れます。
procedure TfmMain.FormCreate(Sender: TObject);
begin
gfgRes:=false; //決着フラグをfalse にリセット
end;
次は、FormActive ほぼ同じですが、このForm(ウインドウ)がアクティブになったときにイベントが発生します。他のアプリなどからこのウインドウへ処理が戻った際にも使えます。
procedure TfmMain.FormActivate(Sender: TObject);
begin
Text1.Text:=ListBox1.items[0]; //最初のセリフ
end;
イベントハンドラを増やすには、オブジェクトインスペクタのイベントのリストで、作りたいイベントの右側、空欄になっているリストの枠をダブルクリックしてください。
コンポーネントがいっぱいあって、どれがどれやら…… のときは、先にデザインの画面でクリックすると、そのコンポーネントが選択されるので、見つけやすくなります。
では、Rectangle2をクリックして、イベントハンドラを図のように作成してください。
イベントハンドラの記述は、
procedure Tフォーム(ウインドウ)の名前 コンポーネントの名前 イベントの名前 (パラメータ);
となっています。
なんかややこしそうですか? イメージとしては、〇〇県 〇〇市 〇〇町 〇〇番地(団地の部屋番号); そんな感じと思ってください。pascalでは、ブロックを表すのに、begin ~ end を使います。そして、この中にプログラムを書きます。
procedure TfmMain.Rectangle2Click(Sender: TObject);
var
k:integer; //kに「手」の種類 1 ぐぅ 2 ちょき 3 ぱぁ
begin
if gfgRes=true then //grgResは決着フラグ Trueは決着済みのためExitします。
exit;
//初期化 「手」の選択表示を灰色(選択してないよ)に戻す
Rectangle2.fill.Color:=$FFE0E0E0; //最初の灰色は$FFE0E0E0
Rectangle3.fill.Color:=$FFE0E0E0;
Rectangle4.fill.Color:=$FFE0E0E0;
//乱数
Randomize; //乱数を初期化
k:=Random(3)+1; //乱数発生3個 (0,1,2)が発生するため+1して範囲を合わせています
if k=k2 then //前回と被ったら振り直し
k:=Random(3)+1;
Glyph1.ImageIndex:=k; //幽霊さんのイラストを更新
k2:=k; //k2へ今回の手を保存
//判定
if k=TRectangle(sender).Tag then //あいこ
begin
Text1.Text:=ListBox1.Items[2]; //あいこのセリフ表示
TRectangle(sender).fill.Color:=$FFE5E79E; //Rectangleを黄色に表示
exit; //あいこはここで抜けます ☆後ろ判定は勝ち負けだけになります☆
end;
case TRectangle(sender).Tag of
1: //あなたがぐーを出した
if K=3 then //幽霊さんはパー出してますか?
KachiMake(sender,true) //勝ち負け表示サブルーチン呼び出し Senderは対象のRectangle
else //true 幽霊さんの勝ち false 幽霊さんの負け
KachiMake(sender,false);
2: //あなたがぴーを出した
if K=3 then //幽霊さんはパー出してますか?
KachiMake(sender,false)
else
KachiMake(sender,true);
3: //あなたがぱーを出した
if K=1 then //幽霊さんはぐー出してますか?
KachiMake(sender,false)
else
KachiMake(sender,true);
end;
//押してるわ!
if PrBar_You.Value<=1 then //ユーザーのprogressbarが 1
Text1.Text:=ListBox1.Items[7]; // 幽霊さんが押しているときのセリフ 「リーチ」
//負けそう...
if PrBar_Urei.Value<=1 then //幽霊さんのprogressbarが 1
Text1.Text:=ListBox1.Items[8]; // 幽霊さんが負けそうなセリフ 「やばっ……」
//勝敗判定
if PrBar_Urei.Value<=0 then //幽霊さんのprogressbarが 0
begin
Glyph1.ImageIndex:=5; //幽霊さんが負けたイラスト
Text1.Text:=ListBox1.Items[5]; //幽霊さんが負けたセリフ
gfgRes:=true; //決着フラグ True
end;
if PrBar_You.Value<=0 then //ユーザーのprogressbarが 0
begin
Glyph1.ImageIndex:=4; //幽霊さんが勝ったイラスト
Text1.Text:=ListBox1.Items[6]; //幽霊さんが勝ったセリフ
gfgRes:=true; //決着フラグ True
end;
end;
###複数のコンポーネントでイベントハンドラを共有します。
Rectangle2,Rectangle3,Rectangle4に tagをそれぞれ 1,2,3 と割り当てました。これはイベントハンドラを共通使用するためです。実は、じゃんけんのぐぅ、ちょき、ぱぁの判定を行うプログラムはほぼ共通の処理になります。
それなら、tagで判定する処理をひとつ増やせば、イベントハンドラは3つのコンポーネントで共通にできます。
こうすると、最初に作ったRectangel2ClickイベントをRectangle3,Rectangle4からも呼び出せます。
###終了のダイアログボックスを表示します。
この処理方法は、@pik様の VCL 利用者が FireMonkey を使う時に陥る罠5選 この記事から勉強させて頂きました。紹介も兼ねて使わせて頂きました。ありがとうございます。
内容は、じゃんけん幽霊さんをクリックすると、「もう、おしまいなの?」と終了処理へいくか? ゲームに戻るのかを聞いてきます。途中中断と、勝敗決定後の2パターンをフラグで分けて処理しています。
procedure TfmMain.Panel1Click(Sender: TObject);
begin
if gfgRes=false then
begin
TDialogService.MessageDialog(
'あれ? もう、おしまい?',
TMsgDlgType.mtConfirmation, // ダイアログのタイプ
mbYesNo, // 表示するボタンの集合
TMsgDlgBtn.mbNo, // デフォルトでフォーカスを持っているボタン
0, // HelpContext
procedure(const AResult: TModalResult) // 応答を受け取るハンドラー
begin
if AResult = mrYes then //結果がYes
Close //アプリを終了
else
exit; //このprocedureから抜けます
end
);
end;
if gfgRes=true then
begin
TDialogService.MessageDialog(
'あらら、まだ、やるの?',
TMsgDlgType.mtConfirmation, // ダイアログのタイプ
mbYesNo, // 表示するボタンの集合
TMsgDlgBtn.mbCancel, // デフォルトでフォーカスを持っているボタン
0, // HelpContext
procedure(const AResult: TModalResult) // 応答を受け取るハンドラー
begin
if AResult = mrNo then
Close
else
begin //再戦を選択
Text1.Text:=ListBox1.Items[1]; //再戦、最初のセリフ
PrBar_Urei.Value:=5; //幽霊のprogressbarを5個に戻す
PrBar_you.Value:=5; //ユーザーのprogressbarを5個に戻す
gfgRes:=false; //決着フラグをリセット
end;
end
);
end;
end;
ダイアログボックスを使わない方法も考えられます。
プログラムの流れは、グローバル変数の決着フラグ gfgRes=true で管理しているため、処理を止める必要はありません。 [はい][いいえ]のボタンを作ったpanelをvisible:=falseで隠しておき、必要な時にvisible:=trueで表示する方法も考えられます。 ![yseno第2案.jpg](https://qiita-image-store.s3.amazonaws.com/0/273793/c289ccd1-44e5-c742-8344-7f68f0623f69.jpeg) この場合、[おしまい]を表示しているtext4clickのイベントハンドラでアプリを終了させます。 [まだあそぶ]のtext5をclick選択した場合は、初期化処理をしてpanel3をvisible:=falseで隠して勝負に戻ります。#プログラムは以上です。実行してみましょう。
実行は、[F9]キーです。 他に、メインメニューから実行を選んでもできます。
ちゃんと動きましたでしょうか?
##プログラムの流れについて説明します
・処理としては簡単で、ProGressBarのValueがゼロになるまで、ループするそれだけです。
・幽霊さんをクリックすると、決着済みの場合は、「あらら、まだ、やるの?」 まだまだの場合は、「あれ? もう、おしまい?」と尋ねてきます。
とても短いプログラムなので、コメントを見て読み解いてくださると嬉しいです。
ポイントになりそうなところを説明してゆきます。
###じゃんけんの「手」を保存する変数は?
幽霊さんの「手」は、ローカル変数の k に入れてます。
kの値は、乱数で決めています。
ユーザーの「手」は、rectangle2~4.tagに入っています。
両方ともに、1 ぐぅ 2 ちょき 3 ぱぁ になります。
procedure TfmMain.Rectangle2Click(Sender: TObject);
var
k:integer; //kに「手」の種類 1 ぐぅ 2 ちょき 3 ぱぁ
varは、このprocedureの中で使う変数の名前と種類を宣言します。delphiは基本的に、変数は使う前に宣言するルールになってます。
それから、1行コメントは // です。複数行をまとめてコメントにしたいときは、 { と } で囲みます。
画面下のぐぅ、ちょき、ぱぁ の選択画面はちょっと、複雑です。
あなたが出した「手」を色の四角で囲み、あたなが勝ち=ピンク あなたの負け=黒 あいこ=黄色と判定結果を塗ります。そのためには、下にある Rectangle の Fill プロパティを使います。囲み表示は、 Rectangle の Padding プロパティを使います。
ぐぅ、ちょき、ぱぁ のどれをクリックしたのか? その判定は tag を使います。先ほど決めたルール通りに、ぐぅ=1 ちょき=2 ぱぁ=3 にします。
こうしておくと、3つのコンポーネントで「手」の判定をするイベントハンドラを共通にできます。
さきほど、FireMonkeyのコンポーネントには親子関係がありますとお話しました。それが、上の図に関係あります。
ぐぅ、ちょき、ぱぁの絵を表示するGlyphには、Clickのイベントがありません。代わりに、色々なコンポーネントの子になって、絵を表示することを専門に請け負うお仕事をしています。このため、Clickなどイベントは、親になっているコンポーネントに転送される仕組みがあります。
図で言うと、ちょきを表示しているGlyphの親であるRectangleが代わりにClickイベントを処理します。そして、RectangleにはTagを設定しましたね。このTagはイベントハンドラから呼び出して確認することができます。
procedure TfmMain.Rectangle2Click(Sender: TObject);
Clickイベントの小かっこの中にあるSenderというパラメータが、それです。Senderには、誰がこのイベントハンドラを呼び出したのか? 犯人の情報が入ります。したがい、TRectangle(sender).Tagと書くと、先ほどのタグの数値が参照できます。これで、ぐぅ、ちょき、ぱぁの区別ができるのです。
###幽霊さんの「手」は乱数で作ります。
ポイントは、グローバル変数のK2へ前回の「手」を保存し、今回の「手」と比較している点です。ニンゲンさんは、2回続けて同じ「手」を出すことを避ける傾向があります。続けて同じ「手」だと、狙われると無意識のうちに思っているみたいです。
Delphiの条件分岐 if 文は、こんな書き方になります。
if 条件式 then 真のとき else 偽のとき ; になります。 複数行の処理を書きたいときは、begin - end のブロック文にしてください。if文ではひとつの文(ひとつのブロック文)を制御します。
k:=Random(3)+1;
if k=k2 then //前回と被ったら振り直し
k:=Random(3)+1;
k2がグローバル変数です。ローカル変数のkはこのprocedureから処理が他へ行くと消えてしまいます。次にこのprocedureが呼ばれても、ローカル変数のkは前回はどんな「手」を出したのか? を記憶していません。便利に使い捨てることができるのが、ローカル変数の良いところです。保存が必要なときはグローバル変数にコピーしておきましょう。
乱数の生成は、Random(乱数の数)です。
Randam(3)とした場合は、 0,1,2から乱数を作ります。1 ぐぅ 2 ちょき 3 ぱぁ に合わせるため+1しています。
※コンピュータはサイコロを振りません。何でも計算しなきゃ気が済まない真面目な機械なので、Random()が生成するのは疑似乱数ですが、じゃんけんなら気になりません。
case文は、タコ足配線みたいに多数の条件分岐をする制御文です。if文でも同じ処理を書けますが、case文の方が綺麗に書ける場合もあります。
#Androidで動かしてみましょう
まず、機種変更した昔のスマホとか、できればいまメインに使用していない予備のスマホをご用意ください。
私は、メイン機にじゃんけん幽霊さんを入れちゃいましたが、プログラムのデバッグに使うのには、変になっても困らない機械をご利用ください。
方法は、Android デバイスで USB デバッグを有効にする この記事をご覧ください。
スマホの設定画面を開き、一番下の方にある[端末情報]を開いてください。
さらに、一番下にある[ビルド番号]を、7回タッピングしてください。
※何もボタンがないのですが、一種の隠しメニューになっています。
それから、パソコンとスマホをUSBケーブルで繋いでください。スマホに付属の純正ケーブルがあれば、純正品を使う方が良いでしょう。繋いで、無事に認識されるとこうなります。
今度は、右上のプロジェクトマネージャを使います。図のように、Android SDKを選択して、ターゲットのフォルダーを開きます。上手く認識されていると、スマホの製品の型番が表示されています。製品型番をクリックして選択してください。
##スマホでテストします
きっと、問題ないはずですが、お約束のセリフ。ここから先は、自己責任でお願いします。
[F9]キーを押すと…… 実行されます。
ただし、神速のウインドウズ環境と異なり、30秒くらいお待ちください。
こんな画面が続いた後、スマホの画面に赤い火の絵が表示されて、実行となります。
幽霊さんの絵をタップすると、「あれ? もう、おしまい?」か「あらら、まだ、やるの?」と聞いて来るので、「はい」または「いいえ」と答えると終了します。
##スマホにインストールします。
ここから先は、ずっとウインドウズ環境だけで過ごしてきた私には、微妙に未知の領域となります。
実際に作業してみた手順を示します。
##権限を設定します。
メインメニュー → プロジェクト → オプション → 使用する権限 の順に選択してウインドウを開いてください。
じゃんけん幽霊さんは、アンドロイドスマホのカメラや電話機能などは何も使いません。したがい、初期値でTrueになっている機能をすべて外してください。
この機能設定は、アプリをインストールする際に権限承認を求めてくるアレのことです。
今回のじゃんけん幽霊さんの場合は、
マイドキュメントの中の Embarcadero\Studio\Projects\000JKUrei\Android\Debug\pJKUrei\binに
pJKUrei.apk というファイルがあるはずです。
これをスマホの一時ファイルを作っても大丈夫な適当なフォルダーにUSB経由で転送します。例えば、外部ストレージにtmpなどの名前で新しくフォルダーを作ってもいいかも知れません。
スマホの機種によっては、USBの接続方法を尋ねられるので、充電用に接続ではなく、ファイル転送用を選択してください。
次に、スマホのファイルマネージャなどでこのファイルを開いて、タップすると…… インストールしますか? と尋ねてきますので、「はい」と答えるとインストールされます。
※そのほか、スマホのセキュリティ設定で、「提供元不明のアプリのインストールを許可する」をONにしてます。もちろん、インストールが終わったら、OFFにしましたけど。
#まとめ
Delphi Community Edition発表を機に、初めましての方にも、プログラムの面白さやDelphiの魅力を紹介したいなと思い、つたないながらも書かせて頂きました。
Delphiは画面づくりはご覧頂いたようにマウスだけでコードを全然書かなくてもできてしまいます。また、プロジェクトマネージャでターゲットを選ぶだけで、そのOSに合わせたネーティブ実行できるアプリをつくれてしまいます。
入り口は簡単なようで、奥行きがもの凄く深い…… そんなプログラムの統合環境がDelphiと思います。
今回は、簡単なじゃんけんゲームを通じて、Delphiの色々な機能やプログラム作りの雰囲気を紹介したいと思いました。でも、まだ、書けていないことはたくさんあります。また、FireMonkey特有のスタイルに関するあたりは、まだ勉強中ゆえご紹介できませんでした。(他には、基本データ型や、VCLのことや……書けてないですね)
なにぶんにも、慣れないことをやってますので、色々と突っ込みどころ満載かと思います。ご指摘を頂ければ幸いです。
また、@pik様の VCL 利用者が FireMonkey を使う時に陥る罠5選は、VCL一筋の私にとっては、大変に参考になりました。ツイッター上でも色々とご指導を頂き、改めて深くお礼を申し上げます。
長文、乱文失礼しました。
ここまでご高覧頂きありがとうございます。