2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

加速度センサーでWheel Colliderを操作して車輪の再発明

Posted at

動機

某教育番組にて車のハンドルを模した玩具を段ボールで工作する回があり、
それを見ながら子供と一緒に実際に作りました。
DSC_0168.JPG

そこそこ気に入ったようで、自分の声でアクセル音やタイヤのスリップ音を
再現しながら遊んでいました。

(これで実際に車の運転が体感できたらもっと面白いだろうな~)

そこで今回は「自分で工作したモノがコンピュータと連動して動かせる!」
という大人のエゴ感動を実現させることにしました。

何を実現させるか

子供の作ったハンドルの玩具を元にして「テレビに映した車が運転できる」を実現させます。

実現方法

使用技術

ハンドルの玩具と連動させるためには回転を判別できるセンサーで検知する必要があります。
 ⇒加速度センサーに決定

ジャイロセンサーも検討しましたが、複雑ですぐに作れなそうだったユーザーの向きなどは
気にする必要がなかったので採用しませんでした。

開発環境

テレビに車を映して操作する必要があり、前述の通り加速度センサーも備えていることを
考えると、スマートフォンで3Dモデル操作の仕組みをすぐに開発できるものということで、
 ⇒Unityに決定

開発

Wheel Colliderによる車の作成

UnityにはWheel Collider(ホイール コライダー)という車輪を再現できるオブジェクトがあり、
車両の3Dモデルに組み合わせることでUnity上で車の操作が実現できます。

このWheel ColliderにはmotorTorquesteeringAngleというプロパティがあり、
motorTorqueで前進/後退のアクセル、steeringAngleでハンドルの操作ができます。

まずはWheel Collider チュートリアルを参考に車のオブジェクトとWheel Colliderを制御する
スクリプトを作成し、スクリプトを車のオブジェクトにアタッチしておきます。

加速度センサーの動作検証

カーレースなどのゲームでよくある操作ですが、スマホを前後左右に傾けることで
アクセルやハンドル制御しています。
今回は加速度センサーで同様の制御を行います。

Unityのスクリプト上では加速度センサーの値をInput.accelerationで取得できます。

今回はAndroidのスマートフォンをlandscape(横向き)で操作することを前提とします。
その上でUnityで加速度センサーの値を取得すると、以下であることが確認できました。

  • Input.acceleration.x左右の傾き
    • -1:左90度
    • 0:地面に垂直
    • +1:右90度
  • Input.acceleration.z前後の傾き
    • -1:画面が天井向きで地面に平行
    • 0:地面に垂直
    • +1:画面が床向きで下で地面に平行

言葉だけでは説明しづらいので、画像でも補足しておきます。

Input.acceleration.x = 0の状態
DSC_0133.JPG

Input.acceleration.x = 0.5の状態
DSC_0134.JPG

Input.acceleration.x = -0.5の状態
DSC_0135.JPG

Input.acceleration.z = 0の状態
DSC_0136.JPG

Input.acceleration.z = -1.0の状態
DSC_0137.JPG

このことから、Input.acceleration.xはハンドル操作を制御するsteeringAngleに、
Input.acceleration.zはアクセルを制御するmotorTorqueに連動させればよいことが
わかりました。

加速度センサーと車の連動

Wheel Collider チュートリアルのコードの中では、Wheel ColliderのmotorTorque
steeringAngleをカーソルキー入力により制御しています。
その個所を加速度センサーから取得する値で制御するよう、以下のように変更します。

ここでInput.acceleration.z-1を乗算しているのは、スマートフォンの前後の傾きで
取得できる値とmotorTorqueプロパティの前進/後退の値を一致させるためです。
(motorTorque>0で前進のアクセル、<0で後退のアクセル、=0はアイドリング)

SimpleCarController.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
    
public class SimpleCarController : MonoBehaviour {
    public List<AxleInfo> axleInfos; // 個々の車軸の情報
    public float maxMotorTorque; //ホイールに適用可能な最大トルク
    public float maxSteeringAngle; // 適用可能な最大ハンドル角度
        
