アヒルのある日

株式会社AHIRUの社員ブログです。毎週更新!社員が自由に思いついたことを書きます。

3Dモデルを動かせ~!

こんにちは、ちゃらいプログラマです。
3Dモデルを触る機会がありましたので、モーションもあることからどうせなら動かしてみたい!と思って作ってみました。  

f:id:charai_ahiru:20201127104013p:plain
実行画面

  移動する範囲は、 NavMeshを利用することで簡単に実装できました。  

f:id:charai_ahiru:20201127104016p:plain
編集画面

移動先は、移動対象のGameObjectに「NavMeshAgent」コンポーネントを追加しプログラム側で以下のように実装するだけで向きに合わせて回転もしてくれます。

[SerializeField]
NavMeshAgent Agent = null;

void Update()
{
    Agent.SetDestination( 指定座標::Vector3 );
}  

 

アニメーション設定も回転方向に合わせて調整。
Rotateパラメータが30を超えた時にモーションを変更するようにしています。(Walkに戻すときは30未満になったらとしています)

f:id:charai_ahiru:20201127140732p:plain
歩きモーションから右方向に向く時の設定

サンプルプログラムはこちらになります。

public class Player : MonoBehaviour
{
    [SerializeField]
    private Animator        Animator            = null;
    [SerializeField]
    private NavMeshAgent    Agent               = null;
    [SerializeField]
    private Vector3[]       NavPositionList     = null;

    private int             _navIndex           = 0;
    private Vector3         _currentPosition    = Vector3.zero;

    // Start is called before the first frame update
    void Start()
    {
        _setTargetPosition();
        _setCurrentPosition();
    }

    // Update is called once per frame
    void Update()
    {
        // 経路設定
        Agent.SetDestination( NavPositionList[_navIndex] );

        _setCurrentPosition();

        // 回転値設定
        var diff = NavPositionList[_navIndex] - _currentPosition;
        var axis = Vector3.Cross( transform.forward, diff );
        var angle = Vector3.Angle( transform.forward, diff ) * (axis.y < 0 ? -1 : 1);
        Animator.SetFloat( "Rotate", angle );

        // 待ちモーション設定
        Animator.SetBool( "IsWait", false );
        if( Random.Range(0, 500) == 0 && !Animator.GetCurrentAnimatorStateInfo(0).IsName( "IdleLookAround" ) )
        {
            Animator.SetBool( "IsWait", true );
        }

        // 移動値設定
        Agent.speed = Animator.GetCurrentAnimatorStateInfo(0).IsName( "IdleLookAround" ) ? 0f : 1f;

        if( Vector3.Distance( NavPositionList[_navIndex], _currentPosition ) <= 1f )
        {
            _setTargetPosition();
        }

        // カメラ注視点更新
        Camera.main.transform.LookAt( transform );
    }

    private void _setTargetPosition()
    {
        _navIndex = Random.Range( 0, NavPositionList.Length );
    }

    private void _setCurrentPosition()
    {
        _currentPosition.x = transform.position.x;
        _currentPosition.z = transform.position.z;
    }
}

移動範囲内に障害物が無いので楽してますが、移動できない範囲もNavMeshで設定可能なのでよさそうですね。
今回は全てが新しい体験だったのですごく楽しかったです。上手く製品に落とし込んで行きたいです。

 

では、また次回!