SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Godot Engine 2Dゲーム開発入門

【詳細解説】Godot Engineで始める2Dゲーム開発──公式サンプルを試してみよう

Godot Engine 2Dゲーム開発入門 第2回

8.Mainのスクリプトの作成

スクリプトをアタッチ

 「Main」のスクリプトを書いていきましょう。

 「シーン」ドックの「Main」を右クリックして「スクリプトをアタッチ」を選択します。

スクリプトをアタッチ
スクリプトをアタッチ

 「ノードにスクリプトをアタッチする」ダイアログが開きます。「テンプレート」の横のチェックボックスをチェックします。前回チェックしていた場合は、チェックした状態になっています。

 パスがres://main.gdになっていますので、変更せずに「作成」ボタンを押します

「ノードにスクリプトをアタッチする」ダイアログ
「ノードにスクリプトをアタッチする」ダイアログ

 先頭行がextends Nodeで、_ready_process関数が用意された状態でmain.gdが作成されます。また、Scriptビューが開きます。「Ctrl+S」で変更を保存します。

main.gd
main.gd

メンバー変数の作成

 スクリプトのextends Nodeの下に変数を追加します。

 まずは、外部に出すメンバー変数mob_sceneを追加します。「インスペクター」ドックを利用して、インスタンス化する「Mob」シーンを設定可能にします。また、得点を表すメンバー変数scoreを追加します。

extends Node

@export var mob_scene: PackedScene
var score

 スクリプトを入力したら「Ctrl+S」で保存します。この時点で「インスペクター」に、「main.gd」>「Mob Scene」という項目が「<空>」の状態で追加されます。

インスペクターに項目追加
インスペクターに項目追加

 この「<空>」の部分にmob.tscnをドロップするか、「<空>」をクリックして「読み込む」を選び、mob.tscnを選択します。すると、インスタンス化する「Mob」シーンがスクリプト内から利用可能になります。

 「Mob」シーンを追加したら「Ctrl+S」で変更を保存します。

mob.tscnを設定
mob.tscnを設定

Playerとのシグナル接続

 「シーン」ドックで「Player」を選択して、右サイドバーの「ノード」ドックを開きます。「シグナル」タブを選択して、「player.gd」の「hit()」を接続します。ダブルクリックするか、右クリックして「接続」を選びます。

「player.gd」の「hit()」
「player.gd」の「hit()」

 「メソッドにシグナルを接続」ダイアログが開きます。ノードは「Main」が選択されています。また、デフォルトでは「受信側メソッド」が「_on_player_hit」になっています。

「メソッドにシグナルを接続」ダイアログ
「メソッドにシグナルを接続」ダイアログ

 この「_on_player_hit」を「game_over」に変更して「接続」ボタンを押します。

「game_over」に変更
「game_over」に変更

 main.gdの中にgame_over関数が追加されます。

 このgame_over関数にはシグナルが接続されている緑色のアイコンが表示されます。また、「ノード」ドック>「シグナル」>「player.gd」>「hit()」に、緑色のアイコンでgame_over関数が接続されていることが示されます。「Ctrl+S」で変更を保存します。

 サンプルの写経は、ほぼこのシグナルの操作を身に付けると言っても過言ではありません。

「game_over」の接続
「game_over」の接続

game_overとnew_gameの実装

 先ほど作ったgame_over関数の処理を書きます。また、new_game関数を作って処理を書きます。

# ゲーム終了
func game_over() -> void:
	$ScoreTimer.stop()
	$MobTimer.stop()


# 新ゲーム開始
func new_game() -> void:
	score = 0
	$Player.start($StartPosition.position)
	$StartTimer.start()

 game_over関数では、「ScoreTimer」ノードと「MobTimer」ノードの進行を停止します。

 new_game関数では、まず得点を0にします。そして「StartPosition」ノードの位置で、「Player」インスタンスを開始します。最後に「StartTimer」ノードを開始します。

各種タイマーとのシグナル接続

 次は「MobTimer」「ScoreTimer」「StartTimer」という3つのタイマーで、シグナルを接続します。それぞれのタイマーの「timeout()」シグナルを、「Main」スクリプトに接続していきます。

 「シーン」ドックに並んでいる順番に接続をおこなっていきます。まずは「MobTimer」を選択して、右のサイドバーの「ノード」ドックの「シグナル」の「timeout()」を右クリックします。そして「接続」を選択します。

「timeout()」の「timeout()」
「timeout()」の「timeout()」

 「メソッドにシグナルを接続」ダイアログが開きます。ノードは「Main」が選択されています。また、デフォルトでは「受信側メソッド」が「_on_mob_timer_timeout」になっています。そのまま「接続」ボタンを押します。

「メソッドにシグナルを接続」ダイアログ
「メソッドにシグナルを接続」ダイアログ

 同じように「ScoreTimer」「StartTimer」も接続していきます。そして「Ctrl+S」で変更を保存します。

3つのタイマーを接続
3つのタイマーを接続

タイマーの処理を実装

 タイマーからシグナルを受けた際の処理を実装します。

 まずは処理が短い_on_score_timer_timeout_on_start_timer_timeoutです。

func _on_score_timer_timeout() -> void:
	score += 1


