6
5

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 3 years have passed since last update.

【Unity】マリオギャラクシーのように惑星の表面を歩こう!

Last updated at Posted at 2021-07-05

・この記事ではUnityでマリオギャラクシーのように惑星の表面を歩くシステムを実装します。

・アセットは使用せず、初めからUnityに搭載されている機能のみを使って実装します。

・動けば良い!の精神でおねがいします。

・筆者の環境:Windows10 Unity 2020.1.3f1 Personal

はじめに

みなさんが子どもの頃に遊んだ好きなゲームってなんですか?

私は小さいころWiiで遊んだマリオギャラクシーが特に大好きです。

マリオギャラクシーのステージは惑星(平面でないステージ)が多く、印象的ですよね。

このシステム、Unityで再現できれば面白いと思いませんか?

というわけで、今回はこの「惑星の表面を歩くシステム」をUnityで実装してみましょう。

今回のゴール

画像では伝わりにくいので動画↓でどうぞ。※クリックすると新規タブでYouTubeが開きます。
Qiita記事_03用動画_01

目標

1:惑星オブジェクトのポリゴンに沿って運動できるようにする
2:惑星を複数配置し、惑星間を飛び回る

実装・その1

  1. Unityを起動し、3Dでプロジェクトを新規作成する。(名前はなんでもよい)

  2. Hierarchy +タブ -> 3D Object -> Capsule

  3. Capsuleの名前を「 Player 」に変更する。

  4. Playerのポジションを[ x = 0, y = 13, z = 0 ]に変更する。

  5. Player -> Inspector -> Add Component -> Physics -> Rigidbodyを追加する。

  6. Player -> RigidbodyUse Gravityのチェックを外す。

  7. Player -> Rigidbody -> Constraints -> Freeze Rotaionx, y, zにチェックを入れる。

  8. このままだと正面がどこかわからないので、Cubeを子オブジェクトにして鼻を付けると分かりやすいかも。(お好みでどうぞ)

  9. Hierarchy +タブ -> 3D Object -> Sphere

  10. Sphereの名前を「 Planet_Sphere 」に変更する。

  11. Planet_Sphereのスケールを[ x = 20, y = 20, z = 20 ]程度に変更する。

  12. Planet_Sphere -> Inspector -> Tag -> Add Tag...から「 Planet 」というタグを新しく設定する。

  13. Planet_Sphereのタグを「 Planet 」に変更する。

  14. Project +タブ -> C# Script から「 Player_Logic 」という名前でスクリプトを新規作成する。

  15. Player_Logic を Player にアタッチする。

  16. Player_Logicに以下のコードをコピペする。

Player_Logic.C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player_Logic : MonoBehaviour
{
    //プレイヤーの移動する速さ
    public float move_speed = 15;

    //プレイヤーの回転する速さ
    public float rotate_speed = 5;

    //プレイヤーの回転する向き
    //1 -> (プレイヤーから見て)時計回り
    //-1 -> (プレイヤーから見て)反時計回り
    private int rotate_direction = 0;

    //プレイヤーのRigidbody
    private Rigidbody Rig = null;

    //地面に着地しているか判定する変数
    public bool Grounded;

    //ジャンプ力
    public float Jumppower;


    void Start()
    {
        Rig = this.GetComponent<Rigidbody>();
    }

    void Update()
    {
        Jump();
    }

    private void FixedUpdate()
    {
        Horizontal_Rotate();

        Vector3 move_direction = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;

        Rig.MovePosition(Rig.position + transform.TransformDirection(move_direction) * move_speed * Time.deltaTime);
    }

    void Jump()
    {
        if (Grounded == true)//  もし、Groundedがtrueなら、
        {
            if (Input.GetKeyDown(KeyCode.Space))//  もし、スペースキーがおされたなら、  
            {
                Grounded = false;//  Groundedをfalseにする
                Rig.AddForce(transform.up * Jumppower * 100);//  上にJumpPower分力をかける
            }
        }
    }

    void OnCollisionEnter(Collision other)//  他オブジェクトに触れた時の処理
    {
        if (other.gameObject.tag == "Planet")//  もしPlanetというタグがついたオブジェクトに触れたら、
        {
            Grounded = true;//  Groundedをtrueにする
        }
    }

    void Horizontal_Rotate()
    {
        if (Input.GetKey(KeyCode.Q))
        {
            rotate_direction = -1;
        }
        else if (Input.GetKey(KeyCode.E))
        {
            rotate_direction = 1;
        }
        else
        {
            rotate_direction = 0;
        }

        // オブジェクトからみて垂直方向を軸として回転させるQuaternionを作成
        Quaternion rot = Quaternion.AngleAxis(rotate_direction * rotate_speed, transform.up);
        // 現在の自信の回転の情報を取得する。
        Quaternion q = this.transform.rotation;
        // 合成して、自身に設定
        this.transform.rotation = rot * q;
    }
}

