Unityやってみる07:【長文注意】オブジェクトの動的生成をやってみる
暑いよう、暑いよう、うーん、うーん。
あっ! こんにちは、Unity素人おじさんです。ただしプログラミング歴は結構長いです。
今回数年ぶりに、Unityをゼロから学びなおしているのですけど、想像していた以上に順調で、自分自身驚愕しています。前回は、「モンスター育成ゲーム」のシーンと、モンスターを生成するための、ボタンを設置しましたね。
で、今回は実際にモンスターを、生成するまでをやってみることにします。
現在のゲーム画面は、こんな感じですね。
モンスターを降らせるシャワーを、どうしようかなと考えてたのですけど、上空にモンスターの巣を設置して、そこからモンスターを落下させる、という簡単な方法に、変更することにしますね。
上空に、モンスターの巣を設置してみます。サイズ的には、高さ5メートルくらいの位置に、10メートルx10メートルの、正方形の板を置いてみます。
やってみました。ちょっと大きすぎですね。5メートルx5メートルに変更します。色も付けてみましょう。
やってみました。まあまあいい感じですね。
カメラの位置と角度を調整しました。ゲームビューはこんな感じになりました。影がちょっとわずらわしいですが、慣れれば大丈夫です、このまま続けます。
で、ここからが今日の最大の難関です。「Generate Monsters」という赤いボタンを押したら、紫の「モンスターの巣」の下に、黒いモンスター(立方体)が出現し、地面まで落下する、という処理を実現します。
最近私は、Unityエディターを起動すると同時に、Microsoft Edge(ブラウザ)を立ち上げて、BingというサイトのチャットAIとの会話を開始するようにしています。で、チャットAIさんに、こんな質問をしてみました。
「3Dオブジェクト(モンスター生成ボタン)がクリックされたら、あるオブジェクト(モンスターの巣)の1メートル下に、モンスターがランダムな位置に生成されるようにしたいのですが、その実現のためには、モンスター生成ボタンのIsTriggerをOnにして、スクリプトを実行させて、プレハブで用意しておいた、モンスターのオブジェクトをインスタンス化すればいいですか?」
知らんけど(笑。
いや、これまでのUnity学習の経験から、「たぶんこういうことなんだろうなあ」、と、適当にでっちあげて、質問としてぶっこんで見ました。
Unityがそのやり方を教えてくれるとしたら、すごく楽なのですけど、どうなるでしょう。質問してみました。
結果は……。
「はい、可能です。そのコードは次のようになります」
うおおおおお、できるんかーーーい、やったああああ(笑。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ButtonClick : MonoBehaviour
{
public GameObject monsterPrefab;
public Transform monsterNest;
void OnMouseDown()
{
float range = (monsterNest.localScale.x - monsterPrefab.transform.localScale.x) / 2f;
Vector3 randomPosition = new Vector3(Random.Range(-range, range), -1f, Random.Range(-range, range));
Instantiate(monsterPrefab, monsterNest.position + randomPosition, Quaternion.identity);
}
}
※実際は何回かやり取りして、その最終的なコードが上記のものです。また実際は「void Generate Monster()」という関数として、提示してくれているので、上記と実際のAIの提示したコードは、少し異なります。
で、私が予想した通り、monsterPrefab(モンスターのプレハブ:出現させたいオブジェクト)への参照と、monsterNest(モンスターの巣:どこにモンスターを出現させるかを指示するための、オブジェクトへの参照)を、定数みたいな感じで内部に持つようになっています。で、その内容は、ここでは記述する必要はなくて、Unityエディターの画面上で、ドラッグ&ドロップで設定可能ですね。ここがUnityの、ぶっとんだ所です。ボタンとして配置したCubeに、上記のスクリプトをアタッチして保存し、Unityエディタ上のInspectorの表示がどうなるか、確認してみましょう。
表示されました! 「Monster Prefab」と「Monster Nest」! すげええええ!(笑。
もしかしたらなぜ私がこんなに驚愕しているか、不思議に思ってる人も多いかも知れませんね。ソフトウェアの「設計思想」的な話になるので、その説明は別途することにして、先に進みましょう。
まずMonsterNest(モンスターの巣)を、左のヒエラルキーパネルからドラッグして、ドロップしてやりましょう。
設定できました! 簡単です! ちょっとスクリプトの説明を、省略してしまってますが、スクリプトでは、ここで設定されたオブジェクト(モンスターの巣)の1メートル下に、モンスターを生成してくれるようになっています。
で、「MonsterPrefab」という、モンスターを生成するための設計図も、設定してやらないといけないのですけれど、まずヒエラルキーパネル上に「Cube」を追加して設定し、これで動くか、動作確認してみましょう。
まずCubeを追加して「MonsterPrefab」に変名します。大きさ(scale)は変更せず一辺1メートルのままとしておきます。右の原点の位置に、四角が配置されてますね。
で、これを、さっきと同様にヒエラルキーパネルから、スクリプトの参照設定に、ドラッグ&ドロップで設定してやります。できましたね。
設定が終わったら実行してみます。ゲームビューに切り替わりました。原点にモンスターのプレハブ(モンスターの設計図)が見えてしまっていますが、ひとまず気にしないことにしましょう。「Generate Monsters」ボタンを押してみます。どうなるでしょうか!
やりました! 紫色の、モンスターの巣の下に、白いモンスターが出現しました! これでオブジェクトの、動的生成にも成功ですね。
と思ったのですけど、あれれ?
ボタンが落下せずに、巣にくっついたままで、そのまま赤いボタンを連打すると、巣の下にモンスターが次々と生成されていきます。チョイキモですね!
なぜこうなるのかというと、モンスターには重力を働かせて落下させないといけないので、RigidBody(剛体)、というコンポーネントを、モンスターのプレハブに、アタッチ(くっつける)してやらないと、ダメなんですね。
※と、ここで、「重力を制御させるのに、なぜRigidBody剛体なんていう名前のコンポーネントが必要なの?」、「モンスターのプレハブって、なんなの?」、という疑問が浮かびましたので、チャットAIに質問してみましたので、興味がおありの方はご覧ください。
うーん、なるほどねー(笑。
まあそれは置いといて、さきほど作成したMonsterPrefabに、RigidBodyのコンポーネントを、アタッチしてみます。
ヒエラルキーパネルで「MonsterPrefab」を選び、表示されたInspectorパネルの一番下の、「Add Component」をクリックし、
表示されたメニューから「Physics」を押します。
するとメニューが切り替わるので、RigidBodyをクリックします。
Inspectorパネル上に、「Rigidbody」関連の設定項目が、追加されました! Use Gravityっていうのにチェックが入ってます。「重力を適用させる」っていうことですね。
では実行してみましょう。と、実行したら何故か、プレハブ用に置いておいたCubeがジャンプしました! 一体これは……、と思いましたが気を取り直して、赤いボタンを押してみます。
やりました! ボタンを押すたびに、白いモンスターが次々と生成され、地面に落下していきます。どんどん押してみましょう!
どんどん生成されてます! このまま押し続けるとどうなるのでしょうか! やってみましょう!
うわあああああ(笑。
ここで私は気づきました。これ、モンスター育成ゲーとして遊ぶんじゃなくて、Cubeを無数に生成させてあふれさせる、「エアキャップゲー」として作った方が、楽しいんじゃね?(笑。
どうせならカラフルな方がいいので、黒い立方体ではなく、色をランダムに変更できるようにしてみます。チャットAIに質問した所、さっきのスクリプトを少し変更するだけで、できるそうです。やりますなあ、AIくん(笑。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ButtonClick : MonoBehaviour
{
public GameObject monsterPrefab;
public Transform monsterNest;
void OnMouseDown()
{
float range = (monsterNest.localScale.x - monsterPrefab.transform.localScale.x) / 2f;
Vector3 randomPosition = new Vector3(Random.Range(-range, range), -1f, Random.Range(-range, range));
// 変更前
// Instantiate(monsterPrefab, monsterNest.position + randomPosition, Quaternion.identity);
// 変更後
GameObject monster = Instantiate(monsterPrefab, monsterNest.position + randomPosition, Quaternion.identity);
Renderer renderer = monster.GetComponent<Renderer>();
renderer.material.color = new Color(Random.value, Random.value, Random.value);
}
}
見比べられるように、変更前のをコメントにして残しておきました。
変更前の1行では、モンスターのプレハブを実体化(Instantiate)して、その後放置だったのですけど、変更後は、作成したモンスターの実体を、「monster」という変数に、入れてますね。で、2行目でそのモンスターの実体のうち、「レンダラー」という部分の参照を取得して、3行目でそのレンダラーの中の、マテリアルの色を、ランダムで作った色に、変更する、というものですね。
いやあ、AIくんが考えてくれて、一発で動いたからこうやって解説もできますけど、ゼロから書いてみなさいって言われたら、絶対無理ですって答えます(笑。でも、みんなそのような状況で、勉強してUnity使いになっていくのですよね。すごいです。
色をランダムに変更する処理が出来たので、実行してみましょう。実行直後に、プレハブ用に設置した立方体が、ぽよん、と飛び跳ねるのはさっきと同じ(笑。これは後でなんとかします。
赤いボタンを連打すると、カラフルなモンスターが出現! やったー。綺麗ですねえ!
うわああああ(笑。
でね。今回の「作品」は、なんかこれで満足しちゃったので、「モンスターを歩かせる処理」はまたいつかやることにして、次回はデコボコの地面とか、森とか、海とかにこの「モンスター(?)生成機」を設置して、モンスター(?)を生成させてみる、というのをやってみたいと思っています。
森とか海とかの地形は、Unityのアセットストアというサイトで無料のものが入手可能ですので、それを使いたいと思います。※ENDOさん、アセットストアの情報ありがとうござました!
で、最後にモンスターのプレハブをなんとかする方法、ですけど、正解がどうなのかはわからないですけど、
①ヒエラルキーパネル上の「MonsterPrefab」を、プロジェクトパネルの「Assets」に、ドラッグ&ドロップ(MonsterPrefabが、Assetsというフォルダにコピーされます)
②ヒエラルキーパネルから、「MonsterPrefab」を削除
③ボタンのスクリプトに設定しておいた、MonsterPrefabの参照が切れてしまい、Missingとなっているはずなので、ここにさっきAssetsにコピーしたMonsterPrefabを、ドラッグ&ドロップ
以前は「プレハブとかアセットとか、一体何なの?」、と思っていた私ですけど、ようやくその使い方が、おぼろげながらわかってきた気がします。もしここをご覧の方で、これまでの内容などでご質問とかあれば、お気軽にコメント欄でご質問ください。ばっちり答えちゃいますよチャットAIくんが(笑。
次回、いろんな所でモンスター生成! こうご期待(笑。
次回はこちら: