tanaka's Programming Memo

プログラミングについてのメモ。

InputSystemを使ったらWebGLのEditorとPCとスマホそれぞれで苦労した話

この記事はQiita Unity Advent Calendar 2022 カレンダー2 の9日目の記事です。

qiita.com

◆前日は chroske さんの 【Unity】ワープポータル転送演出の作り方【AdventCalendar2022】 - かつて代官山らへんで働いてたengineerのUnityブログ でした。

◆次の日は nkjzm - Qiita さんの「なんかかく」です。


ちょくちょくハマる Input System ですが、またも今年のデジゲー博の準備中にWebGLビルド時に操作できなくなる症状にぶつかりました。その原因と解決策です。

目次

問題が発生した状況

デジゲー博2022に出展したVoxelorer BirdのWebGL版の開発中に問題が発生しました。Unityエディター上では問題なく操作できていたのですが、WebGLでビルドしたものをiPadで動かすと最初は問題なく操作できていたのにステージ選択シーンに移動してからゲームに戻ると操作できなくなりました。

以下のバージョンで問題が起きることを確認しています。

  • Unity2021.3.14f1
  • Input System 1.4.4

原因

Voxelorer BirdはスマホではTouchscreen、PCではマウス入力を使います。ゲーム中は移動先や押すブロックなどの指定。

ゲーム画面

ステージ選択では洞窟のスクロール操作なので役割が違います。

ステージ選択画面

操作できなくなるのはゲームシーンのみでCanvas上のUIは操作できます。問題はPlayer Inputのようです。Player Inputはゲームシーンとステージ選択シーンそれぞれにアタッチしてあり、各シーン用のアクションを設定しています。

テストプロジェクトを作ってあれこれ試したところ、シーンを非同期で先読みして切り替える時にTouchscreenとKeyboard&MouseのSchemeが切り替わることが分かりました。

不具合の再現

シーンの切り替えにSceneManager.LoadSceneAsync()を使い、かつ、AsyncOperationのallowSceneActivationをfalseにして次のシーンを非同期に先読みすることで、古いシーンと非アクティブ状態の新しいシーンが混在することで問題が発生していました。

普通にシーンを切り替える場合は古いシーンのPlayer Inputが破棄された後に新しいシーンが読み込まれるので問題は起きません。Voxelorer Birdではシーン切り替えの待ち時間を減らすために画面を覆う演出の開始と同時に裏で次のシーンを非同期に読み込んでいます。古いシーンのPlayer Inputがデフォルトの入力デバイス保有したままだと新しいシーンのPlayer Inputが同じ入力デバイスを選択できないらしく、他の入力デバイスを選んでしまうのが原因でした。

解決策

原因が分かれば対策は簡単です。シーン切り替えで入力が不要になり次第、Player Inputがアタッチされているゲームオブジェクト上で以下のような処理を実行して、有効なPlayer Inputを無効にすることで解決しました。

        foreach (var pi in PlayerInput.all)
        {
            pi.enabled = false;
        }

といいつつ、この解決策にたどり着いたのはデジゲー博後、このブログのための調査をしている時でした。デジゲー博では実行環境を調査して手動でSchemeを割り当てるプログラムで回避していました。アドカレ万歳!

まとめ

Voxelorer Birdで採用していた特殊なシーン切り替え方法と、Player Inputに全てを委ねて手抜きしたことが招いた問題でした。分かってみれば解決策はシンプルで、シーンの切り替え前にPlayer Inputを無効にするだけでした。状態切り替え時の余計な入力による不具合を防げるのでこの解決策は筋が良さそうです。

Input Systemは、一人用の非リアルタイムゲームのような環境だとオーバースペックで使いにくい印象があります。一人用の場合はどの入力デバイスでも操作できた方が楽です。システム設計も密結合で手を加えにくく、もう一段階の進化を願ってます。

以上、Unity Advent Calendar 2022 カレンダー2 の9日目の記事でした!

qiita.com

◆前日は chroske さんの 【Unity】ワープポータル転送演出の作り方【AdventCalendar2022】 - かつて代官山らへんで働いてたengineerのUnityブログ でした。

◆次の日は nkjzm - Qiita さんの「なんかかく」です。

クリスマスまであと16日!

関連・参考URL

GAMEJAMで作ったイノシシのギミックの作り方

この記事は Cluster Creator #1 Advent Calendar 2022 の6日目の記事です。

adventar.org

◆前の日は Sha-la /歌詠しゃら🧸Vシンガー🌷本垢凍結で一時避難中。 さんの clusterで音楽イベントを開いてみたいアーティストの方へ。

◆次の日は さな さんの 会話ロボ in cluster です。


先日開催されたCluster GAMEJAM 2022 in AUTUMNに参加しました。三回目にして初空振りだったと思ってたのですが(毎回自主トレやにぎやかし目的で参加してるので空振りでいいんですけど)、奨励賞をいただけてました!!手広く色々な賞を用意してくださっていて参加して楽しいゲームジャムです。

奨励賞!!

GAMEJAMでは前回の春の時は「天翔ける腕輪」で空飛ぶ腕輪とクマ。

cluster.mu

今回は「イノシシ★ダッシュ!!」で直進しかできないイノシシを作りました。

cluster.mu

Cluster Creator Kitを使えば様々な仕掛けが作れます。公式のテンプレートワールドはどのようなことができるのかや実装テクニックを知ることができる宝の山です。 上記の乗り物もテンプレートワールドのHorseをもとに作りました。この記事ではHorseを観察しながら機能を理解して、イノシシに改造するまでをご紹介します。 Cluster Creator Kit(以降、CCK)を使えるようにするための一助になれば幸いです。

目次

動作環境

  • Unity2021.3.4f1
  • 2022/12/1現在のCCKとCluster

乗り物作りの環境構築

自由にいじりまわせるUnityプロジェクトを作成して、そこに公式のテンプレートワールドを読み込みます(サンプルプロジェクトではありません)。以下の公式サイトの「すぐにワールド制作したい──テンプレートワールドを導入する」を参考にテンプレートワールドをUnityで開いてください。

creator.cluster.mu

テンプレートワールドは、「プロジェクトに含まれるアセットは cluster にアップロードする場合には、すべてクレジット表示不要で自由に使う」ことができるとても有難いものです。活用しない手はありません。

ダウンロードしたClusterCreatorKitTemplate-master.zipを展開して、フォルダーの名前を変更すれば(例えばNorimonoRensyuなど)複数のテンプレートワールドのプロジェクトを扱えるので便利です。

テンプレートワールドをUnityで開いたら以下のガイドに進みます。

creator.cluster.mu

「テンプレートワールド『乗り物』について」を参考にVehicleシーンを開きます。Playして用意されている乗り物を乗り回してみてください。ぱっと思い浮かぶ乗り物は一通り揃っていると思います。使えるようならそのまま利用してもいいですし、仕組みを観察すればCCKの活用方法を学ぶことができます。

イノシシの能力

イノシシは以下のようにします。

  • スペースキーで一定速度まで加速
  • スペースキーを離すと急停止
  • 加減速は着地時のみ
  • 左右旋回はできない

秋のゲームジャムでは上キーで等速で前進させていましたが、せっかくなのでイノシシらしく(?)加速させたいと思います。

既存の乗り物を観察する

一通り乗り物に乗ってみてイノシシに近いのはHorseなのでこれをベースにします。

Horseの階層

階層はこんな感じです。

Horseの階層

  • Horse...Character Controllerやトリガーなどの制御系のコンポーネントで構成
    • Horse...ウマのモデルオブジェクト。アニメもここ。grip_Lとgrip_Rが手の位置
    • Seat...腰掛ける位置を表すオブジェクト
    • Exit...降りた時の位置を表すオブジェクト
    • Sounds...乗り(GetOnSound)降り(GetOffSound)、着地(LandSound)を鳴らすためのオブジェクト

