ビジュアルノベルの超チュートリアル Vol.1

2023年11月15日水曜日

GDevelop Tutorial

X f B! P L

はじめに

今回はアンケートでご要望の多かった「テキスト系」ゲームのチュートリアルをご紹介します。
 
ノベルやアドベンチャーなどを制作するには『吉里吉里Z』や『ティラノビルダー』などテキストメインのゲームに特化した開発ツールがあります。

吉里吉里Z

吉里吉里Zは、吉里吉里2の後継バージョンです。 吉里吉里Zを使うと2Dゲームやアプリケーションを作ることができます。 多くの商用ADV/ノベルゲームで使用されています。

ティラノスクリプト|スマホ対応のノベルゲームエンジン。無料

ティラノスクリプト|スマホ対応のノベルゲームエンジン。無料

本格的なノベルゲームが作れるツール。利用作品は20000作品以上

これらの開発ツールはテキストメインのゲーム制作に最適化されており、グラフィック面でも様々なプラグインがサポートされてます。

GDevelopでもテキストメインのゲームを制作することは可能ですが、可能というだけで得意だというわけではありません。
というのも、アクションゲームやシューティングゲームは便利なビヘイビアやアセットが豊富に用意されているのに比べ、テキストメインのゲームを想定したビヘイビアやアセットがあまり用意されていないので、足りないものはすべて自作する必要があります。

PANDAKOさんが制作したDialog Boxという拡張機能はあります。)

UIを凝れば凝るほどイベントも複雑になってきます。
ですので、手軽さという点においてGDevelopはテキストゲーム特化型開発ツールに及びません。

ただ、GDevelopの自由度、柔軟性を活かし、例えばテキストメインのゲームにパズルやアクション要素のあるミニゲームなどをプラスアルファしたり、パーティクルエミッターや立体音響などダイナミックな演出を加えることで表現力は豊かになり、工夫を凝らせばテキストゲーム特化型開発ツール以上の個性やパフォーマンスを発揮することでしょう。

今回は必要最低限、絵とテキストと選択肢を表示するだけの、シンプルかつオーソドックスなビジュアルノベルの制作過程をご紹介します。

下記リンクより、先にダウンロードしたサンプルをGDevelopで開き、チュートリアルと照らし合わせながらご確認いただくことをおすすめします。
記事の最後にオンラインでプレイできるgd.gamesへのリンクもご用意しています。

サンプルノベルゲーム

ステップ1: オブジェクトを用意する

最初にテキストの背景となる「ダイアログ」をタイルスプライトで追加します。
ビヘイビアにはTweenを追加してください。


そして、枠線を表示するためのアウトラインをエフェクトから追加します。

つぎにテキストオブジェクトを追加しますが、先にテキストをアニメーションさせるエクステンションを追加します。

プロジェクトマネージャーを開き、拡張機能追加から「Auto typing animation for text」を検索して追加してください。

このエクステンションはテキストをタイプライターのように一文字ずつ表示するビヘイビアです。
アクションでスキップして一気に表示することもできまし、「テキストのアニメーションが完了した」という条件でイベントを組み込むことも可能です。
 
シナリオを表示するためのテキストオブジェクトを追加し、それにこのビヘイビアを追加してください。

この他、選択肢となるテキスト、選択肢の結果を表示するテキスト、テキストの背景となるタイルスプライトもそれぞれ追加します。

つぎに、テキストを送るボタンとして使う「アロー」をスプライトオブジェクトで追加します。
画像はアセットストアのものを利用するか、ご自身でご用意してください。

そのほか、背景や人物の絵となるスプライトオブジェクトも追加します。
ひとつのスプライトオブジェクトに、アニメーションパターンとして各人物や風景を追加し、のちにイベントでアニメーション番号を指定して切り替えます。

ビヘイビアにはTweenを追加します。


ちなみに、今回使用したイラストはすべてDALL-E 3を使って作成しています。
DALL·E 3

DALL·E 3

DALL·E 3 understands significantly more nuance and detail than our previous systems, allowing you to easily translate your ideas into exceptionally accurate images.

つぎに、ダイアログからはみ出したテキストを非表示にするためのマスクを追加します。
マスクとは、任意のスプライトをマスクが重なった部分以外は非表示にする拡張機能です。

