2025-01-13

Godotでシンプルな3マッチパズルゲームを作って公開しました

この年末年始はGodotの勉強のために3マッチパズルを作ってました。パズルの基本部分だけ実装できたので年始の終わりに一度公開しましたが、さらにUIや攻略できるステージを整備してリリースしました。


Simple Match 3-5x6 - フリーゲーム投稿サイト GodotPlayer

https://godotplayer.com/games/syjiro_simple_match3_5x6




[基本的なルール]

  • ピースをマウスドラッグかスワイプで動かして、2つのピースを入れ替えてください。
  • 同じ色のピースをタテかヨコに3個以上並べると消えます。
  • ピースを入れ替える度に、画面上部に表示されている移動回数が減ります。0になるとゲームオーバーです。
  • 同じ色のピースを4個並べると、タテまたはヨコに一直線に消せるピースが出現します。
  • 同じ色のピースを5個以上並べると(L字型やT字型も含む)、同じ色のピースをまとめて消せる虹ピースが出現します。

[ステージの紹介]

  • ENDLESS:500点ごとに移動回数が増加
  • Stage1~5:画面左上に提示されているピースを消す
  • Stage6~10:氷ブロックを消す(氷ブロックは近くのピースが消えると一緒に消える)
  • Stage11~15:上から落ちてくるピースは、斜め下が空いていると斜め下にも落ちる
  • Stage16~20:凍っているピースは1回消すと中身のピースが現れる
  • Stage20~25:水滴を一番下まで落とす
  • Stage26~30:上から落ちてくるピースが6色に増える

3マッチパズルのスマホゲームは広告も含めて大量に目にしてきましたが、いざ自分で作ってみると思った以上に大変でした。ルールが単純なので、少量のコーディングですぐに終わるだろうと甘く見ていましたが、大間違いでした。その辺の苦労はまた別の記事で触れたいと思います。

2024-09-18

GDevelopでプロジェクトのassetsフォルダに未使用の画像ファイルが残る

GDevelopでスプライト用の画像を描いたりアセットを入れたりしていると、プロジェクトのassetsフォルダに未使用のファイルが溜まっていきます。

他の記事の調査で作ったプロジェクトのリソースタブを開いてみると、Stop2~5の4つの画像ファイルが表示されました。

一方で、Windowsのエクスプローラでassetsフォルダを確認してみると、7つの画像ファイルが入っています。未使用の画像ファイルが3つあるということです。

プロジェクトをHTML5形式でエクスポートしてみると、使用中の4つの画像ファイルだけがコピーされていました。


ただし、リソースを整理するつもりで不要なファイルをリソースタブに表示している場合は注意が必要です。

今回のプロジェクトのリソースタブで右クリックメニューの「プロジェクトフォルダ内をスキャン>画像」を実行すると、不要なファイルも含めた7つの画像ファイルが一覧表示されます。

この状態でエクスポートすると、未使用の画像ファイルを含めた7つの画像ファイルがコピーされていました。


このような場合は、リソースタブで右クリックメニューの「未使用のファイルを削除...>画像」を実行すると、一覧から未使用の画像が削除されます。ただし、この操作は一覧に表示されなくなるだけで、assetsフォルダには引き続き画像ファイルが残ります。

未使用の画像ファイルが残るのが気になる場合は、事前に空のフォルダを作った後で、GDevelopのファイルメニューで「名前を付けて保存」で空のフォルダを保存先にすると、未使用のファイルを除いたプロジェクトフォルダの内容がコピーされます。

2024-09-17

GDevelopでテキスト型変数を利用する場合は、初期値を空欄にしない方がよい

GDevelopで変数の種類をテキストにした場合、初期値を空欄にすることができます。
初めてGDevelopに触れた時は、この時点で変数に長さ0の文字列が設定されたものと思っていましたが、どうも思ったような動作にならないので調べてみることにしました。

テキストのシーン変数を追加して、初期値を空欄にします。

