Skyrim Mod 製作日記 - 20 - ダンジョンを自動生成する (5)
ウィザードリィ#1のマップを利用したダンジョン生成について、前回は敵の配置について記載しました。
前回まではただ配置していただけで、最初から敵対状態としてありましたのでダンジョンに入った瞬間、敵が動き出してうるさかったです。
そこで、近付いたら敵対するように変更を加えます。
近付いたら敵対するようにする
色々と方法があるのかもしれませんが、配置時はAI DataのAggressionをUnaggressiveにして、TriggerでのScriptで、Very Aggressiveにするという方法をとりました。
Aggression (攻撃性)
Faction Relationships (派閥関係)と関連付け、 Actor がいつ戦闘を開始するのかを決定します。
タイプ | 値 | 説明 |
---|---|---|
Unaggressive(平和的) | 0 | 戦闘に入りません。 |
Aggressive(攻撃的) | 1 | 敵を見つけると攻撃します。 |
Very Aggressive(非常に攻撃的) | 2 | 敵対者及び中立関係の者を見つけると、攻撃します。 |
Frenzied(凶暴) | 3 | 視界に入った者は誰でも攻撃します。 Actor は、標準で Frenzied 設定になっていることは希です。通常、魔法や特殊効果(例えば激昂の呪文など)の結果でしかこの状態にはなりません。 |
※以下のサイトより抜粋
AI Data Tab/ja - Creation Kit
敵配置用のActorの設定を変更します。
[Template Data]の[Use AI Data]のチェックを外して、変更できるようにします。
[AI Data]タブより、[Aggression]のコンボボックスから一番上の"Unaggressive"を選択します。
Scriptは以下のdefaultSetMultiAVTriggerScript
を利用することにしました。
ScriptName defaultSetMultiAVTriggerScript extends ObjectReference {Sets the specified actor value on the actor(s) to the specified value when the player enters the trigger.} import game import debug ObjectReference property Actor1 Auto ObjectReference property Actor2 Auto ObjectReference property Actor3 Auto ObjectReference property Actor4 Auto ObjectReference property Actor5 Auto String property ActorValueName Auto int property ActorValueValue Auto bool property onlyOnce = True Auto bool property evalPackageAfterwards = True Auto bool property onlyPlayer = True Auto auto State Waiting Event onTriggerEnter(ObjectReference obj) if (!onlyPlayer || obj == GetPlayer()) if (Actor1 != None) (Actor1 as Actor).SetAV(ActorValueName, ActorValueValue) EndIf if (Actor2 != None) (Actor2 as Actor).SetAV(ActorValueName, ActorValueValue) EndIf if (Actor3 != None) (Actor3 as Actor).SetAV(ActorValueName, ActorValueValue) EndIf if (Actor4 != None) (Actor4 as Actor).SetAV(ActorValueName, ActorValueValue) EndIf if (Actor5 != None) (Actor5 as Actor).SetAV(ActorValueName, ActorValueValue) EndIf if (evalPackageAfterwards) if (Actor1 != None) (Actor1 as Actor).EvaluatePackage() EndIf if (Actor2 != None) (Actor2 as Actor).EvaluatePackage() EndIf if (Actor3 != None) (Actor3 as Actor).EvaluatePackage() EndIf if (Actor4 != None) (Actor4 as Actor).EvaluatePackage() EndIf if (Actor5 != None) (Actor5 as Actor).EvaluatePackage() EndIf EndIf if (onlyOnce) GoToState("AllDone") EndIf EndIf EndEvent EndState State AllDone Event OnTriggerEnter(ObjectReference obj) ;Do nothing. EndEvent EndState
アクター5人まで、任意のアクターバリューの設定を変更できるので、中々に汎用的なスクリプトではあると思います。
こうして使えそうなスクリプトを駆使するのも面白みはありますが、やりたい事がすんなり出来ないのでもどかしいですね。
次に、このスクリプトを利用するActivatorを登録します。
プロパティはデフォルトで次の設定をしておきます。
後は、マップ設定で、Triggerとして配置する位置と関連付けする敵の設定をします。
これまでは、ただ単に向きを数値指定していただけでしたが、Triggerの配置は先頭に"T"を付けて、後は連番で、配置する向きは":"で区切って向きの数値。
敵の配置はそのまま向きの数値の後に、":"で区切って、Triggerの配置の"T"を除いた数値。
同じ場所に複数配置する場合、"/"で区切るとしました。
わかりづらいなぁと思いますが、まぁおいおいと最適化していきます。
この例だと、右下の部屋は部屋のドアの前に"T1"で1番目のTriggerを北側(1)に配置。
部屋にいる敵は南側(4)を向き、1番目のTriggerに関連付けています。
CKで見ると次のような感じです。
スクリプトのプロパティは次のように配置した敵のFormIDを設定してあります。
これで、扉に近付いた際に敵が敵対して動き出すようにできました。
本当は扉を開いた瞬間に動かすようにしたかったのですが、うまくできそうなスクリプトを発見できませんでした。
また、他の仕組みもまだよくわかっていません。
ちなみに、公開した後に気づきましたが、次のように結構Triggerの幅が狭いため、ギリギリ扉を開ける位置で開くと、感知しないため、遠距離での先制攻撃が出来てしまいます。
今回の対応で、大体やりたいことは出来ました。
PS4版でフォロワーがうまくテレポートできなかったり、敵の反応方法を改善したりなど、そもそも敵の配置や種類の調整などやった方がいい事は多々ありますが、自動生成の仕組み作りとしてはほぼOKかなと思います。
今後改善するなら、よりウィザードリィらしい要素を加えたりなどで、より遊べるModになるでしょうか。
もっともソースコードはかなり汚くなったので、もしツールとして公開するなら、マップの仕組みなども含めて全体的に見直していかなければいけません。
そう考えるとまだまだ未完成ですね・・・
以上。
【2017/04/22 追記】
Mod製作についての動画を作成しました。
www.nicovideo.jp