動きに関するコンポーネントを親オブジェクトにまとめて、モデルデータが子になっています。モデルの差し替えがしやすいUnityのオススメ構造になっていて助かります。

Horseのコンポーネント

ご覧の通りなかなかの量ですが頑張って確認していきます。

Horseのコンポーネント

Character Controllerで動くキャラクタの設定

Character Controllerで動くキャラクタの設定

Character Controllerで制御するキャラクターにするためのコンポーネントです。 パラメータは殆どなく、着地位置や当たる範囲を調整したい時にCharacter Controllerをいじるぐらいです。

乗り物の設定と旋回、移動

乗り物の設定と旋回、移動

Ridable Itemで乗り降りや腰掛ける位置、手の位置、下りる位置、乗った時のアニメを設定できます。

Steer Item Triggerは乗り物の操作入力のためのトリガーで、前後左右操作に加えて、スペースキーなどのAdditionalキーに変化があった時のシグナルと、入力値をトリガーとして送信することができます。

Set Angular Velocity Character ItemGimmickは操作入力で旋回させるギミック、Set Velocity Character Item Gimmickは同様に移動させるギミックです。

間に挟まってるItem Logicは移動を前後に制限するためのものです。入力したmoveInputをそのまま速度に設定すると左右キーでHorseが横移動してしまいます。Item Logicで上下入力だけmove.yに設定することで左右キーの影響を除外しています。

着地とジャンプ

着地とジャンプ

Horseで一番参考になったのがこの辺りでした。着地を確認するIs Grounded Character Item Triggerですが、地面のわずかなデコボコの影響で一瞬だけ空中にいると判定されることがしばしば発生します。そのまま使うとジャンプボタンを押してもジャンプしないことが頻発して操作性が落ちてしまいます。

そこで下から3番目の位置にあるItem Timerを使って、空中にいるかを表すisInAirへの着地状態の反映を0.15秒遅らせる仕組みになっています。ジャンプできるかどうかはisInAirがfalseかどうかで判定しているので、空中に浮いても0.15秒間はジャンプ可能で、その間に着地すれば空中に浮いていたことはチャラになります。ジャンプ開始時にisInAirをtrueにしているのでこの処理によって連続ジャンプすることもありません。

0.15秒後のチェック時に運悪く空中にいる可能性もありますが、ジャンプができなかったと感じることはないので対策として十分だと思います。

イノシシでも加速は着地時にしたいのでこの処理は活用します。

その他

残りは以下のような処理です。

  • 乗った時の演出のためのシグナル送信
  • 降りた時の演出と操作をリセットするためのシグナル送信
  • オーナーが変わった時に操作をリセットするためのシグナル送信
  • 操作のリセット処理

操作や状態を一括してリセットするItem Logicは便利で、作り方の参考になりました。

イノシシへの改造

Horseの機能は一通り把握できました。改造の方針は以下の通りです。

  • モデルをイノシシに差し替え
  • 前後左右操作、ジャンプは不要なので削除
  • Additionalキー(スペースキー)による加減速
  • 加速は着地時のみ

一つずつ手順をまとめます。

モデルをイノシシに差し替え

イノシシは3月のウクライナアセットバンドルで入手したLowPoly Wild Animalsのものを利用しました。前回のシロクマもこれだったと思います。

※これはアフィリエイトリンクです。

Horseのプレハブを複製してBoarに名前を変更します。SeatとExitの位置をモデルに併せて調整して、左右の手の置き場を表すLeftHandRightHandをモデルに追加しました。

イノシシモデルを設定

アニメーション関連は、HorseのモデルからAnimatorやギミックを手作業で移植しました。Animator Controllerは Animator Override Controller を作成してHorseのAnimatorを参照して、イノシシの該当するAnimationを設定しました。Set Animator Value Gimmickは、InspectorウィンドウからHorseのコンポーネントをドラッグしてHierarchyウィンドウのBoarモデルにドロップするのを片っ端からやりました。

おおよそ以上でモデルの対応完了です。Horseを非表示にするなどして動作確認をします。

イノシシに差し替え完了

前後左右操作、ジャンプの削除

Horseの構造から不要なものを削除していきます。ここに書いてないものは後で利用予定なので手を加えないようにします。

  • 上下左右キーでの操作はいらないのでSteer Item TriggerMove Input Triggersを消します。

移動に関する設定を-を押して削除

  • 旋回動作はないのでSet Angular Velocity Character Item GimmickコンポーネントをRemoveします
  • ジャンプは不要なので、Jump Character Item GimmickコンポーネントをRemoveします

以上で、乗っても移動やジャンプができなくなりました。

Additionalキー(スペースキー)での加減速

このブログの本丸である加減速を実装します。RigidbodyならAdd Force系のギミックで加速できるのですが、HorseはCharactor Controllerなので自前で実装する必要があります。

移動速度はSet Velocity Character Item Gimmickにおいてmoveキーで設定しています。Additionalキーが押されていたらmove.yに加速値を足し、離されていたら減速させれば加減速ができます。またmove.yに空気抵抗に見立てた値を掛ければ最高速度の制限ができます。

この処理は物理更新と似たような頻度で実行したいので、やや無理やりですがItem Timerを0.02秒ごとに呼び出し続けて処理することにします。

関連変数の初期化

  • KeyがResetInputItem Logicを探して開きます
  • moveInputは不要になったので削除します
  • ロジックを追加して、VelocityTimerという名前で型はSignalにして、式は=Constant, Boolを選んでチェックします
  • もう一つロジックを追加して、accelという名前で型はFloatにして、式は=Constant, Floatを選んで値を0にします

パラメータの初期化

速度を更新するためのタイマーを設定

  • 新規にItem Timerを追加します
  • TargetはThis, KeyはVelocityTimer, Delay Time Secondsは0.02にします
  • ロジックを追加して、TargetをCheckVelocityValueSignalにします

ItemTimerの始動

Additionalキーの変更時にaccelの値を設定

  • 新規にItem Logicを追加します
  • TargetをThis, KeyをOnAdditionalInputChangedにします
  • ロジックを追加して、Additionalキーの入力が0より大きかったらisAccelがtrueになるように設定します
    • 最初の行はThis, isAccel, Boolを設定します
    • 式は=GreaterThanにします
    • 1つ目をRoomState, Float, This, additionalInputにします
    • 2つ目をConstant, Float, 0にします
  • さらにロジックを追加して、先に設定したisAccelがtrueならaccelに加速値、falseなら減速値を設定します
    • 最初の行はThis, accel, Floatを設定します
    • 式は=Conditionにします
    • 1つ目をRoomState, Bool, This, isAccelにします
    • 2つ目をConstant, Float, 0.13にします
    • 3つ目をConstant, Float, -0.5にします

加減速をaccelに設定

タイマーで0.02秒ごとに呼び出される速度管理の処理

  • 新規にItem Logicを追加します
  • TargetをThis, KeyをCheckVelocityにします
  • ロジックを追加して、速度管理を持続させるためにタイマーを開始するVelocityTimerシグナルを送信します
    • ThisでKeyはVelocityTimerにして型はSignal
    • 式は=ConstantBoolでチェックします
  • ロジックを追加して、着地時のみに加減速するための設定をします
    • ThisでKeyはcurrentAccel、型はFloatにします
    • 式は=Conditionにします
    • 1つ目の設定の条件式はRoomState, Bool, This, isInAirとして、空中かどうかで判定します
    • 2つ目の設定はConstant, Float, 0を設定して、isInAirがtrueの時は空中なので加速しないようにします
    • 3つ目の設定はRoomState, Float, This, accelにします。これでisInAirがfalseで着地時にはcurrentAccelaccelが代入されるので加速か減速をします
  • ロジックを追加して、currentAccelをmove.yに加算します
    • ThisでKeyはmove.y, 型はFloatにします
    • 式は=Addにします
    • 1つ目の設定はRoomState, Float, This, move.yにします
    • 2つ目の設定はRoomState, Float, This, currentAccelにします
  • ロジックを追加して、減速しすぎてバックしないようにします
    • ThisでKeyはmove.y、型はFloatにします
    • 式は=Maxにして、move.yと0のうちの大きい方をmove.yの値にすることで、値が0より小さくなることを防ぎます
    • 1つ目の設定はRoomState, Float, This, move.yにします
    • 2つ目の設定はConstant, Float, 0にします
  • ロジックを追加して、move.yに空気抵抗がわりの定数をかけます
    • ThisでKeyはmove.y, 型はFloatにします
    • 式は=Multiplyにして掛け算をします
    • 1つ目の設定はRoomState, Float, This, move.yにします
    • 2つ目の設定はConstant, Float, 0.95にします