Player_Logic.C#の解説

・宣言部分

Player_Logic.C#
//プレイヤーの移動する速さ
    public float move_speed = 15;

    //プレイヤーの回転する速さ
    public float rotate_speed = 5;

    //プレイヤーの回転する向き
    //1 -> (プレイヤーから見て)時計回り
    //-1 -> (プレイヤーから見て)反時計回り
    private int rotate_direction = 0;

    //プレイヤーのRigidbody
    private Rigidbody Rig = null;

    //地面に着地しているか判定する変数
    public bool Grounded;

    //ジャンプ力
    public float Jumppower;

コメントアウトそのままです。特に説明しなくても大丈夫でしょう。


・Start関数部分

Player_Logic.C#
    void Start()
    {
        Rig = this.GetComponent<Rigidbody>();
    }

スクリプトがアタッチされているオブジェクトのコンポーネントを参照し、Rigidbodyを取得しています。


・Update関数部分

Player_Logic.C#
    void Update()
    {
        Jump();
    }

Jump関数を呼び出しています。Jump関数の中身は↓に


・Jump関数部分
順番が入れ替わりますが、先にJump関数の説明です。

Player_Logic.C#
    void Jump()
    {
        if (Grounded == true)//  もし、Groundedがtrueなら、
        {
            if (Input.GetKeyDown(KeyCode.Space))//  もし、スペースキーがおされたなら、  
            {
                Grounded = false;//  Groundedをfalseにする
                Rig.AddForce(transform.up * Jumppower * 100);//  上にJumpPower分力をかける
            }
        }
    }

ジャンプ機能が重複しない(無限ジャンプができない)ようにしています。
ここのポイントはAddForceで力を加える際に、上方向を「Playerオブジェクトからみて垂直方向(transform.up)」にしてあるところです。
惑星単位で重力を操るので、ワールド基準の垂直方向では意味がなくなってしまうためです。

Rig.AddForce(transform.up * Jumppower * 100);

・OnCollisionEnter関数部分
順番が入れ替わりますが、ジャンプ機能に関連するので先に説明します。

Player_Logic.C#
    void OnCollisionEnter(Collision other)//  他オブジェクトに触れた時の処理
    {
        if (other.gameObject.tag == "Planet")//  もしPlanetというタグがついたオブジェクトに触れたら、
        {
            Grounded = true;//  Groundedをtrueにする
        }
    }

