本講座はUnityでビリヤードゲームの作り方について説明していきます。前回はプロジェクトを作成し、ビリヤード台とボールなどを作りました。
前回の記事:
第二回目はボールの移動と当たり判定処理を実装していきます。
今回から実際にコードを書いていくので、「Visual Studio」や「Visual Studio Code」などコードエディタがない場合は予めダウンロードして使えるようにしておきましょう。
では始めていきます。
ボールを衝突・移動できるようにする
Unityでオブジェクト同士の衝突を扱う場合は主に「Collider」というコンポーネントを使用します。
(コンポーネントとは、オブジェクトやゲームでの振る舞いに関する心臓部、「Transform」「Mesh Renderer」など今まで使用してきたオブジェクトに付与されているものの総称です)
前回作成したボール(Main Ball)を選択してみてください。
インスペクターを見ると「Sphere Collider」というコンポーネントがあると思います。
これは3Dオブジェクトを作成した際に自動的にオブジェクトに付与されたものになります。例えば、Cubeを作成すると「Box Collider」が付与されるなどオブジェクトにあったコライダーがセットされます。
Unityではこの「Collider」を持ったオブジェクトが衝突などの物理的な機能を果たします。
もう一つ重要なのが「RigidBody」というコンポーネントです。
このコンポーネントはゲームオブジェクトを物理特性によって制御できるようになります。
これは重力などの力に関する物理現象を起こすためのコンポーネントです。今後3Dゲームを作成する際に重要になります。
この2つのコンポーネントを使ってボールを打ったり、衝突させたりできるようにしていきます。
コライダーの確認
上記で説明したように、コライダーはUnityで生成した3Dオブジェクトには自動的に付与されますが、確認、また設定の変更をしていきましょう。
まずは、下記の○のついているオブジェクトのコライダーを確認しましょう。Cubeには「Box Collider」、Ballには「Sphere Collider」がついていることが確認できます。
(HoleのCylinderは後で確認します。「Floor」のCubeは特に確認の必要はありません)
(また、本記事の一部画像でMainBallとすべきところがMainSphereのままになっています。Unity上で途中で名前変えたことを忘れてました。インスペクターのMainSphereをMainBallにリネームしておいてください)
1 2 3 4 5 6 7 8 9 |
Table > Cube ○ > Wall >> Cube ○ >> Cube(1) ○ >> Cube(2) ○ >> Cube(3) ○ >> Cube(4) ○ >> Cube(5) ○ |
1 2 3 4 5 6 7 8 9 10 11 12 |
Ball > MainBall ○ > Nine >> 1_Yellow_ColorBall ○ >> 2_Blue_ColorBall ○ >> 3_Red_ColorBall ○ >> 4_Purple_ColorBall ○ >> 5_Yellow_ColorBall ○ >> 6_Orange_ColorBall ○ >> 7_Brown_ColorBall ○ >> 8_Black_ColorBall ○ >> 9_GoldClear_ColorBall ○ |
Trigger コライダー
確認ができたら次は、「Hole」の子にある「Cylinder」を見ていきましょう。
Cylinderには「Capsule Collider」というコンポーネントが付与されています。
これは文字通りカプセルのような形をしており上下部分が丸くなっているため「Cyllinder」のオブジェクトを少し長くしています(このあとの衝突判定を作るときのため)。
コライダーコンポーネントにある「Edit Collider」の横にあるボタンを押してみましょう。
そうすると「Scene View」の選択されている「Cylinder」にカプセル状の緑の枠線が見えると思います。これがコライダーの大きさです。この緑の各点を動かすことで個別に大きさの調整ができます。
今回は大きさの調整の必要はありませんのでそのままの大きさにしておいて下さい。
そして、その下「Is Trigger」という項目のチェックボックスがありますので、これをすべての「Cyllinder」のコライダーでチェックを入れておいて下さい。
(複数選択をしてチェックを入れればOKです)
この「Is Trigger」はとても重要です。
最初にコライダーは、オブジェクトが衝突するためのコンポーネントだと言いましたが、この「Is Trigger」 をチェックするとコライダーが付与されているオブジェクトでも衝突ができなくなります。
では、なぜ「Cylinder」にコライダーが必要なのかというと、「Is Trigger」をチェックしたコライダーをもつオブジェクトは、そのコライダーに接触、侵入した他のオブジェクトを検知することができるようになるからです。
これにより、この「Cylinder」に接触、侵入した他のオブジェクトに対して処理を行うことができるようになります。
逆にチェックを入れていないオブジェクトは、衝突した際に他のオブジェクトを検知することができます。
Physic Material
次にコライダーに設定する「Physic Material」を作成します。
Physic Materialはコライダーに物理的な材質の設定を行うものです。滑りやすさ、ハネやすさなどの特性を決めることができます。
では作成してみましょう。
まず、「Project View」に「PhysicMaterial」というフォルダを作成します。
その中で、「右クリック→Create→PhysicMaterial」を選択し新しいPhysicMaterialを作成し、これに「Common」と名前をつけましょう。
もう一つ同じようにPhysicMaterialを作成し、これに「Table」という名前をつけます。
「Common」のPhysicMaterialを選択してインスペクターを見ます。
各項目について解説します。
Dynamic Friction | 移動している物体に対する摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力や重力がオブジェクトを押さない限り、すぐに止まります。 |
Static Friction | 面上で静止しているオブジェクトに使用される摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力を加えないとオブジェクトは動きません。 |
Bounciness | 表面にどれだけ弾性があるか。0 の場合は弾性がありません。1 の場合はエネルギーが減ることなく跳ねます。シミュレーションには少量のエネルギーを加えるかもしれませんが、ある程度の近似が予想されます。 |
Friction Combine | 衝突するオブジェクト間の摩擦をどう処理するか。 |
Bounce Combine | 衝突するオブジェクト間の跳ね返し度合いをどう処理するか |
「Friction Combine」「Bounce Combine」はどちらも初期値のまま「Average」にしておきましょう。
他の値を下記のように設定します。
1 2 3 4 |
Common Dynamic Friction : 0 Static Friction : 0 Bounciness : 0.92 |
1 2 3 4 |
Table Dynamic Friction : 0.1 Static Friction : 0.1 Bounciness : 0 |
そして、オブジェクト「Table」の子の「Cube」(ビリヤード台の緑の部分)をクリックしインスペクターを見て下さい。
「Box Collider」コンポーネントに「Material」という項目がありますので、その右側の枠内に作成した「Table」という名前のPhysicMaterialをドラック&ドロップして設定しましょう。
「Wall」の子にあるCube(ビリヤード台の茶色い壁)には「Common」という名前をつけたPhysicMaterialを「Box Collider」の「Material」項目にドラック&ドロップして設定します。
そして「MainBall」にも同じように「Common」のPhysicMaterialを設定します。
「Color Ball」は前回プレハブにしたのでヒエラルキーでいずれかの「Color Ball」の名前の右にある「>」をクリックしプレハブを開きます。
その状態で同じように「Sphere Collider」の「Material」項目に「Common」のPhysicMaterialを設定して下さい。
こうすることで同じプレハブから作られている「Color Ball」全てに適用されます。
ここまでで、コライダーの設定は終了です。
Rigidbody
次にリジッドボディの設定をしていきます。
リジッドボディは最初に言ったように「ゲームオブジェクトを物理特性によって制御する」ためのコンポーネントです。
つまり「力を加えて動かしたいもの」または「外部から力が加わったときに動いてほしいもの」に設定します。
今回はビリヤードですので「力を加えて動かしたいもの」は「MainBall」であり、「外部から力が加わったときに動いてほしいもの」は「ColorBall」になります。
「Wall」「Table」などは動いてほしくないものですので必要ありません。
ではリジッドボディを設定していきましょう。
まず「MainBall」に設定します。ヒエラルキーから「MainBall」を選択しインスペクターを見ます。
下の方にある「Add Component」を押して出てきたウインドウの「Seach」のところに「Rigidbody」と入力し下に出てきた「Rigidbody」をクリックします。
これで「MainBall」に「Rigidbody」が付与されました。
少し複雑な項目もあるので、今回は一部だけ簡単に解説します。
Mass | 物体の質量 |
Drag | 空気抵抗 |
Angular Drag | 回転の空気抵抗 |
Use Gravity | 重力に従うかどうか |
Is Kinematic | 物理的な反応の無効化 |
Freeze Position | 各軸における位置の固定(チェックするとその軸方向に移動しなくなる) |
Freeze Rotation | 各軸における回転の固定(チェックするとその軸周りに回転しなくなる) |
詳細設定をする前に「Color Ball」にも「Rigidbody」を付与していきましょう。
「ColorBall」はプレハブ化して有るので、上記と同じようにプレハブを開いて、「Add Component」をクリックして「Rigidbody」を選択しましょう。
プレハブに付与することで「ColorBall」全てに適用されます。
「Rigidbody」の値を設定していきましょう。下記の値以外は変更の必要はありません。
「Main」画像も参考にして下さい。
1 2 3 4 5 |
MainBall Mass : 0.4 Drag : 0.2 Angular Drag : 0.2 Freeze Position : x = チェックなし, y = チェック, z = チェックなし |
1 2 3 4 5 |
ColorBall Mass : 0.2 Drag : 0.2 Angular Drag : 0.2 Freeze Position : x = チェックなし, y = チェック, z = チェックなし |
Freeze Positionのy方向にチェックを付けたことで、ボール衝突時に高さ方向に動かなくなります。これでテーブルから球が飛び出したりすることがなくなります。
以上で設定が完了しました。
スクリプトからボールに力を加える
ここから実際にスクリプトを書いていきます。
まずは簡単に動くかどうかを試してみましょう。
プロジェクトビューに前回作成した「Script」フォルダを開いて、右クリックして「Create→C# Script」を選択しましょう。
そしてできたファイルの名前を「BallController」とします。「BallController」をダブルクリックしてコードエディタを開きます。(コードエディタをダウンロードしていない場合は「VisualStudio」や「VisualStudio Code」などをダウンロードしましょう。)
開いたら、はじめから記載されているコードに少し書き加えて下記のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using UnityEngine; public class BallController : MonoBehaviour { // 「MainBall」ゲームオブジェクト. [SerializeField] GameObject mainBall = null; // 「MainBall」のリジッドボディ Rigidbody mainRigid = null; // Start is called before the first frame update void Start() { // 「MainBall」のリジッドボディを取得. mainRigid = mainBall.GetComponent<Rigidbody>(); // 「MainBall」 に力を加える. mainRigid.AddForce( new Vector3( 50f, 0, 0 ) ); } // Update is called once per frame void Update() { } } |
このスクリプトを「MainBall」オブジェクトにドラック&ドロップしましょう。
そして「BallController」コンポーネントの「MainBall」に「MainBall」オブジェクト(Ballの子)をドラック&ドロップして登録します。
こうすることで、スクリプトから「MainBall」オブジェクトを操作することができます。
ここでこのスクリプトの基礎と重要なところだけ解説します。
まず、
1 2 |
void Start() void Update() |
この2つは、Unityでスクリプトを作成するとはじめから書かれているもので、「Start」ははじめに一回だけ、「Update」はオブジェクトがアクティブのときに1フレーム毎に自動的に実行され続ける関数です。(フレームがわからなければずっと、何回も繰り返し実行され続ける関数と思って下さい)
また、Startの中に書かれている「GetComponent」はコンポーネントを取得する関数。「AddForce」はリジッドボディに力を加える関数です。
このように、何に何を行うかということをスクリプトに記載していきます。
例えば上記のスクリプトの
1 |
mainRigid = mainBall.GetComponent<Rigidbody>(); |
この部分では、「mainBall」に「Rigidbodyを取得する(GetComponent<Rigidbody>)」を行って「mainRigid」に保管しています。
このような書き方はいろんなことに共通していますので覚えておきましょう。
またスクリプト上部にある、
1 |
[SerializeField] GameObject mainBall = null; |
の「SerializeField」を「[ ]」でくくった書き方は「属性(Attribute)」といわれる書き方ですが、今の段階では「これを記載しておくと、Unity側でインスペクターに表示できるようになる」という理解をしておけば問題はありません。詳しく知りたい方は「属性(Attribute)」で検索してみましょう。
では、ここまでできた段階で一度プレイしてみましょう!
「MainBall」が右へ移動して「ColorBall」と衝突、弾けるのが見れたでしょうか。
もしここでボールの動きに違和感がある、とかビリヤードはもっとこう動かなきゃとか有る方は、各ボールのリジッドボディに設定した「Drag」「Angular Drag」やビリヤード台やボールのコライダーに設定した「Physic Material」の値をお好きなように変更して動きの違いを体験してみましょう。
追記:ボールと壁の衝突・反発・摩擦についての設定
ここまで開発を完了して実際にテストした際、早い速度で球を壁にぶつけても壁に反発せず壁に沿うようにして動いてしまったかもしれません。
まずはこの問題から解決していきます。
ボールが壁に沿って動いてしまい反発しない場合の対処法
Unityでは一定速度以下の衝突判定を無視するように設定されています。
Edit > Project Settingを開き、Physicsの項目を選択。その後、Bounce Thresholdの数値を0.05など小さな値に変更してください。
ボールと壁同士の衝突に関する物理特性だけを変更したい場合
さらに反発特性や壁との摩擦特性を変更したい場合は、新しいPhysics Materialとして「Wall」を作成し、Wallの子オブジェクトになっているCubeオブジェクトそれぞれに設定しましょう。
例えばBouncinessを1(最大値)に設定したPhysics Materialを壁になっている「Box Collider」に設定すればより強い反発が生まれます。
ボールのPhysics Materialを変更すると球同士の衝突にも影響が出てしまうので、壁専用のPhysics Materialを作成して設定しました。
次回に向けて
今回はボールやボールと壁との衝突・反発・摩擦などの物理的な動きを作成しました。
次回は、本格的にスクリプトを記載して「ボールを方向を決めて打つ」「穴に落ちたらボールが消える」「はじめからもう一度」などゲームとして成立させていきます。
次回の記事:
コメント
分かりやすい記事ありがとうございます。参考になります。
質問なのですが、ボールをはじくと壁に沿ってゴロゴロと動いていくのですが、壁にうまく反射させることはできるのでしょうか。
よこにんさん、記事を読んでいただきありがとうございます。
記事に質問内容に関する加筆修正を行いました(今後の読者さんにも役に立つはず)。
壁に反射させるための設定方法と壁とボールの物理処理を変更する方法について掘り下げました。
とても勉強になるので参考にさせていただいております。
質問があるのですが、下記コードをscriptに記載するとエラーになってしまいました。
mainRigid = mainBall.GetComponent<Rigidbody>();
このようなエラーが出てしまいましたが、何か足りない記載などありますでしょうか。
All compiler errors have to be fixed before you can enter playmode!
コメントありがとうございます。
こちら確認しましたが講座記事の通りで問題ありません。
どこかで間違っているのだと思いますが紙面ではわからないので3章まで実装したプロジェクトファイルのダウンロードリンクを用意しました。
3章の記事の最後の方に置いてあるので参照してみてください。
ビリヤードゲーム講座を読んでいただきありがとうございます。
→追記します。
コメントではhtmlタグのエスケープシーケンスが表示されないので意図が伝わってませんでした。
記事の方で表記に問題が生じていた箇所は修正済みです。
mainRigid = mainBall.GetComponent&lt;Rigidbody&gt;();
は
mainRigid = mainBall.GetComponentRigidbody>();
に修正済みです(&を半角で表記するとエスケープシーケンスで文字変換されてしまうので全角で返信させていただきました)。
記事の修正は完了していますがプロジェクトファイルの方を参照していただいても大丈夫です。
教えていただきありがとうございました。
他の方が似た質問をされてそうですが、自分と少し違いそうなので、自分からも質問させてください。
「スクリプトからボールに力を加える」というところで、プログラムを入力するところがあると思います。その14行目「mainRigid = mainBall.GetComponent<Rigidbody>();」の文章の「mainBall」、「lt」、「Rigidbody & gt」、「);」この4か所のみエラーが出てしまいます。プログラム言語についてほとんどわからないので、対処法とかもわかりません。
どうか、分かる範囲で教えていただけると嬉しいです。
コメントありがとうございます。
こちら、サイトのプラグイン環境のアップデートの影響でエスケープシーケンスの表示切替形式が変わってしまっていたようです。
もし既に作られた入力スクリプトに
&lt;があれば<に、 &gt;があれば<に、 それぞれ置換してください(エディタの仕様でコメント内でエスケープシーケンスを入力できないので&だけ全角にして返信しています)。 こちら既に修正済みなのでサイトのスクリプトを見直してもらっても大丈夫です。 また、3章記事の終了地点でサンプルプロジェクトファイルのダウンロードリンクも配置しているのでそちらも併せてご活用ください。 表示の不具合を教えていただきありがとうございました。