速度管理のItem Logic

以上で完了です。スペースキーなどのAdditionalキーに該当する操作でイノシシが加速するようになりました。

成果物は以下でご確認いただけます。こちらはもう少し改造して、上キーでも加速するようにしています。

cluster.mu

まとめ

公式テンプレートから実装したいものに近いものを探して観察し、改造することで独自の乗り物や仕掛けを作る手順をご紹介しました。Character Controllerはそのまま使うと等速移動になりますが、自前で速度計算をして加減速に対応させました。またサンプルテンプレートの着地判定を利用することで、苦労せずに着地時のみに加減速する動きが実装できました。

実装している中で機能として欲しいと思ったのは以下の2つでした。

  • Set Animator Value Gimmickに別のゲームオブジェクトのアニメーターを設定したい - これによりアニメギミックを親オブジェクトなどのモデル以外のオブジェクトに構築することで、モデルの差し替えがより簡単にできるようになるのではと思います
  • Is Grounded Character Item Triggerの不安定さをトリガーコンポーネント自体で吸収して欲しい

以上、Cluster Creator #1 Advent Calendar 2022 の6日目の記事でした。創作の一助になれば幸いです。

adventar.org

◆前の日は Sha-la /歌詠しゃら🧸Vシンガー🌷本垢凍結で一時避難中。 さんの clusterで音楽イベントを開いてみたいアーティストの方へ。

◆次の日は さな さんの 会話ロボ in cluster です。

関連・参考URL

デジゲー博2022出展してきました&5年間の感謝

まずはデジゲー博10周年、おめでとうございます。自分は2018年から参加をはじめた中途組ですが、毎年当選という幸運に恵まれてデジゲー博の歴史の半分である出展5周年(?)を迎えました。デジゲー博は自分にとって年末年始のようなイベントになりました。

11/13(日)に秋葉原UDXにて開催されたデジゲー博2022の展示が完了したので簡単な振り返りです。

目次

展示ブースと設営

去年一昨年と1机1ブースで贅沢に使えましたが例年に戻りました。

といっても2ブース分の時も密を避けるために1ブース分の幅で展示してたので特に変わりなし。去年、撤収で苦戦したので今年はイメージトレーニングをして荷造りや出す順番を考えて設営にあたりました。

前日

前日はPCなどは持ち込まずに展示台や小物の設置をしました。

  1. 展示台(タンスの整理用の棚)の袋から小物を全て出して机の上に並べて置く
  2. 展示台を組み立てて机の上に設置
  3. 布を被せて洗濯ばさみで固定
  4. 机に並べていた小物類の設置開始
  5. 展示台の上に名刺入れ、スマホスタンド、イーゼル、粘土細工、マウスパッドを並べる
  6. これ以降、空き箱や袋は中身を取り出し次第、元の入れ物に戻す
  7. イーゼルにB4のちらしを立てかけ
  8. ポスター立てを組み立ててポスター設置
  9. 最後に展示台入れの袋を縛るための紐類を袋の一番手前にしまう

以上で前日設営終わり。おおよそ30分程度でした。

自分のブースの前にProject ICKXのどデカ筐体が設営されててめちゃくちゃ楽しそうでテンション上がりました!

当日

展示当日は9時半過ぎに会場に到着しました。

9時45分ぐらいから設営を始めたと思います。

  1. 机でルキグラの箱を開けてケーブルを取り出して中敷きをしまい、本体をケースから出す
  2. ケースを箱に戻して机の下に片付け
  3. ルキグラを展示台上で組み立ててケーブル接続
  4. AndroidiPadを取り出してスマホスタンドに設置
  5. PCを取り出して机に設置
  6. 電源ケーブルを机の上のよき位置に置いて給電
  7. ルキグラ、スマホのケーブルをPCに接続
  8. Voxelorer Bird起動

以上で40分程度で設営完了。

sketchfab.com

雑にフォトグラメトリした展示ブース。

ルキグラとAndroidiPadのケーブルが全てType-Cで、ノートPCのType-Cが2口だったので口が足りないと当日気づきました。念のために持って行っていた手持ちのiPhone用の給電セットが役に立ちました。備えあれば患いなし!しかし改めて考えるとルキグラに電源コネクタが付属してたのでそれ使えばよかったのでした。

当日設営は忘れ物が怖いので避けてますが、どうしても当日となった時は9時半着ぐらいなら間に合わせられそうな手応えでした。

入場開始前

入場が始まれば終わるまでほぼブースに詰めっきりになるので、少しご近所の作品を遊んだり、ご挨拶に回ったりしました。ご挨拶に来て下さった皆様、ありがとうございました!!

展示本番

自分のブースは比較的静かな感じでした。これまでは缶バッジくじをやったり、WebGLのお持ち帰り版を配ったり、テスト招待を配ったりしてきましたが、今年はリリース方針の検討中で新しいことがあまりなかったので積極的にお声掛けしたりカードを配ることはせず。気づいて足を止めて下さった方に遊んでいただきました。

お昼過ぎに体調不良で一時ブースを離脱。周りの方やスタッフの皆様にはご心配とご迷惑をおかけしました。14時半ぐらいに復帰して後半戦へ。

体調不良の原因は、準備の疲労が溜まっていたところに当日のハイテンション+ルキグラの画面を覗き込むために無理な体制で前かがみを続けていたことの合わせ技だろうと考えてます。次の日はふくらはぎが筋肉痛になってました^^; 例年はUnity上で実行したものをルキグラに映していたのでプレイの様子は手元のPCで確認できました。今年はシーンの切り替え中に画面が乱れる症状があったことと、そこそこしっかりとまとめられていたので滑らかに動作するビルド版で展示をしたのですが、ブース裏から様子を確認することができなくなりました。無理な姿勢でルキグラを長時間覗き込むことで体の疲労が一気に押し寄せてきた感じでした。

ということで復帰後は無理をしないようにUnity上でルキグラ版を動かして覗き込まなくて済むようにしました。やや画面が乱れたり操作の反応が悪くはなりましたが、運用はとても楽になりました。ビルド版でも手元で画面を見れるようにするという課題が見つかりました。

現場復帰後は体調が悪化することはなく、ご挨拶に来て下さった方々と情報交換をしたりして楽しく展示を終えました。

撤収

撤収手順を検討してきていたのでそこそこのペースで片付けが済みました。今回はスーツケースなしで、展示台袋、ルキグラ袋、PCリュックにまとめられたのがよかったです。

展示台袋の下に滑車を付けたら楽かなと思ってつけてみたのですが、小さすぎて袋を引きずってしまうので殆ど役に立たず。袋の下面を保護するパーツと大きめの滑車にして確実に滑車で転がせるようになると楽になるかも、というのを考えています。

いただいたコメント、展示での気づき

展示していていただいたコメントや気付いたことなど。

  • スクロール操作が誤って発動してタップ操作がうまくいかないことがしばしば発生。スクロールは殆ど不要なので操作の割り当てを変えることや設定項目を作るなど遊びにきてくれたO関君とあれこれ検討しました
  • 去年のもので十分にリリースして大丈夫、というご意見を頂戴しました。ありがとうございます!
  • ルキグラと相性の良い、かわいい、そこにある感がよい

かわいいかわいいと連呼しながらクリアしていただいたのが印象的でした。この世界を広げていきたいと実感しました。

以下、気付いたことなど。

  • ステージが多すぎた。試遊版は3ステージ程度の軽いものにして、その先はお持ち帰り版やアプリで、とするのがよさそう
  • ルキグラ版はミラーリングで手元で画面を確認できるようにする
  • 自動デモはとてもよかった
  • しばらく操作がなかったらタイトルに自動的に戻す機能を入れる
  • Undoやブロックの移動バグは発生しなかった
  • ブロックの色やデザインを一新していたが操作に迷ったりする方はいなかったので問題なさそう
  • 氷の仕掛けに気づけない方がいらっしゃった。滑って失敗した時のヒントメッセージは必要
  • ルキグラの給電は電源からできる
  • ポスターが応対の邪魔かも

おおよそこんな感じでした。カードの配布枚数は40枚ほど。途中離脱があったり積極的にお声掛けしなかったこともあり例年の2/3ぐらいでした。

次回に向けて

去年までは広告付きのリリースを目指していたのですが、世界中で変わる法律への対応やSDK変更によるメンテの手間や遊ぶ前の規約の煩わしさ、低年齢層の方に遊んでもらいにくくなるというデメリットがどうにも気になりました。そこで6月ぐらいにリリースの方針を以下のように見直すことにしました。

  1. パズル部分のみで構成した教材用プロジェクトをGitHubで公開し、広告もアナリティクスもなしの無料版をアプリストアで配信。これなら面倒なしにお子さんに遊んでもらえます
  2. 無料版の設計やプログラムの解説書籍を販売する
  3. 仕掛けやストーリーを追加した有料版を出す。買い切りで広告もアナリティクスもなしで規約をシンプルに

無料版を書籍や有料版への呼び水にすることで腑に落とすことができました。

デジゲー博への応募の時点では無料版の公開はできそうかなと考えていたのですが、公開に向けた諸々の技術調査やシステムの見直し、8,9月にやったゲームジャムマラソンなどで大幅に作業が遅れて今回の展示になりました。来年も幸運に恵まれて当選できた暁には本来の今年の目標であった無料版の公開を目指しつつ、あわよくば書籍や有料版も間に合えばと考えています。

いただきものなど

今回は10周年ということでデジゲー博パーカーをゲット!ご挨拶でいただいたパンフなどを添えて。

最後に

改めて、デジゲー博10周年おめでとうございます。年に1度、対外的に発表する機会が持てたことは活動に大いにプラスでした。Voxelorer Birdはデジゲー博の当選がきっかけで生まれた企画なので成長を今後も展示していきたいです。1年の節目になるイベントとして今後もますますの発展を祈念しております。

ブースに遊びに来て下さった皆様、ありがとうございました。もくもく会での縁を確認できたり、チュートリアルを活用していたお礼をお伝えできたり、何年か分からないぐらいぶりにお話できたり、毎年学校の学園祭で後輩を叱咤激励した上にこちらにも遊びに来てくれたりと刺激を得られました。

設営と撤収は手順も固まって落ち着いてできるようになりました。それと同時に、手元で進行を確認できるようにしたり、自動的にタイトルに戻すなどもう一工夫の部分が見つかったのは収穫でした。

近くのブースの皆様やデジゲー博のスタッフの皆様には体調不良でご心配とご迷惑をおかけしました。良くしていただいて大変助かりました。基本的に座ってお客様対応ができるような対策を検討して再発防止に努めます。

来年は当選できるのか、何が展示できるのか、或いは会場に遊びに行くのか今は分かりませんが、何らかの形で参加したいと考えております。

UI BuilderによるEditorWindowのデザインと新規シーンを作るエディタ拡張

エディタ拡張機能を使うと手軽にUnityエディタに機能を追加することができます。エディタのウィンドウはUI Builderというビジュアルエディタで手軽に作ることができます。UI Builderを利用した簡単なエディタ拡張の導入と、新規シーンの作成に少々手間取ったのでその方法をまとめます。

UI Toolkitによるエディタ拡張の導入については以下のマニュアルが分かりやすいです。

docs.unity3d.com

目次

動作環境

このブログはUnity2021.3.4f1で操作しています。UI Builderは2019.4にはあったので、Unity2019.4.x以降のバージョンならおおよそ動くと思います。

やりたいこと

名前を指定してシーンを作成して、そのシーンにシーン名+Behaviourの名前のオブジェクトを作成します。シーンの作成先のフォルダーはダイアログを表示して選択できるようにします。

エディタウィンドウは、Toolsメニューから AM1 > Create New Scene を選択して表示するようにします。

エディタウィンドウにはシーン名の入力欄と Create ボタンを置きます。Createボタンはシーン名が入力されるまでは押せないようにします。

作りたいエディタウィンドウ

以上のようにエディタを拡張します.

エディタウィンドウに必要なファイルを生成

エディタウィンドウのためのC#スクリプトとUXMLファイルを作成します。

  • Projectウィンドウの + から UI Toolkit > EditorWindowを選択します

C#, UXML, USSの3種類のファイルを同時に作成することができます。UXMLはエディタウィンドウの構造、USSはスタイルを定義するものです。UXMLはHTML、USSはCSSと位置づけが近いものです。

EditorWindow作成ダイアログ

  • 今回はUSSは利用しないのでチェックを外します
  • C#欄にNewSceneEditorWindowと入力します。UXML欄も自動的に設定されます
  • Confirmボタンを押して、ファイルが作成されるまでしばらく待ちます

以上でEditorフォルダーが作成されて、その中に指定のファイル名でC#スクリプトとUXMLファイルが出力されます。

作成されたエディタスクリプトとUXML

作成されたC#スクリプトには確認用にメニュー呼び出しが実装されています。メニューで以下を選べば新規作成したエディタウィンドウを呼び出せます。

  • Windowメニュー > UI Toolkit > NewSceneEditorWindow

デフォルトのエディタウィンドウ

ウィンドウには、C#スクリプトで追加されたラベルとUXMLファイルで追加されたラベルが表示されます。

エディタウィンドウのデザイン

UI Builderでウィンドウのレイアウトを作ります。

  • ProjectウィンドウのEditorフォルダーからアイコンが</>になっている方のNewSceneEditorWindowをダブルクリックします

UXMLファイルをダブルクリックするとUI Builderウィンドウが開きます。Visual C#のようにデザインを確認しながらウィンドウを作ることができます。

UI Builderウィンドウ

エディタ機能を有効にする

UI Toolkitはランタイムでも使えて、エディタとは使える機能が違います。今回はエディタとして使うのでそのための設定をします。

  • UI Builderの左のHierarchyで NewSceneEditorWindow.uxml をクリックして選択します
  • UI Builderの右のInspectorの表示が NewSceneEditorWindow のものになるので、 Editor Extension Authoring 欄にチェックを入れます

「これ以降はこのウィンドウはエディタモードでしか実行できません」というような警告が表示されますが問題ないのでそのまま進めます。この設定をすることで、ウィンドウ左下のLibraryにエディタで使えるコントロールが追加されます。

画面を編集する

最初のラベルは不要なので消します。

  • Viewportで「Hello World! From UXML」と書いてあるラベルをクリックして選択します
  • Deleteキーを押して削除します

次にシーン名の入力欄を追加して設定します。

  • ウィンドウ左下のLibraryから Text Field をダブルクリックします。Viewport上にテキストボックスが追加されます
  • Inspectorで以下を設定します
    • Name欄にSceneNameと入力します
    • Label欄にシーン名と入力します
    • Value欄とText欄に入力されている文字を消して空欄にします

SceneName欄

これでシーン名の入力欄はできあがりです。同様にCreateボタンを作ります。

  • Library欄からButtonをダブルクリックして追加します
  • Inspectorで以下を設定します
    • Name欄にCreateButtonと入力します
    • Text欄にCreateと入力します

以上でエディタウィンドウは完成です。Ctrl + Sキーを押して保存したら、UI Builderウィンドウは閉じて構いません。

コントロールに機能を仕込む

Visual C#のようにUI Builderから直に機能を仕込むことはできません。先に作成したC#スクリプトを開いて実装します。

呼び出しメニューの設定

呼び出すメニューを予定の場所に変更します。

  • Projectウィンドウの Assets > Editorフォルダー内の NewSceneEditorWindowC#スクリプトをダブルクリックして開きます
  • メニューはMenuItem属性で編集できます。ShowExample()メソッドの上にある Window/UI Toolkit/NewSceneEditorWindow を呼び出しているMenuItemを変更します。ついでに ShowExample() という名前をShowNewSceneWindow()に変更します
    // 9:
    [MenuItem("Tools/AM1/Create New Scene")]
    public static void ShowNewSceneWindow()

上書き保存してUnityに戻ると、先ほどあった Windowメニューの UI Toolkit > NewSceneEditorWindow メニューが消えています。代わりに Tools メニューが追加されて、 AM1 > Create New Scene と選べるようになります。Create New Sceneを選べば UI Builder で作成したエディタウィンドウが表示されます。

エディタウィンドウの呼び出し

コントロールの状態管理とイベント登録

シーン名が入力されていない時はCreateボタンを無効にしたり、Createボタンを押した時にCreateScene()メソッドを呼び出すようにスクリプトを追加します。追加先はCreateGUI()メソッドです。

サンプルが用意したラベルを追加する以下の3行は不要なので消します。

// 21:
        // VisualElements objects can contain other VisualElement following a tree hierarchy.
        VisualElement label = new Label("Hello World! From C#");
        root.Add(label);

管理しやすいようにコントロールインスタンスを取得しておきます。9行目付近にインスタンス変数として以下を定義します。

// 9:
    TextField sceneNameText;
    Button createButton;

CreateGUI()メソッドの最後にあるroot.Add(labelFromUXML);の下に以下を追加します。

// 29:
        // コントロールのインスタンスを取得
        sceneNameText = root.Query<TextField>("SceneName").First();
        createButton = root.Query<Button>("CreateButton").First();

rootVisualElementのインスタンスからQueryを使ってコントロールインスタンスを取得することができます。このメソッドは結果をリストで返すので、最初の1つだけ取り出すために最後にFirst()を付けています。

NewSceneEditorWindowクラス内に以下のメソッドを追加します。

// 34:
    /// <summary>
    /// コントロールの状態を更新。
    /// </summary>
    void UpdateControl(InputEvent ievt)
    {
        createButton.SetEnabled(!string.IsNullOrEmpty(sceneNameText.text));
    }

    /// <summary>
    /// 新規シーンの作成
    /// </summary>
    void CreateScene(ClickEvent cevt)
    {
        Debug.Log($"シーン{sceneNameText.text}を作成する予定");
    }

UpdateControl()メソッドは、シーン名が未入力かどうかでCreateボタンの有効か無効化を切り替える処理です。CreateScene()メソッドにはあとでシーンの作成処理を実装することにして、とりあえずログにメッセージを表示しておきます。

メソッドができたらそれらを登録します。CreateGUI()メソッドに追加したインスタンスを取得するコードの下に以下を追加します。

// 33:
        // コントロールの状態を更新
        UpdateControl(null);

        // 処理を登録
        sceneNameText.RegisterCallback<InputEvent>(UpdateControl);
        createButton.RegisterCallback<ClickEvent>(CreateScene);

以上できたら上書きしてUnityへ切り替えます。NewSceneEditorWindowを表示するとCreateボタンが無効になります。シーン名を入力するとCreateボタンが押せるようになり、ボタンを押すとログにメッセージが表示されるようになります。

イベント登録

以上でウィンドウの動きが実装できました。

コントロールごとのRegisterCallbackで使えるイベントについて

UI Toolkitには様々なコントロールがありますが、各コントロールでどのイベントが登録できるかをどこで調べればよいかが分かりませんでした。

困った時はChangeEvent<>に扱う型をジェネリックで渡せばよさそうです。EnumFieldの変更を受け取りたい時に、ChangeEvent<System.Enum>とすることで登録することができました。

どこかに資料がまとまっていたらご教示いただけると助かります。

シーン作成

本丸であるシーン作成をCreateScene()メソッドに実装します。

保存先のフォルダーを選択

シーンの保存先のフォルダーを選択します。フォルダーの選択にはEditorUtility.SaveFolderPanel()を使います。フォルダーを選択すると選択したパスが文字列で返され、キャンセルしたら空文字が返されます。空文字が返されたら何も処理せずに戻るようにしておきます。

先に追加したCreateScene()メソッド内のDebug.Log()を削除して、以下のコードを追加します。

// 52:
            // フォルダー選択
            string folder = EditorUtility.SaveFolderPanel("保存先フォルダー", "" , "");
            if (string.IsNullOrEmpty(folder)) return;
            createButton.SetEnabled(false);

オブジェクトやシーンの作成中にアセットの再読み込みなどが発生するため、ボタンが押せる状態のままだと何かと問題が起きがちです。処理を始める前にボタンを無効にしています。

Unityのエディター拡張で新規シーンを保存しようとするとエラーが出る

シーン作成の時に苦戦したのがこの部分でした。当初は保存先とシーン名を指定するためにEditorUtility.SaveFilePanel()EditorUtility.SaveFilePanelInProject()を試したのですが、保存先を指定すると書き込み権限がないというようなエラーが出ることがあり、動作が不安定になりました。作成するシーン名は予め入力しているので、保存先のフォルダーさえ分かればいいということでSaveFolderPanel()に変更してSaveScene()メソッドで保存することで安定して動くようになりました。

新規シーンの作成

新規シーンはEditorSceneManager.NewScene()メソッドで作成できます。このメソッドを利用するためにスクリプトファイルの上の方に以下のusingを追加します。

// 5:
using UnityEditor.SceneManagement;

フォルダーの選択処理に続けて以下を追加します。

// 57:
            // 新しいシーンを作成
            var newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive);

空のシーンを追加シーンとして作成するコードです。引数でデフォルトオブジェクトを配置したり、現在のシーンを解放して作成したシーンのみを開くこともできます。作成したシーンのインスタンスは保存時に使うのでnewSceneに代入しておきます。

テンプレートからシーンを作成する方法はコガネブログさんの以下の記事が分かりやすいです。

baba-s.hatenablog.com

オブジェクトの作成

オブジェクトを作成します。上のコードに続けて以下を追加します。

// 60:
        // オブジェクト作成
        var go = new GameObject();
        go.name = sceneNameText.text+"Behaviour";
        Undo.RegisterCreatedObjectUndo(go, $"Created {go.name} Object.");

new GameObject();を実行すると、空のゲームオブジェクトがアクティブシーンに作られます。先にNewScene()で作成したシーンは自動的にアクティブシーンになっているので、このままで新しく作成したシーンに作ったゲームオブジェクトが配置されます。

オブジェクトを作成したことをUndoのシステムに登録するためにUndo.RegisterCreatedObjectUndo()を呼び出します。これによりオブジェクトの作成をUndoしたり、シーンが更新されたことをシステムが把握できます。

新規にオブジェクトを作成するのではなく、プレハブを読み込んで配置する場合はおもちゃラボさんの以下のブログをご覧ください。

nn-hokuson.hatenablog.com

シーンの保存

作成したゲームオブジェクトにAddComponent()で必要なコンポーネントをアタッチしたり、その他のオブジェクトやプレハブを配置してシーンを完成させたら保存します。シーンはEditorSceneManager.SaveScene()で保存します。保存先のフォルダーは作成済みである必要があります。またフォルダーはプロジェクトフォルダーからの相対パスで指定します。

Pathを利用するためにスクリプトファイルの上の方に以下のusingを追加します。

// 6:
using System.IO;

オブジェクトの作成後に以下を追加します。

