基本メニュー表示と結果取得
アドベンチャーゲームを作るという以上、ユーザに入力を促し、その結果によってシナリオを分岐させる機能は必須です。このとき、モーダル(modal)であること*1がより望ましいです。これを実現するのに最も簡単なのはJavaScriptのconfirm、およびpromptを利用することです。(参考:できるだけ単純にJavaScriptでアドベンチャーゲームを作る。 - Backstage of theater.js) しかし、デザイン・機能的に全く融通が利かないのがツライところです。*2
そこで、PrototypeWindowClassのように半透明の要素でブラウザウィンドウを覆い、その上にメニューを表示するようにしてみました。PrototypeWindowClassをそのまま使うこともできるのですが、高機能すぎて重い(^^;ので、自作しました。
これを使用して、Theaterクラスに以下のメソッドを作成しました。
alertメソッド
【使用例】 new Theater({ scenario: [ function(){ this.alert("あらーと1"); }, function(){ this.alert("あらーと2"); } ] });
シナリオ(関数配列)内の関数で「this.alert(表示文字列);」として使用します。指定文字列とOKボタンが表示されます。OKボタンを押すと閉じ、自動的に次の関数を実行します。なので、上記は「あらーと1」「あらーと2」が続けて表示されます。
confirmメソッド
【使用例】 new Theater({ scenario: [ function(){ this.confirm("かくにん"); }, function(result){ this.alert("けっか:" + result); } ] });
シナリオ(関数配列)内の関数で「this.confirm(表示文字列);」として使用します。指定文字列と「はい」と「いいえ」のボタンが表示されます。「はい」か「いいえ」のいずれかのボタンを押すと、閉じて次の関数を実行します。このとき、関数の引数に結果が設定されます。「はい」が押された場合はtrue、「いいえ」が押された場合はfalseです。上記例では表示しているだけですが、これによりシナリオを分岐させることもできます。
promptメソッド
【使用例】 new Theater({ scenario: [ function(){ this.prompt("なにかいれてね", "でふぉると"); }, function(result){ this.alert("けっか:" + result); } ] });
シナリオ(関数配列)内の関数で「this.confirm(表示文字列[, デフォルト値]);」として使用します。デフォルト値は省略可能です。指定文字列とテキストボックス、「入力」ボタンを表示します。「入力」ボタンを押すと、閉じて次の関数を実行します。このとき、関数の引数にテキストボックスに入力された値が設定されます。
上記3メソッドで表示されるメニューは、いずれも画像ボックス*3の中心に表示され、ドラッグ可能です。
これ以外のメニューを作成する方法については今後解説します。
とりあえず、例です。promptメソッドで名前入力を促し、未入力ならalertメソッドでメッセージを出して再入力を促します。入力ありならconfirmメソッドで入力を確認してもらい、「いいえ」が押されたら入力画面に戻ります。「はい」が押されたら次へ遷移します。
http://susie-t.seesaa.net/article/35350351.html
以下は上記例のブログ内で記述したコードです。(ファイルの読み込みはブログの共通設定で行っています。)
<button id='d20070306reset' class='reset'> はじめから</button> <div id="d20070306play" class='play'> <div id="d20070306frame" class='frame'></div> <div id="d20070306msg" class='msg'></div> </div> <script type="text/javascript"> var d20070306 = {} d20070306.imgRoot = 'http://susie-t.up.seesaa.net/image/' d20070306.img = { sample1: d20070306.imgRoot + 'sample1.gif', sample2: d20070306.imgRoot + 'sample2.gif', sample3: d20070306.imgRoot + 'sample3.gif' }; d20070306.scenario = [ function (){ this.work.name = ""; this.act({ img: d20070306.img.sample1, msg: '名前入力テスト' }); }, function (){ this.act({ img: d20070306.img.sample2, msg: 'お名前を入力してください' }); }, function (){ this.push([ function(){ this.prompt( "お名前を入力してください", this.work.name ); }, function (result){ this.work.name = result; if(result == ''){ this.back(); this.alert("お名前が入力されていません><;"); }else{ this.confirm("あなたのお名前:" + result + "<br/>よろしいですか?"); } } ]); this.play(); }, function (result){ if(result){ this.act({ img: d20070306.img.sample3, msg: "ようこそ" + this.work.name + "さん" }); }else{ this.back(); this.play(); } }, function (){ this.work.name = ""; this.act({ img: d20070306.img.sample1, msg: '名前入力テストおわり。' }); } ]; new Theater({ frameId: 'd20070306frame', msgId: 'd20070306msg', resetId: 'd20070306reset', playId: 'd20070306play', filter: ImageChanger.getFilter({no:10}), outEffect:'Fade', inEffect:'Appear', scenario: d20070306.scenario, img: d20070306.img }); </script>
・・・説明しなきゃいけないことが多いな><;
Theaterクラスインスタンス作成時にframeId等を指定しています。無指定時はデフォルトで'frame'等が割り振られるのですが、同ページに複数Theaterクラスの利用があると、競合してしまうので個別のIDを振る必要があります。なので、いちいち設定しています。また、競合を避けるためd20070306オブジェクトを作成・利用しています。・・・分かりづらくてすみません。
Theaterクラスインスタンス作成時のoutEffect、inEffectオプションは、IE以外にも画像切替効果をつけようとして追加したオプションです。値はscriptaculousのEffectに準じています・・・が、全部が動くわけではありません^^; とりあえずoutEffect(消滅時)に'Fade'、innEffect(出現時)に'Appear'は設定できます・・・。詳しくは今後解説します。
pushメソッドはサブシナリオを設定するメソッドです。引数はシナリオ(関数配列)です。サブシナリオが終了すると、親のシナリオへ復帰します。
backメソッドは、シナリオを「ひとつ戻す」メソッドです。ただし、これにより必ずしも「直前のシナリオ関数」が実行できるわけではありません。やっていることは、当該シナリオのインデックスを減算*4するだけです。このため、サブシナリオから復帰した直後の場合、backメソッドを使用してもサブシナリオへは戻れません。
ここでは、この特性をシナリオ作成に利用しています。サブシナリオ直後に判定し、結果によってbackし、再度サブシナリオを実行させています。
back以外にも、シナリオ操作メソッドとしてjump(指定インデックスへ飛ぶ)、move(現インデックスから指定数減算・加算する)も用意していますが、この二つの使用はあまりお勧めできません。シナリオ修正が異常にしにくくなるためです。たとえば、上記のback+サブシナリオの方法であれば、サブシナリオ部分の修正はbackメソッドに影響しません。サブシナリオを使用せずにmoveメソッドを使用すると、戻る先からbackメソッド間でシナリオ関数の追加・削除が発生すると、moveの引数を変更する必要があります。そして、これは非常に気づきにくいです。jumpメソッドについても同様の理由です。
pushやbackは、それだけでは「シナリオを設定する」だけで、実行はしません。直後に実行したい場合はplayメソッドを呼び出します。ただし、各種メニューを呼び出した場合は、閉じると自動的に次のシナリオ関数が呼び出されます。
・・・この辺りの仕様は改善の余地があるかもしれません。
以上。あ゛ー。分かりにくいですねぇ・・・TT
なにかご質問がありましたらコメントORメールください・・・。