プレビューしてデバッガで Scene variables を確認してみると、「"value" : "0"」となっていました。テキスト型変数を利用する場合は、1文字以上のテキストを初期値として入れておいた方がよさそうです。


代わりに、できるだけ早いタイミングで変数に""を設定する方法を考えます。イベントシートでシーン開始時に2個目のシーン変数に""を設定します。

再びプレビューしてデバッガで Scene variables を確認してみると、今度は2個目のシーン変数が「"value" : ""」になりました。


GDevelopの開発環境で変数に特定のシーン名を設定する時はリストから選びたい

GDevelopでシーンを変更する時はリストから既存のシーン名を選択できますが、変数にシーン名を設定する場合はシーン名を直接入力する必要があります。また、シーンに付けた名前を後から変更した場合、GDevelopの開発環境が影響のありそうな所を自動的に新しい名前で置換してくれますが、直接入力したシーン名は変更されません。

拡張機能を自作する案

堅実な方法としては、拡張機能を自作してテキスト型変数にシーン名を保持し、変数に対するアクセスは拡張機能の提供するアクションと式に限定する、といったやり方があります。

概要だけ示すと、例えば SceneManager という拡張機能を作成し、次のシーン名を管理するために NextSceneName という変数を追加します。シーン変数にするかグローバル変数するかは用途に応じて変えます。

SceneManager に対し、 NextSceneName を参照するための NextScene 式と、変更するための SetNextScene アクションを用意します。

イベントシートで次のシーン名を取得したい時は「SceneManager::NextScene()」式を使います。

イベントシートのアクションで次のシーンを変更する時は「その他のアクション」から SceneManager のアクションをクリックすると、リストからシーンを選択できます。

変数にアクセスする手段を制限することで不正なシーン名が入りにくくなり、名称の変更にも対応しやすくなりました(例えば SetNextScene アクションの名前を SetNextSceneName に変えた場合など)。チームで作業したり、拡張機能を不特定多数に配布する場合、このような方法でプログラムの部品を制御することが重要になります。

一方で、製作しようとしている作品の規模によっては、ここまで徹底するのは大げさすぎるかもしれません。

シーン名を渡すだけの式を作成する案

拡張機能でアクションや式のパラメーターを「シーン名(テキスト)」にすると、イベントシートで入力する際にリストからシート名を選択できるようになります。この特徴を利用して「シーン名(テキスト)のパラメーターをそのまま返すだけの式」を作成すれば、必要な時だけリストからシート名を選択できそうです。

拡張機能の式を作成して、パラメーターを「シーン名(テキスト)」にします。


式の内容は戻り値にパラメーターの値を設定するだけです。戻り値もシーン名なので、式のタイプも「シーン名(テキスト)」にします。


イベントシートの条件やアクションで「MyExt::InputSceneName("")」と入力し、カーソルを""の中に移すと、シート名をリストから選択できるようになります。もし後で該当シーンの名前が変わっても、""の中のシーン名は自動的に新しい名前に変わります。


変数に何回か特定のシーン名を設定するだけの場合は、この方法で事足りるように見えます。とはいえ開発が進んでシーン名を扱う箇所が増えていくと、最終的には SceneManager に相当する機能を自作するかアセットストアから導入することになるかもしれません。

もし将来のGDevelopが変数の種類として「シーン名(テキスト)」をサポートするようになった場合、MyExt::InputSceneNameのような機能は単純に無駄になるので、あくまでも現時点の妥協的な手段と考える必要があります。

2024-09-16

20年ぶりにゲームを作って公開しました

GDevelopで作成した短い2DアクションゲームをWebブラウザ向けに公開しました。
4つのステージでゴールに到達するとクリアです。
※スマホ非対応、キーボード入力のみ

Pixelamid Adventure | Play on gd.games
https://gd.games/syjiro/pixelamidadventure 

  • 十字キーの ← または → で移動
  • スペースキー か Z キー でジャンプ
  • X キーで武器を発射