ジャンプ機能の回復について制御しています。
Jump関数では Spaceキー を押すと Grounded変数が false に設定されます。このままだと二度とジャンプすることができません (´;ω;`)
OnCollisionEnter関数では他のオブジェクトに接触した際、そのオブジェクトのタグがPlanetであった場合に Grounded変数を true に設定します。
これで再びジャンプすることができます。^^ ヤッタネ!


・FixedUpdate関数部分
順番が前後しましたがFixedUpdate関数の説明です。

Player_Logic.C#
    private void FixedUpdate()
    {
        Horizontal_Rotate();

        Vector3 move_direction = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;

        Rig.MovePosition(Rig.position + transform.TransformDirection(move_direction) * move_speed * Time.deltaTime);
    }

一行目ではHorizontal_Rotate関数を呼び出しています。

二行目ではキーボードの入力に対して、Playerの進行方向を設定しています。
また、「 方向 」なので .normalized を用いて正規化しています。

三行目ではRigidbody.MovePositionを用いてPlayerの位置を変更しています。
Rigidbody.MovePositionは移動したい先の座標(ワールド座標・絶対座標)を引数とすることで、オブジェクトを指定した座標に移動させます。
Time.deltaTimeをかける(補間する)ことでスムーズ遷移となります。(本当は違いますが...)

より詳しい説明や考察は以下の記事からどうぞ...

Unity DOCUMENTION Rigidbody.MovePosition
https://docs.unity3d.com/ja/2018.4/ScriptReference/Rigidbody.MovePosition.html

Qiita [Unity初心者Tips]どれが良いかわかる!ものを動かす方法はこうして決める
https://qiita.com/JunShimura/items/ab243cbd29e63e4f27c5

弱火でじっくり [Unity] positionとMovePositionの違いを比べた
https://yowabi.blogspot.com/2017/12/unity-positionmoveposition-rigidbody.html?m=1

また、transform.TransformDirectionは「ローカルな方向・ベクトル・座標」を「ワールドな方向・ベクトル・座標」に変換します。
より詳しい説明は以下の記事を参考にしてください,,,

Unity DOCUMENTION Transform.TransformDirection
https://docs.unity3d.com/ja/current/ScriptReference/Transform.TransformDirection.html

TECH Pjin 【Unity】Transformコンポーネントの便利な関数まとめ
https://tech.pjin.jp/blog/2016/03/29/unity_transform_compo/


・Horizontal_Rotate関数部分

Player_Logic.C#
    void Horizontal_Rotate()
    {
        if (Input.GetKey(KeyCode.Q))
        {
            rotate_direction = -1;
        }
        else if (Input.GetKey(KeyCode.E))
        {
            rotate_direction = 1;
        }
        else
        {
            rotate_direction = 0;
        }

        // オブジェクトからみて垂直方向を軸として回転させるQuaternionを作成
        Quaternion rot = Quaternion.AngleAxis(rotate_direction * rotate_speed, transform.up);
        // 現在の自信の回転の情報を取得する。
        Quaternion q = this.transform.rotation;
        // 合成して、自身に設定
        this.transform.rotation = rot * q;
    }

ここではプレイヤーからみた水平方向の回転について制御しています。

また、Quaternionの合成は積で行うのですが、

Quaternion.AngleAxis(rotate_direction * rotate_speed, transform.up);

この部分で「Playerオブジェクトからみた上方向(transform.up)」を軸として回転させるQuaternionを生成しています。

回転量はrotate_speedで指定し、回転方向はrotate_directionで指定しています。

rotate_direction はキーボード入力(Qキーで反時計回り(-1)、Eキーで時計回り(+1))を設定します。何も入力がないときは 0 を設定します。これがポイントです。

感覚としてはオブジェクトに長い棒をぶっさしてクルクルまわしている感じです。

また、Quaternionは線形代数などで学ぶ回転行列と強い関係を持ちます。

そのため交換法則が必ず成り立つとは限りません。

もし、Quaternionの回転で意図しない動きをしてしまったら、積の順番を入れ替えてみるのもおすすめです。

行列の交換法則についてのわかりやすい説明です。よかったらどうぞ↓

高校数学の基本問題 高卒~大学数学 行列の乗法の性質
http://www.geisya.or.jp/~mwm48961/kou2/matrix3.html

Quaternionについて

Quaternion(クォータニオン)ってなんだ?と思う方もいるかもしれません。

QuaternionはUnityやゲームエンジン、その他の分野で「回転」を扱う際に非常に重要な概念です。

Unityでは回転にかかわることを全てこのQuaternionで制御しています。

「全てだって?!インスペクターではオブジェクトの回転はオイラー角で制御しているじゃないか!(°д°) 」と思う人もいるでしょう。

これはUnityが気を利かせて、内部処理でオイラー角をQuaternionに変形してくれているのです。Unityちゃんありがとう!(≧▽≦)

さて、Quaternionとは何かを語ると非常に面倒くさい大変なので、Quaternionの本質を考えたい方は以下の記事を参考にしてください。

特にセガ公式の記事はおすすめです。大企業の資料を見ることなんてなかなかできません!公開されているうちにぜひ見ましょう!

Twitter セガ公式アカウント クォータニオンとは何ぞや?
https://twitter.com/SEGA_OFFICIAL/status/1404648102477262849

XR-HU3 【Unity】Quaternionでオブジェクトを回転させる方法
https://xr-hub.com/archives/11515

SAMURAIENGINEER 【Unity入門】必ず分かる!一番簡単なQuaternionの使い方入門!
https://www.sejuku.net/blog/55596

クォータニオン (Quaternion) を総整理! ~ 三次元物体の回転と姿勢を鮮やかに扱う ~
https://qiita.com/drken/items/0639cf34cce14e8d58a5

途中経過

さて、ここで一度再生ボタンを押して動作を確認してみましょう。

!注意! ジャンプ力を表す変数Jumppowerは初期値では0に設定されています。

重力の概念を追加していないので、同じ高さで動き回ることが出来れば成功です。

これでプレイヤーの動作を実装できました。

次は重力とその他もろもろについて実装しましょう。

実装・その2

  1. Project +タブ -> C# Script から「 Gravity_Logic 」という名前でスクリプトを新規作成する。

  2. Gravity_Logic を Player にアタッチする。

  3. Gravity_Logicに以下のコードをコピペする。

Gravity_Logic.C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Gravity_Logic : MonoBehaviour
{
    //PlayerのTransform
    private Transform myTransform;

    //PlayerのRigidbody
    private Rigidbody rig = null;

    //重力減となる惑星
    private GameObject Planet;

    //「Planet」タグがついているオブジェクトを格納する配列
    private GameObject[] Planets;

    //重力の強さ
    public float Gravity;

    //惑星に対するPlayerの向き
    private Vector3 Direction;

    //Rayが接触した惑星のポリゴンの法線
    private Vector3 Normal_vec = new Vector3(0,0,0);

    void Start()
    {
        rig = this.GetComponent<Rigidbody>();
        rig.constraints = RigidbodyConstraints.FreezeRotation;
        rig.useGravity = false;
        myTransform = transform;
    }

    void Update()
    {
        Attract();
        RayTest();
    }

    public void Attract()
    {
        Vector3 gravityUp = Normal_vec;

        Vector3 bodyUp = myTransform.up;

        myTransform.GetComponent<Rigidbody>().AddForce(gravityUp * Gravity);

        Quaternion targetRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * myTransform.rotation;

        myTransform.rotation = Quaternion.Lerp(myTransform.rotation, targetRotation, 120 * Time.deltaTime);

    }

    GameObject Choose_Planet()
    {
        Planets = GameObject.FindGameObjectsWithTag("Planet");

        double[] Planet_distance = new double[Planets.Length];

        for (int i = 0; i < Planets.Length; i++)
        {
            Planet_distance[i] = Vector3.Distance(this.transform.position, Planets[i].transform.position);
        }

        int min_index = 0;
        double min_distance = Mathf.Infinity;

        for (int j = 0; j < Planets.Length; j++)
        {
            if (Planet_distance[j] < min_distance)
            {
                min_distance = Planet_distance[j];
                min_index = j;
            }
        }

        return Planets[min_index];
    }

    void RayTest()
    {
        Planet = Choose_Planet();

        Direction = Planet.transform.position - this.transform.position;

        Ray ray = new Ray(this.transform.position, Direction);

        //Rayが当たったオブジェクトの情報を入れる箱
        RaycastHit hit;

        //もしRayにオブジェクトが衝突したら
        if (Physics.Raycast(ray, out hit, Mathf.Infinity))
        {
            //Rayが当たったオブジェクトのtagがPlanetだったら
            if (hit.collider.tag == "Planet")
            {
                Normal_vec = hit.normal;
            }
        }
    }
}

Gravity_Logicの解説

・宣言部分

Gravity_Logic.C#
    //PlayerのTransform
    private Transform myTransform;

    //PlayerのRigidbody
    private Rigidbody rig = null;

    //重力減となる惑星
    private GameObject Planet;

    //「Planet」タグがついているオブジェクトを格納する配列
    private GameObject[] Planets;

    //重力の強さ
    public float Gravity;

    //惑星に対するPlayerの向き
    private Vector3 Direction;

    //Rayが接触した惑星のポリゴンの法線
    private Vector3 Normal_vec = new Vector3(0,0,0);

コメントアウトしている説明そのままです。特に解説する必要はないでしょう。
Normal_vecにゼロベクトルを代入し、初期化しています。(開始後数フレームの間Normal_vecに何も入っていない(わけのわからない数)が代入されてしまうのを防ぐためです。)


・Start関数部分

Gravity_Logic.C#
    void Start()
    {
        rig = this.GetComponent<Rigidbody>();
        rig.constraints = RigidbodyConstraints.FreezeRotation;
        rig.useGravity = false;
        myTransform = this.transform;
    }

一行目では Player の Rigidbody であるrigにコンポーネント経由でPlayerのRigidbodyを格納しています。

二行目・三行目では実装・その1の6番目7番目で行った設定を念のためスクリプト側からも設定しています。

四行目では、このスクリプトがアタッチされているオブジェクトのTransformをmyTransformに格納しています。


・Update関数部分

Gravity_Logic.C#
    void Update()
    {
        Attract();
        RayTest();
    }

一行目では Attract関数 を呼び出しています。Attract関数 は重力とPlayerの回転について制御する関数です。

二行目では RayTest関数 を呼び出しています。RayTest関数Attract関数 内で使用されるNormal_vec にRayが接触したポリゴンの法線を格納する役割を持ちます。


・Attract関数内部

Gravity_Logic.C#
    public void Attract()
    {
        Vector3 gravityUp = Normal_vec;

        Vector3 bodyUp = myTransform.up;

        myTransform.GetComponent<Rigidbody>().AddForce(gravityUp * Gravity);

        Quaternion targetRotation = Quaternion.FromToRotation(bodyUp, gravityUp) * myTransform.rotation;

        myTransform.rotation = Quaternion.Lerp(myTransform.rotation, targetRotation, 120 * Time.deltaTime);

    }

一行目では、gravityUpというVector3型の変数にNormal_vecを代入しています。GravityUpという分かりやすい名前にしたかったので代入しました。意味としては重力の逆ベクトルを表しています。

二行目では、bodyUpというVector3型の変数にmyTransform.upを代入しています。
こちらも分かりやすい名前にしたかったので代入しました。意味としてはPlayerオブジェクトからみた頭上のベクトルを表しています。

三行目では、コンポーネント経由でmyTransformからRigidbodyを参照し、AddForceで力を加えています。
力を加える向きは先ほど指定したgravityUpで、力の大きさはGravityです。この引数からわかる通り、Gravityは負の数で指定する必要があります。

四行目では、Quaternion.FromToRotationを用いてQuaternionを生成しています。
自身がどれだけ回転しているかという情報をmyTransform.rotationで表し加算しています。つまり現在の姿勢からどれだけ回転させるかを計算しtargetRotationに格納しています。

五行目では、Quaternion.Lerpを用いて第一引数と第二引数の間の角度を第三引数で指定した秒数で「線形補間」しながら回転させています。

.Lerp と .Slerp について

五行目でQuaternion.Lerpを用いて回転させていましたが、「線形補間」のほかに「球面補間」というものがあります。

「線形補間」は直線を意識した回転を。
「球面補間」は球面に沿うような回転をします。

より詳しい解説はこちらの記事↓からどうぞ!

【Unity入門】LerpとSlerpの使い方と違い!自在に補間をかけよう
https://www.sejuku.net/blog/83510

今回のプログラムではどちらを使っても特に違いは出ないと思います。ステージの形状の傾向などを考慮してお好みで変更してあげてください。


順番が前後しますが先にRayTest関数の解説です。
・RayTest関数部分

Gravity_Logic.C#
    void RayTest()
    {
        Planet = Choose_Planet();

        Direction = Planet.transform.position - this.transform.position;

        Ray ray = new Ray(this.transform.position, Direction);

        //Rayが当たったオブジェクトの情報を入れる箱
        RaycastHit hit;

        //もしRayにオブジェクトが衝突したら
        if (Physics.Raycast(ray, out hit, Mathf.Infinity))
        {
            //Rayが当たったオブジェクトのtagがPlanetだったら
            if (hit.collider.tag == "Planet")
            {
                Normal_vec = hit.normal;
            }
        }
    }

一行目では、Choose_Planet関数 の戻り値を Planet に代入しています。
Choose_Planet関数 をざっくり説明すると、Planetタグ を持っているオブジェクトで一番 Player に近いオブジェクトを返す関数です。

二行目では、Direction にプレイヤーから見た惑星中心のベクトルを代入しています。

三行目では、Rayを宣言しています。Rayの発射地点はPlayerの座標で、Rayを飛ばす方向はDirectionです。

四行目では、Rayが当たったオブジェクトの情報を入れるhitを宣言しています。

五行目以降では、Rayがオブジェクトに接触した際の処理を書いています。
Rayが接触したオブジェクトのタグがPlanetである場合にRayが接触した惑星のポリゴンの法線(hit.normal)をNormal_vecに代入します。
この代入をすることで、惑星の表面に沿ってPlayerが回転するようになります。
なにげに重要な部分です笑


順番が前後しましたがChoose_Planet関数の解説です。
・Choose_Planet関数部分

Gravity_Logic.C#
    GameObject Choose_Planet()
    {
        Planets = GameObject.FindGameObjectsWithTag("Planet");

        double[] Planet_distance = new double[Planets.Length];

        for (int i = 0; i < Planets.Length; i++)
        {
            Planet_distance[i] = Vector3.Distance(this.transform.position, Planets[i].transform.position);
        }

        int min_index = 0;
        double min_distance = Mathf.Infinity;

        for (int j = 0; j < Planets.Length; j++)
        {
            if (Planet_distance[j] < min_distance)
            {
                min_distance = Planet_distance[j];
                min_index = j;
            }
        }

        return Planets[min_index];
    }

Choose_Planet関数はPlanetタグ を持っているオブジェクトで一番 Player に近いオブジェクトを返す関数です。

アルゴリズムは有名なので解説は不要でしょう。
C#には配列の最大値を返す便利な機能もありますが今回は使っていません。その機能を使えばコードはもう少し短くなると思います。

実行・おわりに

さて、ここまできたら再生ボタンを押して実行してみましょう!

Player が惑星( Planet )の側面に沿って歩くことが出来れば実装成功です!

!注意! ジャンプ力を表す変数 Jumppower は初期値では0に設定されています。お好みで変更してください。

今回はUnityでマリオギャラクシーのように惑星の表面を歩くシステムを実装しました。

これを機にゲーム技術への関心を持っていただけたら嬉しいです。

長い記事になりましたがここまで読んでくれてありがとうございました。

それではまた次の記事でお会いしましょう!お疲れさまでした。(´∇`)

