その9ー3 《総集編》 ロールプレイングゲームの作成 会話表示・会話による分岐

 NPCとの会話 


マップの中をキャラクターが自由に移動できるようになりました

次はNPCとの会話に挑戦です




会話は
RPGゲームを作る作業の中で
最も自由度が高い作業です


思い描いたストーリーに合わせたセリフ
会話による様々な分岐など
会話の骨組みのプログラムを作ってしまえば
わりと気軽に設定できます



まずはNPCと会話するにはどうすれば良いのかを
考えていきましょう






NPCが居ることを判断する条件式


前章でキャラクターが移動する時に
進む先の地形が何かを判断する条件式を組みました


その条件式に
進んだ先がNPCという条件を追加する
という方法が一番楽だと思います


進んだ先は人(15)の場合と
カウンター(2)の場合に会話が発生するので
平地ではなかった場合の条件式として加えていきましょう



会話の部分に、その結果を入れるようにします




ここに会話を表示するプログラムを組みたいところですが
重要な注意点があります


WM_LBUTTONDOWNが発生した後には
WM_PAINTが呼び出されます

WM_PAINT内には
マップを表示させるプログラムがあるため
ここ(LBUTTONDOWN)で会話を表示させてもすぐに
マップを表示させるプログラムに上書きされてしまいます



なので、
マップを表示させるプログラムが終了した後
会話のプログラムを作る必要があるのです







会話の内容表示関数

WM_PAINT内の
マップやキャラクターの表示処理が終わった後に
Kaiwa()という関数を作りましょう



この関数の内訳ですが
会話が成立しなかった可能性が考えられるので
念のため戻り値を取れるint型で定義
以下の関数をグローバルで定義してください


int Kaiwa(HDC kdc, int kx, int ky);


引数はHDC型と、int型が2つ
理由は後ほど説明していきます





そして関数の中身です


まず、青枠表示された部分で
キャラクターの現在位置を判断しています

会話窓を表示させる時、
キャラクターと会話窓が被ってしまわないように
会話窓を表示させる場所
マップに対してキャラクター位置の逆側になるよう調整しています




文字を表示させるのは
TextOut()
という関数です


第1引数 HDC(デバイスコンテキスト)
第2引数 文字の先頭を表示させるx座標
第3引数 文字の先頭を表示させるy座標
第4引数 文字列
第5引数 文字数



描画には
WM_PAINTで使用しているデバイスコンテキストを使用するため
Kaiwa()第1引数には
WM_PAINTで作成されているHDCを受け渡しています



そして
SetBkMode()
SetTextColor()
という関数は
文字を表示させる上での
オプション関数と考えて良いと思います



SetBkMode()には
TRANSPARENT(文字の背景透過、指定しないと四角い枠が付きます)を指定

SetTextColor()では
文字色をRGB(赤、緑、青)で1~255の数値によって指定できます





xx=0;yy=0;
(グローバル変数int型 で定義してください)
の部分ですが
この2つにはキャラクターの現在位置ではなく
会話座標(人・カウンター)の座標を格納します


そして、Kaiwa()関数にその座標を受け渡し、
受け取ったら即、座標をリセットしています



何故そんな面倒な処理が必要になるのか説明すると

会話の条件式があるWM_LBUTTONDOWN
Kaiwa()関数を実行するWM_PAINTには
相関関係は無く
windowからメッセージが送られた際には
個々に命令を実行するからです



ん・・?
でもWM_LBUTTONDOWNの中に
WM_PAINTを呼び出す命令があるじゃん



確かに、
マウスクリックが発生した際はWM_PAINTが呼ばれるようにしています

ですが、WM_PAINT
「再描画が必要な時」
にwindowから呼ばれるので
プログラムを組む人が想定していない時に
Kaiwa()関数を実行する可能性があります




何故組んだコードが 思ったとおりに動かないのか分からない場合の
大きな原因のひとつとして
こうしたウインドウメッセージによるトラップが挙げられます

それに対してのバグ対策だと思ってください



試しにこの1行を消して実行してみると
ウインドウメッセージというものが何か
分かり易くなるかもしれません





kx、kyにはxx、yyからそれぞれ受け取った
会話をする人がいる場所が入っていますので
それを条件式にして
その場所にいる人との会話の内容を作ります






仕上げ


会話の枠のビットマップをキャラクターの位置の反対側に表示し
その上に文字を表示するKaiwa()関数が出来ました


これで準備は全て整ったので
再度NPCが居るかどうか判断する条件式に戻りましょう



条件式の//会話//の部分は上のようになります


Kaiwa()関数に受け渡すため
xx,yyに会話座標を設定します

クリックで進んだ座標(実際には進まない)が入る形になります






実行結果



x=2、y=1の場所にいる人との会話です


あとはNPCのいる場所を元に
Kaiwa()関数内に
条件式を追加していきましょう




会話の内容は自由です

好きなように入力していってみてください



マップ下方にいる人と会話した時は
会話は上方に表示されます






会話による分岐

ここまで出来たら
会話が発生した時の分岐は非常に簡単です


Kaiwa()関数の中で会話を表示させた時に
イベントを発生させるだけです




例えば、

●話したら通れるようになる所がある●

指定した座標のマップチップを別なものに変える
人(15)を(0)にすれば
その人はいなくなります



 ●アイテムが手に入る HPが回復する●

それぞれに該当する変数の値を変える



●状態によって会話の内容が変わる●

フラグの変数を用意して
フラグが立っていれば表示する会話の内容を条件式で変更する


といった感じで
とても楽に、様々なアクションを起こすことができます





準備は大変ですが
この自由度の高さがゲームプログラミングの魅力です


NPCとの会話時に
自分のホームページやSNS
YouTubeチャンネルを表示させることなども出来てしまいます

発想次第で何でも出来ます








次章はRPGで戦闘に突入するための
「エンカウント」
と、戦闘に突入して画面を表示させるところまで解説したいと思います

お楽しみに!