20年以上前にHSP(Hot Soup Processor、Windows向けスクリプト環境)で作ったゲームを公開して以来なので、本当に久しぶりの個人ゲーム制作でした。
キャラクターが自動的に目的地へ歩いたり敵を倒したりするスタート画面を作ったのは初めてかもしれません。
サウンドとBGMはOtoLogic様の音声素材を使用しました。短い期間でゲームに音声を付ける目途が立ったのは、使いやすく音声ごとのテーマが分かりやすい素材の助けあってこそでした。
スプレーの説明を読むために顔を近付けるくらい年齢を感じだした日々の中で、このような貴重な経験ができたことに感謝します。
GDevelopを触ってみての感想などは別の機会に書きたいと思います。

GDevelopの「オブジェクトを生成する」アクションの計算式の中で生成対象のインスタンスの高さを取得できない

タイトルに書いてみると当然の処理結果なのですが、GDevelopは「Ball.Height()」のような式を見ただけでは特定のインスタンスの高さなのかBall全体の初期値としての高さなのかが必ずしも自明ではないため、備忘録として残します。

アクションゲームの製作で、プレイヤーの頭上からボールが落ちてくるギミックを考えます。今回は、プレイヤーが白い箱に接触したら、頭上にボールを表示することにします。


イベントシートで、プレイヤーと白い箱が衝突したことを条件に「オブジェクトを生成する」アクションでボールを生成します。ボールの生成位置のY座標を「Player.Y()-Ball.Height()」と書くことで、プレイヤーの左上座標よりもさらにボールの高さ分だけ高い位置にボールが生成されそうに見えます。


プレビューしてみると、プレイヤーと白い箱が接触した瞬間に、プレイヤーと同じ高さにボールが表示されてしまいました。一方で、同じイベント行の中でボールの生成後に高さを取得することは成功しており、「ボールの高さ=32」と表示されました。




動作確認のために、問題の式を「Player.Y()-32」にすると、プレイヤーの頭上にボールが出現しました。この場限りの対応ならこれで終わりですが、この機能が他のところにコピーされてしまうと、ボールの高さが変わった時に修正の手間が増えるかもしれません。

ボールの高さを直接記入する代わりに変数を使うと、ボールの高さを変えたい時に修正するのが変数だけで済みます。

ボールが一度生成されれば高さを取得できる点に注目して、ボールの生成は人から見えない位置で実行し、後から移動する方法もあります。生成後の移動時のY座標に「Player.Y()-Ball.Height()」と書くと期待通りに動作します。ただしイベントに記入するアクションが常に1つ増えるため、その労力が成果に見合うかは作ろうとしているゲームの仕組みにもよるでしょう。


最後に、変数を使った場合の動作例を載せます。





GDevelopのパソコン用アイコンの設定で極端に小さな画像を指定すると、Electronでビルドした時にEXEファイルのアイコンが変わらない

GDevelopは ゲーム設定>アイコンとサムネイル の「パソコン (Windows、macOSおよびLinux) アイコン:」でパソコン向けのアプリアイコンを設定できるのですが、入力欄に「Desktop icon(512x512 px)」と書いてあるのを無視して16×16の画像ファイルを指定しても、この時点では特にエラーや警告は出ません。

しかし、パソコン向けにエクスポートしてElectronの環境から「yarn build -w portable」でビルドしてみたところ、EXEファイルのアイコンがデフォルトのままでした。

エクスポートで作成されたフォルダを調べてみると、buildResourcesフォルダにアプリアイコンの画像ファイルが入っていませんでした。

代わりに256×256の画像をアプリアイコンに設定して、再びエクスポートとビルドを実行すると、buildResourcesフォルダにアプリアイコンの画像ファイルが配置されて、EXEファイルのアイコンが変更されました。

アイコンとサムネイルの設定画面

古い感覚で16×16のアイコンが使えるか試してみましたが、以上のような結果なので、やはり使えないようです。特にElectronの制限で、アイコンのサイズは少なくとも256 x 256となっています。

※WindowsのEXEファイル内のリソース情報を書き換えるツールも存在しますが、今回はGDevelopとElectronのビルドの話に絞りました。