3Dのアクションゲームに落とし穴ギミックを実装。
床の3Dモデルの頂点の操作は困難なので、穴の3Dモデルで覆って擬似的に再現。
↓の自作ゲームで使用した。
デモ動画
ざっくりした手順
- Pit(落とし穴)プレハブを作成。
- PitタグとPitレイヤーに設定。
- IsTriggerを有効にしたColliderをアタッチ。
- 床を作成。
- Groundレイヤーに設定。
- キャラクタープレハブに追加で設定。
- 落下時用のレイヤーを作成、レイヤーと床との当たり判定を無効化。
- スクリプトでPitタグと衝突判定し、落下時用のレイヤーに差し替え。
詳細な手順
【ダウンロード】落とし穴の3Dモデル
自作。
素人目には中々上手く出来ました。
- ライセンス:CC0
- 頂点数:439
- ダウンロードして適当なフォルダで解凍。
- Pitの3Dモデルとテクスチャを同時選択。
- Projectウィンドウ -> 任意のフォルダに、ドラッグ&ドロップしてインポート。
(3Dモデルのフォルダ下にTexturesという名前でフォルダを作成して除けておいても良い)
Pit(落とし穴)プレハブを作成
*画像の数字と本編の番号は対応していません。
- 上部メニュー -> GameObject -> Create Emptyを選択し、空のオブジェクトを作成、Pitと命名。
- ヒエラルキー -> Pitに先程インポートした3Dモデルをドラッグ&ドロップして設置。
- ヒエラルキー -> Pit下のPit-LowPolyを選択。
- インスペクター -> Transformコンポーネント -> Position Y:0.001に変更。
- ヒエラルキー -> Pitを選択。
- インスペクター -> Add Component -> Box Colliderをアタッチ、続いて設定。
- IsTrigger:有効化
- Center:(0, 0.05, 0)
- Size:(0.1, 0.1, 0.1)
(穴の中心に来るように設置するのがポイント)
- インスペクター -> Add Component -> Rigidbodyをアタッチ、続いて設定。
(多分Rigidbodyが無くても動くが一応)- IsKinematic:有効化
- Collision Detection:Continuous Speculative
- Use Gravity:無効化(一応)
- インスペクター -> Add Component -> Box Colliderをアタッチ、続いて設定。
床の作成 (既に作成している場合はそちらを使用)
上部メニュー -> GameObject -> 3D Object -> Planeを選択、床を作成。
プレイヤーにスクリプトを追加 (移動や3Dモデルは、既に実装している事を想定)
以下のコードをプレイヤーのメインスクリプトに追記するか、新規にスクリプトをアタッチして記述。
using System.Collections;
//使わなかったので一応コメントアウトしている。
//using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//通常状態のプレイヤーのレイヤー。
LayerMask defaultPlayerLayer;
//落下状態のプレイヤーのレイヤー。
LayerMask fallenPlayerLayer;
//落下状態のフラグ。
public bool isFalling;
//落下してから落下状態がリセットされるまでの距離。
float endFallDistance = -2.0f;
//落下コルーチン管理用変数。
Coroutine fall;
//落下開始位置。
float startFallPositionY;
void Awake()
{
defaultPlayerLayer = LayerMask.NameToLayer("Player");
fallenPlayerLayer = LayerMask.NameToLayer("FallenPlayer");
}
void OnTriggerEnter(Collider col)
{
//落下中でない状態で、Pitの中心に設定したColliderに触れた場合のみ実行。
if (!isFalling && col.gameObject.CompareTag("Pit")) {
StartFall();
}
}
void StartFall()
{
fall = StartCoroutine("Fall");
}
IEnumerator Fall()
{
isFalling = true;
gameObject.layer = fallenPlayerLayer;
startFallPositionY = transform.position.y;
while (true) {
if (transform.position.y - startFallPositionY <= endFallDistance) {
isFalling = false;
gameObject.layer = defaultPlayerLayer;
yield break;
}
yield return null;
}
}
//落下コルーチンをリセット(オブジェクトプールで使い回す&死亡等で強制終了させる場合用)。
void ResetFall()
{
if (fall != null) {
StopCoroutine(fall);
fall = null;
}
}
}
タグとレイヤーを作成&設定
- ヒエラルキー -> 何でも良いので適当に選択。
- インスペクター -> 名前欄の下にある「Tag」 > Add Tag…を選択、Tags&Layersを開く。
- 新規タグを作成「Pit」
- 新規レイヤーを作成「Pit」「Ground」「Player」「FallenPlayer」
- ヒエラルキー -> Pitを選択。
- インスペクター -> TagをPitに設定。
- インスペクター -> LayerをPitに設定。
レイヤーの変更時に出るダイアログは「Yes, change children」でも「No, this object only」でも、どちらでもOK。
(ColliderをPitオブジェクト本体に付けている為)
- ヒエラルキー -> 床(前項で作成したならばPlane)を選択。
- インスペクター -> LayerをGroundに設定。
- ヒエラルキー -> Playerを選択。
- インスペクター -> LayerをPlayerに設定。
一部レイヤー間の衝突判定を無効化
*画像の数字と本編の番号は対応していません。
- 上部メニュー -> Edit -> Project Settings…を選択。
- Project Settingsウィンドウ -> サイドバーメニュー -> Physicsを選択。
- 下までスクロール -> Layer Collision Matrixの設定を変更。
- Ground x FallenPlayer:無効化
- Pit x FallenPlayer:無効化
以上で完成!