参考文献

Unity Tutorial: Planet Spherical Gravity (Multiple Planets!) - Super Mario Galaxy Movement
https://www.youtube.com/watch?v=UeqfHkfPNh4&t=164s

How Did They Do That - Mario Galaxy's Gravity
https://www.youtube.com/watch?v=vALtyrp87mI

Unityでのジャンプ【Rigidbody,CharacterControllerどちらも対応】
https://getabakoclub.com/2019/12/01/unity%E3%81%A7%E3%81%AE%E3%82%B8%E3%83%A3%E3%83%B3%E3%83%97%E3%80%90rigidbodycharactercontroller%E3%81%A9%E3%81%A1%E3%82%89%E3%82%82%E5%AF%BE%E5%BF%9C%E3%80%91/#Rigidbody

【Unity】Time.deltaTimeの正しい使い方わかってる?適当に掛ければいいてもんじゃない!
https://qiita.com/toRisouP/items/930100e25e666494fcd6

[Unity初心者Tips]どれが良いかわかる!ものを動かす方法はこうして決める
https://qiita.com/JunShimura/items/ab243cbd29e63e4f27c5#%E6%96%B9%E6%B3%952iskinematic%E3%81%A8moveposition%E3%81%A7%E3%82%B4%E3%83%AA%E6%8A%BC%E3%81%97

