ベーマガ世代、ChatGPTとゼロからRPGを作る旅
第12章:仮タイトル~名前設定~導入イベント
長いストーリーイベントへの対応
これまでの流れで、NPCに話しかけてフラグを立てたりアイテムをもらったりするような通常イベントには対応済みだ。
ただ、タイトル画面からゲームをスタートするところの導入部分ができていない。
オープニングイベントの流れは、脳内でおおむねできつつあった。
ムービーなどでなく、キャラクタがちょこちょこ歩き回るイメージ。
つまり、プレイヤーやNPCが向きを変えたり移動したり、自由自在に動き回って、物語を伝える必要がある。
これさえできれば、ゲーム内のいかなるシーンでも、ストーリーをキャラの動きで伝えられるようになる。
っとその前に、NPCがプレイヤーのほうをまだ向くようになっていなかったっけ。
NPCに話しかけるとプレイヤーを向くようにするにはどうしたらいいかな
いいね、その演出すごく自然!
NPCには既に向きを導入していたのだが、ChatGPTはそのことを忘れていたらしく、もう一度向き設定から説明してくれた。
1. NPCデータに向きを設定する(導入済み)
const npcList = [
{ name: "村人", x: 5, y: 8, direction: "down" },
{ name: "神父さん", x: 7, y: 6, direction: "down" },
];
2. 会話イベントで向きを変える部分の実装
const dx = npc.x - playerX;
const dy = npc.y - playerY;
if (Math.abs(dx) > Math.abs(dy)) {
npc.dir = dx > 0 ? "left" : "right";
} else {
npc.dir = dy > 0 ? "up" : "down";
}
ソースを渡して向きを変える部分だけ改めて修正箇所を確認。
ChatGPTは「マージしようか」と言ってくれたが、任せて動かなくなってデバッグするとかえって手間だ。
vscodeも導入したことだし、ChatGPTに任せるのは止めて自分でマージする。
炎が燃える、みたいなアニメーションも相談してみたのだが、ChatGPTが提案してくれたのが、NPCやeventObjectと別にeffectListを準備する方針。
背景タイル → エフェクト → プレイヤー → 前景タイル → メッセージ/UI
の順で描画するとのこと。
これなら確かにいろいろできそうだが、また新しい機能を導入し、あちこちソースを直し、絵を作ったり、設置する座標を設定していったりと大変そうだ。
いったんエフェクト専用機能の導入は見送り、既存のeventObjectなどで代用する方向で考えることにした。
ところで、イベントシーンでプレイヤー含めて歩きまわったり、 プレイヤーなしでマップを移動したりすることがあるよね。どう実装するのが便利かな。
プレイヤーの移動、向き変更を追加。
ノーマルモードではキー入力に応じてプレイヤーが移動するが、イベント中はイベント用のプレイヤー移動を呼び出すようにした。
ただ、これだけだと、プレイヤーがいきなり到着地点へ高速移動してしまう。
キューに格納し1マスずつ歩かせ、目的地についたらコールバックで次に進む、というような処理を入れる必要がある。
これらを実現するために、playerMoveToという関数を作成した。
🔥イベントにプレイヤー移動を組み込む方法まとめ
1. eventScript.js にplayerMoveToコマンドを追加する!
2. イベント実行ハンドラに登録!
現行ソースには、イベント実行ハンドラなんてものは存在しないが、どうやらChatGPTの脳内ではeventHandlersという関数があると想定しているようだ。
今のevent処理にはeventHandlersなるものが設定されていないんだけど、どこから呼び出すの?
いい質問だね!
実は、今の君の eventScript.js を見ると、
**「typeごとの関数をマッピングするeventHandlers」**みたいなテーブルは存在してないっぽい。
・・・中略・・・
条件分岐のところに、
新しい playerMoveTo を生やせばOK!!
結局、イベントハンドラを使わずとも、条件分岐に書き込むだけで簡単に実装できそうだ。
ちなみに、今回見送ったイベントハンドラーとやらは、以下のようなものらしい。
綺麗にまとめて書きやすいのだとか。
これはまあ、ChatGPTのハルシネーションのお陰で、後日のための勉強になったということで。
const eventHandlers = {
message: (c, next) => messageWindow.setText([...], next),
custom: (c, next) => c.func(),
playerMoveTo: playerMoveToEvent,
// ...その他もろもろの処理
};
プレイヤー、NPCともにイベント内で歩かせる準備はできた。
最低限ならこれでよいが、これだと一体ずつしか動けない。
できれば複数キャラを同時に動かしたい。
これだとたとえば、NPC1が右に3歩動いた後、NPC2が3歩動く、みたいなことは実装できそうだけど、NPC1とNPC2が一緒に3歩動く、ということもできる?
💡 【提案】「パラレル(並列)実行ステップ」を作る
例えば、イベントコマンドにこういう形を追加するのはどう?
{
type: "parallel",
actions: [
{ type: "npcMoveTo", id: "npc1", x: 5, y: 10 },
{ type: "npcMoveTo", id: "npc2", x: 8, y: 12 }
],
next: "次のイベントID"
}
おー、なんかバグりそうでこわいけど、イベントを並列で動かすのってかなり重要そうな気がするので実装したい!
実装したところ、想像通りバグった。
一歩進むのに異様に時間がかかって先に進まない。
どうやら何度も移動開始が呼び出されてしまっていたようだ。
修正コードを出してもらったが、既存のコードを上書きしてしまっているっぽいので別のところにバグが出そう。
そこで、並行処理専用の別コードとして作りなおしてもらう。
NPCについてはなぜかnameで指定されていたので、既存のコードと合わせてidで指定するようにお願いする。
しかし、プレイヤーが一気に最後の座標まで飛んでいき、NPCは動かない。
既存のコードを組み込んでもらおうとしたが何かおかしい……
ChatGPTはひとつ質問に答えるたびに、バグが解決したつもりになって「次はイベント実装する?」みたいなことを言うのだが、そうそう一筋縄では動かない。
結局何がどの順でどう呼び出されているのか、ややこしくなってきたコードと睨めっこしながら、ひとつひとつ追っていくことに。
余計な処理をざっくり削除し、さらにNPCが単体対応になっていたのを自力で複数化して、どうにか組み込むことができた。
ふー、npcの移動が複数対応になってなくてえらい苦労したけど、なんとか実装できたよ。
後は、
・プレイヤーが不在のイベント
・(可能ならば)イベント中のマップスクロール
ができるとよいんだけど、いったんプレイヤー非表示のモードを作ったらいいかな。
ChatGPTはプレイヤー不在のイベントについて、playerVisibleというグローバル変数で非表示にする方法を提案。
いたってシンプルな実装方針なので、私もすぐ理解ができ、組み込み完了した。
現時点では危急でないので、スクロールのほうはいったん後日に回す。
マップ移動機能と合わせて、自由な場所でのストーリーイベント演出ができるようになった。
LOADING、タイトル画面、プレイヤー名選択
ストーリーイベントの実装準備が整ったので、いよいよタイトルから導入イベントまでのつなぎを作っていく。
「ここからゲームの世界が始まる」というワクワク感満載の部分だ。
1)jsのロードが一通り終わるまでLOADINGの文字が表示されている
2)ローディングが終わったら、タイトル画面が出て、「はじめから始める」「途中から始める」が選べる。(トンマナはゲームオーバー画面と合わせて)
3)はじめから始めるにすると、プレイヤーの名前を選べる(ドラクエみたいにカタカナ50音文字が出て、カーソルで選んでいけると理想)
4)名前の決定後、最初のイベントスクリプトが開始する
5)途中から始めるを選んだ場合は、ロードしてゲームを続ける
かなり本格的なRPGの導入部になってきたね!✨
実装方針
ひとつめのローディング画面について、ChatGPTは、既存の画面描画関数 draw()で"loading..."と表示させる方法を提案。
そして一定期間後、たとえば仮に3秒で以下の用にタイマーを起動し、画面を切り替えたらよいのではという。
setTimeout(finishLoading, 3000);
こちらはいったん却下。
なぜなら、draw()が動き始めるころには、ロードはもう終わっているからだ。
draw()は、関連js、画像などを読み込み、初期化完了した「後」に動き出す。
LOADING...は初めから表示されていないと意味がない。
そして、関連js、画像などが(タイマーではなく確実に)すべて読み込まれた直後に、スタート画面に切り替えたい。
つまり、javascriptで余計なことなんてせずに……
HTMLの真ん中に 960×540の四角を出して、真ん中にLOADING...みたいなのが出てる状態を入れられる?
そう、これだけでいいのだ。
もちろんできるよ!
ChatGPTは、loading...とゲーム画面を切り替えるhtml+cssを作ってくれた。
うんうん、divタグでの表示/非表示切り替えって、こういうところでこそ使うべきだよね。
css調整が得意でないので、とても助かる。
一点、フォントをPixelMplus12と指定するミスがあったので、PixelMplusに修正してもらったのだが、これは前にもあったミスだ。
一度間違えて覚えたことを繰り返しがちなのは、ChatGPTも人間と同じようだ。
「シミュレーション」を「シュミレーション」って書いちゃうケース、しょっちゅう見かけるし。
うちの子は小さいとき、「エレベーター」を何度直しても「エベレーター」って言っていたっけ……
名前設定画面
さて、仮のタイトル画面を作り、そこに、ゲーム内で作っていた「ロード機能」をがっちゃんこ(死語?)。
そしていよいよ……!
名前の設定画面の導入だ!
なんかあちこち調整が必要だったけど、実装できたよ~。 次はいよいよ名前入力画面かな!
よし、次はいよいよ「名前入力画面」だね。
ざっくり流れをまとめるね。
________________________________________
🎯 名前入力画面の仕様イメージ
• カーソルで 50音(カタカナ) を選ぶ(グリッド配置)
• ひらがなでもいいけど、今回はドラクエ風にカタカナ!
• 最大 〇文字(たとえば6文字まで)入力できる
• 「けってい」「もどる」ボタンも用意する
• 入力完了したら、プレイヤー名にセットして、最初のイベント開始!
いや、ドラクエはひらがなイケるけどね。
カタカナとひらがな両方対応すると、画面内に納めるのが面倒そうだし、画面切り替えも面倒……。
そして、洋風ファンタジーなので、カタカナのみでよいと思った次第。
さて、ChatGPTは要望を理解して50音の配列表を作ってくれたのだが、濁音などがない。
濁音、半濁音、長音、撥音を追加してほしいな。 もし並べにくかったら、画面上で縦と横が逆でも良いと思う。
了解!!!
濁音・半濁音・長音・撥音まで追加したパターンを考えてみたよ!
________________________________________
📖 フル版カタカナ表(縦方向優先配置案)
こんなふうに、**縦(列優先)**でまとめると自然に配置できる!
出したもらったコード……縦横逆の意味が伝わってない気がするが、いったん教えてもらった通りに導入してみる。
うん、やっぱり縦にはみ出すよね。
実装してみたよ! 下のほうが画面からはみ出してるから、縦と横を逆にできるかな? アイウエオが一番右で、縦に並ぶといいかなと思う。
すごい早いね!✨
なるほど、縦方向を長く使うのではなく、横に長くして、右側にアイウエオが並ぶ形にしたいってことだね。
じゃあ、こう修正するね:
もらったコードを導入すると……
なんと、カーソルキーの動きが逆になってしまった!
縦横の向きは変わらず、画面からはみ出している。
なんというか、ChatGPTは行と列とか、順序とか、幾何学的な配置に弱い気がする。
生成AIも右手と左手を入れ替えたりするし。
小さい子供も文字の左右が逆になったりするけど、脳内で二次元・三次元を理解するのは、結構難しいことなのかもしれない。
説明するのが面倒になったので、とりあえず行と列をエイっと入れ替えてみたら……
直った!
いやあ、簡単に直ってよかった。
50音表を打つだけでも面倒だし、その間をカーソルで移動させるのも自力で作ったらさぞ大変だったろう。
あとは、余白を適当に調整して、50音で名前を入れる機能、ついに導入完了っ!
この勢いで、画面転換のエフェクトも追加。
今までフェードイン・フェードアウトしかなかったが、左右から文字がスライドしてくるようなエフェクトも追加。
……と、ここでなんと、チャットの容量がオーバーして、会話が続けられなくなってしまった。
(20$/月の有料版では、1つのチャットにつき約2万5,000文字が上限らしい。なお、すでにいくつかチャットは分けている)
しかし、とりあえずなんとか導入が完了し、タイトル~導入イベントまでが仮実装できた。
ふ~達成感!
▲ 仮実装したタイトル~導入イベント!(YouTube)(画質悪い場合は右下歯車から1080pを選んでください)
モンスターどうしよ……ついでに家族にも相談
良い頃合いなので、作り中のゲームを家族に見せてみた。
ついでに、懸案事項であった敵についても相談した。
初期の敵がスズメバチとかアブとかなんだよね。
虫が敵のせいで離脱する人が嫌だなーと心配なんだけど、どう思う?
ていうか、ハチはともかくアブがちょっと見た目的に……気持ち悪いかも?
やめたほうがいいって分かってるなら、やめれば?
う……ま、まあ正論だな。
敵のデザインって大事だよ。ポケモンとかドラクエとか見れば分かるでしょ。
グロイ路線狙ってるわけじゃないでしょ?
狙ってない。
じゃあなんでこんなリアル系のモンスターばっか出すの?
うう……でも、ポケモンみたいなかわいいの思いつかない。 それに最初のほうは魔物っぽくない身近な敵にしようと思ったんだよね。
ていうかアブが敵っておかしくない?
でもアブって、噛むよ?
いやいやいや、アブはおかしいでしょ!
……とりあえずアブはやめることにしました。
代わりに何を入れようか。カラスでも入れようかと考えていると、
リアル系の敵にしたいなら、カラスとかにすれば?
おお……人間、考えることって一緒ですなあ。
照準式戦闘って慣れてない人多いと思うから、チュートリアルとして、最初に庭のかかしを倒す予定なんだよね。
へー、いいんじゃない。
そういえばアンダーテールでもかかし倒すのあったな。
えっ、そうなの? かぶるのまずいかな。
てか、アンダーテールってRPGだったの?
(一瞬だけ画面チラ見せしてもらって、アクションかシューティングだと思っていた)
RPGだよ!
別にかかしぐらいなら大丈夫じゃないの?
後でそのかかしが怒って襲ってきたりするんだけど。
げ……じゃあモンスター版のかかし取り下げるわ。
なんか、「人間に粗末に扱われた物たち」シリーズのモンスター群作ろうと思ってたけどやめとくわ。
いやー、やっぱり人間が思いつくことって似てるもんだな。こわいこわい。
アンダーテール、めちゃくちゃ面白そうだし、いつかやってみたいな。
でも反射神経が壊滅的で、チラ見したアクション部分(?)が解ける気がしないんだけど……
なんかそもそも、CG全般的にださくて気になってるんだけどさー
(キャラとかマップとか全部)
別にいいんじゃない?
中途半端にレベルあげると、一気にハードル上がるよ。
分かるでしょ?
……うん、分かる。
「初めて作る素人にしては頑張った」のが、激うまなCGになると「プロと比べると、やっぱしょぼい」ってなりそう。
続編出すころには生成AIのCGももっと使えるようになってるかもしれないし、その時にちゃんとすればいいかな……
えっ、そんなかかるの?
もう大体できてるよね?
いや、できてないよ!!
まだ、町を描いて、城も描いて、途中のフィールドマップもダンジョンも作って、アイテム準備して……
敵もまだまだ足りないし、曲も全部はできてないし、サウンドもまだつけ足りないし、
戦闘バランス調整、レベルアップ調整、イベントシナリオつなげて、
そしてデバッグとかデバッグとかデバッグとか、
ボス戦用の演出とか、エンディングとか、パズル要素、おまけのサブイベントとか、ちょこっとしたお遊び機能とか、
山ほどやることがあるよ!!!
なんといっても百里を行く者は九十を半ばとす、なのだ。
あとちょっと! と油断して、最後の最後で仕上がらない、なんてことはよくある話。
最初の予定では、今ごろリリースしてるはずだったんだけどね……とほほ。
ほんと、RPGって信じられないほどやることが多い。
ドラクエ4あたりのレトロRPGでさえ、なぜあれほどスタッフロールが長いのか、ようやく実感できてきた。
考えなきゃいけないこと、調整しなきゃいけないことが、めちゃくちゃ多い!
これを全部ゼロから一人で作るのって無謀かもしれないけど、だからこそトライする価値はある。
ていうか一人じゃないし。
まあChatGPTと二人で頑張るよ。
いや二人っていうな!
そもそもChatGPTは1体なのか複数ペルソナなのかよく分からないが、分かりやすく1人でまあいいじゃないか。
旅は道連れなのである。
旅といえば、この連載を読んでくださっている酔狂な皆様も、たいへんたいへんありがたい心の支えだ。
本当にありがとう!
絶対年内にはリリースしてみせる。
がんばるぞ~っ!
次回は、いよいよ……
今まで放置していたスマホ対応に取り掛かり、七転八倒悶絶……!