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

More than 1 year has passed since last update.

Godot4で3D風2D縦スクロールシューティングゲームを作る 12回目 アップグレードアイテムの追加

Last updated at Posted at 2024-01-28

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

アップグレードアイテムの追加

 プレイヤー機の性能を向上するアップグレードアイテムを追加します。アップグレードアイテムは、取るタイミングにより、レーザーの威力の向上とプレイヤー機のスピードアップを、プレイヤーが選択できるようにします。

 本記事では、アップグレードアイテムの出現までを実装します。

  • シナリオで、決まったタイミングで出現
  • 画面上方に出現し、下方にまっすぐ移動
  • 一定周期で、パワーアップ「P」用デザインとスピードアップ「S」用デザインが交互に切り替わる

 

github

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

本記事で新規追加・修正する主なノード

 アップグレードアイテム本体の「upgrade_item.gd/tscn」とアップグレードアイテムを生成するシナリオ要素「produce_upgrade_item.gd/tscn」を新規追加します。
 シナリオ要素はシナリオscenario_stage01.tscnに追加します。

image.png

 また、アップグレードアイテムのインスタンスの追加先を追加するため、game.gd/tscnとglobal.gdを修正しました。
 先にこちらから説明します。
image.png

アップグレードアイテム インスタンスの管理ノードを追加

 ゲーム中に動的に生成したインスタンスはgame.tscnのgame/DynamicNodesノードの配下に追加して、管理をしています。アップグレードアイテムを追加する適切なノードが無いため、新規に「others」を追加しました。
res://game/game.tscn
image.png

 インスタンス追加先はglobal.gdのメンバで指定するため、others用のメンバ変数「node_others」を追加します。

res://global/global.gd

extends Node3D

# ゲーム画面の見える範囲
# ゲーム画面の上端をtop、下端をbotommとする
var d_visible_top_z_m = -200.0
var d_visible_top_min_x_m = -75.0
var d_visible_top_max_x_m =  75.0

var d_visible_bottom_z_m = -15.0
var d_visible_bottom_min_x_m = -25.0
var d_visible_bottom_max_x_m =  25.0


# gameのインスタンス
var node_game : Node3D = null 

# 生成したインスタンスの追加先
var node_lasers : Node3D = null
var node_enemies : Node3D = null 
var node_bullets : Node3D  = null
+var node_others : Node3D  = null

# Playerのインスタンス
var node_player : Area3D = null 

 global.gdは、自動読み込みで「g_val」で登録したため、「g_val.node_others」で、いつでもどこからでもアクセスできます。
 game.gdから初期値として、先ほど追加したothersノードを設定します。
res://game/game.gd

extends Node3D

var _scn_scenario_stage = preload("res://scenario/scenario_stage01.tscn")

var _node_scenario_ins

var _i_score : int = 0

func _ready():
	# gameインスタンスを保存
	g_val.node_game = self
	
	# インスタンス化したシーンの追加先を設定する
	g_val.node_lasers = $DynamicNodes/lasers
	g_val.node_enemies = $DynamicNodes/enemy/bodies
	g_val.node_bullets = $DynamicNodes/enemy/bullets
+	g_val.node_others = $DynamicNodes/others

	# Playerインスタンスを設定する
	g_val.node_player = $Player
	
	# ステージシナリオをシーンツリーに追加
	_node_scenario_ins = _scn_scenario_stage.instantiate()
	add_child(_node_scenario_ins)

func _process(delta):
	# シナリオを駆動する
	_node_scenario_ins.drive_scenario()

func _on_add_to_score(add_score):
	_i_score += add_score
	$HUD/score_value.text = "%010d" % _i_score 

アップグレードアイテム本体の実装

シーンの新規追加

 新規シーンを作成します。ルートノードはArea3Dです。bodyとtextはMeshInstance3Dで、他は名称通りのノードです。

res://character/item/upgrade_item.tscn
image.png

 アップグレードアイテムは、球の上にアルファベット一文字が乗っているデザインにするため、bodyノードのMeshプロパティは新規SphereMeshで球にして、textノードのMeshプロパティは新規TextMeshを使用し、「P」の文字を設定しました。それぞれのmaterialプロパティには新規StandardMaterial3Dを追加して、Albedo/Colorで色を設定しました。
 
image.png

下の方にまっすぐ移動する動きを実装

 シーンにスクリプトをアタッチし、下記のように実装します。
 またVisibleOnScreenNotifier3Dのscreen_exited()シグナルを接続して、queue_free()します。

res://character/item/upgrade_item.gd

extends Area3D

var _d_speed_mps = 20.0

func _physics_process(delta):
	# 移動処理
	global_position += Vector3(0, 0, 1) * _d_speed_mps * delta

func _on_visible_on_screen_notifier_3d_screen_exited():
	queue_free()

ぴかぴか光るようにする

 アップグレードアイテムは、画面上で目立つようにしたいので、body(MeshInstance3D)のmaterialプロパティのEmissionセクションの各プロパティを操作して、ぴかぴか光るようにします。
 res://character/item/upgrade_item.tscnのインスペクターのmeshプロパティのmaterialプロパティのEmissionセクションを開きます。
 Enabledプロパティをオンにして、Emissionプロパティはカラーピッカーで白に変更すると光ります。
image.png

 光り具合はEnergy Multiplierプロパティで操作することができます。0.0は光っていない状態です。1.0にするとPの文字が見えなくなるほど真っ白になり、やりすぎなので、光っている状態は0.2くらいでちょうどよさそうです。