Twitter セガ公式アカウント クォータニオンとは何ぞや?
https://twitter.com/SEGA_OFFICIAL/status/1404648102477262849

XR-HU3 【Unity】Quaternionでオブジェクトを回転させる方法
https://xr-hub.com/archives/11515

SAMURAIENGINEER 【Unity入門】必ず分かる!一番簡単なQuaternionの使い方入門!
https://www.sejuku.net/blog/55596

クォータニオン (Quaternion) を総整理! ~ 三次元物体の回転と姿勢を鮮やかに扱う ~
https://qiita.com/drken/items/0639cf34cce14e8d58a5

基礎線形代数講座 - 線形代数・回転の表現 - 株式会社 セガ 開発技術部
https://www.slideshare.net/SEGADevTech/ss-249343092

【Unity入門】LerpとSlerpの使い方と違い!自在に補間をかけよう
https://www.sejuku.net/blog/83510

高校数学の基本問題 高卒~大学数学 行列の乗法の性質
http://www.geisya.or.jp/~mwm48961/kou2/matrix3.html

Unity DOCUMENTION Rigidbody.MovePosition
https://docs.unity3d.com/ja/2018.4/ScriptReference/Rigidbody.MovePosition.html

Qiita [Unity初心者Tips]どれが良いかわかる!ものを動かす方法はこうして決める
https://qiita.com/JunShimura/items/ab243cbd29e63e4f27c5

弱火でじっくり [Unity] positionとMovePositionの違いを比べた
https://yowabi.blogspot.com/2017/12/unity-positionmoveposition-rigidbody.html?m=1

6
5
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
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?