23回目 Gpt4oを最大限活用でポケモン風RPGを作るチャレンジ(3か月チャレンジ 4週目)
お疲れ様です。gyagyaです!
基本的に週末しか時間とれていないです、、くそう、、
今回は3か月チャレンジの進捗報告をさせていただきます。
はじめに
現在バトルシーンを作成中です!
ただ、現状簡単なUIを作成しただけでまだボタン処理がなにもありません。
今日の目的
★前回同様、ボタン押下時の処理について理解すること
としています。
分からないことはとにかくGPT4oに聞きまくります。
1.ボタン押下時の処理実装方法が分からない!!
ボタンを押下した際の処理をどのようにして作成すべきか悩んでいます。
バトルシーンにまとめて書くべきか、ボタンそれぞれに書くべきか。。
SOLID原則から考えるとどのように書くのが適切か。
そもそもどんな風に記述すればいいのか、、(笑)
2.調査してみた!
今回はGODOTアセットから参考になりそうなものを取得しました。
戦闘に関するノードを確認してみましょう。
これを見る限りでは目的は比較的はっきり分けられているように見えます。
つまりCombatノードで全て記述するのではないということですね。
※とはいってもCombatノードには色々組み込まれているのでそれは分けた方が良い可能性があります。
・Combatノード :戦闘の初期化、戦闘の勝利/敗北などを管理する
・UIノード :ボタン押下時の処理を管理する
・Combatantsnノード :戦闘員を表示させる
さて、ここまでは前回の復習でした。
以下、続きになります。
結局、戦闘開始→自分のターン開始→例えば攻撃ボタン押下→相手にダメージ→ターン終了→相手の攻撃→自分にダメージ→ターン終了までの一連の流れが知りたいので、次に攻撃ボタン押下時の処理に進みます。
まず、CombatノードにはUIノードがありました。
![](https://assets.st-note.com/img/1717805328356-HQiK4ht3C9.png)
ここにはAttackボタンがあり、シグナルが接続されているそうです。(Wifiみたいなマーク)
UIのスクリプトを抜粋します。
①宣言
extends Control
@export var combatants_node: Node
@export var info_scene: PackedScene
例のごとくですがUIにもノードとシーンがアタッチされていました。これらを利用するための宣言です。
![](https://assets.st-note.com/img/1717805563582-jHRzhoS2Xo.png)
②初期化
func initialize():
for combatant in combatants_node.get_children():
var health = combatant.get_node("Health")
var info = info_scene.instantiate()
var health_info = info.get_node("VBoxContainer/HealthContainer/Health")
health_info.value = health.life
health_info.max_value = health.max_life
info.get_node("VBoxContainer/NameContainer/Name").text = combatant.name
health.health_changed.connect(health_info.set_value)
$Combatants.add_child(info)
$Buttons/GridContainer/Attack.grab_focus()
ここで体力やキャラクターの情報を取得しています。
毎回呼ばれているのかな?と推測しています。
③攻撃ボタン押下時
func _on_Attack_button_up():
if not combatants_node.get_node("Player").active:
return
combatants_node.get_node("Player").attack(combatants_node.get_node("Opponent"))
これがまさに攻撃ボタンになります。今回はここを掘り下げます。
といっても実際はわずか数行しかありません。
if not combatants_node.get_node("Player").active:は単にプレイヤーがアクティブ状態かどうかを判断し、異なればリターンしているだけです。
重要なのはcombatants_node.get_node("Player").attack(combatants_node.get_node("Opponent"))になります。
・combatants_nodeノードからPlayerノードを再び取得し、そのattackメソッドを呼び出します。
・attackメソッドの引数として、combatants_nodeノードから取得したOpponentノードを渡します。
つまり、こーいうことです。
Combatantsノード、すなわちキャラクター取得ノード(今回はPlayerノードを取得しています。)を呼び出します。
呼び出されたPlayerノードによって、以下のattack(target):メソッドを実行します。初期値ではdamageが1で固定されていました。
class_name Combatant
extends Node
signal turn_finished
@export var damage: int = 1
@export var defense: int = 1
var active = false: set = set_active
func set_active(value):
active = value
set_process(value)
set_process_input(value)
if not active:
return
if $Health.armor >= $Health.base_armor + defense:
$Health.armor = $Health.base_armor
func attack(target):
target.take_damage(damage)
turn_finished.emit()
func consume(item):
item.use(self)
turn_finished.emit()
func defend():
$Health.armor += defense
turn_finished.emit()
func flee():
turn_finished.emit()
func take_damage(damage_to_take):
$Health.take_damage(damage_to_take)
$Sprite2D/AnimationPlayer.play("take_damage")
ここまででかなり理解が深まってきました。
このように見ると、思ってた以上に役割分担がしっかりされていてとてもいいコード、SOLIDの原則従ったコードに見えました。
おまけ
最後にちょっとパラメータをいじってみましょう。
healthノードのInspecterを見るとMaxLifeをいじれるのでいじります。
100を500とかにしときます。
![](https://assets.st-note.com/img/1717807772944-bVMy8C5EjP.png)
すると以下のようになります。
![](https://assets.st-note.com/img/1717807862908-MYYmviIvck.png?width=800)
あれれ?ゲーム開始時点で体力がねえ、、
と思いきや、この500とはあくまでも体力ゲージが500まであるというだけで初期の体力が少ないためでした。
実際には以下のPlayer.gdに記載されています。
ここでmax_lifeを500にすると自動的にInspecterの体力が変わります。
これが@exportで定義するメリットなのですね
![](https://assets.st-note.com/img/1717808428565-bAgXtM0lqf.png?width=800)
次こそ!!
![](https://assets.st-note.com/img/1717808534671-LqkI2EsJFB.png?width=800)
おやおや?!変わってない?!
でも相手から攻撃を受けた瞬間に表示されました。
![](https://assets.st-note.com/img/1717808553859-HzJ9cw5j2s.png?width=800)
原因は初期化時に防御力しか受け取ってなかったからでした。
![](https://assets.st-note.com/img/1717808602198-OdndosOrTo.png)
そこで以下のように初期体力と体力を分けて定義し、初期処理で初期体力を取得します。
![](https://assets.st-note.com/img/1717808731675-0sJewGHmlV.png)
これでどうだ?!
![](https://assets.st-note.com/img/1717808790229-pmMnENI3Gx.png?width=800)
とほほ、、、だが諦めない。
そもそもこの体力ゲージはどこから来るのか探ります。
まず、UIが確実に怪しいのでUIから調査。GPT4oに尋ねると
「var info = info_scene.instantiate()」にあるんじゃね?って教えてくれました。めっちゃ便利。。
![](https://assets.st-note.com/img/1717809569027-vkmSq7VPgE.png?width=800)
info_scene: PackedSceneとされていて、Info.tscnに移動。
![](https://assets.st-note.com/img/1717809680664-tvMTJd8Z7k.png)
![](https://assets.st-note.com/img/1717809710505-EEaiFHhNWq.png?width=800)
ここでMaxValueを500、Valueを500に変更してみます。
![](https://assets.st-note.com/img/1717809904067-tOIQAEXxUH.png)
すると、、、
![](https://assets.st-note.com/img/1717809928792-NibI3YoM8S.png?width=800)
できた!!やったー!
ということでひとまず終わります。
次回はこの技術を参考に実装に進んでいこうと思います。
結論:詰まったらGPT4oが最強。
この記事が気に入ったらサポートをしてみませんか?