// 66:
        // シーンの保存
        string scenePath = Path.Combine(folder, sceneNameText.text + ".unity");
        var relPath = "Assets/" + Path.GetRelativePath(Application.dataPath, scenePath);
        var path = AssetDatabase.GenerateUniqueAssetPath(relPath);
        EditorSceneManager.SaveScene(newScene, path);
        AssetDatabase.Refresh();

        sceneNameText.value = "";

選択したフォルダーとシーン名に.unity拡張子をくっつけて保存先のパスをscenePathに代入します。SaveScene()はプロジェクトフォルダーからの相対パスを指定しますが、scenePath絶対パスなのでApplication.dataPathからの相対パスを取得して、先頭にAssets/をくっつけた相対パスrelPathに代入します。シーン名が重なっていても問題が起きないようにAssetDatabase.GenerateUniqueAssetPath()を使ってファイル名を調整した後、シーンのインスタンスと作成したパスを指定してシーンを保存しています。最後に作成したシーンをエディタに認識させるためにAssetDatabase.Refresh()を実行して、シーン名を空にして完了です。

保存してUnityに切り替えれば作成したエディタ拡張が動作します。

まとめ

UI Builderでエディタウィンドウを作成して、UI ToolkitのC#スクリプトで機能を実装しました。また、保存先のフォルダーを選択して自動で新規シーンを作成してオブジェクトを配置するコードを紹介しました。

エディタ拡張については以下のドキュメントでざっと基本は把握しました。

docs.unity3d.com

UI Builderの始め方やコードでの呼び出し方、シーンの保存など、ドキュメントを探すのに時間がかかったあたりをこの記事でまとめました。現在、これらを使って自家用フレームワークを手軽に組み込めるエディタ拡張を開発しています。

参考・関連URL

今回作成したコード

GDevelop Game Jam #2に参加しました!

7月末の早朝、 itch.io さんのリツイートが目にとまりました。

ゲームジャムと言う目標があると張り合いがあるし、1週間ぐらいなら夏休みの自由研究として丁度良さそう。ということで取り組んだ成果物が以下のゲームです。

キーボードとマウス操作で、WASDキーか矢印キーで移動、マウスでエサを投げます。お墓を舞台にしたボコスカウォーズ的なシュール系シューティングゲームです。評価期間は日本時間の8/13(土) AM4時までなので間に合わないかもしれませんが、遊んで評価を投稿いただけると嬉しいです!!

itch.io

勉強の仕方や開発の流れ、GDevelopを使ってみての感想などをまとめてみました。

目次

はじまり

冒頭のツイートを見た7/30はちょこっとサイトを覗いたりチュートリアルを眺めたぐらいで別のことをしてたと思います。実際に触り始めたのは7/31の午前。

無料で簡単なゲーム制作アプリ | GDevelop

オンラインで試せる!!

オンラインで試せるのはめっちゃ楽!「チュートリアルをフォロー」から How To Make a Platformer のチュートリアル動画を見ながらブラウザー上で試してみました。

俺はPlatformerで行く!!

動画は3本で合計20分程度。動画を見ながら1時間足らずでプラットフォーマーゲームが作れてしまいました。GDevelopのチュートリアル動画は充実していて、1本あたりの長さが数分にまとめられているのでとても見やすいです。英語ですが操作は動画を見れば分かるので問題ない気がします。

GDEVELOPER WIKIチュートリアルなら日本語化されています。内容が少し違うので、こちらのプラットフォーマーチュートリアルも試してみました。

wiki.gdevelop.io

GDevelopのデスクトップ版向けの内容でしたがWebブラウザ上でやりました。Webブラウザーだと画像のアップロードが少々面倒なのでチュートリアルで紹介されていた素材は使わず、アニメーションの画像追加時に利用できるアセットストアからそれっぽい画像を選んで利用しました。アセットストアで手軽に素材が探せるのも大きな魅力です。チュートリアルは、アクション名などが実際のツールと異なっていたり、オブジェクト名やアニメ名が日本語だとエラーになるなど一部読み替える必要はありましたが、大きな問題はなく無事に完了できました。

Webブラウザー版での保存は、プロジェクトのjsonファイルをGoogleドライブにアップロードするか、エクスポートしてダウンロードすることになります。GoogleドライブのUIは暫定的な感じで指定がしにくかったのでエクスポートしました。が、エクスポートしたものはどのように読めばいいのか・・・。この辺りがWeb版で作業する限界そうです。ここまでで問題なさそうならデスクトップ版をインストールしちゃいましょう。このインストールがまたお手軽で、自分だけインストールを選べば管理者権限が不要です!!Webブラウザー上でエディターが動くことと、管理者権限がなくてもインストールができるのは最高です。

これから先の開発はデスクトップ版で行いましたが、ちょっと機能を試したり実動サンプルを見たりする時にWebブラウザー版は便利で今も活用しています。

GDevelopの使い方や簡単なゲームの作り方を把握するには午前だけで十分でした。ちなみにWikiの基本事項はこの時点ではまだ読んでません。開発するゲームによって必要な機能が異なるため、まずはGDevelopが得意そうなジャンルを確認して、企画を決めてから必要そうな機能をみつけて勉強していくようにしました。

企画検討

7/31の就寝前に軽く企画を考えました。考えたのは以下の2案です。

Is that your pet? (それはあなたのペットですか?)

1対1で動物と対峙して、相手の攻撃を防いだりエサを投げたりして手懐けられたらステージクリアです。

Is that your pet?案

勝ったら「Yes! That is your pet!! (そうです。それはあなたのペットです!!) 」、負けたら「You were a bait... (あなたはエサでした) 」とか表示するとか。タイトルや結果のテキストはよさそうに感じましたが、バリエーションを用意するのがしんどそうなのと、ゲームの動かし方のイメージがまとめきれなかったので保留しました。カードゲームとかサイコロゲームにする方向性もありそうでしたが、いずれにせよ素材の用意が大変なのでボツでした。

Haunted Animals in The Cemetery (墓場のお化け動物たち)

2案目が完成させたゲームの案です。

Haunted Animals in The Cemetery案

ハイパーカジュアルでよくみる数字が増えていくブロック崩しとか仲間が増えていく系です。敵にエサを食べさせて手懐けるのがなんとなく今回の自分的なコアだったので、体当たりではなくシューティング要素を導入しました。こちらはプレイヤー、敵1種類、ペット1種類、エサ、背景、墓ぐらいでいけそうで、ゲーム内容も具体的に思い浮かびます。翌日に改めて検討することにして就寝しました。

企画の整理と調査

8/1、前夜に考えた案のざっくりイメージから。

ゲーム画面は360x640の縦画面にして、黄色がプレイヤー、赤がエサ、白が敵、灰色が墓石です。ハイパーカジュアルのゲームを思い浮かべてキャラは小さめにして、キャラが沢山出てくるようにという狙いです。この落書きからキャラを24x24ピクセル、墓石を32x32ピクセルの大きさに決めました。

操作方法や基本的な動き方をNotionでまとめたあとは技術調査です。プレイヤーの移動はGDevelopが最初から用意してくれているトップダウンビヘイビアで行けそうです。画面切り替え方法、シーンの初期化、マウスを狙った弾の撃ち方、演出、スクロールなどなどを調べていきました。今回のゲームの基礎は The Conviction of GUN DUDE のチュートリアルに詰まってました!

夕方ぐらいまでチュートリアルを(遊んだり)見まくったりしながらTodoリストやら仕様やらを作成。それからGitHubリポジトリー登録して開発を開始しました。

開発進行

開発については書き始めると長くなりそうなので別記事ということにして流れだけまとめます。

7/30(0日目)

  • 早朝
    • GDevelopとそのゲームジャムが開催されることを知って興味を持つ

7/31(1日目)

  • 午前
  • 就寝前
    • アイディア出し

8/1(2日目)

  • 日中
    • 仕様まとめと状態遷移、マウス操作などの技術調査、Todoリスト作成

