NPC とは?
NPC (Non Player Character) は「プレイヤー以外のキャラクター」という意味のネットゲーム用語 (?) らしいですが、ここでは RPG 上の非戦闘員を指す言葉として使いましょう。要するに、町をうろうろしていて何かしらの会話ができるアレです。今回は、町に適当な NPC を配置して、会話ができるようにしてみましょう。ついでに、もうひとつマップを追加します。
NPC の作成と配置
localsave int g_Init = 0; // 主人公作成フラグ localsave int g_BoxOpen = 0; // 箱を開けたフラグ /* * 家のマップ関数 */ mapfunc House(){ // (中略) } /* * 町のマップ関数 */ mapfunc Town(){ void *civil = CreateChara(3, 1); // NPC 作成 PutChara(civil, 16, 16, 0, 2); // NPC 配置 // 毎回のロード処理 PutPlayer(); // 主人公を置く PlayMusic("Field.mid", 1); // BGM 再生 TransitMap(-1, 10); // 画面切り替え // メインループ while(1){ // 無限ループ PeekAllMessage(); // 必ず必要 // 家のドアに話しかけると中に入る if(Investigate(11, 12, 0, 1)){ PlaySound("Command.wav", 0); // サウンド再生 // ドアのチップを「開いたドア」に置き換える ReplaceObject(11, 12, 22, 23); RenderMap(0); // マップ描画 SetMap("House.qm"); // 移動先マップを設定 SetTransit(3, 11, 0, 1); // 移動先座標を設定 return; // マップ関数終了 } // 道の端に来たら隣のマップに移動 if(CheckRect2(0, 17, 0, 20)){ SetMap("Field.qm"); // 移動先マップを設定 SetTransit(30, -1, 0, 0); // 移動先座標を設定 return; // マップ関数終了 } // NPC と会話する if(SpeakChara(civil, 1)){ PlaySound("Command.wav", 0); // サウンド再生 ResetWindow(); // メッセージウィンドウ初期化 PushString("今日はよい天気じゃのぉ。", 0x00e0e0e0, 1); Message(); // メッセージ表示 continue; // ループやり直し } NormalProcess(1); // RPG 処理 } } /* * 畑のマップ関数 */ mapfunc Field(){ // 毎回のロード処理 PutPlayer(); // 主人公を置く PlayMusic("Field.mid", 1); // BGM 再生 TransitMap(-1, 10); // 画面切り替え // メインループ while(1){ // 無限ループ PeekAllMessage(); // 必ず必要 // 道の端に来たら隣のマップに移動 if(CheckRect2(31, 17, 31, 20)){ SetMap("Town.qm"); // 移動先マップを設定 SetTransit(1, -1, 0, 2); // 移動先座標を設定 return; // マップ関数終了 } NormalProcess(1); // RPG 処理 } }
NPC を作って会話する
マップ関数 Town の始めで NPC 用のキャラクターを作成して配置しています。プレイヤーが操作するためのキャラクターは RegisterChara 関数を用いてデータベースに登録しなければなりませんが、NPC のように一時的に出現するキャラクターについては登録する必要がありません。また、プレイヤーのキャラクターは PutPlayer 関数を使って配置していましたが、NPC や敵キャラなどは PutChara 関数で配置します。ここで作成したキャラクターのポインタ civil は後で使うので取っておきます。同マップ関数の「NPC と会話〜」の部分ですが、作成した NPC と会話を行うためには SpeakChara 関数を使用します。SpeakChara 関数は、Investigate 関数の対象が動いているキャラクターになったものだと思ってください。ただし、SpeakChara 関数の第 2 引数に 1 を指定すると、対象のキャラクターを振り返らせて自動的にマップを描画してくれるので、コマンド処理でマップ描画を行う必要がありません。
もうひとつマップを追加する
さて、今回も前回と同様にして "Field.qm" というマップを追加しました。手順はほとんど同じですが、キャラクターの座標判定に CheckRect2 関数を使用している点が異なっています。CheckRect2 関数を使うと、この例のように、幅のある道によるマップ移動などをまとめて判定できるので便利です。このとき、SetTransit 関数の座標指定に -1 を指定することで、移動前の座標を継承できるという点に注意してください。
実行してみる
どうでしょうか。NPC と会話することができましたか?隣のマップに移動することはできましたか?道の中を通っていた位置がマップ移動後と対応していることを確認してください。さて、次はいよいよ少し RPG っぽいイベントを作成してみようと思います。