現場レベルのゲーム制作が、すべてここで学べます。
この記事は、Unity ホラー風脱出ゲームの作り方をわかりやすく解説していくシリーズの第7回です。
前回はプレイヤーの行動をもとに正解・不正解を判定し、
その結果に応じて「今何番出口」カウンターを制御しました。
また、プレイヤーが方向感覚を見失わないように、
EXIT看板を設置して進行方向をわかりやすくする工夫も行いました。
前回の記事:

前回までに扱ってきた異変は、物が現れたり消えたり、位置が変わったりするようなシンプルなものが中心でした。今回は一歩進んで、より動きのある“動的な異変”を追加していきます。
動的な異変①:おばけが通過する
まずは、「Room_Start」プレハブに入りましょう。

次に、Hierarchy で右クリックして空のオブジェクトを作成し、名前を 「DynamicAnomalyGroup」 に変更しましょう。

作成した DynamicAnomalyGroup を Hierarchy から選択し、Inspector の Transform を以下の設定にしておきましょう。

Projectウィンドウから
_3DStealthGame > Tutorial_Demo > Demo_Prefabs フォルダ内にある Demo_Ghost を、先ほど作成した DynamicAnomalyGroup へドラッグ&ドロップしましょう。

アタッチした Demo_Ghost を Hierarchy で選択し、Inspector の Transform を以下の設定に変更しましょう。

次に、Hierarchy から DynamicAnomalyGroup をクリックし、右クリックで空のオブジェクトを作成し、DynamicAnomalyGroupの子オブジェクトとなるようにします。作成したオブジェクトの名前を Demo_Ghost_Target に変更しましょう。

作成した Demo_Ghost_Target を Hierarchy から選択し、Inspector の Transform を以下の設定にしておきましょう。

設定が完了したら、Hierarchy から Demo_Ghost を選択し、Inspector 内の Waypoint Patrol (Script) コンポーネントを確認しましょう。
その中の Move Speed を「3」に変更し、Waypoints に新しい要素を追加して、先ほど作成した Demo_Ghost_Target をアタッチします。

設定が完了したら、Demo_Ghost の Inspector 左上にあるチェックボックスをオフにし、オブジェクトを非アクティブ状態にしておきましょう。

次に、前回作成した異変システムに今回の動的異変を追加していきます。
Hierarchy から AnomalySystemOB を選択し、Inspector の Map Anomaly List に新しい要素を追加しましょう。
追加した要素の 表示するオブジェクト(AddObj) には、先ほど作成した Demo_Ghost をアタッチします。
テストがしやすいように、Next Anomaly Forced を True に設定し、Number を「9」に変更しておきましょう。

ここまで設定できたら、一度ゲームを再生して動作を確認してみましょう。
部屋に入った瞬間、ゴーストが横切る演出が再生されていれば成功です。

動的な異変②:おばけが突然現れる
オブジェクトの準備
まず、Hierarchy から先ほど作成した Demo_Ghost を選択し、CTRL+D で複製しましょう。
複製したオブジェクトの名前は Jump_Scare_Ghost に変更しておきます。

複製した Jump_Scare_Ghost を Hierarchy から選択し、Inspector 内の Waypoint Patrol (Script) のチェックを外して、動作しない状態にしておきましょう。

AudioSource コンポーネント内の
Play On Awake と Loop のチェックを外しておきましょう。

スクリプトを作成する
Project フォルダから以前作成した script フォルダを開き、右クリックして Create > MonoBehaviour Scriptを選択します。
作成されたスクリプトの名前を JumpScareTrigger にしましょう。

