クエストシーンでNPCを動かそう!

こんにちは、yousukeVEです。
今回は先日の記事で行ったとおり、ChaosDragonsに新規追加されたシステムの仕組みの備忘録を兼ねた解説になります。
正直こういうのは苦手な分野なのですが、こうやって何らかの形にして残しておかないと、
日々の生活でどんどん忘れていってしまいますからね…。


さて、先日のChaosDragons1.7aアップデートで追加された新機能「ドラゴンボーンの挑発」ですが、
これの効果はドラゴンをプレイヤーの元へ誘導するというものです。

これは機能の実演動画ですね。大体こんな感じで動きます。

この"ドラゴンがプレイヤーの元までやってくる"という一連の動作は全て"クエストシーン"によって動作しています。
このクエストシーンはプレイヤーが発動したパワーがトリガーとなって開始され、ドラゴンがプレイヤーの元までやってきた時点で終了となります。

たったそれだけの為にクエスト作成なんて大げさな…
と思うかもしれませんが、実際スカイリムではこんな感じの見えない所で仕事をするクエストが沢山稼動しています。
NPCの会話だとか、ランダムイベントだとかも全てこのクエストが動かしているんです。
スカイリムにおける様々な事象を実質的に動かしているのはだいたいクエストと言っても良いですね。
ストーリーマネージャーというさらに高次元的な存在も居ますが、現時点で私はこれを全く使いこなせていないので、今回は置いときましょう。

少し話がそれましたが、NPCを動かすとなるとどうしてもクエストが必要になってきます。
特に"動作させたい時だけNPCに影響を与える"というクエストの機能はとても重要です。ようするに後腐れが無いんですね。



前置きが長くなってますね。グダグダ語ってしまうのは私の本当に悪い癖です。

それでは実際に「ドラゴンボーンの挑発」を順を追って作って行きたいと思います。
まず最初に――
qs_img_000.jpg
このきったない絵は設計図です。
システム開発においては、まず目標を決めてそれをどのような構造で組み立てるかを明確にすることが大事です。
アルゴリズムとかフローチャートとかそういうの、プログラムを少しでもかじった事があるのならば聞いたことがあるのではないでしょうか?

行き当たりばったりで行くと絶対に袋小路に嵌ります。無論、経験則です。



それでは設計図の上のほう、トリガーとなるパワーの作成から始めましょう。
「MagicEffect」欄をクリックして新たなMagicEffectを作成します。既存のものをコピーしても良いです。
qs_img_001a.jpg
大体こんな感じで設定して下さい。IDや名前とかは自分が解かりやすいように付けましょう。
個人的にはIDは先頭に「aaa」と付けたりすると後で探しやすくなると思います。
後でこれにスクリプトを付けますが、今はひとまず置いておきましょう。

画像右上の欄「Target Conditions」はこの魔法効果の効果を受ける対象を限定するものです。
内容を文に書き起こすとしたら、
「対象はドラゴン族であり、CrDragonVoice(ドラゴンのモブ声)で、かつMQNoDragonAbsorb(ドラゴンソウルを吸収できないファクション)及びDLCTameDragon(ドラゴンライド関連のファクション)ファクションに所属しておらず、今居る場所はブラックリーチかアポクリファではない場合のみ対象となる」
なんだか制約が多そうですが、これの目的はクエスト関連のNPCが指定されてしまわないようにすることです。
バグってしまったりすると怖いのでね…

続いては「Spell」欄をクリックしてSpellを作成します。
「MagicEffect」はあくまで効果なのでそのままではプレイヤーが装備したり詠唱したり出来ません。
使用するためには「Spell」「MagicEffect」を追加してやる必要があります。
それでは先ほどと同じように作成ないし、コピペして…
qs_img_002.jpg
右側の枠内で右クリックして「New」を選択後、先ほど作成したMegicEffectを選択します。
この際、以下の図に記す事を注意して下さい。
qs_img_003.jpg