例えるなら型抜きです。
もし仮にマスクに使用するスプライトが星型なら、任意の画像を星型に切り抜くことができます。

拡張機能追加で「Masking」で検索してインストールしてください。
マスクに使用するスプライトオブジェクトも追加します。
マスク用のスプライトは単色塗りつぶしで構いませんが明るい色にしないとマスキングするテキストの視認性が悪くなります。

あとはダイアログからはみ出したテキストをマスク内にスクロールさせて表示させるために、スライダーを使います。
新規オブジェクト追加でSliderを追加してください。

これらを使うことで、ダイアログに収まりきらない長い文章を上下にスクロールできます。
スクロールはスライダーを動かしたり、テキストそのものをドラッグで動かすことも可能です。

この部分だけは少し凝っているので、コードもそれなりに複雑になります。
テキストをスクロールせず画面いっぱいに表示する方法もあります。
お好みでお選びください。

さて、作成したオブジェクトをシーンに配置しますが、座標は後ほどイベントで変更しますので配置する場所は大まかで構いません。

ここまでの準備が整ったら、イベントエディタを開きます。

ステップ2: シーン開始時のイベント

シーン開始と同時に、インスタンスの座標や透明度などをイベントで変更します。

まずはダイアログの座標を変更します。
X座標: SceneWindowWidth()/2 - 32 
X座標をウィンドウの幅の半分、そこから32を引いた値にします。
Y座標: SceneWindowHeight() - 416 
Y座標はウィンドウの高さから416を引いた値にします。

X軸に関しては、ダイアログの初期のサイズが32×32なので、ウィンドウの幅の半分から32を引くことで、ちょうど真ん中に座標を変更できます。
Y軸に関しては、完全に開ききったダイアログの高さが352Pixelなので、ダイアログの下に64Pixelのスペースができます。

最初は見えないように非表示か透明度を0にします。


次にメインテキストの座標を変更します。
X座標: 90 
Y座標: Dialog.Y() + 10 

Y座標はダイアログの高さから10Pixel下にします。

続いて、自動で折り返すラッピング幅を変更します。
 SceneWindowWidth() - 190 
ウィンドウの幅から190Pixelを引いた幅にします。
テキストの折り返しを有効にし、エフェクトからアウトラインを追加します。

最初は非表示にして、auto typingを一時停止しておきます。

次はマスクのイベントです。
マスクのサイズを変更します。
X座標: SceneWindowWidth() - 120 
Y座標: 352 

X座標はラッピング幅と同じく、ウィンドウの幅から120Pixelを引いた値にします。
Y座標はダイアログの高さと同じ352Pixelです。

次はページ送り用のオブジェクトです。
X座標: SceneWindowWidth() - 70 
Y座標: SceneWindowHeight() - 80 

X座標はウィンドウの幅から70Pixelを引いた値
Y座標はウィンドウの高さから80を引いた値です。
必要に応じて、画像のサイズはタップしやすい大きさに変更します。


次はスライダーです。
スライダーは初期状態では水平(横向き)です。
これを縦にして使いたいので、角度を変更します。
角度を変更する:90 を代入
座標も変更します。
X座標: SceneWindowWidth() - 210 
Y座標: Dialog.Y() + 160 

次はスライダーの値を変更します
the valueを変更する: (MainText.Height() - Dialog.Height()) 
メインテキストの高さからダイアログの高さを引いた値を代入します。
これも最初は非表示にします。

次はメインビジュアルとなるイラストです。

まず、サイズを変更します。
X座標: SceneWindowWidth() - 100 
Y座標: SceneWindowWidth() - 100 

横幅をウィンドウの幅から100Pixelを引いた値にします。
今回使用するのは正方形の画像なので縦の幅もこれと同じにします。

次に座標です。
X座標: SceneWindowWidth() / 2 
Y座標: (Picture.Height()/2) + 50 

X座標はウィンドウの幅の半分です
Y座標は画像の高さの半分に、50Pixelを足した値です。

一旦、不透明度を0にします。
次にTweenで不透明度を255まで増やして徐々にフェードインさせます。
Tween識別子は"FrameIn"とします。

ステップ3: ダイアログの展開

フレーム開始時の初期設定が終わったので、メインビジュアルがTweenによって表示されたあとにダイアログを展開するアニメーションをTweenで再生します。

Tween識別子は"FrameIn"のTweenの再生が終了したら、ダイアログのオブジェクト変数"Open"を真にします。
このイベントは真になったときに一回だけ実行します。

ダイアログのオブジェクト変数"Open"が真のとき、ダイアログ展開のTweenを再生します。

まずは幅のTweenです。
 SceneWindowWidth() - 100 へ、150ミリ秒かけてTweenします。
32Pixelから、ウィンドウの幅-100Pixelの値へ徐々に大きくなります。

次はX座標のTweenです。
中央から50に向け、150ミリ秒かけてTweenします。

つづいて、透明度のTweenです。
0から200へ、150ミリ秒かけてTweenします。

これらのTweenが再生終了したら、高さのTweenを再生します。
32から352へ、150ミリ秒かけてTweenします。

高さのTweenが再生終了したら非表示にしていたテキストを表示し、一時停止していたauto typingをResumeします。


ダイアログが開ききったら、テキストが一文字ずつ表示されます。
テキストの内容は後ほど解説する変数を代入します。

ステップ4: テキストのスクロール

テキストの行数が多い場合、テキストの高さがダイアログの高さ以上になるとマスクからはみ出た行は隠れてしまいます。
ですので、テキストの高さがダイアログの高さを超えそうな場合、自動で行を送るイベントを追加します。


その他条件の「イベントと制御フロー」にある「二つの数値を比較する」を選択します。
最初の式: MainText.Height() 
二つ目の式: 352 
テスト記号: >(より大きい) 

テキストの高さがダイアログの高さである352を超えたら、テキストの座標を変更します。
テキストのY座標: Dialog.Y() - (MainText.Height() - 352) 

テキストの高さから352を引いた値をダイアログのY座標から引くことで、テキストの高さが増えるたびに上に移動して自動的に行が送られます。


無条件(常に実行)で、スライダーのThe maximum valueを変更します。
 MainText.Height() - 340 
スライダーの最大値が、常にテキストの高さから340を引いた値になります。

タイプライターのアニメーションが終了してテキストがすべて表示されたら、非表示にしていたスライダーを表示し、The valueを変更します。
 (MainText.Height() - Dialog.Height()) 
テキストの高さからダイアログの高さを引いた値にします。

スライダーを上下させてスライダーの値が変わると、それに連動してテキストのY座標を変更します。
テキストのY座標: Dialog.Y() - Slider.Value() 
ダイアログのY座標から、スライダーの値を引きます。

オブジェクトに「ドラッグ可能」のビヘイビアを追加することで、ドラッグによる移動を可能にします。
このビヘイビアを使って、スライダーによるテキストの上下移動のほかに、テキストを直接ドラッグして移動できるようにします。

このとき、ドラッグによってX座標の方向にテキストが動かないようにX座標を固定します。
そして、Y座標の移動をスライダーの値に反映させます。
スライダーの値: Dialog.Y()-MainText.Y() 

これで、テキストのスクロールが実装されました。


つぎは、テキストのタイプライターアニメーションをスキップして、いっきにすべて表示できるようにするイベントを追加します。

ダイアログのMultiTouch buttonのビヘイビアを追加します。
イベントで、ダイアログをタップしたとき(タップを離したとき)に「Skip to the end of …」のアクションを実行します。

タイピングアニメーションが終了した、またはタイピングアニメーションをスキップした時にスライダー、アローボタンを表示し、テキストの末尾を表示するように座標を変更します。
同時に、シーン変数"Progress"に1を加算します。
このシーン変数は進捗具合を判断するためのものです。

テキストがすべて表示されたあとにアローボタンを押したとき、テキストを非表示にしてダイアログを閉じます。


ここまでの工程が終わったら、つぎはグローバル変数に文章を追加していきます。

ステップ5: グローバル変数

プロジェクトマネージャーからグローバル変数エディターを開きます。
グローバル変数を新規追加します。


ノベル系ゲームは、なんといっても膨大な量のテキストを扱います。
あとから修正を加えるのも大変な作業です。
なので、テキスト管理には変数を使用します。
種類を配列に変更し、子要素を文字列として追加します。


この場合、MainTextという配列に番号が割り振られた子要素を追加していく形です。

ゲームの進捗をシーン変数"Progress"で管理し、"Progress"の値と配列の子要素の値が同じになるように文章を追加していきます。

つまり、"Progress"の値が5のときには、MainTextの配列にある子要素5のテキストに変更します。

変数エディタで、配列の子要素はドラッグで順番を入れ替えることが可能ですので、あとから新しい文章を挿入することも容易ですし、カットする場合も該当の子要素を削除するだけです。
ただ、どの文章にどの番号が割り当てられているのかは、別途メモなどで管理して把握しやすくしましょう。

メインテキストのほか、選択肢用の変数と、結果表示用の変数も同じ様に配列で追加します。

ステップ6: 進捗状況に応じてイベントを起こす

進捗具合を示す変数"Progress"の値に応じて選択肢を生成します。
Tweenでフェードインさせ、座標や折り返しなど表示に関する部分を調整します。

表示された選択肢をタッチしたら選択肢のインスタンスを破棄して、結果となるテキストを生成します。
これも同様に座標などを調整します。

結果が表示されたら閉じるためのボタンなどを表示し、進捗を進めます。

つぎは進捗状況に応じて表示する画像を変更します。

同じように進捗状況に応じてBGMを変更したり、効果音を鳴らしたりします。

立体音響をつかって臨場感あふれる効果音なども鳴らすことができます。

おわりに

①文章を表示する
②ページを送って"Progress"を進める
③"Progress"の値に応じて配列から文章を呼び出して代入する。
④"Progress"の値に応じて選択肢を表示する。
⑤選択肢の結果を表示する。
⑥"Progress"の値に応じて画像を変更する。
⑦"Progress"の値に応じてサウンドを変更する(鳴らす)。

基本的に今回のサウンドノベルはこのような工程を繰り返しています。
"Progress"の値を基準にし、文章を変数で管理しているので楽です。

また、ここからさらに真偽値の変数でフラグを作成して複雑な分岐に派生させることも可能です。
UIも凝ってみたり、脱出ゲームのように画面のタッチ要素なども自由に追加できます。
今回のようなテキスト枠とスクロールを使わずに、表示行数を管理すればテキストを画面全体に表示することもできます。
フォントを自由に変更できますし、BBテキストによるリッチテキストを使えば凝った文字装飾もできます。
テキストにエフェクトをかけたりアニメーションさせることもできます。

今回のベースシステムは静的かつ必要最低限なのでシンプルですが、小説1冊分に相当するテキストを編集したり管理する作業はそれなりに骨が折れました。
(それが理由でこの記事を書くためのサンプル完成にかなりの時間を要しました…)
ただ、前述したようにノベルゲーム特化型ゲームエンジンより表現力が豊かなのでオリジナリティを発揮しやすいと思います。

本記事のタイトルが「ビジュアルノベルの超チュートリアル Vol.1」となっていますが、Vol.2は予定していません。

もし、コメント欄でご質問やご要望などが多く寄せられましたらVol.2移行で補足などを書くかもしれませんが、ひとまずはこれで完結です。

記事を書くために制作したサンプルゲームをgd.gamesで一般公開していますので、もしよろしければ試遊してくださいませ。


最後までお読み頂きありがとうございました。

最後までお読みいただきありがとうございました😆
もしよろしければ下記のボタンから応援よろしくお願いします🙇



こちらの記事はいかがでしたか?
ぜひご評価をおねがいします🙏

プロフィール


My name is Cratier.
I'm an indie game developer.


Read more...

このブログを検索

Translate

UPDATE

最新コメント

人気の投稿

アーカイブ

リンク元ランキング

カテゴリー

アンケート



Q.クレイティアのGD覚書でお気に入りのコンテンツはどれですか?

チュートリアル
TIPS
RTA Develop
雑記
That's談
その他


Q.あなたのGDvelop使用歴はどれくらいですか?

1ヶ月未満
半年未満
1年未満
1年以上
2年以上
3年以上
4年以上
5年以上

オープンチャット

LINEアカウント

ご連絡フォーム、またはLINEから お問い合わせ、ご要望、ご指摘など、お気軽にご連絡くださいませ。

ご連絡

名前

メール *

メッセージ *

💗雑談CHAT💗
お気軽にお話しください🐹
同時接続人数:

もしよろしければ下記のボタンから応援よろしくお願いします🙇




QooQ