8/2(3日目)

  • 午前
    • 状態遷移の実装

  • 午後以降
    • 外部関数やビヘイビアの調査、フェードの改良、スコア管理、リーダーボードの組み込み開始

8/3(4日目)

  • 午前
    • リーダーボードなどを含むゲームループ完了
  • 午後
    • 音周り実装、プレイヤー操作、カーソル操作、仮アニメ、1つエサ投げ

8/4(5日目)

  • 午前
    • エサ投げ続き
  • 午後
    • 出講のため作業無し

8/5(6日目)

  • 午前
    • スクロール関連
  • 午後

8/6(7日目)

8/7(8日目)

  • 午前

  • 午後
    • 東京ゲームダンジョンに遊びに行く。元気を得て帰宅
  • 21:35
    • 演出を入れて、最小版をゲームジャムに提出!
  • 26:00
    • **今回のプロジェクト、完了!

GDevelopの良い点、気になった点・不明点

1週間使ってみてのGDevelopへの感想です。

良い点

沢山あるのでざっと思いついたところを。

  • インストール不要のWebブラウザ版エディターで機能が一通り試せる
  • デスクトップ版が管理者権限なしでインストールできるお手軽さ
  • HTML5ビルドのみなら制約なく無料で使える
    • 他のビルドはお値段によって1日の回数制限があります
    • 無料だとデバッガー使う時などにちょいちょいお支払い確認のダイアログが表示されます
  • プラットフォーマートップダウン系のゲームを開発するための便利機能が揃っていてすぐ作れる
  • アセットストアで簡単に素材を入手できる
  • チュートリアルが充実
  • 物理エンジン、Tween、パーティクル、ブルームを含む画面エフェクトなど、予想以上に表現力が高く、また手軽に使える
  • HTML5ビルドが超速。下手すると1秒程度で終わる
  • Liluoにはツールからアップして公開ができる。itch.ioへの公開も楽

コントリビュート案

GDevelopはオープンソースなので、不満は言うものではなくコントリビュートするものだ!ということで、気になった部分を改善・解消できそうな機能案です。コミュニティを全然把握していませんし、本気でやることを検討しているのではなく、ちょっと思いました程度のものです。

  • テキストオブジェクトのAlignを幅基準に変更
  • 日本語モードでも英語のコマンド検索を有効にする
    • 日本語にわざわざ変換して「変数」とか検索するのが辛いので....
  • Tweenの時間の単位設定の追加
    • 他は秒が基本なのに、Tweenだけミリ秒指定で何回もハマったため
  • 式エディター内でのネストした構造体や配列の補完
  • 構造体の要素変数の並び順の設定(変数は自由に並び替えできました。2022/8/18追記)
    • 自動的にアルファベット順位並び替えるのをやめてほしい。構造体の要素変数の並び方は自分で選びたい
  • 繰り返しの設定を条件にも入れる
    • 今はイベントを右クリックして、他を追加 から選ぶようになっていますが、条件内にあっていいと思うもので
  • 変数にコメント欄を追加
    • 変数にコメントは必要だと思っているのですがそうでもないですかね
  • イベントエディターで、オブジェクトが全てのオブジェクトなのか、条件に合致したオブジェクトなのか、インスタンスごとなのかを表示したい
  • アニメーションをPiskelで編集する際、既存の画像を他から指定したものを保存する時、上書き保存ではなく名前を付けて保存ダイアログを出す
  • シーンエディターのプロパティの拡充
    • 色や透過度、非表示、センタリングなどのデザインまわりはシーンエディターで完結できるようにしたい
  • ベクトルと行列の拡張
    • ベクトル好きとしてはGDevelopにベクトルがないことに愕然としました。2Dだってベクトルがあった方が遥かに楽です。XとYを別々に宣言するとか面倒で嫌な訳です
  • 各種座標指定の強化
    • 中心座標、当たり判定バウンディングなどを条件やアクション、式の中で自由に使いたい

Tweenの時間の単位設定などの実際にできそうなものから、シーンエディターのプロパティとかは無理っぽいものまであれこれ書きました。まずはコミュニティをROMったり、リポジトリーをクローンして眺めたりして実現できそうか見極めてみます。

気になった点

その他、気になった点です。

閉じたイベントが見にくい

デフォルトのテーマであるGDevelop default Darkの時のイベントの閉じているアイコンの見え方は以下の通りです。

GDevelop default Darkだと閉じたアイコンが見えない!

赤で囲まれた部分はイベントを畳んでいるのですが、アイコンが全然見えません。危うく「ここ空っぽじゃん」と思って消そうとしたり、「あの処理は一体どこに書いたっけ・・・」と行方不明になることが何度かありました。一通り確認してみたのですが、畳んだ状態が見やすいのはGDevelop default Lightのみでした。

これなら見える

ダークの方が目に優しいので、色のカスタマイズ方法を探してみるつもりです。

変数とコードが分かれているのが面倒

処理を書きながら必要な変数に気づいた時に変数ウィンドウを開くのが地味に面倒でした。全エディター画面がフローティングウィンドウならめちゃくちゃ便利なのですが流石にそれは贅沢がすぎる望みですね。素直にショートカットを覚えます。

定義しない変数が使える

変数を定義せずに使えるのは手軽な反面、タイプミスをしてもエラーにならないので問題の発見に時間がかかります。これはJavaScriptの仕様なのでやむを得ず。理解して気を付けるしかありません。

PiskelのUndo

「塗るの失敗しちゃった。Undoしよ」とやったらGDevelopごと落ちました。検索しても問題になってなさそうなのでうちのPCの問題っぽいですが、何回か発生したのでUndoは封印しました。

次回に向けて

濃厚な一週間で収穫が盛り沢山でした。他の参加者の皆さんの作品を遊んで感じたことや、終盤でようやく気付いた機能など、次回に向けて書き残しておきます。

Bloomを使う

最初の技術調査で見落としていて今回はBloomが使えない想定で画面を検討していました。Bloomが使えるならデザインが違っていたと思います。次回はBloomを使ったプリミティブなデザインを試してみたいところです。やっぱドット絵を描くのは辛い・・・

フレームワークは開始前に作っておく

1週間のうち3日程度はフレームワークに費やしていました。ハイスコアを一度登録しのがすと再度の登録ができないようなまずい仕様になっているのに気づかなかったりしましたし、この辺りは事前に整備しておきたいところです。

変数は構造体でまとめる or 命名規則でなんとかする or ビヘイビアを活用する

チュートリアル程度だとそれほど変数が多くないのでシーンやらオブジェクトにぼこぼこ変数を追加していたのですが、定数なんかも変数に定義しておきたいよね~とやっていったらかなりの数になって探すのが面倒に^^;

プレイヤーの変数。1画面で納まりきらず

この辺りの運用はもう少し検討が必要そうですが、ビヘイビアをちゃんと勉強するのが正解な気がしています。

画面レイアウト

PCで公開するなら、ゲーム画面が縦画面でも基本レイアウトは横サイズで作った方がよかったです。 Liluo だと画面をセンタリングしてくれないのでかっこ悪い・・・。操作説明を余白に表示するなどの活用もできます。

スクリーンショットに動画をつける

前回のWall Walkerではちゃんとプレイ動画をアップしていたのですが、今回は作っていたにも関わらずアップし忘れ。一目でどんなゲームか分かった方が遊びやすいと思うので動画は必須だった気がします。

公開後はすぐに他の人の作品を遊んでおく

作品数が多いのでこちらから遊びにいかないと全く遊ばれません!(Unity1週間ゲームジャムの遊ばれ方が異常)。遊べばちゃんと遊び返してもらえるので、目に付きやすい初期に遊びまわってコメントを残しておくのが吉でした。

最後に

GDevelopは2Dに特化したゲームエンジンで、導入コストの低さが印象的でした。Webブラウザーで試せて、インストールも管理者権限が不要、サンプルの素材がアセットストアですぐに見つけることができ、スプライトエディターや効果音エディターが組み込まれています。プラットフォーマートップダウンに必要な処理は予め用意されており、物理エンジン、Bloom、パーティクルといった各種機能も揃っています。2Dゲームを作るなら選択肢に入れて損はないゲームエンジンだと感じました。

