この記事はUnity アセット真夏のアドベントカレンダー 2018 Summer!23日目の記事です。
この記事ではホラーゲームなどで活用できる視界ジャックの実装方法を紹介します。
基本的なキャラクターの動かし方や、敵の徘徊システムなどは他の方が書いた記事の方が参考になると思うので、ここでは取り扱いません。
視界ジャックとは
ホラーゲーム「SIREN」シリーズで登場する特殊能力である。(幻視とも言う)
この能力を持つプレイヤーは他のキャラクター(味方や敵)の視界を覗き見ることができる。
ジャックとあるが乗っ取るわけではなくあくまで見るだけ。また聴覚も聞き取れる。
敵との戦闘を避けたり、謎を解いたりと本作のキーとなるシステムである。
Unityでは、各キャラクターが持つCameraオブジェクトのアクティブ化を切り替える方法で再現していきます。
0. 開発環境
Unity2018.2.3f1
1. 素材とAssetの用意
使うステージとキャラクターはお好みでインポートしましょう。
プレイヤーキャラクターにはプロ生ちゃんを使用します。
ステージの方は雰囲気を出すためにこちらのMMDステージモデルをお借りします。
MMDモデルなのでMMD4Mecanimも一緒にインポートしておきましょう
敵キャラクターは、こちらのAssetを使います。
ゾンビなどのモデルでもいいですが「SIREN」に登場する屍人は見た目こそゾンビっぽいですが別物です。今回は一般人っぽいモデルを使っていきます。
UI用の素材です。マークやプログレスバーなどのパックです。
また、有料AssetですがCameraFilterPackを使います。
このAssetはCameraに様々なエフェクトを追加することができ、
雰囲気作りのために入れておきます。
2. Sceneへの配置
2.1 ステージ(自前のステージを用意している場合はスキップしてもokです)
インポートした古や村_集落セットの中から、
「古や村_集落v1.62.MMD4Mecanim」を選択しModelデータを作成します。
「古や村_集落v1.62.MMD4Mecanim」が表示されていない場合、MMD4Mecanimがインポートされていない可能性があります。
同じフォルダ内に同名のModelデータができているので、SceneビューかHierarchyビューにD&Dして配置しましょう。
デフォルトのDirectional Lightの設定だとちょっと暗めです
地面の判定をつけたい場合、重くなるかもしれませんがMeshColliderを使うと楽です。
同様の処理を「古や村_集落_橋v1.62.MMD4Mecanim」と「古や村_集落対岸v1.62.MMD4Mecanim」にして、
ちょうどよくScene内に配置するとより雰囲気がでます。
モデルはそのまま使うと小さいので、全てScaleを(2, 2, 2)にしておきましょう。
2.2 プレイヤー
Hierarchyビューに空のGameObjectを作り、名前を「Player」に変更します。
この「Player」の子オブジェクトに、プロ生ちゃん(または自前のキャラクターモデル)を設定します。
「PronamaChan」のPositionは(0, 0, 0)にしておきます。 少しモデルが小さいのでScaleを(2, 2, 2)に変更します。
同じく、「MainCamera」も「Player」の中に入れPositionを(0, 2.5, -4)にします。
ちょうど後方視点となるような配置にしましょう。
Gameビューからはこう見えます。
2.3 敵キャラクター
プレイヤーと同じくHierarchyビューに空のGameObjectを作り、名前を「Enemy」に変更します。
インポートした「Audience」フォルダに「Audience.FBX」があるので、
「Enemy」の子オブジェクトに設定します。
Positionは(0, 0, 0)に、Scaleは少し小さいので(2, 2, 2)にします。
Playerと同じくCameraを持たせます。とりあえずは「Enemy」の直下に置き、
Positionをちょうど顔のあたりにくるように調整します。
3. キャラクターのセットアップ
「Player」と「Enemy」に共通の処理を施します。
まずは、以下の「CharacterSensory.cs」Scriptsをアタッチします。
また、それぞれのCameraにCameraFilterPackから「CameraFilterPack_Noize_TV.cs」をアタッチします。
これはCameraにノイズをかけるフィルターです。強度も自在に変えることができます。
Fadeの初期値が1になっているので0にしておきます。
3.1 プレイヤー
「Player」の「CharacterSensory.cs」のeye、noizeFilterに「Player」の中にあるMainCameraをそれぞれ紐づけます。
他のパラメータはプレイヤーに関係ありません。
「SIREN」ではプレイヤーの視界が狭い設定なので「Player」のカメラにだけフォグをかけます。Cameraに「CameraFilterPack_Atmosphere_Fog.cs」をアタッチします。
Nearが霧が発生し始める距離、Farが霧が発生し終わる距離に該当します。
値を調整する場合、Near < Farの関係を維持しましょう。NearがFarより大きくなると正常に動作しません。
Nearが0、Farが0.05~0.07位がちょうどいいと思います。
Farを0.3以下にすると視界が数メートルも無くなり、映画「ミスト」のような恐怖感を得ることができますが、
「暗すぎるゲーム」「視界が悪すぎるゲーム」は非常にストレスが溜まるのでほどほどにしましょう。
3.2 敵キャラクター
「Enemy」の「CharacterSensory.cs」のeye、noizeFilterに「Enemy」の中にあるCameraをそれぞれ紐づけます。
敵の視界をジャックした場合、敵との距離に応じてノイズがかかります。
敵キャラクターの場合、他のパラメータはそれぞれ以下の意味を持ちます
- minNoizeIntensity 最短距離でのノイズの強度
- maxNoizeIntensity 最長距離でのノイズの強度
- minNoizeDistance 最短距離の値
- maxNoizeDistance 最長距離の値
このデフォルト値の場合、敵との距離が30以下の場合、ノイズ強度が0になり。
距離が延びるにつれノイズ強度が上がり、距離90で最大の0.5になります。
Scriptの設定はこれで完了ですが、もうひと工夫加えます。
「Enemy」の中に入っているCameraですが、これをモデルの中にいれます。
ちょうど頭の位置に親子関係を変化させます。
この時、Position、Rotationの値が変化しますが、0に初期化しないようにしましょう。
Cameraに新しく「CameraFilterPack_Classic_ThermalVision.cs」をアタッチします。
これは赤外線カメラのような効果を与えるフィルターです。
数値でお好みで構いません。赤味かかったようにしたいので、以下のようにします
「エイリアン」のようなホラー映画や、「バイオハザード」で怪物の視点になるシーンがたびたびありますが、その視点を再現します。
補足:なぜCameraをModelの位置に入れるのか?
こうすることでキャラクターが待機や歩行アニメーションをするたびにCameraが大きく揺れます。視界ジャックの特性上、臨場感の向上が期待できます。(本家「SIREN」でも使われている手法です)
4. 視界ジャック
ここから視界ジャックを実装していきますが、簡単にいうとただCameraを切り替えるだけです。
4.1 サイトジャック
「Player」に以下の「SightJackControl.cs」Scriptsをアタッチします。
パラメータを以下のように設定します。
PlayerSensoryには「Player」自身を。Charactersの要素には「Enemy」を紐づけ。
NoizeFilterとFogFilterには「Player」のMainCameraを紐づけます。
最初に書いた通り視界ジャックはCameraを切り替えて実現しているので、MainCamera以外のCameraは非アクティブ化しておく必要があります。
CameraDummyPosには、「Player」の頭にあたるオブジェクトを設定します。
プロ生ちゃんの場合、以下のheadを選ぶとよいでしょう。
このCameraDummyPosは、後述するプレイヤーの位置マーカーで使います。
この時点で移動する処理などは入れていないので視界ジャックしかできませんが一旦起動してみましょう。
キーボードのQキーで視界ジャックのオンオフを切り替えることができます。
CameraFilterのノイズが一瞬働き、他のカメラに切り替わります。
「Player」と「Enemy」の距離でジャック中のノイズも変化します。
「Enemy」を複数Duplicateし、「SightJackControl.cs」のCharacter配列に登録すると、キーボードのEキーでチャンネルを切り替えることもできます。
4.2 位置マーカー
視界ジャックまでは実装できました。 次はマーカーの表示を行います。
SIREN | ソフトウェアカタログ | プレイステーション® オフィシャルサイト
視界ジャック中、ジャック対象の視界にはプレイヤーの位置が青いマーカーで表示されます。
また、視界ジャックを終えた後は、ジャックしていた敵の位置がプレイヤーの視界に赤いマーカーで表示されます。
HierarchyビューにCanvasを作成します。
「Canvas」のRenderModeはScreenSpace-Overlayに。
CanvasScalerのUIScaleModeはScaleWIthScreenSizeにしておきましょう。
Canvasができたら、その中にUI -> ImageをCreateします。
名前を「PlayerMarker」にします。これはジャック対象の視界に映る青いマーカーです。
この「PlayerMarker」に以下の「SearchPointer.cs」Scriptをアタッチします。
ImageのSpriteにインポートしたUI Elementsから「circlefillRy86px512px」を選びます。
Colorも青にしておきましょう。
「SearchPointer.cs」は、Pointerに自身のRectTransformを設定してあげます。
これでプレイヤーのマーカーは完成です。次はジャック対象のマーカーを作成します。
「PlayerMarker」をDuplicateで複製し、名前を「JackMarker」に変えます。
複製した「JackMarker」を調整しますがImageの色を赤に変えるだけです。
注意点として、DuplicateするとPointerが複製元のものを参照し続けていることがあるので、「JackMarker」のRectTransformを持っているか確認しておきましょう。
ここまでできたら、「PlayerMarker」「JackMarker」ともに非アクティブ状態にしておきます。
最後にこれらのマーカーが作動するようにします。
マーカーを動かすのは、「Player」にアタッチされている「SightJackControl.cs」です。
PlayerPointer、JackPointerの所に先ほど作ったMarkerをそれぞれ紐づけましょう。
これでマーカーも完成です。実際にゲームを起動して視界ジャックを使ってみましょう。
敵の視界からはプレイヤーの位置が青く表示されます。
視界ジャック終了後は、プレイヤーの視界にジャックしていた敵の位置が数秒間赤く表示されます。
ちなみにこれらのマーカーは距離は遮蔽物関係なく表示されます。
立体的な地形や入り組んだ場所ではより慎重な立ち回りが要求されるでしょう。
これで視界ジャックの実装方法は終了です。
まとめ
ここまででやってきたのは、あくまで視界ジャックというゲームシステムの一つを実装したにすぎません。
ここからプレイヤーを動かしたり、アニメーションさせたり、敵が徘徊し襲い掛かってきたり、システムをうまく使ったギミックの構築などゲームとしてはまだまだやるべきことがあります。
定番のホラーゲーム「five nights at freddy's」のようなゲームや、監視カメラをハッキングして機密施設に潜入するようなゲームなど、まったく別のアイデアやシステムを組み合わせてゲームを作っていくというのもいいと思います。
また、私自身UniRxの勉強中ということもあり、載せているコードが中途半端だったりおかしいところがあるかもしれません。ベストなやり方をご存知の方はぜひ教えてほしいです(∩´∀`)∩
他にもGameObjectやComponentを直接参照してる箇所がありますが、そこを自動化したり、いらない部分を削ったりするといいかも!
どんどん改造して自分だけのゲームを作っていきましょー!
あとがき&おまけ
実は私、今までブログというものを書いたことがありません。なのでこの記事が初めてです。
所々レイアウトやCSSが部分な残念なところがあったかもしれませんがゆるして!!!
今回使用しているこちらのカメラフィルターアセット。
実は非常におもしろいアセットです。
これらの他に全部で300ほどのフィルターが含まれてあります。
異界、電脳世界、マトリックス空間、などなど触っているだけでも楽しいので、
興味のあるかたは是非調べてみてください。たびたびセールもしてますよ。
ちょっと長くなりましたが、今回の記事いかがでしたでしょうか?
アセット真夏のアドベントカレンダーも残りあと少し!
明日、24日の担当はTAN-Y(たに) (@TANY_FMPMD) | Twitterさんです。