Unity3dタンクチュートリアル:シャーシ(レッスン1.車両力学の基礎)

画像

エントリー


したがって、Unityの初心者ではなく、シーンを作成したり、ステージ上でオブジェクトを配置したり、地形を作成したり、プレハブを作成したりできます。 このレッスンではさらに詳しく説明するので、この知識はすべてあなたにとって有用です。

つまり、このレッスンの最初の部分では、ホイールコライダーとは何か、それを使用して車両を運転し、現実的な車のサスペンション動作を作成する方法を学びます。 。

実際、上の画像に表示されているもの(このレッスンの結果です)をブラウザーで 「ライブ」で試すことができます。 自分でやりたいですか? それからキャットへようこそ

Unityで自動車整備士のモデリングの基本について話を始める前に、公式ウェブサイトのこのトピックに関するレッスンが既にあることに注意するしかありません。 確かに、このすべてを通して、どのスクリプトをどのオブジェクトにアタッチするかについての指示のみが与えられており、たまに有用な何かを説明し、レッスンの第3部では最終的にメインスクリプトがどのように機能するかを説明しますが、それは最初の部分で行わなければならず、ホイールコライダーがどのように動作し、リジッドボディとどのように相互作用するかを説明します。最終的に、このレッスンはUnityの初心者向けではなく、修正したいと思います。

しかし、Wheel Colliderが何であり、何と一緒に食べられるかを既に知っている場合は、このレッスンをスキップできます。

1.「車」を作成する


開始するには、標準的な手順に従って、シーンを作成し、地形を作成するか、既製のものを使用してから、空のゲームオブジェクト(GO)を作成し(GameObject-> Create Empty)、Carなどのオリジナルの名前を付けましょう。

次に、キューブを作成し(GameObject-> Create Other-> Cube)、標準マテリアルを適用して、見やすくします。 これが車のボディであると想像し、Scaleを使用して幅と長さを拡大して、このボディの前面がZ軸(青い軸、Unityの世界では正式に前面と見なされます)に沿って見えるようにし、CubeをタブのCarオブジェクトにドラッグします車の子になるように階層。 Carオブジェクト自体に移動して、Rigidbodyを追加します(Component-> Physics-> Rigidbody)。 約1500 kgの適切な体重を彼に割り当てます。車体の準備ができました。
画像

車体に加えて、車にはホイールがあり、シリンダーを作成し(GameObject-> Create Other-> Cylinder)、同じScaleを使用してホイールの外観を与え、Z軸に沿って90度回転します(重要!Z軸にのみ!) )
画像
Wheel Forward Leftで新しく作成したシリンダーの名前を変更し、ホイールをその場所、つまりキューブの前面と左側に設定します(繰り返しますが、Z軸の正の部分はUnityの前面と見なされます)。
画像
ホイールを左に向かってCarオブジェクトにドラッグします。 ホイールの回転を見やすくするために、ホイールにテクスチャをより詳細に割り当てます。 次に、ホイールをコピーし(Wheel Forward LeftとDuplicateを右クリック)、Wheel Back Leftを呼び出して、他の2つのホイールと同様に適切な場所に配置します。
画像

画像

これで、スーパーカーの準備がほぼ完了しました! 地形の表面より少し上に持ち上げてPlayを押すと、車は地面に落ちて杭の付いた車輪の上に立ちます。ソフトサスペンションを夢見ることができ、Playモードを終了します。 ご覧のとおり、ホイールにはCapsule Colliderと呼ばれるコンポーネントとBox Colliderボディがあります。このレッスンでは、衝突とは何か、それらに基づいて空間内のオブジェクトの位置を計算する方法については説明しません。単純なコライダー(ボックス、カプセル、メッシュ、...)の場合、このオブジェクトは、リジッドボディと1つ以上のコライダーを含む他のオブジェクトと対話できます。次に、リジッドボディを含むオブジェクトは、下位のすべてのコライダの衝突に基づいて位置を計算しますそして彼らの物理的なm aterials。

上記から何も理解していない場合、気にしないでください、理解は練習に伴います。

