2020/11/09
今回のお題は「破壊時にバラバラになる木箱」です!
ちょっと前に「乗ると崩れるブロック」というものを作成しました。動的にではなくあらかじめモデルを分解した状態であれば自分でも出来そうだったので、その流れでのトライです。
木箱のモデリング
木箱は検索すればいくらでも出てきますが、好みでバラバラにしたかったこと、モデリングの練習の一環となることからBlenderで自作してみました。
フレームと板を等間隔に配置するのがポイントです。Blenderのスナップ機能 (メニューの磁石マーク) を使用すると綺麗に並べやすくなります。
とはいえ、ゲーム上では多少ずれていてもほとんど気にならない (と思う) のでフィーリングで配置しても大丈夫です。
木のテクスチャはフリーで転がっていたものを使いました。
Unityへインポートする前にUV展開しておくのを忘れないようにしましょう。
モデルのオブジェクトを分割する
ひととおり出来たら戻せるように.blend
ファイルのバックアップをとっておきます。
分割するための下準備としてループカットを入れます。
どのくらいバラバラにしたいかによりますが、他のゲームの破壊できる木箱を見る限りでは、そこまで念入りに分割しなくても十分それっぽく見えそうです。
今回はフレームと板をそれぞれ2等分にし、適当に頂点をずらしてみました。
ループカットした辺が選択状態のまま「Vキー→即左クリック」で頂点を分離させます。分離部分はメッシュが貼られていないので、全選択→Fで貼っておきます。
あとは分離後の各オブジェクトのみを選択し、Pキーでオブジェクトとして分割します。
コンポーネントの設定
各破片にRigidbody
とMeshCollider
を設定します。
木箱破壊前に破片が飛んでいくと困るので、Is Kinematic
にチェックを入れておきます。
バラバラにするロジックの作成
ブロック用のスクリプトに破壊時にバラバラにする処理を記述します。私の場合は破壊時にdestroyObject()
を呼ぶようにしているので、そこに処理を付け加えました。
public void destroyObject() { var random = new System.Random(); var min = -3; var max = 3; gameObject.GetComponentsInChildren<Rigidbody>().ToList().ForEach(r => { r.isKinematic = false; r.transform.SetParent(null); r.gameObject.AddComponent<AutoDestroy>().time = 2f; var vect = new Vector3(random.Next(min, max), random.Next(0, max), random.Next(min, max)); r.AddForce(vect, ForceMode.Impulse); r.AddTorque(vect, ForceMode.Impulse); }); Destroy(gameObject); }
GetComponentsInChildren()
で子となっている破片を取得し、ForEach()
で回して設定していきます。一応破片以外のものを取得しないように型引数にRigidbody
を指定しておきます。
AutoDestroy
は自作クラスで、Start()
時にコルーチンでtime
秒後にDestroy()
を呼び出します。これを各々に付けているので、timeで指定した秒数後に破片が消えます。
AddTorque()
は今回初めて使いましたが、破片が回転してくれるので雰囲気が良くなります。AddForce()
で指定するベクトルをそのまま流用するのは問題な気がしますが、挙動はよろしかったので気にしないようにします。
そんなスクリプトを設定し、destroyObject()
を発動させます。(発動までの処理は割愛します)
ちょっとバラバラになりすぎている感はありますが、ばらけ具合は良い感じです。もっとこだわる場合はiTween.FadeTo()
あたりを使って破片の削除をフェードにしてみると、さらにゲームっぽくなりそうですね。
ちなみにRigidbodyのUser Gravity
のチェックを外すとこんな感じ。
アクションゲームである「エリアを遮る透明な壁」みたいのを破壊するときに使えそうです。
Rigidbodyの各種パラメータやAddForce()
のベクトルを調節すれば違った挙動もできるので、ゲームに合わせて試してみてください。