1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Godot4で3D風2D縦スクロールシューティングゲームを作る 17回目 ボスの攻撃 全方位に弾発射

Posted at

Godot4.1.3でシューティングゲームを作っていきます。

ボスキャラBigFireに全方位弾を発射させる

 今回は攻撃方法を実装します。ボスBigFireの中心から一定周期で全方位(20°毎)に弾を発射するように実装します。
image.png

方針

 シーンやスクリプト間の関係はなるべく疎にしたいと思います。
 一定周期で全方位弾を発射するだけなので、全方位弾を発射するために必須とするボスBigFire情報は「発射位置」のみです。位置だけなら、ボスBigFireシーンの子ノードは自動的に親の位置を引き継ぐことができますので、一定周期で全方位弾を生成するシーンを1個作って、BigFireシーンに子ノードとして追加することで、勝手に全方位弾を発射するようにします。

github

 本記事で実装したものをgithubで公開しています。

修正および新規追加ファイル

 全方位弾発射用シーン「fire_360_bullet_periodically.tscn」とスクリプトを新規実装して、ボスBigFileシーン「boss_bigfile.tscn」に子ノードとして追加します。
image.png

全方位弾発射用シーンを追加

 一定時間毎に全方位弾を発射するシーンを追加します。
 res://character/enemy_bulletに新規シーンを追加して、fire_360_bullet_periodically.tscnに名称変更します。ルートノードはMarker3Dにします。子ノートにTimerノードを追加して名称をFireTimerに変更しました。
image.png
 発射周期を管理するTimerノードのタイムアウト時間は、スクリプトからタイマーを開始する時に設定するので、Wait Timeプロパティは、ディフォルトの設定のままで良いです。
 タイムアウト後は自動でタイマーを再開してほしいので、One Shotプロパティもディフォルトのままオフです。
image.png

全方位弾発射用シーンのスクリプトを実装

 ルートノードにスクリプトをアタッチして下記のように修正します。

res://character/enemy_bullet/fire_360_bullet_periodically.gd

extends Marker3D

var _d_fire_interval_sec = 2.0
var _i_fire_interval_deg = 20

var _scn_bullet : PackedScene = preload("res://character/enemy_bullet/enemy_bullet.tscn")

func _ready():
	$FireTimer.start(_d_fire_interval_sec)	

func _on_fire_timer_timeout():
	for deg in range(0, 360, _i_fire_interval_deg):
		var ins = _scn_bullet.instantiate()
		var dir = Vector3(cos(deg_to_rad(deg)), 0.0, sin(deg_to_rad(deg)))		
		ins.set_pos( global_position, global_position + dir)
		g_val.node_bullets.add_child(ins)

 スクリプトの説明をします。
 _readyメソッド内で、全方位弾を発射するためのタイマーを開始するために、周期時間を指定してstartメソッドを実行します。

var _d_fire_interval_sec = 2.0

func _ready():
	$FireTimer.start(_d_fire_interval_sec)	

 次にタイムアウト時に、全方位弾のインスタンスを生成するように実装します。
 まず、タイムアウトを検知したいので、FireTimerノードのtimeoutシグナルをスクリプトの_on_fire_timer_timeoutメソッドに接続します。
 最初のfor文では、「range(0, 360, 20)」分繰り返します。つまり、0~360を20刻みなので、0, 20, 40, ....320, 340まで18回ループします。
 ループの中では、敵の弾のインスタンスを生成したあと、dirに弾が移動する向きを設定しています。XZ平面上で、ある角度を向いている方向のx座標はcos関数、z座標はsin関数で得ることができるので、

dir = Vector3( cos(角度), 0, sin(角度) )

で移動する向き、dirを計算することができます。sinとcosの引数の単位はラジアンなので、角度はdeg_to_rad関数でラジアンに変換する必要があります。
 あとは敵の弾のインタンスのset_posメソッドを使って、現在の位置と移動方向の位置を設定します。

 現在の位置  :global_position
 移動方向の位置:global_positionにdirを足した値

最後に敵の弾のインスタンスを動的インスタンスの管理ノードに追加します。

var _i_fire_interval_deg = 20
var _scn_bullet : PackedScene = preload("res://character/enemy_bullet/enemy_bullet.tscn")

func _on_fire_timer_timeout():
	for deg in range(0, 360, _i_fire_interval_deg):
		var ins = _scn_bullet.instantiate()
		var dir = Vector3(cos(deg_to_rad(deg)), 0.0, sin(deg_to_rad(deg)))		
		ins.set_pos( global_position, global_position + dir)
		g_val.node_bullets.add_child(ins)

全方位弾発射用シーンをボスBigFireに追加

 ボスBigFireシーン(res://character/boss/boss_bigfire.tscn)に、全方位弾発射用シーン(re_360_bullet_periodically.tscn)を追加するだけです。
image.png

以上です。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?