これでシーンのトリガーとなるスペルの準備は出来ました。
続いてはシーンのアクションを担当する「AI Package」の設定を行いましょう。

AI Packageは簡単に言えばNPCに特定の行動を取らせるものです。
例えば、ホワイトランの鍛冶屋エイドリアンさんは昼間はいつも鍛冶場で鉄を打っていますが、あれはAI Packageによって制御されている行動なのです。

戦闘行動を除けば、スカイリムにおけるNPCの行動の全てはAI Packageによる制御といえるでしょう。
AI Packageは以下の画像のようにNPCに直接設定することも出来ますが、今回の目的においては賢い手段ではありません。
qs_img_004.jpg
バニラのオブジェクトを変更するということはそれだけ他のModとの競合の危険性が増しますからね。
今回の用法は、クエストにより必要となった場合のみ、NPCにこのAI Packageを提供するという形で行きます。
スカイリムのMod製作においては、なるべくバニラのオブジェクトは弄らずに、なるべく新規作成したオブジェクトから必要な時だけ参照するという作り方をするのが良いと思います。
無論、何のModを作るかによりますけどね。

ではでは、作っていきましょう。
右クリックから「New」で新規作成。名前は適当に決めて、以下の画像のように設定します。
qs_img_005.jpg
赤枠の「Orbit」とはドラゴンのようなNPCが上空を旋回しながら飛ぶ為の設定です。
続いて青枠、一番上の項目「Target Location」は旋回の中心となるポイント。
qs_img_006.jpg
クリックしてこのように設定することで中心点をプレイヤーに設定することが出来ます。

下に続く数値はそれぞれ「旋回の内径」「旋回の外径」「高度」となっています。
狭いにこしたことは無いですが、狭すぎると挙動がバギーになりますのでホドホドにしときましょう。

では次のタブに移って、以下のように設定します。
qs_img_007.jpg
「Ingore Combat」の項目にチェックを入れるとこのAI Packageの稼働中は戦闘を無視するようになるそうです。
なんでそんな曖昧な言い方をするかって言うと、この設定をしてあるにも関わらず、普通にパッケージを無視して戦闘をしてたりすることがよくあるからです。
「No Combat Alert」も似たようなことを目的としてますが、あまり効果を実感できなかったり…。
「Must Complete」も同上…まあ、願掛けみたいなものです。

戦闘中のAI制御はとても難しいです。
なので万一の時の為にもちゃんと処理を完了できるようにバイパス処理を用意しておくことが重要です。
上でお見せした設計図でもいざと言う時の為の強制終了処理の記述がありますね。
それに関しては後々、説明することにしましょう。

ここまで設定できたらAI Packageの設定はこれで終わりです。「OK」を押しましょう。



さて、それではいよいよクエストを作っていきましょうか。

Object Windowからクエストの欄を選択し、いつもの如く右クリックからの新規作成を行います。
すると、まずこのような画面が現れます。
qs_img_008.jpg
名前は自分の好きなように、設定は上の画像のようにします。
「Priority」はクエストの優先度。同じオブジェクトが複数のクエストにより指定された場合、どちらを優先するかの指標となります。
なるべく優先して欲しい場合はこれを高めに設定しておきましょう。
今回は50に設定。
「Start Game Enabled」にチェックを入れるとゲーム開始時にこのクエストが自動的に開始するようになります。

これらの設定が終わったら一旦「OK」を押してウィンドウを閉じ、データをセーブしましょう。
こうしないとクエストの項目の設定が上手くできません。

では続きの設定をしていきましょう。

先ほど作成したクエストを開き、「Quest Aliases」タブに飛びます。
qs_img_009.jpg
このエイリアスというのは先ほど書きましたクエストの最大の利点「動作させたい時だけ影響を与える」事が可能になるものです。
クエストにおいて最も重要といえる設定です。これを使いこなせればMod制作の幅は大きく広がるはずです。

