第12回:メッセージスキップ



ゲームが長くなると、次のメッセージを読むためにマウスクリックを繰り返すことが
だんだん面倒になってきます。
ボタン1つで選択肢が出てくるところまでメッセージをスキップさせられると便利ですね。
てなわけで、第12回ではメッセージスキップの実装について説明します。

メッセージスキップは、大きく分けて二通りのパターンがあります。
  1. Ctrlキーを押している間、メッセージをスキップする
  2. 何かのキーを押してスキップを開始する。
    スキップを開始したら、Enterキーを押すまでメッセージをスキップし続ける
今回は2.に似た形で、ポップアップメニューで「メッセージスキップ」を選択したら
メッセージスキップが行われるように実装します。
どこまでスキップさせるか、という終了条件は、
といった形で良いでしょう。
なお、今回は未読メッセージも既読メッセージもスキップできるものとします。
昨今のゲームでは既読メッセージのみスキップさせるというのが一般的ですが、
既読メッセージのみスキップという処理を行うためには、
未読メッセージを「どこまで読んだら」既読とするか、等の理論にも触れることになり
やたら長くなってしまうため、他に機会があればそちらで書くことにします。

PopupMenuのメニューデザイナを呼び出して、新規メニュー項目を1つ追加します。
メッセージスキップの機能は使用頻度が高いので、メニューの一番上に持ってきましょう。
オブジェクトインスペクタでプロパティを設定します。

「メッセージスキップ」メニューのプロパティ
プロパティ名 設定値
Caption メッセージスキップ
Name MnuSkip

メニューデザイナ上で「メッセージスキップ」メニューをダブルクリックして
イベントの雛形を生成し、中身を実装します(リスト29)。

(リスト29)
            
//「メッセージスキップ」メニューをクリックしたときに発生するイベント
procedure TMainForm.MnuSkipClick(Sender: TObject);
begin
            
            
   //メッセージスキップ中であることを示すフラグをオンにする
   SkipLoop := True;  ------------------------------------------------(43)

   while SkipLoop and (phase = normal) do  ---------------------------(44)
   begin
      //次のメッセージを表示する手続きを呼び出す
      OneStep;  ------------------------------------------------------(45)
      //メッセージ・キューに溜まった処理を行う
      Application.ProcessMessages;  ----------------------------------(46)
   end;

   //フラグをオフにする
   SkipLoop := False;  -----------------------------------------------(47)
            
            
end;
            

SkipLoopは、現在メッセージスキップをしているかどうかを示すフラグです。
これがTrueの時はメッセージスキップ中であることを示します。
グローバルで宣言し、FormCreateで初期値をFalseに設定してください。

            
implementation
(中略)
var
(中略)
  ChoiceNum : Integer; //選択している選択肢番号
            
            
  SkipLoop : Boolean; //メッセージスキップ中であることを示すフラグ 
            
            
{$R *.dfm}

procedure TMainForm.FormCreate(Sender: TObject);
var
   i : Integer;
begin
   //セーブデータのファイルが無ければロード不可に
   if not FileExists('savedata.sav') then
      MnuLoad.Enabled := False;

   //変数の初期値を代入
   CurBack := 1;
   CurChara := 1;
   SetChara := False;
   TextPoint := 0;
   phase := normal;
   for i := 0 to 3 do
      SkipTo[i] := -1;
            
            
   SkipLoop := False;
            
            
   //オブジェクトの実体を生成する
   BackBmp := TBitmap.Create;
(以下省略)
            

MnuSkipClickイベントの説明に入ります。

(43)でフラグSkipLoopをTrueにし、メッセージスキップ中であることを明示します。
(44)はスキップ中であるという条件と、
「選択肢ではない(phaseがchoiceではない)」こと、
「シナリオが終わっていない(phaseがstopではない)」ことをまとめたものです。
これがTrueの間、whileループが回ります。
ループ内では、次のメッセージを表示する手続きをOneStep(45)で呼び出し、
(46)ではループ中にマウスがクリックされた場合、それを検知するために
メッセージ・キューに溜まった処理を行えるようにします。
ループを抜けた後は、(47)でフラグをFalseにします。

SkipLoopはループ内でいつFalseになるの?

マウスがクリックされると、PrimImageMouseDownイベントが呼び出されます。
そのイベントの最初でSkipLoopをFalseにしましょう。

            
procedure TMainForm.PrimImageMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
            
            
   //メッセージスキップ中なら、メッセージスキップを終了する
   if SkipLoop then
   begin
      SkipLoop := False;
      Exit;
   end;
            
            
   //押したボタンが左だったら
   (以下省略)
            

実行してみましょう。
右クリックで出現するポップアップメニューで「メッセージスキップ」を選択すると、
選択肢のページが表示されるまで一気に進みます。
選択肢のページ以降でスキップを行った場合は、最後のページで止まります。

シナリオが短いので試すのは難しいですが、
スキップ中にマウスをクリックしたらスキップが中断することも確認してみると良いでしょう。


第13回へ
アドベンチャーゲーム設計論トップへ戻る
開発分室へ戻る
トップページへ戻る