Create  Edit  Diff  Phillro Industries  Index  Search  Changes  History  Source  RSS  Note  wikifarm  Login

tut-tut_number

Author: NISHIO Mizuho

数当てゲーム

今まで紹介したコントロールを使用して簡単な数当てゲームを作ります。

スクリプト

$(Apollo)/sample/tutorial/number.rb

   1|require 'phi'
   2|require 'rgui/ui'
   3|require 'dialogs'
   4|
   5|MAX = 5
   6|$anwser = nil
   7|srand
   8|
   9|# control
  10|form = RGUI::Form.new(:form1, '数当てゲーム')
  11|
  12|form.width = 350
  13|form.height = 90
  14|
  15|start_btn = Phi::Button.new(form, :start_btn1, 'ゲーム開始')
  16|stop_btn = Phi::Button.new(form, :stop_btn1, 'ゲーム終了')
  17|stop_btn.enabled = false
  18|hbox1 = UI::Hbox.new([start_btn, stop_btn], 5)
  19|  
  20|edit = Phi::Edit.new(form, :edit1, '')
  21|answer_btn = Phi::Button.new(form, :answer_btn1, 'OK')
  22|hbox2 = UI::Hbox.new([edit, answer_btn], 5)
  23|
  24|vbox = UI::Vbox.new([hbox1, hbox2], 5)
  25|form.add(vbox)
  26|
  27|
  28|# method
  29|def ok_msg(msg)
  30|  Phi::message_dlg(msg, Phi::MT_INFORMATION, [Phi::MB_OK], 0)
  31|end
  32|
  33|def error_msg(msg)
  34|  Phi::message_dlg(msg, Phi::MT_ERROR, [Phi::MB_OK], 0)
  35|end
  36|
  37|def start_game
  38|  Phi::SCREEN.form1.start_btn1.enabled = false
  39|  Phi::SCREEN.form1.stop_btn1.enabled = true
  40|  $answer = rand(MAX)
  41|  ok_msg("答えは 0〜#{MAX - 1} の数字です。")
  42|end
  43|
  44|def stop_game
  45|  Phi::SCREEN.form1.start_btn1.enabled = true
  46|  Phi::SCREEN.form1.stop_btn1.enabled = false
  47|  $answer = nil
  48|  Phi::SCREEN.form1.edit1.text = ''
  49|end
  50|
  51|# event
  52|answer_btn.on_click = proc do
  53|  unless $answer.nil?
  54|    if edit.text == $answer.to_s
  55|      ok_msg('正解です。')
  56|      stop_game
  57|    else
  58|      error_msg("正解は #{edit.text} ではありません。")
  59|    end
  60|  else
  61|    error_msg("ゲームを開始してください。")
  62|  end
  63|end
  64|
  65|start_btn.on_click = proc do
  66|  if $answer.nil?
  67|    start_game
  68|  else
  69|    error_msg('BUG')
  70|  end
  71|end
  72|
  73|stop_btn.on_click = proc do
  74|  if $answer
  75|    stop_game
  76|  else
  77|    error_msg('BUG')
  78|  end
  79|end
  80|
  81|form.on_resize = proc do
  82|  form.layout
  83|end
  84|
  85|form.show
  86|Phi.mainloop

このスクリプトを実行すると、このような ウィンドウがあらわれます。

解説

このゲームでは「ゲーム開始」のボタンを押すと、「答え」に整数が設定されます。ゲームの目的はこの「答え」を当てることです。エディットに数字を入力した後「OK」ボタンを押すと、エディットの数字と「答え」が一致しているかどうかを調べます。答えが当たっている場合は「正解です。」というダイアログが表示され、答えが間違っている場合は間違っていることを示すダイアログが表示されます。

初期化とコントロールの生成

1〜3行はコントロールを使うためのおまじないです。すべてこれまでのチュートリアルで紹介したものですので、どういうものか分からない時は前のページに戻って調べてみてください。

5〜7行は数当てゲームに使う変数や定数の設定です。 MAX には数当てゲームの「答え」に使われる最大の整数よりも一つ大きい値を定数として指定します。例えば、 MAX に3を代入すると、「答え」に使われる整数は0、1、2の三つになります。

$answer はこのゲームの「答え」です。今までと違って先頭に「$」が付いていますが、これはRubyの大域変数を表わします。詳しくはRubyのマニュアルを見て欲しいのですが、簡単に言えばどこからでも参照することができる変数のことを大域変数と言います。逆に一定の範囲でしか使えない変数もあります。そういった変数にはいくつか種類がありますが、この章ではローカル変数についてのみ後ほど説明を行います。$answer には nil が代入されていますが、これは Ruby の NilClass? のオブジェクトで、偽を表します。偽を表すといっても、 false とは多少意味合いが違います。詳しいことは Ruby のMLトピックスやマニュアルを参照してください。

7行目の srand は乱数の初期化を行う Ruby のメソッドです。今回は「答え」を作るために乱数を使うので、ここで乱数を初期化しておきます。

10〜25行はフォームやボタンを生成したり、配置や大きさを設定しています。以前紹介したパッキング行う UI::Hbox や UI::Vbox を使っているので、少々分かりにくいかもしれませんが、ウィンドウの外見とスクリプトを比較すれば理解できると思います。

