System4.0のSACT標準MENU_SELECTの改造
※ 注意 ※ このtipsはSACT内部を改造しています。 |
06/12/24 update!
CSactMenu.jaf の改造箇所にバグがあったのを修正しました。
MENU_SELECTのバグ
実はSACT標準のMENU_SELECTには、バグがあります。
1.sys40ひそひそ話 で述べられているような、MENU_SELECTからのコールバック処理
2.MENU_SELECT中での選択コールバック中でのMENU_SELECT1の方は、MENU_SELECT自体の仕様的には仕方の無いところはありますが、
2の方は、完全なバグだと考えられます。
しかしながら、MENU_SLECT系コマンドが呼び出す CSactMenu クラスは、
かなり頑丈な作りになっています。
そのため、少し改造するだけで、上述のバグは修正可能となります。
remenu.jaf をダウンロード
改造場所はこのファイルの記述を参考にしてください。
テキストエディタによっては、行数が表示されなかったり、途中改行で行数が合わない場合があります。
使い方
remenu.jafの先頭コメントにある改造を行ったものとして話を進めます。
まずは、初期化時に
MENU_INIT_FIRST(); |
を、呼び出します。これが無いと、ぬるぽです 選択肢系命令でエラーが起きます。
そのため、MENU_SET_METRICS などで選択肢レイアウトを設定する前に呼び出してください。
逆に言うと、これを呼び出しておけば、MENU_ から始まる命令を実行可能となります。
コールバックを使用する場合は、コールバックを登録する際に
MENU_KEY_WAIT_CALLBACK( コールバック関数名 ); |
を実行してください。
// 例 MENU_KEY_WAIT_CALLBACK("コールバックA"); // 追加すべきコード REGISTER_MSG_KEY_WAIT_CALLBACK(&コールバックA); // 通常のコールバック登録 |
また、コールバック時にセーブを行いたい場合は
SACT_RESUME_SAVE をよびだした戻り値がロードの時に
MENU_RESUMESAVE_LOAD(); |
を呼び出す必要があります。
// 例 MENU_START(); // 追加すべきコード MENU_ADD(1, "セーブ"); MENU_ADD(2, "ロード"); MENU_ADD(3, "戻る"); int nSelect = MENU_SELECT(); if (nSelect == 1) { int res; if(SACT_RESUME_SAVE("key","save.asd",res)==0){ // ロードされた // 何か他に再構築するものが有れば、再構築するコト。 // 注意:ここでMENU_INIT_FIRST();が呼び出されないようにしてください。 MENU_RESUMESAVE_LOAD(); // 追加すべきコード } } else if (nSelect == 2) { SACT_RESUME_LOAD("key","save.asd"); } |
実際に使用する直前に以下の命令を発効します。
MENU_START(); |
つまり、以下のような流れになります。
// 例 MENU_START(); // 追加すべきコード MENU_ADD(0,"1番"); MENU_ADD(1,"2番"); MENU_ADD(2,"3番"); int sel=MENU_SELECT(); |
必要最低限の変更で済ませたい場合は、
MENU_START 命令を、上から表示されるメニューにのみ適用しても構いません。
つまり、コールバック関数での選択肢、選択時自動実行関数での選択肢 の2つの時です。
なお、選択時自動実行関数というのは、具体的には以下のものです。
void あなたはギターを演奏するか(){ 'する、あなた、プレイ、グィター? 'B;R; MENU_ADD(0,"はい",&Yes); MENU_ADD(0,"いいえ",&No); MENU_SELECT(); } void Yes(){ void No(){ |
どうやってるの?
この改造で、どうして動作するようになるのか。
まず、重要なことは、CSactMenuクラスは複数の選択肢表示に対応しているが、
MENU_SELECT系コマンドは、複数表示に対応していないと言うことです。そのため、通常のMENU_SELECT系命令で、無理矢理に複数表示しようとすると
2つの内容がくっついてしまうなどの問題が生じます。なぜ、MENU_SELECT系の命令は、1つしか対応していないのか。
これは、CSactMenuクラスのインスタンスをグローバル変数で保持し、
そのインスタンスへのラッパとして、MENU_SELECT系コマンドが存在するためです。そのため、今回の改造では、
CSactMenuクラスのインスタンスへの参照をグローバルで保持し、
MENU_START を実行することで、参照先を切り替えるという手段をとりました。こうすることにより、複数表示が可能となります。
ですが、ここで問題が出てきます。
上から表示されるメニューと、下から表示されるメニューが重なってしまいます。
そのため、UPDATEされない間で、スプライト表示を高速で切り替えています。
こうすることで、一番上のメニューのみしか表示されなくなります。また、SACT_RESUME_SAVEを行った場合、
メニューのスプライトが消えてしまいます。
( ※ SACT_RESUME_SAVEではスプライトの中身は保存されない )
そのため、MENU_RESUMESAVE_LOAD を実行してもらって、
全ての選択肢のスプライトを再作成するようにしています。
感想
問題は無いハズですが、ちょっと怖いです(ぇ
使用される方は、各自問題がないかどうか確認しながら実装してください m(_ _)m