この機能に関して簡単に説明してみましょうか。
いわば、NPC等を職業に就かせる様なものです。(ちなみにエイリアスに入れるのは何もNPCに限りません)
例えばリディアさんは普段はブリーズホームの二階でパンをかじってます。
しかし、プレイヤーが彼女をフォロワーに誘うと、彼女はフォロワーという職に就いて、フォロワーとしての仕事を始めるというわけです。
だいたいこれがエイリアスの効果です。

また、クエスト内で稼動するシーンに参加させるためにはこのエイリアスに対象となるNPCが入っている必要があります。

それでは作っていきましょう。
枠内にて右クリックから新規作成。いつもの事ですね。
qs_img_010.jpg
このように設定しましょう。
ちなみに、スクリーンの解像度が1600*900だとウィンドウが画面に入りきらないので下の項目の設定が出来ません。
また、下にある「OK」のボタンが押せないので、編集を完了させたい場合は名前欄をクリックした後にEnterキーを押す必要があります。
まあ、重要な項目はだいたい上のほうにあるので、あまり困る事はないのですが…。

設定項目の解説をしましょう。
赤枠の「Specific Reference」にチェックを入れることで、外部からオブジェクトをエイリアスに引っ張ってこれるようになります。
青枠の「Allow Reuse in Quest」は既に他のクエストのエイリアスに所属しているNPCであってもこのエイリアスに入れるようにするものになります。

これでエイリアスの設定は終わりです。編集を完了しましょう。



続いて「Scenes」タブに飛びます。
シーンはスカイリム内のイベントの設定になります。
オープニングの壮大なイベントもこのシーンによって制御されているのです。
実際にはオープニングにはもっと色々な機能が複雑にかみ合っているのですが…まあ、スカイリム最大規模のイベントですからね。
それは置いといて。
qs_img_011.jpg
これが記事冒頭から何度も書いてきたシーンというやつです。今は何も設定されていないので空ですね。
作っていきましょう。
まず左側の枠を右クリックして「New」からシーンを作成します。
名前は自分がわかりやすいように設定。

作成が終わったら作ったシーンをクリックして右側の枠を右クリック。
qs_img_012.jpg
赤枠内の「Add Phase at End」を選択肢しシーンのフェイズを作ります。
シーンの進行はこのフェイズによって管理します。
例えばA点からB点に行き来するシーンを作りたいのならば、フェイズ1にA点からB点へいくアクションを、フェイズ2にB点からA点に戻るアクションを設定します。

今回用意するフェイズは3つ。
フェイズ1は待ち時間とします。
待ち時間を設ける理由は、これを設定することにより心なしかシーンの成功率が上がるからです。
フェイズ2では実際にドラゴンがプレイヤーの元にやってくるアクションを行います。
最後のフェイズ3は終了処理となります。

実は今回のような場合、フェイズは1つあれば十部だと思います。
ただ、私はこういう処理はなるべく解かりやすいようにまとめたいので、このようにフェイズごとにハッキリと処理を分けております。
これを見ている方は別に私のやり方にあわせる必要は無いので、自分のやりやすいように設定して下さい。

フェイズを設定したら今度は右クリックからのメニューで上の画像の青枠内の「New Actor」を選択。

先ほど作成したエイリアスを追加します。
すると右側の枠内はこのようになるはず。
qs_img_013.jpg
それではいよいよアクションを設定していきます。
まずはフェイズ1から。
フェイズ1の上にカーソルを持っていき、右クリックから「New Action」「Timer」を選択。
qs_img_014.jpg
「Timer」というのはその名の通り時間経過によるフェイズの移行を行いたい時に使います。
qs_img_015.jpg
これがTimerの設定ウィンドウです。
重要なのは赤枠内の項目で、ここで待機する時間を設定します。
時間は1秒に設定。

次はフェイズ2。
フェイズ1と同じ要領でフェイズ2の上で右クリックからの今度は「Package」を選択。
qs_img_016.jpg
このようなウィンドウが開くのでここで右クリックから先ほど作成したパッケージを選択します。
そしたら「OK」でウィンドウを閉じて設定完了。

