「Godot Engine」を使用したゲーム、例えば「Like Coins」など、ゲームの開発に関する記事の第2部を待つのにうんざりしていませんか? 多くの「おいしい」と「健康」が議題に用意されています。 この記事では、以前に開始したゲームを完了することをすぐに予約します。このゲームの始まりは、ここで読むことができます-Godot Engineでのゲーム「Like Coins」の作成。 パート1ですが、一連の記事は続きます。 あまりにも多くの資料があったので、その一部を取っておきましたが、後でまた取り上げることは間違いありません。 「gamedev」を始めましょう!
シーン「メイン」
記事の前の部分では、メインステージ( Main
)で停止しましたが、おそらく継続します。 以前に追加されたすべてのものを削除し(もちろん、すべてがどのように機能するかを確認するために何かを追加した場合)、シーンに何もロードされなかった場合は、 Node
を追加する必要があります。シーンにも追加する必要があります。
ColorRect
( "Background")-背景色を塗りつぶします。
Player
「Player」オブジェクト( Player
シーンをオブジェクトと呼ぶので、混乱しないでください);
Node
(「コンテナー」)-コインの一時保管用の「コンテナー」。
Position2D
( "PlayerStart")-ゲームの開始時に、 "Player"オブジェクトの初期位置を設定します。
Timer
(「GameTimer」)-制限時間カウンター。
ColorRect
を選択し、ツールバーで以下を選択します: Layout -> Full Rect
ColorRect
を画面の領域全体に拡大します(将来、この機能にしばしば頼るので、 Layout
リストで指定された他の操作をLayout
で勉強することをお勧めします)、プロパティ「色」で、目的の塗りつぶし色を指定します。 TextureRect
でも同じことができます。 TextureRect
代わりに、 "Texture"プロパティで画像を読み込む必要があります。 Position2D
場合、「position」プロパティで、「x」と「y」の値を指定します。これは、 Player
初期位置として機能します。 もちろん、スクリプトの助けを借りて、 Player
自体で直接位置の値を設定できますが、ゲームの開発を学ぶだけでなく、「Godot」も学習します。したがって、1つの問題を解決するためのさまざまなオプションを考慮することは不要ではありません。
「メイン」のスクリプト
Node
スクリプトを追加し、次を印刷します。
extends Node
プロパティ「Coin」および「playtime」がInspector
表示されます。 シーン「Coin.tscn」を「Coin」プロパティにドラッグし、「playtime」を「40」(秒単位のゲームの継続時間)に設定します。
ゲームが開始すると、毎回初期化が必要になります-作業の準備、アプリケーションの高品質でエラーのない操作に必要なパラメーターの決定。 これは必須の手順であるため、最初にこれに注意する必要があります。
func _ready(): randomize()
Player
オブジェクトの名前を指定する場合、「$」記号が使用されることに注意してください。これは、現在のシーンのノードに直接アクセスできる「構文糖」です。 「Node1」に「Node2」の子孫がある場合、このメソッド$Node1/Node2
使用することもでき$Node1/Node2
。 自動入力はGodotでうまく機能するため、無視しないでください。 ノードの名前にスペースを使用することは望ましくありませんが、それでも有効です。この場合、引用符を使用します- $"My best Node1"
。
新しいゲーム
新しいゲームを開始するために、これに対応する機能を決定します。この機能は、たとえばボタンを押すことで呼び出すことができます。
func new_game(): playing = true
引数が$PlayerStart.position
である関数 "start()"は、プレーヤーを開始位置に移動します。関数 "spawn_coins()"は、ご想像のとおり、競技場でのスポーンコインを処理します。
func spawn_coins(): for i in range(4 + level): var c = Coin.instance() $CoinContainer.add_child(c) c.window_size = window_size c.position = Vector2(rand_range(0, window_size.x), rand_range(0, window_size.y))
range(4 + level)
関数は、コインの数と現在のレベルの値の合計に等しい値を持つ、指定された範囲の配列を返します。 範囲には、2つの引数または3つの引数のいずれかで、1つの引数を含めることができます(3番目の引数は配列ステップになります)。 この関数では、「Coin」オブジェクトのインスタンスをいくつか作成し、子要素としてCoinContainer
を追加します( PackedScene
おかげで、オブジェクトに既にアクセスできることを忘れないでPackedScene
)。 新しいノード( instance()
メソッド)のインスタンスを作成するたびに、 add_child()
を使用してツリーに追加する必要があることに注意してください。 次に、コインが誤って画面の後ろに表示されないように、コインが発生する可能性がある領域を設定してから、ランダムに位置を割り当てます。 最後の行は、見た目があまり美しくないので、Singletonesを使用して簡略化することをお勧めします。
シングルトン
シングルトンのミドルネームは「スタートアップ」です。 すでに示唆に富んでいますよね? シングルトンは次のように機能します:変数の宣言から始まり、シーンの「スイッチ」で終わる(ロードとアンロードを含む)必要なものを書き込むことができるスクリプトが最初にロードされ、アプリケーションが実行され、そのすべてのコンテンツにアクセスできますプロジェクトポイント。 ある意味では、これは、いつでも利用可能な「すべて」の一種のカスタムグローバルリポジトリです。
プロジェクトには独自のグローバルリポジトリがあり、そのコンテンツも使用できますProjectSettings.get_setting(name)
を使用してアクセスできますProjectSettings.get_setting(name)
は必須パラメーターの名前です。
ここで、リポジトリ「_G」から何かを使用するには、名前で呼び出してから、呼び出すメソッド、またはそこにあるものを指定するだけで十分です。 したがって、空のスクリプトを作成し、以下に示す関数を記述してください。
extends Node func rand(): var rrand = Vector2(rand_range(40, 760), rand_range(40, 540)) return rrand
次に、保存してプロジェクト設定に移動します: Project -> Project Settings -> AutoLoad
新しく作成したスクリプトを選択し、「_ G」などの名前を設定し、「spawn_coins()」関数に戻って期限をわずかに調整し、次のコードに置き換えます。
... c.position = _G.rand()
「_ready()」ブロックに「spawn_coins()」を配置し、F5でアプリケーションを実行して、何が起こったかを確認する価値があります。 Main.tscn
をメインシーンとして選択することを忘れないでください。何らかの理由でミスをした場合は、メインシーンを手動で変更できます。そのため、プロジェクト設定に移動する必要があります。 General -> Run -> MainScene
動作しますか? 次に進みます。
コインは何枚残っていますか?
続けましょう。 次に、プレーヤーを次のレベルに移動するために残っているコインの数を確認し、5秒ずつ時間を増やした形で小さな「ボーナス」を与えてから、コインを再スポーンします。
func _process(delta):
ユーザーインターフェース
インターフェース全体は、スコアインジケーター、現在のレベル、時間、ゲームの名前、およびゲームの起動をトリガーするボタンで構成されます。 CanvasLayer
親を使用してシーン( HUD.tscn
)を作成します(競技場の上にユーザーインターフェイスを描画できます)。 少なくとも、私にとっては、ユーザーインターフェイス要素を管理することはあまり便利ではありませんが、要素のかなり広いリストと積極的な開発は、エンジンのこの側面の開発に明るい未来で前向きな姿勢を植え付けます。
Godotには、いわゆる「コントロールノード」があり、親の指定されたパラメーターに関して子要素を自動的にフォーマットできます。 「制御ノード」の各タイプには、子孫の位置を制御する方法を制御する特別なプロパティがあります。 このタイプの鮮明な代表はMarginContainer
であり、シーンに追加する必要があります。 [ Layout -> Top Wide
を使用して、ウィンドウの上部でストレッチし、このオブジェクトのプロパティの[ Margin
セクションで、端からのインデント(左、上、右)を指定します。 MarginContainer
は、 LevelLabel
、 LevelLabel
、およびTimeLabel
という名前の3つの子Label
が必要TimeLabel
。 それらをシーンに追加します。 Align
プロパティを使用して、左、中央、および右になるように配置します。 もう1つのLabel
( Messagelabel
)を追加して中央に配置し、すべてLayout
を使用し、ボタン( StartButton
)のすぐ下に配置します。
次に、インターフェイスをレスポンシブにします。時間、収集したコインの数を更新し、現在のレベルを強調表示する必要があります。 HUD
ノードのスクリプトを追加します。
extends CanvasLayer signal start_game func update_score(value): $MarginContainer/ScoreLabel.text = str(value) func update_level(value): if len(str(value)) == 1: $MarginContainer/TimeLabel.text = "0: 0" + str(value) else: $MarginContainer/TimeLabel.text = "0: " + str(value) func update_timer(value): $MarginContainer/TimeLabel.txt = str(value)
MessageLabel
場合、メッセージのテキストを短時間変更するためにタイマーが必要です。 Timer
ノードを追加し、その名前をMessageTimer
置き換えます。 インスペクタで、待機時間を2秒に設定し、[ One Shot
フィールドのボックスをOne Shot
ます。 これにより、起動時にタイマーが1回だけ実行されるようになります。
func show_message(text): $MessageLabel.text = text $MessageLabel.show() $MessageTimer.start()
timeout()
シグナルを「MessageTimer」に接続し、次を追加します。
func _on_MessageTimer_timeout(): $MessageLabel.hide()
StartButton
[ノード]タブで、 pressed()
信号を接続します。 StartButton
ボタンをクリックするとStartButton
それはMessageLabel
とともに消え、メインシーンに信号を送信します。その後、関数を実行して「new_game()」を実行することで、正常にインターセプトします。 以下のコードを使用してこれを実装します。 Text
プロパティのボタンを使用して、ゲームを開始するテキスト呼び出しを設定することを忘れないでください。
func _on_StartButton_pressed(): $StartButton.hide() $MessageLabel.hide() emit_signal("start_game")
インターフェースを最終的に仕上げるために、最後の最終関数、つまりゲームの終了に関するメッセージを表示する関数を作成します。 この関数では、碑文「Game Over」が2秒以内に表示され、その後消える必要がありますが、これは「show_message()」関数により可能です。 ただし、ゲームが終了したことを知らせるメッセージが消えたらすぐに、新しいゲームの開始ボタンを再び表示する必要があります。 yield()
、 MessageTimer
からのシグナルを受信するまで関数の実行を一時停止し、その実行に関するMessageTimer
からのシグナルを受信すると、関数は実行を続け、元の状態に戻り、新しいゲームを再び開始できます。
func show_game_over(): show_message("Game Over") yield($MessageTimer, "timeout") $StartButton.show() $MessageLabel.text = "LIKE COINS!" $MessageLabel.show()
終わった?
HUD
とMain
間にフィードバックを設定しましょう。 HUD
シーンをメインシーンに追加し、次を追加してメインシーンのtimeout()
を介してGameTimer
信号を接続します。
func _on_GameTimer_timeout(): time_left -= 1
次に、プレーヤーのpickup()
およびdie()
信号を接続します。
func _on_Player_pickup(): score += 1 $HUD.update_score(score) func _on_Player_die(): game_over()
ゲームの終わりに、見落とされてはならない、さらにいくつかのことが起こるはずです。 次のコードを書いて、説明します。
func game_over(): playing = false $GameTimer.stop() for coin in $CoinContainer.get_children(): coin.queue_free() $HUD.show_game_over() $Player.die()
この関数はゲームを停止し、残りのコインがshow_game_over()
、残りのコインがshow_game_over()
、 show_game_over()
がHUD
に対して呼び出されます。 次のステップは、アニメーションを開始し、 Player
ノードの実行を停止することです。
最後に、 new_game()
関数に接続する必要があるStartButton
アクティブにする必要があります。 HUD
ノードをクリックし、接続ダイアログで[ Make Function to Off
する]をクリックする必要があり(これにより新しい関数が作成されなくなります)、[ Method In Node
のMethod In Node
フィールドで接続する関数の名前new_game
を指定します。 これにより、新しい関数を作成するのではなく、既存の関数に信号が接続されます。
最後の_ready()
関数からnew_game()
を削除し、次の2行を_ready()
関数に追加します。
... $HUD.update_score(score) $HUD.update_timer(time_left)
これで、ゲームの準備ができたと自信を持って言えるようになりました。今では非常に「プレイ可能」ですが、効果はありません。 次の記事では後者を検討し、ゲームプレイを多様化し、「Godot」の可能性をさらに探るために、さまざまな「装飾」に多大な注意を払います。 したがって、記事のリリースに従うことを忘れないでください。 頑張って!