func _on_start_timer_timeout() -> void:
	$MobTimer.start()
	$ScoreTimer.start()

 _on_score_timer_timeout関数では、スコアータイマーのtimeoutシグナルが発行されるたびに、scoreの値を1ずつ大きくします。

 _on_start_timer_timeout関数は、ゲーム開始の待機時間が終了するとtimeoutシグナルが発行されます。ここでは、MobTimerScoreTimerを開始します。

 次は_on_mob_timer_timeoutです。こちらは少し処理が長いです。ただ、おこなっていることはそれほど難しくはありません。

func _on_mob_timer_timeout() -> void:
	# Mobシーンのインスタンスを作る
	var mob = mob_scene.instantiate()

	# MobSpawnLocationのランダムな進行比率からMobの登場場所を決める
	var mob_spawn_location = $MobPath/MobSpawnLocation
	mob_spawn_location.progress_ratio = randf()

	# MobSpawnLocationを利用して、Mobの登場場所を設定
	mob.position = mob_spawn_location.position

	# MobSpawnLocationのパスの向きに90度足して方向とする
	var direction = mob_spawn_location.rotation + PI / 2

	# 向きをランダムに左右45度変えて、Mobに設定する
	direction += randf_range(-PI / 4, PI / 4)
	mob.rotation = direction

	# 速度のベクトルをランダムに設定する
	var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
	mob.linear_velocity = velocity.rotated(direction)

	# 子ノードとして、Mobのインスタンスを追加する
	add_child(mob)

 おこなっていることを箇条書きにします。

  • Mobシーンのインスタンスを作る。
  • パスのどこかの地点を、発生場所にする。
  • 画面の内側を向かせる。向きについては若干ランダムを入れる。
  • ランダムに速度を決める。
  • Mainの子ノードとして、Mobのインスタンスを追加する。

 角度について少し補足です。Godot Engineでは、角度の計算はラジアンを使います。円周率PIは180度に相当します。角度とラジアンの変換はdeg_to_rad関数、rad_to_deg関数でおこなえます。

 randfrandf_rangedeg_to_radrad_to_degなどの関数は、グローバルスコープの関数です。グローバルスコープには多くの関数が用意されています。

実行確認

 ここまでの内容を実行してみましょう。_ready関数からnew_game関数を呼び出すようにします。

func _ready() -> void:
	new_game()

 そして、画面右上の▶マークの「プロジェクトを実行」ボタンを押します。

プロジェクトを実行
プロジェクトを実行

 「確認」ダイアログが出るので「現在のものを選択」ボタンを押します。

「確認」ダイアログ
「確認」ダイアログ

 ゲーム画面が表示されて、「Player」の表示と、「Mob」の生成が成功しているのが分かります。

ゲーム画面
ゲーム画面

 もし、誤って他のシーンをメインシーンにしてしまっている場合は、「ファイルシステム」ドックのmain.tscnを右クリックして、「メインシーンとして設定」を選択します。

メインシーンとして設定
メインシーンとして設定

 ここまで確認できたら、new_game()をコメントアウトしてpassを追加します。実際のゲームではいきなり開始せずに、別の手段で開始させるからです。

func _ready() -> void:
	#new_game()
	pass

ここまでのスクリプト

 ここまでのスクリプトを掲載します。

main.gd
extends Node

@export var mob_scene: PackedScene
var score


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	#new_game()
	pass


# Called every frame. 'delta' is the elapsed time since the previous frame.
@warning_ignore("unused_parameter")
func _process(delta: float) -> void:
	pass


# ゲーム終了
func game_over() -> void:
	$ScoreTimer.stop()
	$MobTimer.stop()


# 新ゲーム開始
func new_game() -> void:
	score = 0
	$Player.start($StartPosition.position)
	$StartTimer.start()


func _on_mob_timer_timeout() -> void:
	# Mobシーンのインスタンスを作る
	var mob = mob_scene.instantiate()

	# MobSpawnLocationのランダムな進行比率からMobの登場場所を決める
	var mob_spawn_location = $MobPath/MobSpawnLocation
	mob_spawn_location.progress_ratio = randf()

	# MobSpawnLocationを利用して、Mobの登場場所を設定
	mob.position = mob_spawn_location.position

	# MobSpawnLocationのパスの向きに90度足して方向とする
	var direction = mob_spawn_location.rotation + PI / 2

	# 向きをランダムに左右45度変えて、Mobに設定する
	direction += randf_range(-PI / 4, PI / 4)
	mob.rotation = direction

	# 速度のベクトルをランダムに設定する
	var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
	mob.linear_velocity = velocity.rotated(direction)

	# 子ノードとして、Mobのインスタンスを追加する
	add_child(mob)


func _on_score_timer_timeout() -> void:
	score += 1


func _on_start_timer_timeout() -> void:
	$MobTimer.start()
	$ScoreTimer.start()

 メイン部分ができましたので、次はゲーム周辺のUIを作っていきます。得点表示やタイトル画面などを作っていきましょう。

main.gd
main.gd

次のページ
9.ヘッドアップディスプレイの作成

この記事は参考になりましたか?

Godot Engine 2Dゲーム開発入門連載記事一覧

もっと読む

この記事の著者

柳井 政和(ヤナイ マサカズ)

クロノス・クラウン合同会社 代表社員http://crocro.com/オンラインソフトを多数公開。プログラムを書いたり、ゲームを作ったり、記事を執筆したり、マンガを描いたり、小説を書いたりしています。「めもりーくりーなー」でオンラインソフト大賞に入賞。最近は、小説家デビューして小説も書いています(『裏切りのプログラム』他)。面白いことなら何でもOKのさすらいの企画屋です。 

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/21370 2025/05/28 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー