質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • C#

    7697questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4411questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • プログラミング言語

    702questions

    プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Unity 移動している方向に球を回転させたい

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 326

regulus123

score 5

Unityで球を移動している方向(rigidbodyのvelocity)に回転をさせたいのですが、今一やり方がわかりません。
どの様な感じにすればいいのでしょうか?よろしくお願いします。

※Rigidbodyの物理挙動に任せずあくまでスクリプト上で回転させたいです。
※イメージとしては塊魂の様な感じでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+5

こんな考え方でどうでしょう?

あるフレームで球がrigidbody.velocoty * Time.deltaTime移動したとし、これをtranslationとします。
移動距離はtranslation.magnitudeで、これをdistanceとします。
オブジェクトのスケールをscaleとすると、コライダーの本来の半径がsphereCollider.radiusですので、球の半径はthis.sphereCollider.radius * scaleとなり、弧度法による回転量はdistance / (this.sphereCollider.radius * scale)となります。

移動量と回転角

回転軸は地面の法線(さしあたりVector3.upとする)とtranslationの外積の向きですので、Vector3.Cross(Vector3.up, translation).normalizedとします。

...ということで、下記のようなコードを試してみたところ、

using UnityEngine;

[RequireComponent(typeof(Rigidbody), typeof(SphereCollider))]
public class SphereController : MonoBehaviour
{
    private Vector3 destination;
    private new Rigidbody rigidbody;
    private SphereCollider sphereCollider;

    private void Start()
    {
        this.rigidbody = this.GetComponent<Rigidbody>();
        this.sphereCollider = this.GetComponent<SphereCollider>();
        this.rigidbody.isKinematic = true;
    }

    private void Update()
    {
        // とりあえず、マウスポインタの位置を球の移動目標にする
        var plane = new Plane(Vector3.up, this.rigidbody.position);
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float rayDistance;
        plane.Raycast(ray, out rayDistance);
        if (rayDistance > 0.0f)
        {
            this.destination = ray.GetPoint(rayDistance);
        }

        var translation = this.rigidbody.velocity * Time.deltaTime; // 位置の変化量
        var distance = translation.magnitude; // 移動した距離
        var scaleXYZ = transform.lossyScale; // ワールド空間でのスケール推定値
        var scale = Mathf.Max(scaleXYZ.x, scaleXYZ.y, scaleXYZ.z); // 各軸のうち最大のスケール
        var angle = distance / (this.sphereCollider.radius * scale); // 球が回転するべき量
        var axis = Vector3.Cross(Vector3.up, translation).normalized; // 球が回転するべき軸
        var deltaRotation = Quaternion.AngleAxis(angle * Mathf.Rad2Deg, axis); // 現在の回転に加えるべき回転

        // 現在の回転からさらにdeltaRotationだけ回転させる
        this.rigidbody.MoveRotation(deltaRotation * this.rigidbody.rotation);
    }

    private void FixedUpdate()
    {
        var velocity = this.rigidbody.velocity;
        this.rigidbody.MovePosition(Vector3.SmoothDamp(this.rigidbody.position, this.destination, ref velocity, 1.0f, 10.0f, Time.fixedDeltaTime));
    }
}

このような動きになりました。見やすくするため地面オブジェクトを配置しましたが、動きはスクリプトで制御されているので、球が地面から外れても落下しません。

結果

 追記

angularVelocityの書き換えで回転させたい場合、オブジェクトを非キネマティックにしないとならないようです。
ですので、適宜重力を作用させなくしたり、他のオブジェクトから作用を受けないようにレイヤーを変更したりといった設定調整が必要かもしれません。
angularVelocity方式の例としては、こんな感じでどうでしょうか?

using UnityEngine;

[RequireComponent(typeof(Rigidbody), typeof(SphereCollider))]
public class NonKinematicSphereController : MonoBehaviour
{
    private Vector3 destination;
    private new Rigidbody rigidbody;
    private SphereCollider sphereCollider;

    private void Start()
    {
        this.rigidbody = this.GetComponent<Rigidbody>();
        this.sphereCollider = this.GetComponent<SphereCollider>();
        this.rigidbody.isKinematic = false; // 非キネマティックにする場合...
        this.rigidbody.useGravity = false; // 重力を作用させなくする
    }

    private void Update()
    {
        var plane = new Plane(Vector3.up, this.rigidbody.position);
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float rayDistance;
        plane.Raycast(ray, out rayDistance);
        if (rayDistance > 0.0f)
        {
            this.destination = ray.GetPoint(rayDistance);
        }
    }

    private void FixedUpdate()
    {
        var velocity = this.rigidbody.velocity;
        Vector3.SmoothDamp(this.rigidbody.position, this.destination, ref velocity, 1.0f, 10.0f, Time.fixedDeltaTime);
        // 非キネマティックに変えたので、MovePositionによる位置操作の結果が自動的にrigidbody.velocityに
        // 反映されなくなるため、更新されたvelocityをrigidbody.velocityに再代入してやる
        // SmoothDampの返り値は破棄し、rigidbody.velocity書き換えによってのみ移動させることでつじつまを合わせる
        this.rigidbody.velocity = velocity;

        // 先に投稿したコードのtranslationをvelocityに置き換えると、得られる回転角は
        // 1秒あたりの弧度法による回転量...つまり角速度の大きさとなる
        // 回転軸も前回と同様の方法で求め、これが角速度ベクトルの向きとなる
        // あとは求めた角速度ベクトル(向きaxis、大きさangularSpeed)を
        // rigidbody.angularVelocityに代入すればいいはず

        var speed = velocity.magnitude; // 速さ
        var scaleXYZ = transform.lossyScale; // ワールド空間でのスケール推定値
        var scale = Mathf.Max(scaleXYZ.x, scaleXYZ.y, scaleXYZ.z); // 各軸のうち最大のスケール
        var angularSpeed = speed / (this.sphereCollider.radius * scale); // 角速度の大きさ
        var axis = Vector3.Cross(Vector3.up, velocity).normalized; // 角速度の向き
        this.rigidbody.angularVelocity = angularSpeed * axis;
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/14 22:30

    コードを確認させていただきました。
    大体実現したかった事が無事出来ました!
    ありがとうございますm(__)m

    キャンセル

  • 2018/07/15 02:54

    また少し要望なのですが、今のコードではMoveRotationを使って回転をさせていますが、angularVelocityで同じように回転させようとしましたがうまくいきませんでした。
    angularVelocityで回転させる場合はどの様なコードになるのでしょうか?

    キャンセル

  • 2018/07/15 07:02

    angularVelocityを使う方法を検討してみました。
    Rigidbodyがキネマティックだと、AddForceやvelocityの変更による移動、あるいはAddTorqueやangularVelocityの変更による回転はできないかと思いますので、非キネマティックに変更しています。

    キャンセル

  • 2018/07/15 10:07

    要望にお応えいただきありがとうございます。
    お陰様で製作が捗りそうです。
    ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C#

    7697questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4411questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • プログラミング言語

    702questions

    プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。