最後はフェイズ3ですが特にアクションは設定しません。
まだシーンにスクリプトを設定する必要があるのですが、それは後回しにしてとりあえずシーン設定を一旦ここで切ります。



さて、次はスクリプトの編集を始めましょうか。
これを見ている方の中にはスクリプトの事を考えただけで頭がクラクラするという方も居るかもしれません。
でも、要領さえ解かってしまえばそんなに難しいものではないので、是非一度勉強してみてください。
プログラムが自分の思い描いた通りに動作することに快感を感じられるのならば絶対にハマると思います。
このブログの右メニューにあるリンクの項目にCKで使用されているスクリプト言語「Papyrus」についてのページがあるので、
是非とも一度覗いてみてください。(ただし、英語のページですが…)

ではScriptタブへと飛びます。
qs_img_017.jpg
右クリックから「Add Script」を選択。続いて出てくるウィンドウでは一番上の「NewScript」を選択します。
名前は自分の解かりやすいように、探しやすいようにつけましょう。
なるべく作るModに合わせた名前をつけるのが良いと思います。

ここでスクリプトの編集についてなのですが、CKに付いてるエディタよりも「Subline Text2」というエディタを使用するのをお勧めします。
デフォルトのものはとても使いづらく、複雑なスクリプトを書くのには向いていません。
Subline Text2の導入方法についてはそれについてまとめられている方が居るので、調べてみてください。
ここに書くにはあまりにも脱線しすぎますし、かと言って私が解説記事を作るのもなんだか気がひけるので、その点ご容赦下さい。

それではScriptを書きましょう。
先ほど追加したスクリプトを右クリックし、
CKのエディタを使うのならば「Edit Source」を、
外部のエディタを使うのならば「Open in External Editor」を選択します。
qs_img_018.jpg

で、実際のスクリプトの入力なんですが…
正直、これを何処まで解説したら良いのやら…本当にこういうのは情報量が半端無いので1から説明してたら、何十個も記事が必要になってしまいます。
一体何処から説明しよう?if文の意味から?プロパティについてから?

う~ん、とりあえず以下の画像が説明コメント付きのソースコードになります。
qs_img_019.jpg
ちょっと解説してみましょう。


●一番上の変数宣言について
タイトルのすぐ下のの記述はプロパティ宣言となります。
基本的には変数型の次に「property」と記述します。
例えばint型変数ならば――
int property (好きな名前) auto
という感じに記入します。
この宣言の役割は外から情報を持ってくることにあります。

ソース内でこのように記述することでCKでスクリプトをダブルクリックで開いた際に
qs_img_020.jpg
このように外部の情報をスクリプトに渡すことが出来るのです。

例えばヘイムスカー氏にあれこれしたいスクリプトを作るとして、スクリプトの内から外にあるヘイムスカー氏の情報を持ってくることは出来ません。
そういう場合は「actorbase property pHeimskr auto」といった感じでスクリプト内でプロパティ宣言、コンパイルしておき、次にCK側でスクリプトを開いてからヘイムスカー氏の情報を渡してやれば良いのです。
こんな説明で解かるかな?

あと、プロパティ宣言しない場合は普通の変数として扱われます。
変数型はプログラムを少しでもかじったことのある人ならば誰もが知ってるであろう、「int」「float」「bool」等が使えます。

で、肝心の内容なんですが――
「pDragonAlias」は先ほど作成したDragonのエイリアスを持ってくるため。
「pSceneMsg~」と続いているものは処理の節目に表示させるメッセージのため。
「pDragonGoPlayerScene」はさっき作ったシーンを持ってくるため。
「pExpEffect」は効果が発動した時に爆発エフェクトを発生させる為に用意したものになります。


●Event OnInit()について
OnInitは初期化の処理となります。
ぶっちゃけて言えば、今回のスクリプトにおいてはあまり意味の無い処理です。
いわゆる願掛けとして設定してます。


