Cocoa Break Logo Top Soft Develop  脱力空間 Logo
Apple Web Badge
made by mi

概要 翻訳 ソース リンク がらくた

概要 Examples ADC Samples 3rd Parties etc CBOriginals

Simon

1 概要

Cocoa の開発環境をデモンストレートするためのシンプルなゲ−ムです。このサンプルのアプリケーションがどんな機能を持っているのか、まずは実際に動かして確かめてみましょう。ダウンロードしたファイルの中には、ビルドされたアプリケーションが入っているので、ダブルクリックするだけで、すぐに動かすことが出来ます。

起動すると、上図のように4つの色の違うボタンがある四角いウインドウが表示されます。真ん中に現在の Count を表示する部分と、その下にメッセ−ジを表示する部分があります。下にはゲ−ムを開始する Start ボタンがあります。この Start を押すと、4つのボタンがランダムに暗く変化します。その順を記憶して、その通りにボタンを押します。このとき、Start ボタンはゲ−ムを中止する Stop ボタンにタイトルが変わっています。

注意:この内容は 2003 年 4 月に、個人的な覚え書きとして作成されました。その後一部修正しているものの、古い内容が残っている可能性があることに注意してください。

2 プロジェクトのファイル構成

では、プロジェクトを構成しているファイルを見ていきます。まず、Project Builder でプロジェクトファイル(Simon.pbproj)を開きます。

Classes のところに、「SimonController.h」と「SimonController.m」がありますが、これがアプリケ−ションをコントロ−ルするメインのクラスです(NSObject のサブクラス)。

Resources の「SimonController.nib」で、ユーザーインターフェイス等の定義がなされています。

3 SimonController.nibの構成

次に、SimonController.nib をダブルクリックして、Interface Builder でその中身を見てみましょう。

SimonController.nib のウィンドウを見ると、先程出てきた SimonController クラスのインスタンスがあります。この MySimonController には、水色で表示している 7 つのアウトレットがあります。これは、実行中にメッセ−ジを変えたり、ボタンの表示を変えたりするために用いられます。myButton1 〜 4 から ListenSequence: というメッセ−ジが送られます。また、myStartStop ボタンからは、startStopGame: というメッセ−ジが送られます。

4 SimonController クラス

まず、SimonController.h を見てみます。

SimonController.h
#import #define MAX_SEQUENCE_LENGTH 100 @interface SimonController : NSObject { id myButton1; id myButton2; id myButton3; id myButton4; id myCounter; id myMessage; id myStartStop; int listening; int sequenceLength; id sequence[MAX_SEQUENCE_LENGTH]; } - (void)StartStopGame:(id)sender; - (void)ListenSequence:(id)sender; - (void)PlaySequence; @end

Interface Builder で定義した 7 つのアウトレット以外に、listening、sequenceLength、sequence という3つのインスタンス変数が定義されています。また、定数 MAX_SEQUENCE_LENGTH という操作の最大回数を決める数を定義しています。

メソッドは3つですが、そのうち2つは、Interface Builder でボタンから接続されたアクションを実行します。PaySequence は、ゲ−ムの開始的に見本となるボタンの点滅を行います。

5 クラスの初期化

SimonController.m を見ていきます。まず最初にソ−スで使用する定数を宣言しています。

SimonController.m
#define HALF_A_SEC 30 #define ONE_SEC 60 #define TWO_SEC 120 #define NUM_SIMON_BUTTON 4 #define BUTTON_ONE 0 #define BUTTON_TWO 1 #define BUTTON_THREE 2 #define BUTTON_FOUR 3 #define START_STR "Start" #define STOP_STR "Stop" #define PRESS_START_STR "Press start to begin." #define PLAYING_STR "Remember the sequence..." #define LISTENING_STR "Repeat the sequence..." #define GAME_OVER "Incorrect Sequence. Game Over"

そして初期化メソッド init の実装になります。