17行目では stop_btn.enabled( Phi::Button#enabled )の属性にfalseが代入されていることに注目してください。 Phi::Button#enabled はボタンを有効にするかどうか決める属性です。これにfalseが代入されると、ボタンの文字が淡色になってボタンを押すことが出来なくなります。

メソッド定義

28〜49行はメソッド定義です。説明はそれぞれのメソッドが実際に実行される時に行います。

イベント処理(イベントハンドラ)

51〜83行は何かイベントが起きた時のアクションを決定しています。

最初に65〜71行の「ゲーム開始」のボタンが押された場合を説明します。「ゲーム開始」のボタンが押されると、$answer.nil?( Object#nil? Kernel#nil? )で $answer が nil でないかどうかを調べます。ゲームが開始されていると、$answer には数字が入りますので、67行が実行されます。ゲームが開始されていない場合は69行目が実行されます。

67行目は37〜42行で定義された start_game のメソッド呼び出しになっています。 start_game が実行されると、「ゲーム開始」のボタンが押せなくなって、代わりに「ゲーム終了」のボタンが押せるようになります。次に「答え」が設定されて、どの範囲に「答え」があるのかメッセージダイアログを使って表示します。

38と39行は見なれない形ですが、実行している事は17行目と同じようにボタンを有効にしたり、無効にしたりしているだけです。違う点はボタンのオブジェクトを参照するために start_btn や stop_btn を使っていないことです。どうしてこういう事をするのかというと、先ほど触れた Ruby のローカル変数の参照の問題があるからです。今まで触れませんでしたが、 start_btn や stop_btn は Ruby のローカル変数です。 Ruby のローカル変数は参照できる範囲が制限されていて、上のサンプルスクリプトだとメソッド定義の部分ではその外で使われている start_btn や stop_btn を参照することはできません(39行目くらいに p stop_btn を加えて確認してみてください )。そこで、以前説明した Phi::Button.new の第2引数や Phi::Form.new の第1引数を使って、Phi::SCREEN.form1.start_btn1 のようにしてメソッド定義の外にあるオブジェクトを参照しています。一部の定数や大域変数はメソッドの定義の部分でも自由に参照できるので、このような方法で「ゲーム開始」や「ゲーム終了」のボタンのオブジェクト( start_btn、stop_btn )を参照することが可能になります。

40行目は Ruby のメソッドである rand を使って、乱数を発生させ、0 〜 MAX-1 までの整数を $answer に代入しています。

41行目は29〜31行で定義されている ok_msg のメソッド呼び出しです。これはダイアログで説明した show_ok_msg と全く同じメソッドになっているので、説明はいらないでしょう。

元に戻って66行目で $answer が nil でない場合、69行目が実行されて、33〜35行で定義されている error_msg のメソッドが呼び出されます。 error_msg はメソッドの第1引数を使ってエラーメッセージを表示するメソッドですので、 $answer が nil でない場合、「ゲーム開始」ボタンが押されると、'BUG'というメッセージが表示されるわけです。時間がある人はどうしてこれがバグになるのか考えてみてください(スクリプトを実行してみれば分かりますが)

次に「ゲーム終了」のボタンが押された時のアクション(73〜79行で定義されています)を考えます。「ゲーム終了」のボタンが押されると、74行で $answer が nil でないかどうか判断します。「 if $answer」という形は馴れないと気持ち悪いかもしれませんが、この形では $answer が nil 以外のオブジェクトだと、 $answer は true を返します。 $answer が nil でない場合は75行が実行されて stop_game のメソッドが呼び出され、逆に $answer が nil の場合は error_msg のメソッドが呼び出されて、'BUG'というエラーメッセージが表示されます。

44〜49行で定義されている stop_game のメソッドが呼び出されると、「ゲーム開始」のボタンが押せるようになり、代わりに「ゲーム終了」のボタンが押せなくなります。次に $answer に nil が代入されて、エディットの文字が空になります。これらの処理は次のゲームをするための準備になるわけです。

52〜63行は「OK」ボタンが押された時のことがコードされています。53行ではゲームが開始されているかどうかを $answer の値で判断します。unless は if とは逆で「unless 〜」の〜の部分が false を返す時にその次の部分が実行されます。ゲームが開始されていれば、54行が実行され、「答え」の数字とエディットの数字を比較します。答えが正解であれば '正解です。' というメッセージを表示し、 stop_game のメソッドを呼び出します。答えが間違っていれば、不正解のメッセージを表示します。58行の #{edit.text} は edit.text( Phi::Edit#text )の値を文字列に変換して"〜"の部分に埋めこんでいます。変数の埋め込みの詳しいことは Ruby のマニュアルを読んでください。53行の条件分岐でゲームが開始されていなかった場合は61行が実行されて、"ゲームを開始してください。"というメッセージを表示します。

最後の81〜83行ではコントロールの配置を変更する form.layout( RGUI-Form#layout? )を呼び出しています。

今回のスクリプトはあまり良い例ではないです。 Phi::SCREEN を使ってオブジェクトを参照するよりはクラスを定義してインスタンス変数を使う方が良いですし、 $answer のような大域変数は使用するべきではありません。自信のある方は数当てゲーム用のRubyのクラスを自分で定義して、上のスクリプトを書き直してみてください。

すいません

今回はApolloの解説よりRubyの解説の方が多いです。Apolloのチュートリアルにふさわしくなるように上記の文章を修正してくださる方はいらっしゃらないでしょうか?

クラスやメソッド

Rubyの組み込みモジュール

  • Kernel

Rubyの組み込みクラス

  • NilClass?
  • Object
  • Fixnum

Rubyの組み込みメソッド

  • srand
  • rand

Phi::Button

http://znzwam.com/

Last modified:2004/11/26 05:28:15
Keyword(s):
References:[tut-tut_index]