それまでの間、各ホイールを選択して、Capsule Colliderを削除します(右クリックしてコンポーネントを削除します)。 [再生]をクリックします。車は車輪に乗らず、地形を通過し、身体だけが表面と相互作用します。

2.ホイールコライダーの追加


それで、この神秘的なホイールコライダーは何ですか? 正しくしましょう。 空のGameObjectという名前をWCollider Forward Leftとして作成し、Wheel Colliderコンポーネント(Component-> Physics-> Wheel Collider)を追加します。セグメントが内部にある円のように見えます。ホイールに比べて大きすぎたり小さすぎたりします。スケールの使用量に依存します。 幸いなことに、彼はこのパラメーターを変更し、ホイールの半径に合わせて半径パラメーターを変更し、WColliderという名前の新しいプレハブを作成し(資産->作成->プレハブ)、WCollider Forward Leftをプレハブにドラッグします。 ホイールと同数のコライダーがあり、それぞれのパラメーターを変更しないように、プレハブパラメーターを変更し、残りのコライダーはそのプロパティを継承するため、便宜上、プレハブを作成しました。 次に、標準の手順を実行し、WCollider Forward LeftをCarオブジェクトにドラッグし、左前のホイールの中央に配置し、3回複製し、名前を変更して、他のホイールに従って移動します。
画像

画像

Playを押すと、車は転倒して再び車輪の上に立ちます(ところで、車輪がまだ地形を通過している場合、それは車が非常に高速で地面に落ちることを意味し、地面までの距離を短くするか、RigidbodyのDragパラメーターを大きくする必要があります)。 ご覧のように、ホイールコライダーのパラメーターを設定しなかったため、カプセルコライダーが車輪の上に立っていた場所と結果はそれほど変わりません。すべて正しいです。

したがって、ゲームモードを終了し、WColliderプレハブを選択し、Wheel Colliderコンポーネントのプロパティを変更しましょう。
  1. サスペンションの距離-実際、これはサスペンションのスプリングの長さで、0.15に設定されています
  2. サスペンションスプリング->スプリング-サスペンションの剛性、Rigidbodyの重量が大きいほど、剛性を大きくする必要があります。9000に設定します。
  3. サスペンションスプリング->ダンパー-サスペンションソフトナー、値を大きくするとスプリングの動きが遅くなり、100に設定
  4. 質量-ホイールの質量、1を残す
  5. 前方摩擦-「フロント」ホイールの摩擦力、そのままにしておきます
  6. 横方向の摩擦-「横方向」の車輪の摩擦力は、車のドリフトを実装する場合に便利で、そのままにしておきます
合計:
(半径を見ないでください、あなたは別のものを持っているかもしれません、主なことは円があなたのホイールと一致することです)
画像

だから、今すぐ再生をクリックしてください、私たちの車はまったく異なる方法で動作するようになりました、今では地形の表面から跳ね上がり、丘の斜面に置くと、それから転がります、これがホイールコライダーが私たちのために働く方法です。

しかし、これが彼らの能力のすべてではありません。それらを使用して車を運転し、車輪を回転させて地形のバンプに反応させる方法を見つけましょう。 スクリプトを開始します!

3.ホイールコライダーの管理


このチュートリアルでは、C#でスクリプトを記述し、JavaScriptを使用する人を許してくれます。私はそれをよく知っていると思います。

新しいC#スクリプトを作成し(Assets-> Create-> C Sharp Script)、CarControllerを呼び出して開き、以下を記述します。

