0
1

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 1 year has passed since last update.

【Godot 4.0】スマホ3Dゲームを作るための勉強 その10 敵を増やしました。またBullet vs Enemyの処理を実装しました。

Posted at

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

目的

 敵をシーンファイル化して、複数設定できるようにします。
 またBulletがEnemyに当たった場合、お互い攻撃してHPが0になったら消える様にします。

ベースプロジェクト

 下記で作成したプロジェクトをベースに機能追加をします。

 【Godot 4.0】スマホ3Dゲームを作るための勉強 その9 敵を検知するとホーミングするようにしたい
 https://qiita.com/FootInGlow/items/5b1c78669e2d56d98f1b

 github(Godotのプロジェクトマネージャーからインポートして利用できます)
 https://github.com/footinglow/Godot4/tree/main/02_study/S09_enemy_001

Enemyブランチをシーンファイルにする

 Enemyを右クリックして「ブランチをシーンとして保存」を実行します。
 ダイアログが表示されるので問題なければそのまま保存します。
 スクリーンショット (44).png
Enemyとその子ノードがひとつのシーンになりました。映画のカチンコ🎬アイコンが表示されます。
(_) global.tscn - S10_enemy_002 - Godot Engine 2023_03_01 21_52_27 - コピー.png
 またファイルシステムにはenemy.tscnとして保存されました。
(_) global.tscn - S10_enemy_002 - Godot Engine 2023_03_01 21_52_27.png

Enemyを増やす

 Enemyを追加しましょう。
 globalを右クリックして、「Instantiate Child Scene」を実行します。
 スクリーンショット (45).png
 enemy.tscnを選択して「開く」ボタンを押下します。
スクリーンショット (46).png
 Enemy2が追加されました。
スクリーンショット (47).png

 Enemy2を選択して、インスペクタのNode3D/Transform/positionのX=-2.0m、Z=-8mを設定します。
(_) global.tscn - S10_enemy_002 - Godot Engine 2023_03_01 22_01_07.png

Enemyを倒す

 Enemy、Bulletに攻撃力とHPを設定してHPが0になったら消えるようにしましょう。
 攻撃力は1秒間に削るHP量にします。

enemy.gdに追加

@export var m_attack_power_ps = 1.0
@export var m_hp = 10

bullet.gdに追加

@export var m_attack_power_ps = 1.0
@export var m_hp = 1

BulletがEnemyとバトルする

 攻撃力を1秒間に削るHP量にしたので、_physics_processで継続的にBulletがEnemyを接触しているか判定するようにします。

Enemyを「EnemyGroup」グループに設定する

 Bulletが衝突したノードが攻撃対象であるか判定を簡単にするため、グループ機能を利用します。
 グループに登録したノードは検索できるようになります。

 enemy.tscnを開いてEnemyを選択します。
 インスペクタの横のノード/グループを選択します。
 「EnemyGroup」と入力して、追加ボタンを押下します。
enemy.tscn - S10_enemy_002 - Godot Engine 2023_03_01 22_37_52.png
 追加されました。
enemy.tscn - S10_enemy_002 - Godot Engine 2023_03_01 22_37_54.png
 シーンのEnemyノードの右にはグループに参加していることを表す四角の中に●があるアイコンが表示されました。このアイコンの上をマウスオーバーすると「Node is in this group: EnemyGroup」と表示されるので、「EnemyGroup」グループに登録されたことがわかります。
スクリーンショット (49).png

bullet.gdにバトル処理を追加

 _physics_process()のmove_and_slide()実行後にバトル処理を追加しました。

extends CharacterBody3D

@export var m_v_dir = Vector3.FORWARD
@export var m_d_speed_mps = 2.0

@export var m_attack_power_ps = 1.0
@export var m_hp = 1

var m_v3_enemy_pos = null

func _physics_process(delta):
	if m_v3_enemy_pos:
		m_v_dir = m_v3_enemy_pos - transform.origin
	else:
		m_v_dir = Vector3.FORWARD
	velocity = m_v_dir.normalized() * m_d_speed_mps
	move_and_slide()
	
	# バトル判定
	for index in range(get_slide_collision_count()):
		var collision = get_slide_collision(index)
		if (collision.get_collider() == null):
			continue
		if collision.get_collider().is_in_group("EnemyGroup"):
			var enemy = collision.get_collider()
			
			# Bulletの攻撃
			enemy.m_hp -= m_attack_power_ps * delta
			# Enemyの攻撃
			m_hp       -= enemy.m_attack_power_ps * delta

	# HPが0になったら消える
	if m_hp < 0:
		queue_free()
	
