【Godot 4.0】スマホ３Dゲームを作るための勉強　その６　CharacterBody3Dを動かしましょう

 ゲームエンジン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)を使用しています。

# 目的
　CharacterBody3Dを動かしましょう。

# CharacterBody3Dを動かす
　新規プロジェクトを作成して下記のようになるようにノードを追加しましょう。
　ルートノードはNode3Dで、名称をglobalに変更しています。

　![(_) global.tscn - S06_CharacterBody3D_Control - Godot Engine 2023_02_24 11_39_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/f64b0c22-4330-c8df-05a8-e41ad817e2ab.png)
1. Camera3Dはトップビューにします。上から見下ろす感じです。
　　インスペクタ内のNode3D/Transform/position/x,y,z に0.0m, 5.0m, -1.0mを設定
　　インスペクタ内のNode3D/Transform/rotation/xに-90°を設定
1. MeshInstance3Dにカプセル型を設定します。
　　インスペクタ内のMeshInstance3D/Meshを新規CapsuleMeshに設定します。
1. CollisionShape3Dに衝突形状を設定
　　MeshInstance3Dと同じ形にします。
　　インスペクタ内のCollisionShape3D/Shapeに新規CapsuleShape3Dを設定
1. DirectionalLight3Dをほかのノードと重ならないように移動
　　x=-10に変更しました※。　

　※DirectionalLight3Dは3D空間の中のどこにあってもよいのですが、中央にあると邪魔なので移動しています。


　シーン内のCharacterBody3Dを右クリックし、スクリプトをアタッチします。
　スクリプト全体を下記のように書き換えましょう。

``` GDScript
extends CharacterBody3D

func _physics_process(delta):
	velocity = Vector3(0.0, 0.0, -1.0).normalized()
	move_and_slide()
```
* extends CharacterBody3D
　CharacterBody3Dを継承しましょう。
* func _physics_process(delta): 
　_processではなく、_physics_processメソッドを使用します。
　物理エンジンの演算結果（現在位置、向き、速度など）を使用するまたは、動きの指示をする場合は、_physics_processメソッドの中で実行しましょう。
* velocity = Vector3(0.0, 0.0, -1.0).normalized()
　速度を設定します。単位はm/sです。
* move_and_slide()
　設定した速度でノードを動かすように物理エンジンに依頼します。
　衝突なので速度に変化があった場合、velocityが上書きされます

　実行しましょう。1ms/の速度で動いていると思います。

![Screenshot 2023_02_24 13_54_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/b7141675-c164-037c-9aa3-499cd6e02d5e.png)


# CharacterBody3Dが衝突する時の動作
　CharacterBody3Dが進む先に障害物としてStaticBody3Dを置きます。
　
![「【Godot 4.0】スマホ３Dゲームを作るための勉強　その６」を編集 - Qiita - Google Chrome 2023_02_24 13_57_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/0c0e9844-a868-9b82-f086-191488851cbe.png)

1. StaticBody3Dの立方体の角がCharacterBody3Dに衝突するように回転します
　インスペクタ内のNode3D/Transform/position/x,y,z に0.0m, 0.0m, -3.0mを設定
　インスペクタ内のNode3D/Transform/rotation/x,y,z に0.0°,-40°,0.0°を設定　
![global.tscn - S06_CharacterBody3D_Control - Godot Engine 2023_02_24 23_28_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/30cc93df-4cc1-7c53-8c29-c1f6843463af.png)

1. MeshInstance3Dにboxを設定します。
　　インスペクタ内のMeshInstance3D/Meshを新規BoxMeshに設定します。
1. CollisionShape3Dに衝突形状を設定
　　MeshInstance3Dと同じ形にします。
　　インスペクタ内のCollisionShape3D/Shapeに新規BoxShape3Dを設定

　ビューメニューから2ビューポートを選択しています。camera3Dを選択した状態で下のビューポートのプレビューのプレビューをチェックすると実行時の構図を確認することができます。
![(_) global.tscn - S06_CharacterBody3D_Control - Godot Engine 2023_02_24 14_03_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/e5928a89-93f1-f44e-64a8-ec7f0e7b4cec.png)


　実行します。
　衝突すると、障害物にそって斜めに進みます。
![「【Godot 4.0】スマホ３Dゲームを作るための勉強　その６」を編集 - Qiita - Google Chrome 2023_02_24 14_05_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/4cc0dbc5-34b3-9fc2-79ff-e33b35c07374.png)

障害物がなくなると、前方（Z軸マイナス方向）に進みます。
![S06_CharacterBody3D_Control (DEBUG) 2023_02_24 14_05_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/3ed19c98-9396-ca39-b371-d072970a4226.png)

障害物をよけた後に、前方に進むのは、_physics_processメソッドの中で、Vector3(0.0, 0.0, -1.0)を毎回設定指示しているためです。
　下記のようにvelocityは初期化時に1回のみ設定するようにしてみましょう。
　またvelocityをprintします。

``` GDScript
extends CharacterBody3D

func _ready():
	velocity = Vector3(0.0, 0.0, -1.0).normalized()
func _physics_process(delta):
	move_and_slide()
	print(velocity)
```
* func _ready():
　初期化時に1回のみ実行されるので、velocityも1回だけVector3(0.0, 0.0, -1.0).normalized()にします。
* move_and_slide()
  物理エンジンにより、衝突などにより変更した速度がvelocityに反映されます。

　衝突した瞬間にVelocityが物理エンジンによって書き換えられました。

```
  :
(0, 0, -1)
(0, 0, -1)
(0, 0, -1)
(0.122316, 0, -0.015192)
(0.122316, 0, -0.015192)
(0.122316, 0, -0.015192)
  :
```

# move_and_collideで移動する
　move_and_slideメソッドは便利ですが、衝突したときの動きを実装したい場合、move_and_collideを使用します。

``` GDScript
extends CharacterBody3D

var m_velocity = Vector3(0.0, 0.0, -1.0) 
func _physics_process(delta):
	move_and_collide(m_velocity.normalized() * delta)
```
* move_and_collide(m_velocity.normalized() * delta)
　move_and_collideの場合は、引数に経過時間(delta)あたりの移動量を設定します。
　

実行すると、衝突すると停止します。

下記のようにすると、衝突したときに反発するようにできます。

``` GDScript
extends CharacterBody3D

func _ready():
	velocity = Vector3(0.0, 0.0, -1.0) 

func _physics_process(delta):
	var collision_info = move_and_collide(velocity.normalized() * delta)
	if collision_info:
		velocity = velocity.bounce(collision_info.get_normal())
```

* var collision_info = move_and_collide(velocity.normalized() * delta)
　衝突情報としてKinematicCollision3Dデータが返却されます。
* 	if collision_info:
　衝突した場合collision_infoには何か設定されるのでtrueになります。
* velocity = velocity.bounce(collision_info.get_normal())
　collision_info.get_normal()で衝突面（の法線）を取得します。normalized（正規化）とは別物です
　velocity.bounceで衝突面に反発するような速度を取得します。
　

以上