image.png

 次に、0.5秒くらいで、0.0と0.2の間を変化する変数を作りたいと思います。スクリプトで実装してもよいのですが、AnimationPlayerノードを使用します。
 スクリプトにメンバ変数d_cycle_valをfloat型になるように追加します。AnimationPlayerで操作するので、exportします。

+@export var d_cycle_val : float = 0.0	# AnimationPlayerで変更

 次のAnimationPlayerでアニメーションを追加します。
 アニメーションボタンから新規で「repeat」を追加します次に、「+トラックを追加」からプロパティトラックを選択し、upgrade_itemのd_cycle_valを開きます。
 以下の吹き出しに従い、設定を変更します。
image.png

 d_cycle_valの右側を右クリックして、「キーを挿入」を実行し、3つキーを追加します。追加したキーはクリックして選択すると、インスペクターで設定を変更できます。以下のように変更します。

  • Time:0.00 、 Value:0.0
  • Time:0.25 、 Value:0.2
  • Time:0.50 、 Value:0.0
     再生ボタンを押下し、ルートノードのupgrade_itemのインスペクタを表示すると、「d_cycle_val」の変化を確認できます。
    image.png

 スクリプトで、d_cycle_valの値を、Energy Multiplierプロパティを設定します。
 下記がスクリプトの実装です。

extends Area3D

@export var d_cycle_val : float = 0.0	# AnimationPlayerで変更
var _d_speed_mps = 20.0

+var _material_body : StandardMaterial3D = null

+func _ready():
+	# Bodyマテリアル用
+	_material_body = ($body.mesh as SphereMesh).material
func _physics_process(delta):
	# 移動処理
	global_position += Vector3(0, 0, 1) * _d_speed_mps * delta
+	# アニメーション
+	_material_body.emission_energy_multiplier = d_cycle_val

func _on_visible_on_screen_notifier_3d_screen_exited():
	queue_free()

 _readyメソッドで、bodyノードのmesh(Meshクラス)を取得しますが、Meshクラスのままではmaterialにアクセスできないので、実体のSphereMeshクラスにキャストして、materialメンバ変数を取得します。material(Materialクラス)からEmissionセクションのプロパティにアクセスするためにStandardMaterial3Dにキャストが必要ですが、代わりに代入先の_material_bodyをStandardMaterial3D型で宣言しています。 

+	_material_body = ($body.mesh as SphereMesh).material

一定周期で、パワーアップ「P」用デザインとスピードアップ「S」用デザインが交互に切り替わる

  • 2秒周期でデザインを変更する
  • パワーアップの場合、bodyは赤で、文字は「P」にする
  • スピードアップの場合、bodyは青で、文字は「S」にする

 2秒周期の切り替えは、Timerノードのtimeout()シグナルでスクリプトに通知します。
 Timerノードのインスペクターで、Wait Timeプロパティを2sに変更し、AutoStartプロパティをオンにします。
image.png

 Timerノードのtime_out()シグナルをスクリプトに接続します。
 アップグレードアイテムの状態は、global.gdに追加したenum値で管理します。

res://global/global.gd

extends Node3D

+# アップグレードアイテムの種別
+enum EnItemKind{
+	POWER_UP,
+	SPEED_UP	
+}

# ゲーム画面の見える範囲
# ゲーム画面の上端をtop、下端をbotommとする
  :

 _on_timer_timeout()メソッドが呼ばれた直後の、スピードアップとパワーアップのenum値の切り替えは、3項式を使いました。
res://character/item/upgrade_item.gd

extends Area3D

@export var d_cycle_val : float = 0.0	# AnimationPlayerで変更
var _d_speed_mps = 20.0

var _material_body : StandardMaterial3D = null
+var _mesh_text : TextMesh = null
+var en_item_kind = g_val.EnItemKind.SPEED_UP

func _ready():
	# Bodyマテリアル用
	_material_body = ($body.mesh as SphereMesh).material
+	# P/Sのテキスト変更用
+	_mesh_text = $body/text.mesh

func _physics_process(delta):
	# 移動処理
	global_position += Vector3(0, 0, 1) * _d_speed_mps * delta
	# アニメーション
	_material_body.emission_energy_multiplier = d_cycle_val

func _on_visible_on_screen_notifier_3d_screen_exited():
	queue_free()

+func _on_timer_timeout():
+	# アップグレードアイテムの種別を切り替える
+	en_item_kind = g_val.EnItemKind.POWER_UP if en_item_kind == g_val.EnItemKind.SPEED_UP else g_val.EnItemKind.SPEED_UP
+	
+	# アップグレードアイテムの種別に応じて、デザインを変更する
+	if en_item_kind == g_val.EnItemKind.SPEED_UP:
+		# Speedに変更
+		_mesh_text.text = "S"
+		_material_body.albedo_color = Color(0.5, 0.5, 1, 1)
+	else:
+		# Powerに変更
+		_mesh_text.text = "P"
+		_material_body.albedo_color = Color(1, 0, 0, 1)

アップグレードアイテムのシナリオ要素をシナリオに追加

 produce_upgrade_item.tscnをシナリオに追加します。
res://scenario/scenario_stage01.tscn
image.png

実行結果

image.png

まとめ

 アップグレードアイテムを出現させることができるようになりました。
 次は、プレイヤー機がアップグレードアイテムをゲットすると、プレイヤー機の性能が向上するようにします。

 以上です。

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