●Function ShowStartOrEndMessage()について
渡された引数を元に処理の開始メッセージか終了メッセージを表示します。
「Function」で始める関数は自分の好きに名前や引数を設定できます。
そのかわり「On~(上のOnInitとか)」の処理と違って、自分で何処からか呼び出してやる必要があります。
この処理はシーンの開始と終わり際に呼び出すように後で設定します。


●Function DragonCombatStop()について
対象となるNPC(ドラゴン)の戦闘を一旦終了させます。
この処理はシーンの開始時に呼び出すように後で設定します。


●Function ClearAlias()について
エイリアスをクリアします。
シーンが終わった時に、情報を初期化しスタンバイ状態に戻す為の処理です。
この処理はシーンの終了時に呼び出すように後で設定します。


●Function SceneStart()について
シーンを始めるための処理です。
シーン開始にはいくつかの条件があり、まずはプレイヤーと対象の距離が一定以上である必要があり、Dragonのエイリアスは空であり、ヘルス残値が35%以上である場合のみシーンが開始され、呼び出された際にこの条件を満たさない場合は弾かれます。
これはトリガーとなるパワーから呼び出されるように後で設定します。


●Function SceneShutDown()について
一定時間後、シーンを強制終了する処理です。
何らかの外的要因でシーンが正常に終了しなかった為の逃げの処理です。設計図にも書いてありましたね。
これは先ほど書いた「SceneStart」関数が呼び出され、シーンが開始した時に発動します。

これでメインのスクリプトは終わりです。ではコンパイルして仕上げに掛かるとしましょうか。



まずスクリプトに情報を渡してやる必要があります。
せっかくプロパティ宣言しても何も情報を渡さなければ意味がありません。
CKでスクリプトをダブルクリックしてそれぞれのプロパティ設定をします。
そうそう、「pSceneMsg~」のプロパティで受け取るメッセージはまた後で設定するので今は置いといてください。

それが終わったらScenesタブへ。

フェイズ1をクリックして開き、「Completion」タブを開きます。こちらのタブはフェイズ終了時のアクションを担当します。
フェイズ開始時にしたい場合は「Start」タブの方を編集して下さい。
では、下の空欄に以下の画像のように記入します。
qs_img_021.jpg
ここでは先ほど作成したメッセージ表示処理とドラゴンの戦闘を一時中断させる処理を呼び出します。

「(GetOwningQuest() as 【スクリプト名】 ).【呼び出したい関数や変数名】」と入力することで、このシーンの親となるクエスト内のスクリプトを参照できます。
終わったらCompileを押してコンパイルします。

続いてフェイズ3へ。先ほどと同じように開いて―
qs_img_022.jpg
このように記述します。
ここでは先ほど作成したメッセージ表示処理とDragonのエイリアスをクリアさせる処理を呼び出します。
終わったらCompileを押してコンパイルします。

ここまで設定したらクエストの設定は終わりです。最後にOKを押して編集を完了しましょう。

最後に冒頭で作成したMagic Effectを開きます。
クエストにスクリプトを追加した時と同じ要領でこちらも右下の欄からスクリプトを新規作成します。
そしたらエディタを開いて――
qs_img_023.jpg
このように記述します。
「OnEffectStart」の処理は魔法効果が始まった時に呼び出される処理です。
そしてここでさっき作ったクエストのスクリプト「SceneStart」を呼び出します。
このスクリプトの役割はこれだけです。
コンパイルしてCKに戻りましょう。

qs_img_024.jpg
プロパティにクエストスクリプトの情報を渡して完了です。


最後に、Messageについて説明しておきます。
これは別に必要の無い項目なのですが、シーンの進行を視覚化したいので作っておきます。
メッセージ自体はスクリプトに直接記入することも出来るのですが、翻訳関連で難があるので、CKでオブジェクトとして作成するようにしたほうが良いです。

作成するメッセージは4つ。
シーン開始時、シーン終了時、失敗時1(対象との距離が近すぎる)、失敗時2(一連の処理がリセットされていない)
となります。