    public void FixedUpdate()
    {
        // カーソルキーで操作する場合
        // float motor = maxMotorTorque * Input.GetAxis("Vertical");
        // float steering = maxSteeringAngle * Input.GetAxis("Horizontal");

        // 加速度センサーで操作する場合
        float motor = maxMotorTorque * Input.acceleration.z * (-1);
        float steering = maxSteeringAngle * Input.acceleration.x;

        foreach (AxleInfo axleInfo in axleInfos) {
            if (axleInfo.steering) {
                axleInfo.leftWheel.steerAngle = steering;
                axleInfo.rightWheel.steerAngle = steering;
            }
            if (axleInfo.motor) {
                axleInfo.leftWheel.motorTorque = motor;
                axleInfo.rightWheel.motorTorque = motor;
            }
        }
    }
}

[System.Serializable]
public class AxleInfo {
    public WheelCollider leftWheel;
    public WheelCollider rightWheel;
    public bool motor; //このホイールがエンジンにアタッチされているかどうか
    public bool steering; // このホイールがハンドルの角度を反映しているかどうか
}

車と効果音との連動

次にアクセルやハンドル操作に連動してエンジン音やタイヤのスリップ音を
出力できるようにします。

AudioSourceコンポーネントを追加したオブジェクトを3つ作成します。
AudioClipには「アイドリング音」「アクセル音」「スリップ音」を用意します。
image.png

スクリプト側で再生・停止が制御できるように、各AudioSourceのSerializeFieldを
宣言しておきます。

SimpleCarController.cs

public class SimpleCarController : MonoBehaviour
{
    [SerializeField] private AudioSource audioSourceIdling;
    [SerializeField] private AudioSource audioSourceAccel;
    [SerializeField] private AudioSource audioSourceSkid;

    (中略)

Scriptのコンポーネントにて、追加したSerializeFieldにAudioSourceをアタッチします。
image.png

ここからは再びコーディングです。
アイドリング音は起動時にスタートしたいので、以下のように記述します。

SimpleCarController.cs

public class SimpleCarController : MonoBehaviour
{

    (中略)

    void Start() {
        audioSourceIdling.Play();
    }

    (中略)

アクセル音とスリップ音の再生はFixedUpdate()内に記述します。
Wheel Colliderへの処理が終わった直後あたりにそれぞれ追加します。

スリップ音ですが、ここではsteeringが±5の時には停止させています。
これは、ハンドルの回転にある程度の遊びを持たせておくことで、むやみやたらに
スリップ音が鳴ることを抑止するためです。

さらに臨場感を求めたい人であれば、アクセル音を数種類用意し、motorの数値によって
多段階にする、といったこだわりを入れても良いのではないかと思います。

SimpleCarController.cs

public class SimpleCarController : MonoBehaviour
{

    public void FixedUpdate()
    {
        (中略)

        foreach (AxleInfo axleInfo in axleInfos)
        {
            if (axleInfo.steering)
            {
                axleInfo.leftWheel.steerAngle = steering;
                axleInfo.rightWheel.steerAngle = steering;
            }
            if (axleInfo.motor)
            {
                axleInfo.leftWheel.motorTorque = motor;
                axleInfo.rightWheel.motorTorque = motor;
            }
        }

        // アクセル音
        if(motor == 0)
        {
            audioSourceAccel.Stop();
        }
        else
        {
            if(!audioSourceAccel.isPlaying)
            {
                audioSourceAccel.Play();
            }
        }

        // スリップ音
        if(steering >= -5 && steering <= 5)
        {
            audioSourceSkid.Stop();
        }
        else
        {
            if(!audioSourceSkid.isPlaying)
            {
                audioSourceSkid.Play();
            }
        }
    }

車の3Dモデルを走らせる際には、Planeの広さを決めたり、壁を作ったり、
今回、車の3Dモデルやサーキット場の平面図はフリーのものを利用させてもらいました。
スマホ単体でも十分遊べる完成度w

ハンドルと連動させる

さあ結合テストです笑

スマートフォンの映像は、Chromecastでテレビに映しておきます。

以下のようにハンドルの裏にスマートフォンをアタッチ(!?)させます笑
隙間からアプリを起動したら、スタートです。
DSC_0170.JPG

ハンドルを前に倒すと進み、左右に切ると、ちゃんと曲がります。
testplay1.gif

最後に

平日の夜中に開発を進め、土曜の朝にお披露目。
ちゃんと動くこともあって、子供は素直に感動してくれたので良かったです。

作り終えて、こうして記事に起こしている時に知った、というか思い出したことですが、
段ボールの動作が連動する玩具としてNINTENDO LABOがありましたね。

それを踏まえると今回はまさに車輪の再発明

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?