作成した JumpScareTrigger をダブルクリックすると、
Visual Studio(または設定している外部エディター) が起動し、スクリプトが開きます。
JumpScareTriggerに、以下のコードを記述しましょう。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using UnityEngine; public class JumpScareTrigger : MonoBehaviour { public float triggerDistance = 3f; // 反応する距離 public AudioClip jumpScareClip; // 再生したいオーディオクリップ private AudioSource audioSource; private Transform playerTransform; private bool hasTriggered = false; // 一度だけ再生したい場合に使用 void Start() { // AudioSource を取得 audioSource = GetComponent<AudioSource>(); audioSource.playOnAwake = false; // Player タグのオブジェクトを探す GameObject playerObj = GameObject.FindGameObjectWithTag("Player"); if (playerObj != null) { playerTransform = playerObj.transform; } // 初期スケールを0にしておく(見えない状態にしたい) transform.localScale = Vector3.zero; } void Update() { if (playerTransform == null) return; // 距離を計算 float distance = Vector3.Distance(transform.position, playerTransform.position); // 一定距離以内に入ったら if (distance <= triggerDistance && !hasTriggered) { hasTriggered = true; // スケールを1に(出現) transform.localScale = Vector3.one; // オーディオ再生 if (jumpScareClip != null) { audioSource.PlayOneShot(jumpScareClip); } } } } |
スクリプトの解説
このスクリプトは、
プレイヤーが一定距離まで近づいたときにゴーストのジャンプスケアを発動する仕組みを実装しています。
ゴーストは最初は非表示の状態で、距離条件を満たした瞬間に出現し、音を再生します。
変数の役割
|
1 |
public float triggerDistance = 3f; |
プレイヤーがどれだけ近づいたらジャンプスケアを発動するかを決める距離です。
|
1 |
transform.localScale = Vector3.zero; |
ゴーストの大きさを「0」にして、
ゲーム開始時は見えない状態にしておきます。
Update() の処理
|
1 |
if (playerTransform == null) return; |
Player が見つからず null のままの場合は、その後の処理をスキップします。
|
1 |
float distance = Vector3.Distance(transform.position, playerTransform.position); |
今のゴーストの位置とプレイヤーの位置から、
現在の距離をリアルタイムで計算しています。
|
1 |
if (distance <= triggerDistance && !hasTriggered) |
-
プレイヤーが指定距離以内に入っている
-
まだジャンプスケアを発動していない
この2つの条件が揃ったらジャンプスケアが起動します。
|
1 |
transform.localScale = Vector3.one; |
スケールを 1倍 に戻すことで
一瞬でゴーストが目の前に現れる演出になります。
|
1 2 3 4 |
if (jumpScareClip != null) { audioSource.PlayOneShot(jumpScareClip); } |
設定されていればジャンプスケア音を再生します。
複雑な構文の追加解説(初心者向け)
Vector3.Distance(a, b) ってどういう仕組?
Vector3.Distance は
2点の距離を3次元空間で計算する関数 です。
数学の「距離の公式」を Unity が内部で計算しています。
例:
|
1 |
float distance = Vector3.Distance(pointA, pointB); |
!hasTriggered の「!」とは何?
「!」は 否定演算子 (NOT) です。
-
hasTriggeredが false →!hasTriggeredは true -
hasTriggeredが true →!hasTriggeredは false
つまりこの条件
|
1 |
if (!hasTriggered) |
は「まだ発動していないなら」という意味になります。
transform.localScale = Vector3.zero; の効果
Vector3.zero は (0,0,0) のこと。
スケールが 0 になると、
物体は完全に見えなくなる
=レンダリングされません。
逆に出現させるときは
|
1 |
transform.localScale = Vector3.one; |
Vector3.one は (1,1,1) を表すので元の大きさに戻ります。
スクリプトを実装してみる
スクリプトの入力が完了したら、CTRL+S で保存し、Unity に戻りましょう。
次に、作成した JumpScareTrigger スクリプトを、Hierarchy 内の Jump_Scare_Ghost にドラッグ&ドロップしてアタッチします。

Hierarchy から Jump_Scare_Ghost をクリックして選択します。
その状態で、Inspector を確認し、
Jump Scare Trigger (Script) コンポーネントを探しましょう。
コンポーネント内の JumpScareClip の欄に、
SFXLose を検索してアタッチします。

次に、前回作成した異変システムに今回の動的異変を追加していきます。
Hierarchy から AnomalySystemOB を選択し、Inspector の Map Anomaly List に新しい要素を追加しましょう。
追加した要素の 表示するオブジェクト(AddObj) には、Jump_Scare_Ghost をアタッチします。
テストがしやすいように、Next Anomaly Forced のNumber を「10」に変更しておきましょう。

ここまで設定できたら、一度ゲームを再生して動作を確認してみましょう。
部屋に入り、暖炉へ近づいた際にゴーストが出現すれば成功です。

周回を重ねていく中で、ゴーストが出現したままになる場合がありますが、これは問題ありません。
現在は Next Anomaly Forced の Number を使って異変を強制的に指定しているため発生している挙動です。本来は「一度出現した異変は再度出ない」仕組みになっており、通常プレイでは正しく制御されます。
今回のプロジェクトファイル
まとめと次回予告
今回は、動的な異変を2種類追加しました。
これらのスクリプトは単体でも動作しますが、組み合わせることで、より多彩でユニークな異変を自由に作成できます。ぜひいろいろ試してみてください。
次回はいよいよ クリア演出 を実装していきます。
これが加わることで、ゲーム全体の流れがついにひとつの形として完成します。
次回の記事↓

現場レベルのゲーム制作が、すべてここで学べます。






コメント