Godot4.1.3でシューティングゲームを作っていきます。
アップグレードアイテムの追加
プレイヤー機の性能を向上するアップグレードアイテムを追加します。アップグレードアイテムは、取るタイミングにより、レーザーの威力の向上とプレイヤー機のスピードアップを、プレイヤーが選択できるようにします。
本記事では、アップグレードアイテムの出現までを実装します。
- シナリオで、決まったタイミングで出現
- 画面上方に出現し、下方にまっすぐ移動
- 一定周期で、パワーアップ「P」用デザインとスピードアップ「S」用デザインが交互に切り替わる
github
本記事で実装したものをgithubで公開しています。
本記事で新規追加・修正する主なノード
アップグレードアイテム本体の「upgrade_item.gd/tscn」とアップグレードアイテムを生成するシナリオ要素「produce_upgrade_item.gd/tscn」を新規追加します。
シナリオ要素はシナリオscenario_stage01.tscnに追加します。
また、アップグレードアイテムのインスタンスの追加先を追加するため、game.gd/tscnとglobal.gdを修正しました。
先にこちらから説明します。
アップグレードアイテム インスタンスの管理ノードを追加
ゲーム中に動的に生成したインスタンスはgame.tscnのgame/DynamicNodesノードの配下に追加して、管理をしています。アップグレードアイテムを追加する適切なノードが無いため、新規に「others」を追加しました。
res://game/game.tscn
インスタンス追加先は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
アップグレードアイテムは、球の上にアルファベット一文字が乗っているデザインにするため、bodyノードのMeshプロパティは新規SphereMeshで球にして、textノードのMeshプロパティは新規TextMeshを使用し、「P」の文字を設定しました。それぞれのmaterialプロパティには新規StandardMaterial3Dを追加して、Albedo/Colorで色を設定しました。
下の方にまっすぐ移動する動きを実装
シーンにスクリプトをアタッチし、下記のように実装します。
また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プロパティはカラーピッカーで白に変更すると光ります。
光り具合はEnergy Multiplierプロパティで操作することができます。0.0は光っていない状態です。1.0にするとPの文字が見えなくなるほど真っ白になり、やりすぎなので、光っている状態は0.2くらいでちょうどよさそうです。
次に、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を開きます。
以下の吹き出しに従い、設定を変更します。
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」の変化を確認できます。
スクリプトで、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プロパティをオンにします。
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
実行結果
まとめ
アップグレードアイテムを出現させることができるようになりました。
次は、プレイヤー機がアップグレードアイテムをゲットすると、プレイヤー機の性能が向上するようにします。
以上です。