using UnityEngine; using System.Collections; public class CarController : MonoBehaviour { //1 public WheelCollider[] WColForward; //2 public WheelCollider[] WColBack; //3 // Use this for initialization void Start () { //4 } void FixedUpdate () { //5 } } 

  1. スクリプトのメインクラスは、スクリプトファイルと同じ方法で呼び出す必要があります。そうしないと、コンパイラはエラーをスローします。
  2. フロントコライダーの配列。
  3. リアコライダーの配列。
  4. Start()関数を使用して初期化します。
  5. Unity3dスクリプトの基本チュートリアルで述べたように、オブジェクトとの物理的な相互作用には、Update()関数よりもFixedUpdate()関数を使用する方が適切です。
次に、スクリプトをCarオブジェクトにドラッグします。インスペクターで確認できるように、スクリプトには2つのフィールドがあります。実際、これらは宣言した配列です。コライダーを次のようにドラッグする必要があります。
画像

次に、コライダーで作業し、スクリプトを補足します。

 using UnityEngine; using System.Collections; public class CarController : MonoBehaviour { public WheelCollider[] WColForward; public WheelCollider[] WColBack; public float maxSteer = 30; //1 public float maxAccel = 25; //2 public float maxBrake = 50; //3 // Use this for initialization void Start () { } void FixedUpdate () { float accel = 0; float steer = 0; accel = Input.GetAxis("Vertical"); //4 steer = Input.GetAxis("Horizontal"); //4 CarMove(accel,steer); //5 } private void CarMove(float accel,float steer){ //5 foreach(WheelCollider col in WColForward){ //6 col.steerAngle = steer*maxSteer; //6 } if(accel == 0){ //7 foreach(WheelCollider col in WColBack){ //7 col.brakeTorque = maxBrake; //7 } }else{ //8 foreach(WheelCollider col in WColBack){ //8 col.brakeTorque = 0; //8 col.motorTorque = accel*maxAccel; //8 } } } } 

Playを押し、W、Sボタンまたは前後矢印を使用して「式1」を移動し、A、Dボタンまたは左矢印を使用して右に曲がります。

このスクリプトの機能を見てみましょう。
  1. ホイールの最大回転角。
  2. ホイールに伝達される最大トルク。
  3. 最大制動トルク。
  4. InputクラスのGetAxis()関数は、コントローラーの移動キーを押すか、ジョイスティックのスティックを移動するときに発生するイベントを待機します。関数は仮想軸の方向を取ります(たとえば、「垂直」はW、Sキー、またはジョイスティックが前後に移動します)。 -1から1までの数値を返します。-1は左への後退、Sキーは「垂直」軸、Dは「水平」)0-軸はアクティブではなく、1は前進、または右(W垂直の「軸」、Aから「水平」、またはジョイスティックのスティックを左右に動かします)。
  5. 仮想軸から取得した結果をCarMove()関数に渡します。
  6. WColForward配列に配置されている各Wheel Colliderについて、steerAngle変数(ホイールの回転角度)に、水平軸から取得した値を乗算して変更します。
  7. 垂直軸が静止している場合(つまり、WキーまたはSキーを押さない場合)、ブレーキ力の原因であるbrakeTorqueコライダー変数を変更します。これは、移動キーを押さない場合に慣性で車が移動しないようにするために必要です。
  8. それ以外の場合(WキーまたはSキーを押した場合)、ブレーキ力はゼロになります。次に、垂直軸から取得した値を掛けることでmotorTorque変数(ホイールトルク)を変更し、その結果、車が加速し始めます。

それだけですよね? マイナーな欠陥を修正するために残っています、まず、高速で回転しようとすると、車は横に倒れます。これは、リジッドボディがそれに接続されているすべてのコライダーに基づいて私たちの車の重心を計算するという事実によるものであり、次に、私たちの車輪はまだありませんスピンして、不均一な地形に反応しません。

順番にすべてについて話しましょう。

4.重心


それは素晴らしくシンプルに設定されています。最初に空のGOを作成し、それを重心と呼び、それをCarオブジェクトにドラッグし、たとえば、高速で曲がるときに私の車が横転しないように、おおよその位置に配置する必要があります私はこのようにしなければなりませんでした:

画像

画像

別の方法でそれを作ることができます、それはすべて私たちの体のBox Colliderの幾何学的な寸法に依存するので、重心を試してください、しかし、最初にスクリプトを追加してください:
  1. 変数を宣言します:public Transform COM。
  2. GOの重心をスクリプトのCOMフィールドにドラッグします。
  3. Start()関数内で、次の行を記述します:rigidbody.centerOfMass = COM.localPosition

これで、[再生]をクリックして結果を確認できます。

5.ホイールを「復活」させる


さて、私はこのレッスンで最も興味深いトピックであると同時に、やや複雑なトピックである私の意見では最後に到達しました。

ホイールを復活させるために、各固定フレームの回転の位置と角度を計算する必要があります。すばらしいWheelCollider、そのGetGroundHit()メソッドは、コライダーと地形の接触点を含むWheelHit構造を返すことができます。可変ポイント)。 GetGroundHit()メソッドのおかげで、サスペンションスプリングの動きに基づいてホイールの位置を計算できます。 さて、回転角度については非常に簡単です。WheelColliderにはfloat変数rpmがあり 、これは1分あたりの回転の省略形です。これに基づいて、ホイールの回転角度を決定できます。

スクリプト自体に渡します。スクリプトは大きくなり、厚くなって、次のようになります。
 using UnityEngine; using System.Collections; public class CarController : MonoBehaviour { public WheelCollider[] WColForward; public WheelCollider[] WColBack; public Transform[] wheelsF; //1 public Transform[] wheelsB; //1 public float wheelOffset = 0.1f; //2 public float wheelRadius = 0.13f; //2 public float maxSteer = 30; public float maxAccel = 25; public float maxBrake = 50; public Transform COM; public class WheelData{ //3 public Transform wheelTransform; //4 public WheelCollider col; //5 public Vector3 wheelStartPos; //6 public float rotation = 0.0f; //7 } protected WheelData[] wheels; //8 // Use this for initialization void Start () { rigidbody.centerOfMass = COM.localPosition; wheels = new WheelData[WColForward.Length+WColBack.Length]; //8 for (int i = 0; i<WColForward.Length; i++){ //9 wheels[i] = SetupWheels(wheelsF[i],WColForward[i]); //9 } for (int i = 0; i<WColBack.Length; i++){ //9 wheels[i+WColForward.Length] = SetupWheels(wheelsB[i],WColBack[i]); //9 } } private WheelData SetupWheels(Transform wheel, WheelCollider col){ //10 WheelData result = new WheelData(); result.wheelTransform = wheel; //10 result.col = col; //10 result.wheelStartPos = wheel.transform.localPosition; //10 return result; //10 } void FixedUpdate () { float accel = 0; float steer = 0; accel = Input.GetAxis("Vertical"); steer = Input.GetAxis("Horizontal"); CarMove(accel,steer); UpdateWheels(); //11 } private void UpdateWheels(){ //11 float delta = Time.fixedDeltaTime; //12 foreach (WheelData w in wheels){ //13 WheelHit hit; //14 Vector3 lp = w.wheelTransform.localPosition; //15 if(w.col.GetGroundHit(out hit)){ //16 lp.y -= Vector3.Dot(w.wheelTransform.position - hit.point, transform.up) - wheelRadius; //17 }else{ //18 lp.y = w.wheelStartPos.y - wheelOffset; //18 } w.wheelTransform.localPosition = lp; //19 w.rotation = Mathf.Repeat(w.rotation + delta * w.col.rpm * 360.0f / 60.0f, 360.0f); //20 w.wheelTransform.localRotation = Quaternion.Euler(w.rotation, w.col.steerAngle, 90.0f); //21 } } private void CarMove(float accel,float steer){ foreach(WheelCollider col in WColForward){ col.steerAngle = steer*maxSteer; } if(accel == 0){ foreach(WheelCollider col in WColBack){ col.brakeTorque = maxBrake; } }else{ foreach(WheelCollider col in WColBack){ col.brakeTorque = 0; col.motorTorque = accel*maxAccel; } } } } 


それをコピーし、スクリプトに貼り付けてから、階層タブでCarオブジェクトを選択します。インスペクターでわかるように、スクリプトに新しい変数と配列があります。前輪と後輪をそれぞれwheelsFとwheelsB配列に転送する必要があります(wheelsとnot Wheel Collier's!)[再生]をクリックする方法。 ホイールが地形の下にある場合、変数wheelRadiusの値を変更すると、コライダーの半径とほぼ一致するはずです。

そのため、奇跡が起こるはずです。車輪は実際の車輪と同じように回転し、地形の隆起に反応します。

画像

それらが間違った方向または他の方向に回転している場合は、車を作成したステップ1をもう一度お読みください。Z軸に沿って車輪を正確に90度回転させることが重要であると述べました。その理由を説明します。 スクリプトを分析しましょう。
  1. 車輪の変形を保存する配列を作成します。
  2. これらの変数は私たちにとって有用です。その理由を以下で説明します。
  3. 各ホイールについて必要な情報を含むクラスを作成しましょう。
  4. ホイールを変形します。
  5. Wheel Collider Wheels;
  6. ホイールの開始位置。
  7. ホイールの回転角度。
  8. WheelData型でホイールの配列を宣言します。
  9. 必要なデータをwheels配列に渡します。このために、SetupWheels()関数を作成しました。
  10. SetupWheels()関数は、ホイールとそのWheelColliderの変換を受け入れ、必要なデータをWheelDataクラスに含まれる変数に渡し、それを返します。
  11. ホイールの回転の位置と角度を計算するUpdateWheels()関数を作成します。
  12. ホイールの回転が時間内に均等に引き伸ばされるように、必要なTimeクラスの変数fixedDeltaTimeを覚えています。
  13. ホイール配列の各要素に対して、次の操作を実行します。
  14. クラス変数WheelHitを作成します(上で説明しました)。
  15. ホイールのローカル位置を覚えています(ローカル位置は親座標に相対的な位置で、グローバルは世界に相対的です)。
  16. ホイールのWheelColliderが地形(または何か)の表面と衝突した場合。
  17. 次に、コライダーがテレインサーフェスと接触するポイントの開始点(hit.point)と現在のホイール位置の終了点(w.wheelTransform.position)の間、およびCarオブジェクトに対して上向きのベクトルの間のホイールのローカル位置のY座標からDot()を減算します(transform.up)そして、これらすべてからwheelRadius変数も減算して、ホイールが適切な場所になるようにします。 (上記から単語を理解しなかった場合、ほとんどの人がこれを初めて理解しないので、落胆しないでください。これは、 ドット製品が何であり、それが上記のベクトルにどのように関連するかを知る必要があるか、ホイール位置をそのように計算する必要があることを知っているだけです);
  18. WheelColliderがテレインサーフェスに触れない場合。 次に、ホイールの初期ローカルポジションのY座標からwheelOffsetを取り除きます。これにより、車が高さから落ちたり、「後ろ」に横たわっているときに、ホイールが未知の方向に飛び去ることがありません。
  19. ホイールの変更された位置を現在の位置に適用します。
  20. MathfクラスのRepeat()関数を使用してホイールの「回転」角度を計算します。この関数は、角度を0〜360度の範囲に保つのに役立ちます。あまり洗練されていない式(w.rotation + delta * w.col.rpm * 360.0f / 60.0f)ここで、実際に現在の回転角度にコライダーに保存されている1分あたりの回転数を掛けた時間デルタに360/60を掛けます。
  21. 結果を現在のローカル回転角度に適用します。 クォータニオンクラスのオイラー()関数はこれに役立ちます。オイラー角度でクォータニオンを返します(ただし、クォータニオンという単語が怖い場合は、ローカル回転角度とグローバル回転角度を格納する構造として抽象化して扱うことをお勧めします)それはそれが完全に異なることを意味します、ここでは正確に何を伝えるのではなく、単に理解しやすいでしょう)。 最初の引数(X軸の周りの角度)は計算されたホイールの「回転」角度を転送し、2番目の引数(Y軸の周りの角度)はコライダーの回転角度を送信し、3番目の引数(Z軸に沿った角度、これで段落1で重要だった理由がわかりました)ホイールをZ軸の周りで正確に回転させます)定数90.0fを裏切ります。


おわりに


さて、Unity3Dで通常の車のメカニックを構築する方法についてお話しできるのはこれだけです。上記のすべてを読んで理解した後、すぐにレースシミュレーターを作ることができます。

レッスンの次の部分では、約束したように、戦車トラックの仕組みを構築する方法について説明します。また、3Dエディターでモデル化する方法と、そこからモデルをエクスポートしてUnityにインポートする方法についても説明します。当然、強制的にシミュレートすることはありませんこのデモで見たものですが、既製のモデルを提供します。 Unity3dの学習にご関心をお寄せいただきありがとうございます。

>>レッスン2

Source: https://habr.com/ru/post/J115557/


All Articles