カード式で多数vs多数のシステム
ヒロインのターンで攻撃関係で、それなりに理想の動きになるところまでできました
敵の攻撃とコスト周りの設計ができたら、とりあえずのゲームにはなるかなといった状態ですね
遊べるエロゲ用システムとして作ってるので、あんまりゲームがゲームするのも合わないと思ってますし、ほどよくそれっぽい感じを目指してます
クリエイター支援サイト Ci-en
フォローするにはユーザー登録が必要です。
栗片いづも/妄想御殿 2023/10/16 01:34
ヒロインのターンで攻撃関係で、それなりに理想の動きになるところまでできました
敵の攻撃とコスト周りの設計ができたら、とりあえずのゲームにはなるかなといった状態ですね
遊べるエロゲ用システムとして作ってるので、あんまりゲームがゲームするのも合わないと思ってますし、ほどよくそれっぽい感じを目指してます
栗片いづも/妄想御殿 2023/10/15 09:55
@exportが一番確実とはいえ使いたくない場面は多いです
「エディタで毎回ドラッグ&ドロップするのが面倒」から「動的生成するからエディタでのアタッチができない」まで
その場合はget_node()/$を使ってパスを作るのですが、このタイミングが動的生成時には特に問題になる場合があります
一番多いパターンは「func _ready()」内や、変数宣言時に「@onready」で読み込ませる方法だと思います
しかし動的生成して生成後に関数を使う場合、パス生成が終わってない状態でアクセスしてしまう場合は当然発生します
なので動的生成では生成後の最初だけ動かす関数の最初にget_node()/$をしてやるのが安全だと思います
動的生成したSceneの変数がそのScene内だけで完結するのであれば、あまり気にしなくてもいいです
素直に
const 「スクリプト用の変数」 = preload(「スクリプトのパス」)
で変数を先読みしてその変数からクラスを呼び出すのが無難
とはいえ、何かと面倒なのでよほどの理由がないならDictionary型で処理した方が楽だし安全だと思います
どうしてもクラスが必要であるなら「クラスとDictionary型を相互変換する何かを用意する」とかをすればいいと思います
なぜか無いので、位置決めにも困る
なので最初に[font_size=xx]を書いておくのが楽
そもそもBBCode使わないならLabelの方が楽
テキスト表示の時にも、処理としてテキストデータの最初に[font_size=xx]を差し込む仕組みにしておくと楽だと思います
よく忘れるので
randi_range(x、y)
は、x以上y以下の整数
C#とかのrand関数だとy未満になるので、うっかりしがち
栗片いづも/妄想御殿 2023/10/06 08:19
これまでに感じたトラップ的な要素です
マウス入力のためのArea2Dがある場合に、マウスポイント直下にColorRectがあるとなぜか反応しません
ほかにもこういうことがあるかもしれないし、そもそもシンプルな四角形はもっぱら何かの代用なので素直に「Polygon2Dで四角形を作る」「10pixel四方の白い四角い画像を用意してそれをテクスチャにSprite2Dにしてサイズを合わせる」あたりにしておいた方がいいと思いました
フォルダの構成変更で移動させたファイルを参照してるSceneが保存されているtscnファイルがたまに壊れます
フォルダ構成を変更する場合には臨時でプロジェクトをまるごとバックアップしておいた方がいいです
マップとかでの横8マス縦5マスの広さみたいな感じはゲームではよく使いますし、そのときにMapData[x, y]とかMapData[x][y]みたいな感じにしてデータを収納したくなります
しかしArray[Array[Sprite2D]]みたいなのはできないので、Sprite2Dを2次元配列したい場合は
var DataArray:Array
const X_count = 8
const Y_count = 5
func _DataArraySet():
var _data_array_y:Array[Sprite2D]
for x in X_count:
DataArray.append(_data_array_y)
な感じでひな形を作ってあげるといいです
マップとかではSprite2Dとなってるところは個々のマップパネルデータの自作クラスだったりとかが入ると思います
栗片いづも/妄想御殿 2023/10/04 02:26
というわけで今後よく使うであろう部分の練習製作としてのカード方式戦闘をGodotで作ってみました
双方ダメージ与えあって終わりでエロもゲーム要素もなく、本当に実運用としての実装テストな仕上がりになっています
MockCardGame.zip (24.75MB)
ダウンロードマウスの左クリック : カードやボタンの選択・メッセージを進める
Ctrlキー : メッセージを進める
ESCキー : タイトルに戻る
手札の追加も手札の使用もEN消費は1です
ENは毎ターン3回復します
カードのPowerがモンスターに与えるダメージです
どちらかのゲージが0になったらゲーム終了です
カードを引くには「Draw+1」をクリックしてください
ターンエンドするには「Turn End」をクリックしてください
このゲームの実装で気になったことがあればコメントに書いておいてもらえると、答えられる範囲なら備忘録で答えられると思います
栗片いづも/妄想御殿 2023/09/30 15:39
今回はボタン系です
2項目くらいごとが見やすいなと思いました
ボタンそのものは用意されていますが「画像の上にマウスオーバーさせたときに何かさせる」とかそういうのをやる場合はUnityの時もそうですが自前で作ってしまったものの方が扱いがしやすいというのがあります
ButtonNode
└Area2D
├CollisionShape2D
└ボタン用画像(Sprite2D)
このようなSceneがボタン用のNodeになります
CollisionShape2DはShapeをRectangleShape2Dにして、ボタン画像と同じサイズに変更してください
ボタン画像を「とりあえず四角の画像でいいや」でColorRectで作ったら動きませんでした
親NodeのButtonNodeに新規スクリプトをアタッチして、Area2Dのノートタブからinput_eventとmouse_enteredとmouse_exitedを接続してください
これでArea2Dからでるsignalが接続され、対応したコードが3つ追加されています
func _on_area_2d_input_event(viewport, event, shape_idx):
func _on_area_2d_mouse_entered():
func _on_area_2d_mouse_exited():
そこから必要なコードを書いてこうなります
signal BtnClick_R
signal BtnClick_L
signal BtnEnter
signal BtnExit
func _on_area_2d_input_event(viewport, event, shape_idx):
if event is InputEventMouseButton and event.pressed:
if event.button_index == MOUSE_BUTTON_RIGHT:
emit_signal("BtnClick_R")
if event.button_index == MOUSE_BUTTON_LEFT:
emit_signal("BtnClick_L")
func _on_area_2d_mouse_entered():
emit_signal("BtnEnter")
func _on_area_2d_mouse_exited():
emit_signal("BtnExit")
これでCollisionShape2Dの範囲内でマウスを操作するとButtonNodeからボタン信号をだす仕組みができます
func _on_area_2d_input_event内で右クリックと左クリックを検知して、検知したらBtnClick_RとBtnClick_Lを発信させます
_on_area_2d_mouse_enteredはマウスがCollisionShape2Dの範囲内に侵入したときに呼び出されるので、そのときにBtnEnterを発信させます
_on_area_2d_mouse_exitedはマウスがCollisionShape2Dの範囲内から出た時に呼び出されるので、そのときにBtnExitを発信させます
もしマウスオーバーでボタンの画像を変えたり、ボタンの一部を変えたい場合は、_on_area_2d_mouse_enteredと_on_area_2d_mouse_exitedにそのための処理を増やすだけになります
カードゲームの手札などでよくある重なった演出で使う、重なった画像の一番手前のものを取得する方法です
まずカード単体のSceneを上のボタン的なものと同じように作ります
CardNode
└Area2D
├CollisionShape2D
└カード画像(Sprite2D)
CardNodeにアタッチしたスクリプトもほぼ同じで
signal BtnEnter(card_no)
signal BtnExit(card_no)
var CardNo:int
func _on_area_2d_mouse_entered():
emit_signal("BtnEnter", CardNo)
func _on_area_2d_mouse_exited():
emit_signal("BtnExit", CardNo)
ここでの違いはsignalに引数を持たせることです
複数のカードにCardNoという変数を持たせることで、BtnEnterとBtnExitがどこから来た信号なのかをわかるようにします
そしてカードを選択するSceneとして
CardSelectNode
├CardNode_0
└CardNode_1
とします
新規Sceneを作り、その子Nodeとして上記で作ったCardNodeのSceneを入れただけです
CardSelectNodeに新規スクリプトをアタッチして、そこに
@export var CardNode:Array[Node2D]
func _ready():
for i in CardNode.size():
CardNode[i].CardNo = i
CardNode[i].BtnEnter.connect(_SelectAdd)
CardNode[i].BtnExit.connect(_SelectRemove)
func _SelectAdd(card_no):
pass
func _SelectRemove(card_no):
pass
と記述します
そしてエディタ上でCardNodeに子ノードのCardNodeをツリーの上から順に追加してください
これによって、このSceneが動いたら自動的に2つの子Nodeの信号をCardSelectNodeのスクリプトへ接続でき、子Nodeにはそれぞれカード番号が振られます
子Nodeのsignalはそれぞれ
・BtnEnterは_SelectAddに引数付き
・BtnExitは_SelectRemoveに引数付き
への接続となります
そしてここから接続先への処理を記述します
var _SelectCardArray:Array[int]
func _SelectAdd(card_no):
if not card_no in _SelectCardArray:
_SelectCardArray.appent(card_no)
func _SelectRemove(card_no):
if card_no in _SelectCardArray:
_SelectCardArray.erase(card_no)
これによりカードにマウスが乗った場合には「_SelectCardArrayにそのカード番号が無ければ追加」となり、カードからマウスが外れた場合には「_SelectCardArrayにそのカード番号があれば削除」という処理ができるようになりました
そして最後に
func _process(delta):
if _SelectCardArray.size() > 0:
_SelectCardArray.sort()
var _card_index = SelectCardArray.size() - 1
print(_SelectCardArray[_card_index])
とすると、カードにマウスが乗っている時に、マウス直下の一番上に表示されている(ツリーで一番下)のカード番号がデバッグログに表示され続けるようになります
これを_SelectCardArrayへのNodeの登録番号とカード番号を同じにすることで、いろいろな演出や操作ができるようになりました
カードのオブジェクトを動的生成とも相性がよかったです