【Godot 4.0】スマホ３Dゲームを作るための勉強　その３　Node3Dで位置と向きを設定する

 ゲームエンジンgodot4.0で3Dスマホゲームを作りたいと思いますが、その前にお勉強しています。
 [Godot_v4.0-rc1_win64.exe.zip](https://downloads.tuxfamily.org/godotengine/4.0/rc1/Godot_v4.0-rc1_win64.exe.zip)を使用しています。

# 目的
　Node3Dを理解する

:::note info
Godot3.5の時はSpatialという名前でしたが、4.0で名称がNode3Dに変更しました。
:::

# Node3Dとは
　Godot 3DエンジンはNode3Dを継承（inheritance）するノードを3D空間に表示します。
　Node3Dを継承しているノードとは、子ノードを追加するウィンドウでNode3Dにぶら下がっているすべてのノードです。今まで登場したMeshInstance3Dや、DirectionalLight3D、Camera3DもNode3Dを継承しているため3D空間に配置することができます。

![GodotParts.pptx - PowerPoint 2023_02_21 10_17_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/c68fcb69-80ba-b373-8091-d7e285fdc994.png)

　MeshInstance3Dを選択して、右側のインスペクタを表示すると上の方には自身のMeshInstance3Dの設定・属性値が表示されています。継承元の情報・属性は下の方に表示されていて、Node3Dの情報・属性などがあります。他のNode3Dを継承したノードもインスペクタの下の方にNode3Dがあります。

![GodotParts.pptx - PowerPoint 2023_02_21 10_24_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/e1d0dedc-afcf-f057-2289-8bfbcf71a399.png)


# global座標とlocal座標
　シーンのルートノードを配置する座標系をglobal座標系といいます。
　ノードを親子関係にした場合、子は親のlocal(ローカル)座標系に存在します。

　ここでは雪だるまをつくって、ローカル座標の便利さを確認しようと思います。
　

　新規プロジェクトを作成して、3Dシーンを押下してNode3Dを追加します。　
　Node3Dを右クリックしてMeshInstance3Dを追加してください。名称をMeshInstance3D_bodyに変更してください。
　インスペクタのMeshInstance3DのMeshの<empty>をクリックして、新規SphereMeshを選択します。

　Node3Dを右クリックしてMeshInstance3Dを追加してください。名称をMeshInstance3D_headに変更してください。
　インスペクタのMeshInstance3DのMeshの<empty>をクリックして、新規SphereMeshを選択します。
　MeshInstance3D_headを選択して、Node3DのTransformのpositonのyを0.7mに設定してください。
　次にMeshInstance3Dの球をクリックしてください。Meshの詳細パラメータが表示されます。
　radius（半径）を0.5から0.3mにして、Heightを0.6mにすると少し小さいに球になります。

　雪だるまが完成しました。

![(_) TestGlobalLocal - Godot Engine 2023_02_21 10_55_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/b2280bd3-8473-d738-790a-36c1e4318bf4.png)

　では体を移動しましょう。
　MeshInstance3D_bodyを選択して、ギズモの赤い矢印をドラッグして左にうごかしましょう。
　頭（MeshInstance3D_head）はついてきませんね。
　このときのインスペクタ内のNode3D-Transform-positionのXの値を覚えておきましょう。
　
![(_) TestGlobalLocal - Godot Engine 2023_02_21 10_59_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/727343c2-cf1f-eec9-8b43-9f19c8388504.png)

　では次にMeshInstance3D_headを選択して、ギズモの赤い矢印をドラッグして左に動かして、体の上に頭が乗るようにしましょう。
　このときのインスペクタ内のNode3D-Transform-positionのXの値を確認すると、MeshInstance3D_bodyと同じような値になっていると思います。
　
![(_) TestGlobalLocal - Godot Engine 2023_02_21 13_02_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/cb88167f-f6d4-2c0d-1901-b2e00aad0671.png)

　でも本当は体を動かしたときは、頭も一緒についてきてほしいですよね。
　その場合は、ベースとするノードを決めて、ほかの一緒に動いてほしいノードはその子供にします。

　（下記操作をする前に、MeshInstance3D_headとMeshInstance3D_bodyのXの値は同じにしてください。）

　シーンの中でMeshInstance3D_headをドラッグアンドドロップしてMeshInstance3D_bodyに重ねると、MeshInstance3D_bodyが親でMeshInstance3D_headが子供になってぶら下がるようになります。

![キャプチャ 2023_02_21 13_17_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/b4a4e996-4351-0ae1-849d-de1700e3dd55.png)


　あたらめてMeshInstance3D_bodyを選択してギズモを表示して、赤い矢印をドラッグすると頭がついてきます。
　この時にMeshInstance3D_headを選択してインスペクタ内のNode3D-Transform-positionのXを確認すると、0mになっていると思います。


　はじめの例ではglobal座標系にbody（MeshInstance3D_body）とhead（MeshInstance3D_head）の位置を定義していました。そのためbodyを動かしてもheadはそのままの位置でした。
![GodotParts.pptx - PowerPoint 2023_02_23 12_08_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/14687029-647a-d3e5-5e3c-b30c04ac73ee.png)

　後の例ではノードを親子にしました。
　Node3Dは親子にすると、子のNode3D(head)は親(body)の位置からの差分（位置、回転）を表すようになります（local transform)。今回の例では、頭の位置は体の中心からY軸方向に0.7mにあるという相対的な位置関係を表しています。
　そのため、bodyを移動しても、head(子）はbody(親）との位置関係を保持するため、headがbodyについてきます。headのx座標はbodyとの関係を保持しているので、0mのままです。
![GodotParts.pptx - PowerPoint 2023_02_23 12_08_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/f298cac2-5d5d-1f70-cd05-d7899678eab1.png)


　Godotの3D表示内の赤、青、緑の軸の座標系、3次元空間全体をglobal座標系といいます。
　それに対して、個々のノードが持つ座標系をローカル座標系といいます。

　これはとても便利な仕組みで、複数のノードで構成されているキャラクターを動かすときに、ひとつの親ノードを動かすだけで全部ついてくるし、多関節なものもうまく管理することができます。

# global座標とlocal座標の注意点
　ノードを追加するときの階層を意識する必要があります。
　BodyとGunをもつ砲台から弾丸を発射する場合に、その弾丸を追加する例で考えます。

　砲台Node3D_Palayer_01 親ノードにBody01とGun01とGun01から発射されたBullet01をぶら下げています。
　砲台Node3D_Palayer_02 親ノードはBody02とGun02のみが子ノードとして、Bullet02はルートノードにぶら下げています。

![C__Users_hathr_Videos_Captures 2023_02_22 9_24_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/e9966520-feb2-d0a9-18cd-23bd882399ad.png)

　砲台Node3D_Palayer_01 を選択して移動すると、砲台Node3D_Palayer_01の子のBullet01も一緒についてきてしまいます。多くの場合意図しない動作になります。
　砲台Node3D_Palayer_02選択してを移動すると、Bullet02はついてきません。

![(_) node_3d.tscn - 03_Node3D_2 - Godot Engine 2023_02_22 9_19_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/baae5316-4718-472f-6b99-d101bcda1145.png)


　こうしてエディターで見ると当たり前でわかりやすいのですが、プログラムからBulletを追加するときには、背景＝global座標系を持つノードにBulletを追加する必要があります。


以上