func discover_enemy(enemy_pos):
	m_v3_enemy_pos = enemy_pos
	
func _on_visible_on_screen_notifier_3d_screen_exited():
	queue_free()

 move_and_slide()の後がバトルの処理です。

衝突情報をチェックして、Enemyを検索します。

  • for index in range(get_slide_collision_count()):
    get_slide_collision_count()により、move_and_slide()の結果、衝突した回数(衝突により方向を変えた回数)を取得し、forループします

  • var collision = get_slide_collision(index)
     index番目の衝突情報をcollisionとして取得

  • if (collision.get_collider() == null):
     collision衝突情報がない場合continueして次を検索

  • if collision.get_collider().is_in_group("EnemyGroup"):
     衝突したノードが「EnemyGroup」に属しているかチェックします

  • var enemy = collision.get_collider()
     「EnemyGroup」グループに所属しているノードインスタンスを取得します。

Enemyと接触している場合、お互いの攻撃力を使用してHPを削ります。
 1秒間でHPを削る量なので、deltaを掛けた攻撃量をHPから減算しています。

  • enemy.m_hp -= m_attack_power_ps * delta
  • m_hp -= enemy.m_attack_power_ps * delta

ループを抜けた後、Bulletのhpが0になっていたらBulletを消します。

  • if m_hp < 0:
  • queue_free()

EnemyのHPチェック処理を追加

 enemy.gdを開いてhpをチェックする処理を追加します。EnemyのHPが0になったら、Enemyを削除します。
 _physics_process()が追加した処理です。

extends CharacterBody3D

@export var m_attack_power_ps = 1.0
@export var m_hp = 10

func _physics_process(delta):
	if m_hp < 0.0:
		queue_free()
	
func _on_bullet_sensor_body_entered(body):
	body.discover_enemy(transform.origin)

 実行しましょう。
 Bulletが10個ぶつかるとEnemyが消えるようになりました。

バグ修正:Bulletが残る

 Enemyが消えたあとに、残るBulletがいます。
 Enemyを倒してもその前にBulletに設定した目標位置m_v3_enemy_posが残っているためです。
 やり方はいくつかありそうですが、ほぼ目標位置に到達した場合(Enemyがいる場合はぶつかって止まる)目標位置を削除することで対処します。

extends CharacterBody3D

@export var m_v_dir = Vector3.FORWARD
@export var m_d_speed_mps = 2.0

@export var m_attack_power_ps = 1.0
@export var m_hp = 1

var m_v3_enemy_pos = null

func _physics_process(delta):
	if m_v3_enemy_pos:
		m_v_dir = m_v3_enemy_pos - transform.origin
		# 向かっている途中でEnemyが消えた場合、ほぼm_v3_enemy_posの位置まできたら目標位置を消して再び前進する
		if m_v_dir.length() < 0.1:
			m_v3_enemy_pos = null
	else:
		m_v_dir = Vector3.FORWARD
	velocity = m_v_dir.normalized() * m_d_speed_mps
	move_and_slide()
	
	# バトル判定
	for index in range(get_slide_collision_count()):
		var collision = get_slide_collision(index)
		if (collision.get_collider() == null):
			continue
		if collision.get_collider().is_in_group("EnemyGroup"):
			var enemy = collision.get_collider()
			
			# Bulletの攻撃
			enemy.m_hp -= m_attack_power_ps * delta
			# Enemyの攻撃
			m_hp       -= enemy.m_attack_power_ps * delta

	# HPが0になったら消える
	if m_hp < 0:
		queue_free()
	
func discover_enemy(enemy_pos):
	m_v3_enemy_pos = enemy_pos
	
func _on_visible_on_screen_notifier_3d_screen_exited():
	queue_free()

 _physics_process()メソッドのm_v3_enemy_posが設定されている場合の処理の中に下記の処理を追加しました。
 0.1は十分近づいた値として適当に設定したものです。

		# 向かっている途中でEnemyが消えた場合、ほぼm_v3_enemy_posの位置まできたら目標位置を消して再び前進する
		if m_v_dir.length() < 0.1:
			m_v3_enemy_pos = null

 実行しましょう。
 Bulletがとまることがなくなりました。

以上

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?