SimonController > init
- (id)init { self=[super init]; // スーパークラスの呼び出し listening=FALSE; sequenceLength=0; return self; }

スーパークラスの初期化メソッドを呼び出し、2つのインスタンス変数を初期化しているだけです。

6 ゲ−ムの開始

次に、StartStopGame: メソッドを見てみます。

SimonController > StartStopGame:
- (void)StartStopGame:(id)sender { static int playing = FALSE; if(playing == TRUE) { // ゲ−ムが実行中なら playing = FALSE; // 実行中だから停止する listening = FALSE; // ボタンの押下をチェックしない // Start/Stop ボタンのタイトルを変える [myStartStop setTitle:[NSString stringWithCString:START_STR]]; [myStartStop display]; // タイトル表示をリフレッシュ // メッセージを停止時のものに変える [myMessage setStringValue: [NSString stringWithCString:PRESS_START_STR]]; [myMessage display]; // メッセ−ジをリフレッシュ sequenceLength = 0; // 手番を 0 にリセット } else { playing = TRUE; // 停止中だからゲームを開始 [myCounter setIntValue:0]; // カウンタのリセット [myCounter display]; // スクリ−ン表示をリフレッシュ [myStartStop setTitle:[NSString stringWithCString:STOP_STR]]; [myStartStop display]; // タイトル表示をリフレッシュ // メッセージをプレイ中のものに変える [myMessage setStringValue: [NSString stringWithCString:PLAYING_STR]]; [myMessage display]; // メッセージをリフレッシュ [self PlaySequence]; // 新しい手番を開始する } }

基本的に難しことはしていません。プレイ関係の変数をプレイ中か停止中に従って設定し、ボタン表示とメッセ−ジを変更しているだけです。プレイ中に新しい手番を開始するときは、メソッド PlaySequence を呼んで、それにまかせます。

7 各手番の実行

各手番は、メソッド PlaySequence によって行われます。

SimonController.m > PlaySequence
- (void)PlaySequence { int i = 0; long junk; listening = FALSE; // ボタンのチェックをしない srand(time(NULL)); // C 言語ライブラリの乱数発生準備 switch (rand() % NUM_SIMON_BUTTON) { // 乱数を生成してそれをボタンの数で割った余りで // 0〜3 の間の乱数を得て、それによってケ−スを分ける case BUTTON_ONE: sequence[sequenceLength++] = myButton1; // 手順配列に新しい手順を追加する break; case BUTTON_TWO: sequence[sequenceLength++] = myButton2; break; case BUTTON_THREE: sequence[sequenceLength++]=myButton3; break; case BUTTON_FOUR: sequence[sequenceLength++]=myButton4; break; } // 新しい手番が追加できたので見本の表示に移る [myMessage setStringValue: [NSString stringWithCString:PLAYING_STR]]; [myMessage display]; // メッセ−ジを表示 for (i=0; i < sequenceLength; i++) { // 手番の数だけ表示を行う Delay(HALF_A_SEC,&junk); [myCounter setIntValue:i+1]; [myCounter display]; [sequence[i] performClick:self]; // ボタンクリックをシミュレートする } listening=TRUE; // ボタンチェックを開始する [myMessage setStringValue: [NSString stringWithCString:LISTENING_STR]]; // プレイヤ−の入力を待つメッセージに変える [myMessage display]; // それを表示 }

これも難しくはない。単に乱数を作り、新しい手順の番号のボタンに対する参照を配列のなかに追加して、その配列で参照されるボタンにクリックをシミュレートさせ、そしてプレイヤーの入力を待つだけである。

ここで、見慣れないメソッドは、performClick: です。これはマウスがそのボタンで押された時と同じように、設定されたターゲットにアクションを送ることができます。

8 ボタンをクリックしたときの処理

ボタンをクリックしたときには、listenSequence メッセ−ジが送られます。このなかで、現在ユーザの手番であれば、押されたボタンが見本と同じかどうかをチェックしています。listening が FALSE であれば、見本のあとにユーザーが入力したわけではないので、それを無視します。

このように、ボタンなどのコントロ−ルに状態によって複数の処理をさせたい場合、コントロ−ラ−となるオブジェクトに状態変数を定義して、その値によって処理を変えると、呼ばれるメソッドが同じでも処理の内容を変えることができます。

では、listenSequence メソッドを見てみましょう。

SimonController.m > listenSequence
- (void)ListenSequence:(id)sender { static int index = 0; // いまチェックしている手番のインデックス long junk; Delay(HALF_A_SEC,&junk); // すこし間をあける if(listening == TRUE) { // チェックを行うべきなら if(sequence[index] == sender) { // プレイヤ−の選択があっていたなら index++; // 次の手番に進む [myCounter setIntValue:index]; // カウンタを更新する [myCounter display]; if(index == sequenceLength) { // 手番の最後なら [sender highlight:NO]; // ハイライトをリセットする [sender display]; [self PlaySequence]; // 新しい手番を始める index=0; } }else{ // 選択が間違っていたらゲームオーバー [myMessage setStringValue: [NSString stringWithCString:GAME_OVER]]; [myMessage display]; // メッセージを表示する [sender highlight:NO]; // ハイライトをリセットする [sender display]; Delay(TWO_SEC,&junk); // 少し時間をかせぐ [self StartStopGame:self]; // ゲームを停止する } }else index=0; }

これも難しい処理はなにもない。単にボタンをチェックすべきならチェックして、正しいかどうかによって処理を変えているだけである。


管理人:神吉 秀典 E-mail:puer@ba.wakwak.com