【Godot 4.0】スマホ３Dゲームを作るための勉強　その２６　動く障害物を作る

　ゲームエンジンGodot4.0で3Dスマホゲームを作りたいと思いますが、その前にお勉強しています。
　2023/3/1にstable版がリリースされました。
　Godot_v4.0-stable_win64.exe.zipを使用しています。

# 目的・方法
　左右に動く縦長のバーを作って、Bullet/EnemyBulletを押して邪魔をします。
　StaticBody3Dは衝突によって動かされることはなく、逆にStaticBody3Dが移動すると移動先にいるCharacterBody3Dを押すことができますので、障害物に最適です。

# ベースプロジェクト
　下記で作成したプロジェクトをベースに機能追加をします。
　【Godot 4.0】スマホ３Dゲームを作るための勉強　その２５　Bulletが増殖するエリアをつくる
　https://qiita.com/FootInGlow/items/3471795db18e4480cd3d
　
　github(Godotのプロジェクトマネージャーからインポートして利用できます）
　https://github.com/footinglow/Godot4/tree/main/02_study/S25StageItemMultiplicationArea

# 左右に動く縦長のバーをつくります。
　縦長のバーを作って、一定距離の間を左右に往復するようにします。

## 新規シーンをStaticBody3Dで作成します。
　シーンメニューから新規シーンを実行します。
　「その他ノード」ボタンを押下して、StaticBody3Dを選択します。
　「MovingWall」と名称を変更します。
　保存します。保存先はStageItems配下にします。
![スクリーンショット (294).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/b8edc17b-0cd3-c8c3-9430-bc5b74b6be2c.png)

## 新規MeshInstance3Dを追加して新規BoxMeshを設定
　MovingWallを右クリックして、子ノードを追加からMeshInstance3Dを追加します。
　MeshInstance3Dを選択した状態で、インスペクターのMeshInstance3D/Meshの＜空＞をクリックして、新規BoxMeshを選択します。
![スクリーンショット (296).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/64919e03-1b07-55f8-dd4e-df99839a2356.png)
　Meshの設定された正方形のアイコンをクリックして詳細設定を開きます。
　Sizeのxを0.3mにします。
![スクリーンショット (315).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/7005f229-c006-6447-36c9-b8b792ee5905.png)
　またNode3D/Transform/Positionのyに0.5mを設定します。
![スクリーンショット (297).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/f163c78f-d905-ebd2-3c73-8433a74bda62.png)
## MeshInstance3Dと同じ大きさ・位置のCollisionShape3Dを追加
　MovingWallを右クリックして、子ノードを追加からMeshInstance3Dを追加します。
　CollisionShape3Dを選択した状態で、インスペクタのCollisionShape3D/Shapeに新規BoxShapeを設定します。
![スクリーンショット (298).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/40638c8c-3390-291a-e69a-eb640452f8f3.png)
　設定されたShapeの右のBoxMesh3Dをクリックして詳細設定を開き、Sizeのxを0.3mに設定します。
　またNode3D/Transform/Positionのyに0.5mを設定します。
　![スクリーンショット (301).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/0f30ada6-7087-855c-1bcd-4429c65ed21e.png)

# 左右に移動するスクリプトを実装します。
　MovingWallを右クリックして、「スクリプトをアタッチ」を実行します。
![スクリーンショット (318).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/59fb7343-ca87-03f7-b570-79744103476f.png)
res://StageItems/moving_wall.gdとして追加されました。
![スクリーンショット (317).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/d6443be2-a196-263d-98b3-03d80986feed.png)

　下記のように実装します。

* **パラメータの追加**
　パラメータを追加します。
　左右に往復する移動距離と移動速度を@exportで宣言します。
```GDScript
extends StaticBody3D

@export var m_d_x_extents_m = 2.0		# 初期設置位置からX方向の最大移動距離
@export var m_d_speed_mps = 1.0			# 移動速度
```
　m_d_x_extents_m が2.0の場合は初期設置位置からx軸方向（左右）に2mの範囲で往復するという意味にします。
　パラメータm_d_speed_mpsが1.0の場合、1秒間に1m移動するという意味です。
* **メンバ変数の追加**
　初期設置位置を記憶するためm_v3_init_posを用意します。
　また現在の移動方向を示すm_d_directionを用意します。+1もしくは-1を設定します。
```GDScript
var m_v3_init_pos
var m_d_direction = 1
```
* **初期化処理**
　初期化処理の_ready()メソッドの中で現在の位置を初期位置として保存します。
```GDScript
func _ready():
	m_v3_init_pos = transform.origin
```
* **_physics_process**
　「m_d_speed_mps * m_d_direction」で移動方向への速度に変換しています。+1で右に、-1で左に移動します。deltaを掛け算して移動量に変換します。deltaが0.1秒の場合、1m/s×0.1秒=10cm移動します。　
```GDScript
func _physics_process(delta):
	transform.origin.x += m_d_speed_mps * m_d_direction * delta
```
　absf(transform.origin.x - m_v3_init_pos.x)で初期位置のxから現在位置のxまでの移動量を計算してm_d_extentsを超えた場合、m_d_directionの符号を反転することで移動方向を逆にします。

```GDScript
	if absf(transform.origin.x - m_v3_init_pos.x) >= m_d_x_extents_m:
		m_d_direction = -m_d_direction
```
　res://StageItems/moving_wall.gd全体としては下記のようなスクリプトになります。
```GDScript
extends StaticBody3D

@export var m_d_x_extents_m = 2.0		# 初期設置位置からX方向の最大移動距離
@export var m_d_speed_mps = 1.0			# 移動速度

var m_v3_init_pos
var m_d_direction = 1

func _ready():
	m_v3_init_pos = transform.origin

func _physics_process(delta):
	transform.origin.x += m_d_speed_mps * m_d_direction * delta
	if absf(transform.origin.x - m_v3_init_pos.x) >= m_d_x_extents_m:
		m_d_direction = -m_d_direction
```

# MovingWallをステージに配置する
　res://Stages/stage001.tscnを開きます。
　Stageを右クリックして、Instantiate Child Sceneを実行します。
![スクリーンショット (303).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/501341ec-f7c0-c3c7-1f69-241a8b754b51.png)
「StageItems/moving_wall.tscn」を選択します。
![スクリーンショット (304).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/c0eb788a-89b6-f027-c998-fbfa889bfd61.png)
「MovingWall」が追加されました。
![スクリーンショット (305).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/ba09e2cc-5fcc-f3f1-02b1-69c8ced41d54.png)
　MovingWallを選択した状態で、インスペクタのNode3D/Transform/Positionのｚに-4を設定します。
　少しZ方向に長くしたいですね。Scaleで調整してみます。
　MovingWallを選択した状態で、インスペクタのNode3D/Transform/Scaleの右の鎖をクリックしてはずしてのｚに３を設定します。（鎖がつながったままの場合、zを3にすると、xとyも3になります）
![スクリーンショット (307).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/a1e677c4-f5d3-5c23-11fa-e6ec9b9198b9.png)

　実行します。壁が動くとBulletが押されています。
![スクリーンショット (311).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691050/7f300889-4c75-0447-6fa5-01d2876857a3.png)

　以上