前回の記事ではブロック崩しプロジェクトを作成し、必要なGameObjectを配置しました。マテリアルの色付けなどの基本機能も学習しましたね。
前回の記事:
この記事ではUnityの入力機能であるUnityEngine.Inputと物理エンジン機能RigidBodyコンポーネントやAddForce()機能を用いてプレイヤーを操作できるようにしてみましょう!
UnityでPlayerオブジェクトを動かしてみよう
ブロック崩しでは左右キーでプレイヤーとなる棒を移動させることができます。
Playerをキー入力に合わせて移動させるには新しくコンポーネントを作成する必要があるので、スクリプトを作成しそのファイル名をPlayerにしてください。
スクリプトの作成方法はUnity C#入門講座にて触れているのでここでは省略します。
作成できたら、シーンにあるPlayerに忘れずにアタッチしてください。
ここまでできたら実際にスクリプトの中身を書いていきます。Player.csの内容は次のようにしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// … using UnityEngine; public class Player : MonoBehaviour { [Range(0, 100)] public float Speed = 1f; void Update() { var horizontal = Input.GetAxis("Horizontal"); transform.position += Vector3.right * horizontal * Speed * Time.deltaTime; } } |
Playerコンポーネントの内容はとてもシンプルで、Updateメソッドで毎フレーム”Horizontal”という横軸を表す入力から値を受け取り、それに応じてPlayerをX軸方向に移動させています。
スクリプトが無事コンパイルできたら再生してみてください。
問題がない場合はキーボードの左右キーを押すとPlayerが左右に移動します。移動スピードはSpeedフィールドを変更すると調節できます。
ただし、今のままだと壁をすり抜けてしまいます。これについては物理エンジンを使用し、当たり判定を導入することで回避できます。
物理エンジンについてはこの記事の後半で解説していくのでひとまず気にせず進めていきましょう!
Unityの入力処理について
UnityではUnityEngine.Input
を使用するとハードウェアからの入力を受け取ることができます。
入力データの管理はInputManagerからできます。
確認方法はメニューのEdits > Project Settingsをクリックすると開くタブの左側の一覧からInput Managerをクリックできます。
先ほど登場した“Horizontal”もUnityのInputManagerで管理されているボタンになります。
ここから”Horizontal”の設定を確認することもできますが、デフォルトのままで十分なので詳細については省略します。詳しく知りたい方は各自調べてください。
※この記事を書いている時には新しい入力管理用のパッケージが実装されていますので、将来的にはInputManagerは使用されなくなるかもしれないので注意してください。
Unity物理エンジンを利用してプレイヤーを動かしてみよう!
Unityでは物理エンジンが標準で備わっています。物理エンジンを使うと現実世界と同じような自然な動きを難しいスクリプトを実装することなく再現できます。
また、物理エンジンを利用するとGameObject同士の当たり判定も行ってくれるので、先ほどのPlayerのように壁をすり抜けたりしないようにすることもできます。
物理エンジンを利用する際はInspector画面でAdd Componentを選択し、RigidBodyコンポーネントをGameObjectにアタッチしてください。
アタッチした後、物理エンジンの動作を確認するためにそのまま再生してみてください。
そのまま再生するとPlayerが画面下に落ちていくのが確認できます。
これは物理エンジンによって重力がPlayerに掛けられているからです。
ブロック崩しにおいて重力は必要ないので、RigidBodyコンポーネントのUse Gravityのチェックを消しましょう。
そうすると再生してもPlayerに重力はかかりませんので、画面下に落ちて行かなくなります。
物理エンジンの設定の確認の仕方
物理エンジンはUnityの内部処理によって管理されています。
こちらもInput Managerと同じくメニューのEdit > Project Settingsをクリックすると開きます。
Project Settingsタブから左側の一覧のPhysicsをクリックすると物理エンジンの設定を確認することができます。
(余談ですが、そこから重力の強さと向きを変更できます。)
キー入力に合わせて物理エンジンを動かしてみる
RigidBodyをアタッチした状態で、一度Playerオブジェクトのz軸回転を+20くらいにしてみてください。そして、左右キーを押して壁に押し付けてみてください。
すると先ほどとは異なり、移動すると左右以外の方向にも移動したり回転します(PlayerオブジェクトとWallオブジェクトが完全に並行だと回転しないです)。
これはRigidBodyコンポーネントによってUnityの物理エンジンの影響を受けているからです。そのため壁にぶつかるとそれに当たるようになります(実験が終わったら回転角度を0に戻しておきましょう)。
今回は単純に左右に移動するだけで十分なので、RigidBodyコンポーネントのConstraintsの中にあるFreeze PositionとFreeze Rotationを変更してみましょう。
これらのパラメータは物理エンジンによって各軸の位置や回転を固定する時に使用します。
- Freeze Position: YとZにチェックを入れる。
- Freeze Rotation: XとYとZにチェックを入れる。
設定が終わると、Playerは左右にしか移動しなくなります。
すり抜けは発生するものだと考えておく
注意点としてPlayerコンポーネントのSpeedを大きくするとすり抜けてしまいます。
これは物理エンジンの特徴の一つです。Unityの物理エンジンをそのまま使うと、移動スピードを速くした場合、ワープしているのと同じ状態になってしまいます。
コンピュータシミュレーションの問題になるので、すり抜けを完全になくすことはできません。
何らかのテクニックを使用すると回避できるかもしれませんが、基本的には無理やり操作すればすり抜けてしまうものと認識しておいた方がいいでしょう。
次の項目に注意するとすり抜けしづらくなりますが、気休め程度に捉えてください。
- 当たり判定を大きくする。
- 移動の速さをあまり大きくしない。
Unityの物理エンジンでは基本単位としてfloat型の値の1は1メートルになります。
Speedを100にすると秒速100メートルとなり、時速に変換すると360キロメートルになります。
Speedを40にしても時速だと144キロメートルになるので、かなり速い移動速度になりますね。覚えておくといいでしょう。
また、UnityではUpdateメソッドを1秒間に30~60回ほど呼び出していますので、値をそのまま使用すると実際の速さよりも速くなってしまいます。
それを防ぐためにTime.deltaTime
を使用し前のフレームからかかった時間(ミリ秒)を速さにかけてやると正確な値になります。
1 |
transform.position += Vector3.right * horizontal * Speed * Time*deltaTime; |
物理エンジンを使ってPlayerを動かしてみよう!
ここまでで無事Playerを操作することができました。
余談になりますが、直接Transformを操作するのではなくRigidBodyを使ってPlayerを動かすこともできます。
RigidBodyを使うと簡単に物理的な挙動を再現できるのでオススメです。
ただパラメータ次第では思ったように動かない場合もあるので、直接Transformを使用するかRigidBodyを使用するかは作る対象に応じて切り替えるといいでしょう。
RigidBodyをアタッチしたGameObjectをスクリプトから制御するにはRigidBodyのメンバを利用する必要があります。
- AddForce:力を加えるメソッド
- velocity: 移動量
- accelaration:加速度
などが用意されています。
RigidBodyには質量を表すMassというプロパティが存在しています。Massによってオブジェクトの重さを表現されているため、重たいものにはMassの値を大きくし、軽いものは小さくしてください。
Massが大きいほど、AddForceに指定する力を大きくする必要があります。
ただし、AddForceの引数には力の掛け方を指定するものがあります。
- ForceMode.Force: 質量を考慮して力をかける。
- ForceMode.Impulse 質量を考慮して瞬間的な力をかける。
- ForceMode.Acceleration 質量を無視して加速度を加える。
- ForceMode.VelocityChange 質量を無視して移動速度を変更する。
この中でForceMode.VelocityChangeがTransformを直接操作するのと似たものになります。
ただし、ForceMode.VelocityChangeだとRigidBodyを使用しているため、GameObjectにかかっていた速さや加速度も考慮されるようになるので、物理的に自然な動きになります。
Transformを直接操作すると、物理エンジンからの影響と組み合わさって不自然な力が加わったようになりやすいです。
次のサンプルコードではCurrentTypeフィールドによってスクリプト制御か物理エンジン制御か切り替わるように変更しています。
実際に動かしてみて挙動の違いを確認してみるといいでしょう。
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 |
using UnityEngine; public class Player : MonoBehaviour { public enum Type { Transform, RigidBody_Force, RigidBody_Impulse, RigidBody_Accel, RigidBody_VelocityChange, } public Type CurrentType = Type.Transform; [Range(0, 100)] public float Speed = 1f; // Update is called once per frame void Update() { var horizontal = Input.GetAxis("Horizontal"); var rigidBody = GetComponent<Rigidbody>(); var vec = Vector3.right * horizontal * Speed * Time.deltaTime; switch (CurrentType) { case Type.Transform: transform.position += vec; break; case Type.RigidBody_Force: rigidBody.AddForce(vec, ForceMode.Force); break; case Type.RigidBody_Impulse: rigidBody.AddForce(vec, ForceMode.Impulse); break; case Type.RigidBody_Accel: rigidBody.AddForce(vec, ForceMode.Acceleration); break; case Type.RigidBody_VelocityChange: rigidBody.AddForce(vec, ForceMode.VelocityChange); break; } } } |
RigidBody.IsKinematicについて
RigidBodyのIsKinematicプロパティを使用するとそのGameObjectはRigidBodyの影響を受けなくなります。
物理的な挙動が必要ない場合に使用するといいでしょう。
まとめ
今回の記事ではキー入力に合わせてプレイヤーを動かしてみました。
また、物理エンジンを使用して壁に当たるようにしたり動かしてみました。
今回の記事をまとめると次のようになります。
- 入力を受け取りたい時はUnityEngine.Inputを使用する。
- プロジェクトに設定されている入力情報を見る時はプロジェクト設定のInputManagerを見る。
- 物理エンジンを利用したい時はRigidBodyコンポーネントをアタッチする。
- RigidBodyではUseGravityで重力の有無を設定できる。
- スクリプトからRigidBodyをアタッチしたGameObjectに物理的な力を与えたい時はAddForce()を使用する。
- RigidBodyのIsKinematicを有効にすると、物理エンジンの影響を受けなくなる。
それでは次の記事に行ってみましょう!
コメント