GDevelopが良いゲームエンジンであり、使い方や今後の方針も把握できました。勉強しはじめて1週間でゲームジャムにゲームを投稿できることの実証もできました。ゲームジャムの成績がどうあれ、すでに十分以上に成果を得られたゲームジャムへの参加でした!!

参考・関連URL

itch.io

Unity2021LTSでAndroidビルドのエラー

Voxelorer BirdをUnity2021LTSにバージョンアップしてAndroidでビルドしてみたのですが諸々エラー。Cross Platform Native Pluginsを入れるとエラーになるのですが、原因はUnityがインストールしたAndroid SDKのライセンスが通ってないという感じでした。

Android Studioを起動して、SDK Managerで以下をインストール。

上記をインストールした先のパスを、UnityのPreferencesのExternal ToolsのSDKパスとして設定しました。詳しくは以下の通り。

youdoyou-motto.com

エラー

発生したエラーは以下のような感じでした。

1つ目

Starting a Gradle Daemon, 1 incompatible and 6 stopped Daemons could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
File C:\Users\YuTanaka\.android\repositories.cfg could not be loaded.
Checking the license for package Android SDK Build-Tools 29.0.2 in C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\licenses
Warning: License for package Android SDK Build-Tools 29.0.2 not accepted.
Checking the license for package Android SDK Platform 31 in C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\licenses
Warning: License for package Android SDK Platform 31 not accepted.

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

2つ目

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':unityLibrary:com.voxelbusters.essentialkit.androidlib:compileReleaseAidl'.
> Failed to install the following Android SDK packages as some licences have not been accepted.
     platforms;android-31 Android SDK Platform 31
     build-tools;29.0.2 Android SDK Build-Tools 29.0.2
  To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
  Alternatively, to transfer the license agreements from one workstation to another, see http://d.android.com/r/studio-ui/export-licenses.html
  
  Using Android SDK: C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 10s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

3つ目

CommandInvokationFailure: Gradle build failed. 
C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK\bin\java.exe -classpath "C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

stderr[

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':unityLibrary:com.voxelbusters.essentialkit.androidlib:compileReleaseAidl'.
> Failed to install the following Android SDK packages as some licences have not been accepted.
     platforms;android-31 Android SDK Platform 31
     build-tools;29.0.2 Android SDK Build-Tools 29.0.2
  To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
  Alternatively, to transfer the license agreements from one workstation to another, see http://d.android.com/r/studio-ui/export-licenses.html
  
  Using Android SDK: C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 10s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
]
stdout[
Starting a Gradle Daemon, 1 incompatible and 6 stopped Daemons could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-30\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
File C:\Users\YuTanaka\.android\repositories.cfg could not be loaded.
Checking the license for package Android SDK Build-Tools 29.0.2 in C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\licenses
Warning: License for package Android SDK Build-Tools 29.0.2 not accepted.
Checking the license for package Android SDK Platform 31 in C:\Program Files\Unity\Hub\Editor\2021.3.3f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\licenses
Warning: License for package Android SDK Platform 31 not accepted.
]
exit code: 1
UnityEditor.Android.Command.WaitForProgramToRun (UnityEditor.Utils.Program p, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.Command.Run (System.Diagnostics.ProcessStartInfo psi, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.Command.Run (System.String command, System.String args, System.String workingdir, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.AndroidJavaTools.RunJava (System.String args, System.String workingdir, System.Action`1[T] progress, System.String error) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, Unity.Android.Gradle.AndroidGradle androidGradle, System.String workingdir, System.String task, System.Action`1[T] progress) (at <089eca9a0a77417a901dda0093fda7f3>:0)
Rethrow as GradleInvokationException: Gradle build failed
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, Unity.Android.Gradle.AndroidGradle androidGradle, System.String workingdir, System.String task, System.Action`1[T] progress) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.PostProcessor.Tasks.BuildGradleProject.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <089eca9a0a77417a901dda0093fda7f3>:0)
Rethrow as BuildFailedException: Exception of type 'UnityEditor.Build.BuildFailedException' was thrown.
UnityEditor.Android.PostProcessor.CancelPostProcess.AbortBuild (System.String title, System.String message, System.Exception ex) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.PostProcessAndroidPlayer.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, AndroidPlayerBuildProgram.Data.AndroidPlayerBuildProgramOutput buildProgramOutput) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.Android.AndroidBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <089eca9a0a77417a901dda0093fda7f3>:0)
UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, System.Int32 subtarget, System.String installPath, System.String companyName, System.String productName, System.Int32 width, System.Int32 height, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <31b86d204baf45de8328f2d1261a79f7>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

参考URL

ぺんそろ~Unity1週間ゲームジャム「そろえる」

ぺんそろ

ぺんそろ | フリーゲーム投稿サイト unityroom

unityroom.com

2022年05月02日(月) 00:00〜2022年05月08日(日)のGW中に開催されたUnity1週間ゲームジャム「そろえる」に参加しました。完成作品はこちらの「ぺんそろ」です。

ざっくり振り返りです。

目次

評価や結果

まずは終わったばかりで感覚を忘れないうちに結果から。いただいた評価は以下の通りでした。

みんなの評価

  • 楽しさ 3.952
  • 絵作り 4.048
  • サウンド 3.476
  • 操作性 3.571
  • 雰囲気 3.905
  • 斬新さ 3.714

楽しさ、絵作り、雰囲気が良い感じで、だ氏さんの参加の効果が発揮されています!!コメントでも「あぶな~い!!」システムが好評でした^^楽しさで44位にランクインできました。

楽しさ44位!!

遊んで評価を入力してくださったり、コメントいただいた皆様、ありがとうございました!!

今回の自分のテーマ

今回も開発関連のテーマ主体でした。

  • オブジェクト指向や設計、インターフェースの練習
  • URPとShaderGraphをいじる
  • アイテムなどにバリエーションを作る
  • 共同制作

自己完結できるテーマなので一通り達成できて収穫がありました。このあたりはまた別ブログで。

企画の振り返り

インターフェースを使ったり拡張性が出せそうなもので、苦手としているカードゲームや3マッチゲームのアレンジ辺りから考えてみたのですがまとめられず。共同制作だから確実に完成させられるように、床の高さを揃えてキャラクターを先に進める案で進めることにしました。これなら2~3日ぐらいでゲームは動くかな?と思ったのですが甘かったです^^;

クライマックス要素を入れたくて無敵アイテムで床まで壊しまくれるように考えました。発動すると面白いのですが、狙ってできないし、発生頻度も低いので不発だった気がします。

無敵!!

その代わりにお助けシステムが救済になりました。これによってキャラクター性が出せて、これまでの自分の作品にはない味わいが出ました。

あぶなーい!!

折角縦画面で作ったのでスマホアプリ化もなんとなく検討しています。が、スクロール型でいいのかとか、メイン要素が足りない気がするとか、検討中です。

次回に向けて

強そうな企画案が思い浮かばなかったので今回も開発練習が主体になりましたが、思い浮かびさえすれば企画主導のものも作ってみたいというのがあります。参加者の皆様の作品を見て感じたこと、自分でも試みてみたいことを次回に向けて挙げておきます。

  • 1画面にメインゲームを収める
  • 非リアルタイムで疲れない、癒し
  • 操作で変わった体験ができる
  • 操作やタイミングを失敗に直結させない
  • ランキングは最初に名前登録して自動送信(ただしランキングは無くても大丈夫)
  • (なんちゃって)リアルタイム順位表示
  • 動画撮影時は効果音のみにして、BGMは動画編集で入れる

今回も実り多い1週間ゲームジャムでした。ちゃんと収穫しないと・・・

参加の皆様、お疲れさまでした。遊んで下さった皆様、ありがとうございました!また次回の1週間ゲームジャムで!!