ではMessage欄に移動していつもの要領で新規作成、以下のように設定します。
qs_img_025.jpg
このメッセージはシーンの開始時に表示させるものです。
他のも同じ要領で作成しましょう。

作成が終わったら、クエストスクリプトのプロパティに追加するのを忘れないようにして下さい。

ちなみに、赤枠の中にクエストを指定して、「< Alias=○○(クエストエイリアスの名前)>」と記入することで、そのエイリアスに所属するオブジェクトの名前を表示できます。
このメッセージの場合は効果対象となったドラゴンの名前が表示されるようになります。



これで一連の処理が完成しました。
しかし、このままではパワーをコンソールで取得しないといけません。
それは面倒なので、セーブデータを読み込んだ時に自動で取得するようにしてみましょう。

クエストのスクリプトにプロパティを追加します。

spell property pSpell auto

これはスペル用の変数宣言です。
続いて同じスクリプト内のOnInit()の処理に以下を追記します。

actor player = game.GetPlayer()
if(!player.HasSpell(pSpell))
player.AddSpell(pSpell)
endif


終わったらスクリプトをコンパイルしてCK側でプロパティにトリガーとなるスペルを渡します。

これで初回ロード時に自動的にパワーが追加されます。
OnInitの処理は最初の一度しか呼び出されないので、負荷の心配とかはしなくていいです。

ちなみに、ChaosDragonsではこの方法ではなく、別途にパワー追加クエストを用意して二通りのタイミングでプレイヤーに取得させるようにしています。
一つはミルムルニル撃破時、もう一つは既にミルムルニルを撃破したセーブデータを読み込んだ時。
個人的にここら辺の設定には変にこだわりがあったのでこのようにしました。
構造的には何も特別な事はしておらず、初回ロード時に「OnInit()」処理にてパワーを取得できるかどうか判別。
ミルムルニルを既に撃破していた場合はそのままパワーを取得して終わり、まだ撃破していないのならば取得させずに一旦処理を終了。
そしてミルムルニルが撃破されたら、スクリプトが起動し、パワーを取得と言う流れです。
ミルムルニルが死んだかどうかの判定には「OnDying()」の処理を使っています。
これはNPCに掛ける処理になるので、あらかじめミルムルニルを作成したクエストのエイリアスに入れておき、エイリアス側にスクリプトを設定するという方法で行っています。



ふう…何だかとても長くなってしまいましたね。
しかしこれでもかなり端折った方です。全部事細かく記していたら論文みたいな文量になってしまいますよ、ホントに…。
今回、解説した事柄の中には私が勘違いしていたり、間違っていたりする情報があるかもしれません。
「ここ違う」とか「こうしたほうがもっと良い」という点等がございましたら遠慮なく言ってください。
この記事も何回も読み返してチェックしましたが、もし間違いや新たな発見等がありましたら内容を修正するかもしれません。

それではこの辺りで…

あ!そうそう、スクリプトに関してなんですが、1.7a時点でのスクリプトには少し不備があります。
といっても致命的なものではないのですが、修正と調整を行ったものをパッチファイルとして出来れば近日中にアップロードしたいと思います。
スポンサーサイト

コメント

非公開コメント

No title

>最後に冒頭で作成したMagic Effectを開きます。
>クエストにスクリプトを追加した時と同じ要領でこちらも右下の欄からクエストを新規作成します。
>そしたらエディタを開いて――
新規作成するのはスクリプト?

Re: No title

すいません、誤字ですね。
修正しておきました。
プロフィール

yousukeVE

Author:yousukeVE
TESV:Skyrimのプレイヤーにて大のドラゴン好きのyousukeVEと申します。
ちなみに読みは「ようすけ」じゃなくて「ゆーすけ」です。
最後の"VE"は別に読まなくていいです。

最近はFallout4に浮気気味。

生態:主な活動時間は午後6時から午前0時前後。(日曜、祝日を除く)

Nexusにて"yousukeve"の名で自作Modをアップロードしてます。

最新記事
最新コメント
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QR