tanaka's Programming Memo

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

Unity Adsの初期化がネット未接続時に失敗した時の対策

デジゲー博で展示する際に、Voxelorer BirdのUndoが回復されない症状が発生しました。会場では自動的にネットに接続されないため、広告やUndo回復を取得するためのサーバーアクセスに失敗していたのが原因と気付いて手元のスマホテザリングしてみましたが、広告を見れるようにするにはアプリの再起動が必要でした。ネットに接続すればアプリを再起動しなくても広告を見れるようにする方法を調査したところ、現行のUnity Adsの動作で分かりづらいところが見つかったのでまとめておきます。

  • 2021/12/27 「さらなる不具合」を追記

確認した環境

  • Unity2020.3.9f1
  • Unity Ads 3.7.5と4.0.0

Unity Adsの初期化失敗時の仕様と問題点

Unity Adsを利用する際には、Initialize()を一度呼び出しておきます。呼び出し時にインターネットに接続されていなかった場合、その場では初期化は失敗しますが、ネットに接続されたら自動的に初期化が実行される仕様になっています。

この仕様はUnity2020.3.9f1のエディター上では動かないようで、初期化に失敗するとアプリを再起動する必要がありました。念のため、AndroidiOSで試したところ、実機ではちゃんと仕様通りに再初期化することが分かりました。

Unity Ads 3.7.5ではもう一つ問題があって、初期化が失敗した後に再初期化が成功した際にOnInitializationComplete()が呼ばれません。そのため、このコールバックを受け取る前提で作成していたVoxelore Birdはアプリの再起動が必要になったのでした。4.0.0では修正されています。

広告の初期化はLoad()を使う

Unity Ads3.x.xでは、IsReady()で広告を表示する準備できたかどうかを確認できたのですが、4.0.0ではこのメソッドが廃止されてしまいました。Load()を手動で呼び出して、コールバックで読み込み成功を確認することになったようです。

docs.unity.com

さらなる不具合

4.0.0では、広告の初期化時にネットに接続できない状態でアプリを一時停止させてしまうと、アプリの再開後にネットに接続しても初期化は実行されず、Inittialize()を呼び出してもOnInitializationFailed()が呼ばれて失敗するようです。

また、広告の読み込み成功後にネットから切断してShow()を呼ぶと、OnUnityAdsShowFailure()が呼ばれて失敗します。

まとめ

まとめると以下のような感じです。

  • Advertisement.Initialize()は起動時に一度呼び出せばよい
  • UnityAds3.7.5では、OnInitializationComplete()が呼ばれない可能性があるので、IsReady()で完了を確認してからShow()を実行
  • UnityAds4.0.0では、Load()で必要な広告種類を手動で読み込み、OnUnityAdsAdLoaded()が呼ばれたことを確認してからShow()を実行

UnityAdsのマニュアルの手順に従って実装しておけば問題は回避できるということですね。Unityエディター上では再初期化がされない可能性があるので、正常に動いていないようでも実機で試すのをお忘れなく。

追記

マニュアルは勿論読んでたはずなのでおかしい・・・とこの記事を書きながら思っていたのですが、最後にマニュアルの更新日を見て納得しました。更新されたのはこの記事を書いた前日の12/17でした^^; Unity Adsの調査をしたのは数日前なので、その頃にはないドキュメントだったのですね。

参考URL

ゆるく使うUnityTest

Qiita Advent Calender 2021 Unity カレンダー1の8日目の記事です。

前の日は @neusstudio さんの 【Unity】Vivox でボイスチャットを始めよう! - Qiita です!

次の日は @nkjzm さんの【Unity】テスト対象のプレハブを名前で検索するUtilityメソッド - Qiita です!

この記事は、Unityに標準で用意されているテストフレームワークを使ったことがない人や、使ってみたけど今一つ使いどころが分からなかった人向けに、既存のプロジェクトに手軽にテストを導入する例をご紹介します。

f:id:am1tanaka:20211203152122p:plain

目次

ブログの動作環境

  • Unity 2020.3.9f1
  • Creator Kit - Puzzle 1.0

Unity Test Frameworkとは

Unityには、.NETプラットフォーム向けのテストフレームワークである NUnit を元にした Unity Test Framework がデフォルトで用意されています(以降、UnityTestと書きます)。以下、公式マニュアルです。

nunit.org

docs.unity3d.com

ソフトウェアのテストについてはあちこちで述べられているので詳細は割愛しますが、関数やクラス、システムが予想通りに動くかどうかを自動的に確認するためのものです。テストのために引数と結果の組み合わせを検討することで実装内容が明確化できることや、手動でテストする手間の削減、実装後のリファクタリングによるエンバグの発見など、テストの導入には多くのメリットがあります。プログラミングにある程度慣れてきた段階で、軽くでもよいので一度試してみると発見があって面白いと思います。

ゆるく使うとは

テストというとTDD(テスト・ドリブン・デベロップメント)などを語りたくなりますが、既存のプロジェクトでも導入するメリットはあります。このブログでは、Unity Hub2.4.5の「使い方を学ぶ」にあるCreator Kit: Puzzleに用意されているサンプルステージのレベル1を自動操作して、星3つを獲得したかを確認するテストを作ってみます。すぐに享受できるメリットからはじめて、徐々にテストへの理解を深めていくのもよいだろうと思います。

Creator Kit: Puzzleをテストする

プロジェクトの読み込みからテストの作成までの手順です。

対象プロジェクトを開く

  • Unity Hubを起動して、使い方を学ぶからCreator Kit: Puzzleを選択します

f:id:am1tanaka:20211203113922p:plain
チュートリアルを開く

  • はじめての時は、プロジェクトをダウンロード をクリックします
  • ダウンロードが完了したら、 プロジェクトを開く をクリックします
  • Projectウィンドウから Creator Kit - Puzzle > Scenes > ExampleScenes を開いて Level01 シーンをダブルクリックすると、以下のシーンが開きます

f:id:am1tanaka:20211203152122p:plain
Level01

Playして遊んでみてください。スペースキーで仕掛けを動かして、ゴールに玉を転がしたらクリアです。

テスト内容

作成するテストは以下のような流れにします。

  • Level01を読み込む
  • 開始時に星の獲得数を0に設定
  • 適当な秒数が経過するまで、ゴール待機のループ
    • ゴールしたら星が3つ獲得できたか確認して、ループ終了
    • ボールが一定の位置を通過したら仕掛けを作動
  • ループが終了してゴールしていなければ失敗

テストスクリプトの作成

UnityTestで最初にやることは、テスト用のフォルダーを作成することです。

  • ProjectウィンドウでTestsフォルダーを作成したいフォルダー(Assetsなど)を右クリックして、Create > Testing > Tests Assembly Folder を選択します。フォルダー名はTestsのままでよいかと思います

f:id:am1tanaka:20211203121503p:plain
Testフォルダーの作成

この手順はプロジェクトで1回だけでOKです。あとは必要に応じてテストスクリプトを作成します。

  • 作成した Tests フォルダーを右クリックして、 Create > Testing > C# Test Script を選択して、Level01Testsなどの名前でスクリプトを作成します

f:id:am1tanaka:20211203121725p:plain
テストスクリプトの作成

作成したスクリプトから不要な行を削除したりして整理します。単体テスト用のメソッドの前には[Test]、コルーチンで複合的なテストを行うメソッドには[UnityTest]を書きます。今回は単体テストはしないので[Test]は不要です。コメントも消して以下のようにすっきりさせておきます。

using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

public class Level01Tests
{
    [UnityTest]
    public IEnumerator Level01TestsWithEnumeratorPasses()
    {
        yield return null;
    }
}

以上で上書き保存します。

テストの実行

テストコードは何も書いてませんがテストを実行してみましょう。Unityに切り替えて、以下を操作してください。

  • Windowメニューから General > Test Runner を選んで、テストランナーウィンドウを起動します

f:id:am1tanaka:20211203125825p:plain
テストランナーの起動

  • PlayMode をクリックします

f:id:am1tanaka:20211203130000p:plain
PlayModeに切り替え

  • 先ほど作成したテスト Level01TestsWithEnumeratorPasses をクリックして選択したら、Run Selected をクリックしてテストを実行します

f:id:am1tanaka:20211203130100p:plain
特定のテストを実行

以上でテストランナーが起動します。まだ何もテストコードを書いていないので成功して終了します。

f:id:am1tanaka:20211203130232p:plain
起動成功

テストのためのAssembly Definitionファイルの作成

UnityTestの面倒ポイントの一つが、テストスクリプトからプロジェクトのスクリプトを参照するための Assembly Definitionファイルを作る必要があることです。ある程度の段階までは触らない機能なので、知らない場合はとにかく以下の操作をして必要なファイルを作成してください。

  • Assets/Creator Kit - Puzzle Scripts フォルダーを右クックして、Create > Assembly Definition を選択します

f:id:am1tanaka:20211203134445p:plain
Assembly Definitionの作成

  • 作成されたアセットの名前をCKPuzzle などにします
  • Inspectorウィンドウの Assembly Definition References欄の List is Empty の右下の + をクリックします
  • 追加される欄の None の右の二重丸をクリックして、Unity TextMeshProを選択します
  • 同様に、com.unity.cinemachine と Unity.Postprocessing.Runtime を追加します
  • 下の方の Apply ボタンを押します

スクリプトから参照しているものが他にもある場合は、都度、同様の操作で追加する必要があります。

  • 先ほど作成した Tests フォルダー内の Testsファイル をクリックして選択します
  • Inspectorウィンドウの Assembly Definition References欄に、先ほどと同様の手順で CKPuzzle への参照を追加します
  • 下の方の Apply ボタンを押します

以上でテストランナーからプロジェクトのスクリプトを参照できるようになります。

シーンの切り替えとタイムアウト

テストコードの作成開始です。まずは「Level01を読み込んで」「指定秒数待って」「終了時に指定秒数の経過状態をテスト」してみましょう。

先ほどのLevel01Testsスクリプトを以下のようにします。

  • 冒頭に以下のusingを追加します
// 6:
using UnityEngine.SceneManagement;
  • テストメソッドを以下のように実装します
// 10:
    [UnityTest]
    public IEnumerator Level01TestsWithEnumeratorPasses()
    {
        float timeOut = 10;

        SceneManager.LoadScene("Level01");
        yield return null;
        var timing = GameObject.FindObjectOfType<TimingRecording>();
        while (timing.timer < timeOut)
        {
            yield return null;
        }

        Assert.That(timing.timer, Is.LessThan(timeOut), "クリアしたか");
    }

以上できたら上書き保存してテストランナーを実行してください。操作せずに放っておくと、10秒経過したらテストが失敗して実行が停止します。

テストを開始するとInitTestScene?????という感じの名前のテスト用のシーンが起動します。このシーン上にテストに必要なオブジェクトをInstantiateで配置する想定なのですが、今回のようにステージが必要なテストをコードで用意するのは面倒です。15行目のようにLoadScene()でシーンを読み込めば手軽にテストを始められます。

16行目:シーンを読み込んだら yield return null; で1フレーム待って、シーンを初期化させてます。

17行目:経過時間はTimingRecordingスクリプトtimerで確認できます。この辺がpublicなのは助かります(アクセサなどで読み出し専用にしてたらなお良し)。必要なインスタンスはテストコードなので多少効率が悪くても問題ないだろうということで FindObjectOfType<>() で強引に取得しました。

18行目:timeOutに設定した秒数が経過するまで待つwhile()には、後ほどパドル操作とクリアチェックのコードを追加します。

23行目:最後にAssertで経過秒数がtimeOutの時間以内であることを確認します。今は時間が経過するまでwhileループを抜けないので必ずテストは失敗します。

f:id:am1tanaka:20211203140921p:plain
最初のテスト失敗

状態をテストするのはAssert.That()というNUnitが提供するstaticメソッドを使います。最初に検証したいデータが入っている変数、2番目に予想する結果、3番目に失敗時に表示するコメントを書きます。2番目の引数には色々なものが用意されています。詳しくはこの辺りこの辺りを参照してください。

仕掛けを動かす

テストから仕掛けを動かせるようにするために、元のコードに少し手を加える必要があります。Projectウィンドウから Assets > Creator Kit - Puzzle > Scripts > InteractivePuzzlePieces フォルダーを開いて InteractivePuzzlePiece スクリプトをエディターで開きます。24行目あたりに仕掛けを動かすためのコードがありますが、Inputが直書きされているのでテストから操作できません。ちょこっと手を加えます。

  • InteractivePuzzlePieceクラスに以下のstatic変数を追加します
// 22:
    public static bool interactKeyState;
  • FixedUpdate()のif文に以下のように条件を追加します
// 24:
    protected void FixedUpdate ()
    {
        if ((Input.GetKey (interactKey) || interactKeyState) && m_IsControlable)
        {
            ApplyActiveState ();
        }
        else
        {
            ApplyInactiveState ();
        }
    }

これでBaseInteractivePuzzlePiece.interactKeyStatetrueを代入すれば仕掛けが動き、falseなら解除します。

本来は、入力を管理するクラスを作成して入力を取りまとめた方がいいのですが、本論から外れるので今回はお手軽な手法にしました。

テストを以下のように変更します。

// 10:
    [UnityTest]
    public IEnumerator Level01TestsWithEnumeratorPasses()
    {
        float timeOut = 10;
        float activateX = -1.5f;

        SceneManager.LoadScene("Level01");
        yield return null;

        var marble = GameObject.Find("Marble");
        var timing = GameObject.FindObjectOfType<TimingRecording>();
        while (timing.timer < timeOut)
        {
            yield return null;
            if (marble.transform.position.x > activateX)
            {
                BaseInteractivePuzzlePiece.interactKeyState = true;
            }
        }

        Assert.That(timing.timer, Is.LessThan(timeOut), "クリアしたか");
    }

上書きしてテストを実行したら操作せずに眺めていてください。玉がactivateXを越えたら仕掛けが自動的に動いてクリアします。まだクリア判定をしていないのでテストは終わりません。UnityのPlayボタンを押して手動で停止してください。

クリアと結果の判定

クリアと獲得した星の数の確認を追加します。どちらもSceneCompletionスクリプトで確認できます。必要なパラメーターはpublicで宣言されているのでそのまま利用できます。

以下のようにテストスクリプトにコードを追加します。

// 10:
    [UnityTest]
    public IEnumerator Level01TestsWithEnumeratorPasses()
    {
        float timeOut = 10;
        float activateX = -1.5f;

        SceneManager.LoadScene("Level01");
        yield return null;

        var comp = GameObject.FindObjectOfType<SceneCompletion>();
        comp.sceneReference.earnedStars = 0;

        var marble = GameObject.Find("Marble");
        var timing = GameObject.FindObjectOfType<TimingRecording>();
        while (timing.timer < timeOut)
        {
            yield return null;
            if (marble.transform.position.x > activateX)
            {
                BaseInteractivePuzzlePiece.interactKeyState = true;
            }

            if (comp.panel.activeSelf)
            {
                Assert.That(comp.sceneReference.earnedStars, Is.EqualTo(3), "星3つ");
                break;
            }
        }

        Assert.That(timing.timer, Is.LessThan(timeOut), "クリアしたか");
    }

追加したのは以下の行です。

  • 19行目付近
        var comp = GameObject.FindObjectOfType<SceneCompletion>();
        comp.sceneReference.earnedStars = 0;
  • 32行目付近
            if (comp.panel.activeSelf)
            {
                Assert.That(comp.sceneReference.earnedStars, Is.EqualTo(3), "星3つ");
                break;
            }

上書き保存をしてテストを実行したら操作せずに見ていてください。クリアしたのち、結果が表示されるタイミングでテストが失敗します。

f:id:am1tanaka:20211203151004p:plain
星が足りなかった

Expected: 3
But was: 0

上記は、獲得した星の数が「3を予想したが結果は0だった」ということで動作結果と一致します。これでテストコード完成です!

仕上げ

テストコードの14行目付近のfloat activateX = -1.5f;の値を変えれば、仕掛けが動く場所を調整できます。星3つ獲得できたらテストが成功するので、良さそうな値を探してみてください。数当てみたいでこれはこれで楽しめると思います。

これは本来の使い方ではありませんが、自動テストで同じ状況を繰り返し再現できることで、バグを探したり、コード変更の影響を確認するのが楽になりそうなことを実感いただければ幸いです。

また、テストコードの15行目付近に以下のコードを追加してみてください。

// 15:
        Time.timeScale = 4;

テストを4倍速で実行できます。これもテストの便利なところです。ただし、あまり速くしすぎると物理演算の誤差で結果が不正確になるので倍率はほどほどに。

得られた知見

今回のようなテストをする場合に重要になるのが以下の2点です。

  • 操作を外部からできるようにする
  • 状態を外部から把握しやすくする

何かを操作するコードに直接Inputを書き込むと今回のようにテストがしにくくなります。オブジェクトを制御するクラスと、入力値を読み取ってアクションに変換するクラスは分けた方がテストがしやすくなります。テストがしやすくなるだけではなく、カットシーンでプレイヤーを自動制御したり、リプレイ機能を付けることも簡単にできるようになるオマケが付いてきます。

ユーザー操作を想定したテストをする場合、人間が無意識にやっている操作できるようになるまで待つというのをテストコードで実装する必要があります。状態を外部から把握しやすくすることで、操作したい状況になるまでの待機が簡単に実装できるようになります。このことは、例えば会話中はプレイヤーの操作を停止させたい、とか、メニューを表示するアニメ中は操作を停止したい、というような仕組み作りに役立ちます。最初からこのような設計で作っておけばゲーム中の面倒な処理が簡単に実装できます。

テストを前提にしたシステムを考えることと、設計について学ぶことは近い関係にあります。ゆるい使い方に慣れてきたら、改めてテストや設計について学んでみてください。

実用例

現在開発中のVoxelorer BirdでもUnityTestを利用しています。

f:id:am1tanaka:20211206232753p:plain
VoxelorerBirdのテスト一覧

個人制作のそれほど大きなプロジェクトではないので必要と感じた以下のようなもののみ用意しています。

  • 保存データの確認
    • テスト用のファイルにすることで、自由に保存状態を変えてテストできます
  • 発話やメニュー、操作の排他処理確認
    • 確認のための手順が多いので、テストで自動操作させることで大幅に省力化できました
  • 起動からステージクリア、ステージ選択の流れの確認
    • 機能追加や変更をすると不測の不具合が出る可能性があるので、時々、ゲームを一通り操作してみるのが肝要です。手動でやるのは億劫なので、これこそ自動テストの出番です
  • Undoやシナリオキューの開発
    • 動きがややこしい処理はTDDの出番です。予想外の不具合がいくつも見つかったので大いに助かりました

f:id:am1tanaka:20211207004145g:plain
100回クリアテスト

こんな感じで普通にアプリを起動してステージを読み込んで、じゃかじゃかボタンやプレイヤーの操作をテストランナーに実行させて不具合がないかも確認できます。これで見つけた予想外の不具合が結構あるのでテストの恩恵を実感しています。

最後に

UnityTestは最初から用意されているので、Assembly Definitionファイルの作成さえなんとかなれば導入ハードルはそれほど高くありません。今回紹介したPlayモードのテストは、コルーチンに馴染んでいれば感覚的に利用できると思います。

記事の中で入力のコードを変更しましたが、「テストをしやすいコードにするにはどうしたらよいか」を考えるのは、良い設計への道しるべです。テストの雰囲気が掴めたら、本来のテスト手法や手順も学んでみてください。とっかかりとして、新しい挑戦をしたい時に見る本 Vol3 - まんてらスタジオ - BOOTHの第6章、murnanaさん執筆の「Unityとテスト駆動開発で作る〇×ゲーム」がオススメです。

booth.pm

以上、Qiita Advent Calender 2021 Unity カレンダー1の8日目の記事でした。

前の日は @neusstudio さんの 【Unity】Vivox でボイスチャットを始めよう! - Qiita です!

次の日は @nkjzm さんの【Unity】テスト対象のプレハブを名前で検索するUtilityメソッド - Qiita です!

参考URL

デジゲー博2021出展してきました!

恒例となってきましたデジゲー博、今年も出展してきました。

f:id:am1tanaka:20211114104834j:plain

最初に出展したのが2018年だったので気が付けば4回目。ついにスマホ版のオープンテスト版を配信できるところまで辿り着きました!忘れないうちにざっくり書いておきます。

目次

今回の目的

4回目にしてようやくスマホのオープンテスト版をお届けできる準備が整いまして、今回の最大の目的はオープンテスト版のダウンロードURLのQRコードを印刷したカードを配布することでした。

その他、難易度や操作性の確認、バグの発見、設営と撤収の練習、ルキグラ自慢などなど、展示をすることで開発しているだけでは入手できない貴重な経験を得ることができるので、本当にデジゲー博さんにはありがたい機会を提供していただいています。

展示の様子

ブースはこんな感じになりました。

去年はスマホの操作データをPCに送って初代ルキグラで表示ということをしていて、実装に時間がかかった割には遅延がすごくて微妙なデモ状態でした。今年はLooking Glass Portraitが届いたのですが、対応に割ける時間があまり残っていなかったため、何かないかと考えた結果、マウスを台においてPCで普通に操作してもらえばいいんじゃん、ということに気づきそれで実装。結果、実装は楽だったし、去年よりちゃんと遊べる状態で展示できました。

毎度のことですが、ルキグラ目当てで足を止めて下さったお客さんにVoxelorer Birdを遊んでいただいて、ゲームも面白いじゃん、となればいいなというような感じで、今年もルキグラは頼りになりました。Portraitはレイアウトがスマホのをそのまま使えるので素晴らしいです。

ルキグラの公式サイトは以下です。ご興味がありましたら。

lookingglassfactory.com

配布したカード

こんな感じのカードをA4に10枚並べて、自分でカットして配布しました。

f:id:am1tanaka:20211114211529p:plain
オープンテストご招待カード

300dpiでカード1枚の縦横のドット数を計算して、Unity Recorderでそのサイズで出力。1枚分の画像ができたら、GIMPで左右に2枚並べてから、縦に5行並べて、あとはA4のドット数にキャンバスを拡大すれば原稿のできあがり。

印刷はファミマのネットプリントを利用しました。ネットプリント光沢紙、ネットプリント普通紙、カラーコピー光沢紙の3パターンを試してみたところ、今回のデザインだとグラデーションや細かい部分の発色が光沢紙より普通紙の方が良くて、ネットプリント普通紙で印刷しました。カラーコピーの方がネットプリントより安いのですが、今回のようなグラデーションや淡い色だとスキャンしきれず、あまり奇麗に印刷できませんでした。普通紙ならネットプリントでも1枚60円だったのでまあそのぐらいはいいかということで全部ネットプリントで出力しました。

印刷できたら、大昔に出席カードを作るためにゲットしていた裁断機で裁断。

f:id:am1tanaka:20211112185746j:plain
裁断

最初に上か下をカットしてから、縦方向に短冊状にカットして、短冊状にしたやつを3~4枚ほど並べてまとめてカット、という感じでやるとスパスパできあがりました。

試しに印刷した20枚と、ネットプリントの普通紙のカード60枚の合計で80枚を持っていき、61枚配布できました!ニアピン賞です。受け取って下さった皆様、ありがとうございました!

今回のオープンテストは、一旦、会場で配布した分で様子見をします。その間に、展示で見つかった不具合を解消したり改良を加えて、機が熟しました公開しようと考えています。

今回の展示で気付いたこと

プレイの様子を見ながら、あるいは、ご意見を伺って、以下のようなことが確認できました。

  • 通信がないところだと広告APIの初期化がコケて様々な不具合を巻き起こした
    • 手元のスマホテザリングして緊急回避
    • 展示モード時は、Adsの初期化を回避する処理が必要
    • 初回の初期化に失敗すると再起動しないと正常に動作しなくなる作りだったので、失敗したら初期化からやり直すようにする必要あり
  • ブロックが落ち切らずに吹き飛ぶことがある
    • 移動はRigidbodyを使わないようにした方がよさげ
  • プレイヤーキャラクターが空中に浮くことがあった
    • ブロックの不具合と同じ原因と思われる。独自移動に変更することで解消できそう
  • メッセージ表示中だとUndoボタンが押しにくい
    • メッセージ表示中でもUndoボタンを有効にする
  • iPadのカバーが画面に微妙に触れているようで、メッセージがどんどん飛んでしまうことがあった
    • 画面端は当たり判定を無くす
  • Undoの確定ボタンが気付きにくい
    • Undoの確定とキャンセルは不要かも。戻したい場面になったら画面をタップすればそこで確定でいいような気がする
  • Undo放題の時間はもう少し長くて良い

いただいたアイディア

  • 広告を見るとコスチュームが入手できたり、別のトリにできたり
    • ハクの物語で考えていたけど、トリごとに洞窟にやってくる目的が変わるといいかも?大変か?

来年に向けて

来年のデジゲー博こそは、正規版のダウンロードURLを大々的に公開したい、ということで、Voxelorer Bird の開発を継続するのが野望です。もう一つ。チームでこういう感じの作ろうか、という話が出ていて、その試遊版が展示できたらいいなということを考えてます。

そして、去年はそこそこ成功した設営と撤収でしたが、今年は荷造りに頭が回ってなくて撤収に手間取り、2Fで最後に片付いたぐらいの遅延ぶりでした。設営機材がほぼ揃って安心して、小物とかをどこに入れるかを考えずに袋に放り込んでいったのが敗因でした。ハンズとかビックカメラの袋ではなく、どこに何を入れるかが決まっている展示用収納を構築するのも来年度の密かな野望です。

最後に

試遊をして貴重なご意見やバグを見つけてくださったり、オープンテストカードを受け取ってくださった皆様、ありがとうございました。

差し入れなども本当にありがとうございました。疲れが癒えます。毎度のことですが、なかなかブースから離れられず、全然遊び返しに行けていなくて恐縮です。なるべくTwitterとかで情報を追って遊びたいと思ってます。

デジゲー博はなぜだか肌に合い、あまり展示などをしない自分にとって貴重な場です。運営の皆様、主催や共催の皆様、ありがとうございました。今後も末永く続きますよう及ばずながら応援してまいります。

Scroll Viewのメモ

スクロールビュー(Scroll View)の設定方法をいつもすぐ忘れるので備忘録。

目次

対象バージョン

この記事は Unity 2020.3.9f1 を元にしています。

Scroll Viewの構成

デフォルトのScroll Viewは以下のような構成です。

f:id:am1tanaka:20210805174832p:plain
Scroll Viewの構成

  • Scroll View
    • 表示する範囲やスクロールの動作設定などをするオブジェクト
  • Viewport
    • スクロールビューの外を消すマスク処理をするためのオブジェクト
  • Content
    • スクロールする対象のUIオブジェクトを配置するためのオブジェクト。スクロールできる範囲や、最初に表示される位置をこのオブジェクトで設定します
  • Scrollbar Horizontal / Scrollbar Vertical
    • スクロールバーのオブジェクト。不要ならScroll Viewの設定を消した上で、このオブジェクトを消してもよい

表示範囲

(1)と(2)の表示範囲は、Scroll ViewのWidthとHeightなどのRect Transformで設定します。AnchorのMinとMaxを01にして、画面いっぱいに広げるような設定をしても問題なく動きます。

f:id:am1tanaka:20210805170130p:plain
表示範囲とスクロールバー

スクロールバーを消す

スマホ用などでスクロールバーがいらない場合は、Inspectorウィンドウの(3)と(4)の欄を削除してNoneにして、Scrollbar Horizontal と Scrollbar Vertical を削除します。

スクロールバーを使わない場合、スクロールするかどうかに応じたViewportのサイズ調整が動作しないようで、そのままだとスクロールバーの場所が空いてしまいます。ViewportのRect TransformのRightは0にするのがよさそうです。

コンテンツの配置

f:id:am1tanaka:20210805173446p:plain
コンテンツの配置

コンテンツを配置する先

表示するコンテンツは Content オブジェクトの子供にします。

スクロールできる範囲

Contents オブジェクトの幅や高さがスクロールできる範囲になります。図では、Scroll Viewの高さが900、Contentsの高さが2000なので、表示範囲が900で、画面外に1100スクロールできます。

最初に表示される場所

Contents の Pos X や Pos Y に設定した状態で始まります。図では、Anchorが上端でPos Yが0なので、上端が表示された状態で始まります。

プログラムでコンテンツを追加する場合などは、Anchorをうまく設定しておくと計算が楽になる場合があります。例えば中央から表示したい場合なら、AnchorのMinとMaxを0.5にして、Pos Yを0にしておけば、自動的に中央から表示できます。

参考URL

Voxel ImporterでMagicaVoxelのボクセルを読み込んで透過させたり光らせたり

f:id:am1tanaka:20210801001016p:plain
光る砂時計

この記事は Unity アセット真夏のアドベントカレンダー 2021 Summer! – Unity公式 Asset Portal の4日目の記事です。

assetstore.info

▲前の日は さとや さんの「単独でも活用できる!Corgi Engine/TopDown Engineに同梱されているMMFeedbacksの紹介」でした。

▼次の日は kido さんの「History Inspector の紹介」です。

この記事では、ボクセルのモデルを簡単に読み込んだり、ボーン設定ができる定番アセット Voxel Importer を利用して、透過や自己発光するボクセルモデルを手軽に作成する方法をご紹介します!!

assetstore.unity.com

モデリングにはMagicaVoxelを利用します。

ephtracy.github.io

目次

記事の環境

以下の環境で作成しました。

  • Windows10
  • Unity2020.3.9f1
  • Voxel Importer 1.2.2
  • MagicaVoxel 0.99.6.2

MagicaVoxelでモデルを作成する

光る砂時計を作ってみます。今回のミソは素材ごとに違うマテリアルが割り当てることです。そのためにMagicaVoxelのRenderモードで色に素材の設定をします。また、今回のような多層構造を作るのに便利なレイヤーとオブジェクトの使い方も簡単にご紹介します。

MagicaVoxelの使い方は以下の書籍がとても参考になります。これまで使ってなかったあれこれの機能が使えるようになりました^^

モデリング

素材は以下の3種類にします。

  • 上下の木の枠のボクセル
  • 透過するガラスのボクセル
  • 光らせる砂のボクセル

上下の枠

必要に応じてサイズを設定します。今回は15 15 15で作成しました。

f:id:am1tanaka:20210801130851p:plain
オブジェクトのサイズ設定

  1. index:96のパレットを選びます
  2. EditパネルのSHAPE欄からCyliをクリックして円柱を作ります
  3. Eraseモードにします
  4. Faceモードにします
  5. 高さが2になるまで削除します

f:id:am1tanaka:20210801131132p:plain
下の枠の作成

EditパネルのMIRROR欄のZをクリックして、作成したのと同じ形を上にも作ります。

f:id:am1tanaka:20210801131313p:plain
上の枠

BrushパネルのMirrorモードのX, Y, Z全てONにして、角取りをしたら枠は出来上がり。

f:id:am1tanaka:20210801132847g:plain
枠の角取り

砂とガラスの部分は二重構造になっています。先に内側の砂で形を作ってから、ガラスのボクセルで砂を覆えば良さそうです。

砂のパレットはindex:184の緑でこんな形にしました。

f:id:am1tanaka:20210801140202g:plain
砂の作成

f:id:am1tanaka:20210801140423p:plain
枠と砂

ガラス

砂を覆うようにindex:73のパレットでガラスのボクセルを置きます。

f:id:am1tanaka:20210801141848g:plain
ガラスで覆う

f:id:am1tanaka:20210801191120p:plain
覆った

マテリアルを設定

マテリアルを分けるために色のMatter設定をします。まずは以下の通りガラスの設定をします。

  1. Renderモードに切り替えます
  2. ガラスのパレットであるindex:73を選択します
  3. MatterパネルのMATERIAL欄からGlassを選択します
  4. 適当にパラメーターを設定します

f:id:am1tanaka:20210801180019p:plain
ガラスの素材設定

砂の設定をします。

  1. 砂のパレットであるindex:184を選択します
  2. MatterパネルのMATERIAL欄からEmitを選択します
  3. 適当にパラメーターを設定します

f:id:am1tanaka:20210801180326p:plain
砂の素材設定

以上で素材の設定が完了です。枠、砂、ガラスに異なる設定をしたので、別のマテリアルが割り当てられます。

オブジェクトとレイヤー

雰囲気は良い感じになりましたが、砂が上から下まで詰まっていて砂時計に見えません。Unityに持って行く前にちょっと砂を減らします。

砂の調整はガラスや枠のボクセルをずらせばできますが面倒です。そこで砂を別レイヤーにします。この辺の操作がMagicaVoxelは独特で、理解するのに苦戦したので本筋とは違いますが備忘録として。

  1. Modelモードに切り替えます
  2. 右上の上三角形のアイコンをクリックしてワールドモードに切り替えます

f:id:am1tanaka:20210801180658p:plain
ワールドモードへ]

何もない場所をクリックすると、砂時計の大きさの立方体のワイヤーの色がレイヤーの色になります。砂時計がレイヤー0にあるオブジェクトだということを表しています。

f:id:am1tanaka:20210801180755p:plain
レイヤーを表す色

起動時にいじっているのはレイヤー0にある1つのオブジェクトということになります。MagicaVoxelでは1つのファイルにこのようなオブジェクトを複数持たせることができます。オブジェクトは新しく追加したり、コピーして複製したり、丸ごと移動したり、他のvoxファイルからImportして読み込むことができます。

オブジェクトの複製

現在のレイヤー0のオブジェクトを、レイヤー1に複製します。

  1. 砂時計をクリックして選択します
  2. EditパネルのSELECT欄からCopyをクリックします
  3. Pasteをクリックします

f:id:am1tanaka:20210801181351p:plain
オブジェクトを複製

見た目には分かりませんが、これで砂時計は2つに増えています。赤の矢印をドラッグして移動させると、2つの砂時計が確認できます

f:id:am1tanaka:20210801181539p:plain
コピーした砂時計を移動

レイヤーの設定

編集しやすくするためにレイヤーを分けます。BrushパネルのLAYER欄から、赤い丸の右の1と書いてある欄のさらに右の小さな四角の部分をクリックします。< が1の行に移動します。

f:id:am1tanaka:20210801181710p:plain
レイヤーの設定

これで選択していたオブジェクトがレイヤー1に移動しました。よくあるツールだと「レイヤーを指定してオブジェクトを作成」という感じですが、MagicaVoxelでは「オブジェクトを作成してから別のレイヤーへ移動」という感じです。

LAYERの0の左の丸をクリックすると片方の砂時計が消えます。1の丸をクリックすると、もう一方の砂時計が消えます。丸をクリックし直せば表示します。これで、好きな方だけ砂時計を表示することができます。

f:id:am1tanaka:20210801182139g:plain
レイヤーの表示と非表示

レイヤー0から砂を消す

レイヤー0を表示して、レイヤー0の砂時計をクリックして選択します。

f:id:am1tanaka:20210801182402p:plain
レイヤー0の砂時計を選択

  1. 右上の下三角アイコンをクリックしてモデルモードにします。
  2. Region Selectツールで枠の部分をクリックして選択します
  3. Transformツールで移動させて砂時計のボクセルを見えるようにします
  4. Region Selectツールで砂時計のボクセルの一つをクリックして選択したら、右のEditパネルのSELECT欄からCutで削除します
  5. 枠を元の位置に戻します

f:id:am1tanaka:20210801185004g:plain
砂を消す

レイヤー1を砂だけにする

同じような操作をして、レイヤー1のオブジェクトを砂だけにします。

  1. 右上の三角をクリックしてワールドモードに切り替えます
  2. 赤い枠のレイヤー1の砂時計をクリックして選択します
  3. 右上の三角をクリックしてモデルモードに切り替えます

f:id:am1tanaka:20210801185429p:plain
レイヤー1の砂時計を選択

  1. Region Selectツールを選択します
  2. 枠のボクセルの一つをクリックして選択します
  3. Cutで削除します

f:id:am1tanaka:20210801185616p:plain
枠を削除

f:id:am1tanaka:20210801185722p:plain
枠の削除完了

同様にしてガラスを削除します。

f:id:am1tanaka:20210801185750p:plain
砂だけ

あとは、砂を削除して好みの状態にします。削除する前の砂のオブジェクトをコピーして、別のレイヤーに取っておくと砂のさまざまな状態を作りやすくなります。

f:id:am1tanaka:20210801185944p:plain
砂完成

右上の三角をクリックしてワールドモードに切り替えたら、レイヤー1の場所を移動させて、レイヤー0の砂時計に重ねます。

f:id:am1tanaka:20210801190601g:plain
レイヤー0と1を重ねる

以上で完了です。Renderモードでレンダリングすると、砂が光っている砂時計がレンダリングされます。

f:id:am1tanaka:20210801190653p:plain
砂時計ボクセル完成!!

任意の場所にvoxファイルとして保存して、MagicaVoxelでの作業は完了です。

Unityにボクセルを読み込む

Voxel Importerでvoxを読み込む

ここからはあっという間です。UnityのプロジェクトにVoxel Importerをインストールします。

assetstore.unity.com

ついでにPostProcessing Stack V2も設定しておくといい感じで光るので良いです。PostProcessing Stackについてはこちらなどを。

Voxel Importerをインストールすれば、ボクセルの読み込みはvoxファイルをProjectウィンドウにドラッグ&ドロップするだけです。

f:id:am1tanaka:20210801213741p:plain
ボクセルをインポート

読み込んだボクセルをシーンにドラッグ&ドロップすれば表示できます。

f:id:am1tanaka:20210801213839p:plain
ボクセルの表示

パラメーターの調整

MagicaVoxelで設定したMatterの設定の多くはUnityへは反映されないのでUnity側で調整が必要です。また、他にもいくつか設定しておきたい項目があるので調整します。

  1. Projectウィンドウで読み込んだボクセルを選択します
  2. デフォルトでは1ボクセルが1mです。砂時計は15ボクセルなので15mと巨大なので、Scaleを0.066にしておおよそ1mにします
  3. Applyをクリックして変更を適用します
  4. Extract Materials...ボタンをクリックして、Materialsなどのフォルダーを指定して、マテリアルを保存します

f:id:am1tanaka:20210801214719p:plain
基本設定

ライトをベイクする場合は、さらに以下を設定すると問題が起きにくくなります。

  1. Advancedに切り替えます
  2. Share same faceのチェックを外して、面の共有をやめます
  3. Generate Lightmap UVにチェックを入れます
  4. ベイク時にoverlapの警告が表示される場合は、Pack Marginを増やすと軽減できる場合があります
  5. 全て設定したらApplyボタンを押します

f:id:am1tanaka:20210801215125p:plain
Advanced設定

マテリアルの設定

Extractしたマテリアルを編集して見た目を調整します。保存したマテリアル名ではどのマテリアルか不明ですが、ガラス用のマテリアルはシェーダーがTransparentになっているので分かりやすいです。

  1. Albedoのアルファを下げて透過させます
  2. Smoothnessを大きくしてピカピカにします

f:id:am1tanaka:20210801215752p:plain
ガラスの設定

残り2つのマテリアルのAlbedoを変更してみて、砂のマテリアルを探します。見つけたら、Emissionを設定して光らせます。

f:id:am1tanaka:20210801220103p:plain
Emissionの設定

以上で完成です!!

f:id:am1tanaka:20210801001016p:plain
完成!!

Voxel Importerのメリット

MagicaVoxelはobj形式でのエクスポートができるので、Voxel Importerがなくても同じようなことはできます。ただし、objだと以下のような感じに読み込まれます。

f:id:am1tanaka:20210802122335p:plain
objだとメッシュやテクスチャが分かれてしまう

Voxel Importerなら1つのメッシュで済みます。他にも、ボクセルにウェイトを設定してアニメさせることもできますし、ボクセルの最適化などもできますので、持っていると何かと有難いアセットだと思います。

まとめ

MagicaVoxelで作成したモデルをVoxel Importerで読み込んで、透過や自己発光を設定しました。

assetstore.unity.com

MagicaVoxelで色のMATERIALを変えるとUnityに別マテリアルとして読み込める性質を使って、1つのボクセルモデルに複数のマテリアルを設定しました。静止オブジェクトならドラッグ&ドロップだけでボクセルを読み込むことができ、マテリアルの取り出しもボタンひとつでできます。あとはマテリアルの設定をいじるだけ。また、MagicaVoxelのレイヤーを使うと多重構造などを作りやすくなります。

こんなことをしながら、3年目に突入したVoxelorerBirdの制作を続けています。

大半がMagicaVoxelの記事のような気がしますが、以上、Unity アセット真夏のアドベントカレンダー 2021 Summer! – Unity公式 Asset Portal の4日目の記事でした。

assetstore.info

▲前の日は さとや さんの「単独でも活用できる!Corgi Engine/TopDown Engineに同梱されているMMFeedbacksの紹介」でした。

▼次の日は kido さんの「History Inspector の紹介」です。

では良い制作の夏を!

参考URL

参考図書

conoHa WINGサーバーにFileZillaでSFTP接続

公式だとFTPの設定になってたのでSFTPで接続できるようにする設定を。

目次

SSHキーの作成

以下の手順でSSHキーを作成して、ユーザーフォルダーの.sshフォルダーなどにダウンロードしておきます。

support.conoha.jp

サイトマネージャーにサイト情報を作成

FileZillaでconoHaへの接続情報を作成します。

  • FileZillaのファイルメニューからサイトマネージャーを起動します
  • 新しいサイト をクリックして、conohaなどの名前にします

f:id:am1tanaka:20210531180712p:plain
新しいサイトの作成

  • 右の欄を以下のように設定します
    • プロトコル欄をSFTP - SSH File Transfer Protocol
    • ホスト欄にconoHaのSSH設定のホスト名
    • ポート番号はconoHaのSSH設定のポート番号(8022)
    • ログオンタイプを鍵ファイル
    • ユーザー欄にconoHaのSSH設定のユーザー名
  • 以上設定したら、鍵ファイルの 参照 ボタンをクリック

f:id:am1tanaka:20210531181829p:plain
サイト情報

  • ファイルの種類をPEM fileに変更して、conoHaからダウンロードした秘密鍵を選択して、開くボタンをクリック

f:id:am1tanaka:20210531182252p:plain
PEMファイルを開く

  • OKボタンをクリックします

以上で設定完了です。サイトマネージャーを開いて、conoHaの設定を選択すれば接続できます。

参考URL

LEGO MicrogameのBUILD YOUR OWN GAME!コンテストに応募しました!

子供の時に遊んでいたLEGOがUnity上で動く!

そんなUnity Hubからインストールできる学習プロジェクトの一つLEGO Microgameを使ったゲームコンテストがLEGO IDEASで開催されるということで応募してみました。応募総数は1,150作品!? 盛り上がってます。

コンテストページはこちら。

ideas.lego.com

応募したゲームは以下から遊べます。

ideas.lego.com

日本だと「ブロック」って言ってますけど、英語表記だと「Brick(ブリック=レンガ)」なんですね。今回初めて気づきました。

目次

制作過程

2/1のUnityさんのツイートでコンテストを知りました。

この直後にUnity Learningが日本語化され、LEGOチュートリアルも日本語化されました。

2/18に青木ととさんが解説してくださいましたUnityステーションのLEGO® を使ったゲーム開発コンテスト「BUILD YOUR OWN GAME!」に参加しよう!YouTube動画で概要を把握した辺りから実働開始。

Unity Hubで2019.4.xや今なら2020.3.xで新規プロジェクトを作成する際に、左のテンプレートに注目するとLEGO Microgameがあります。これをチュートリアルでインストールすると、使い方を短い動画などで知ることができるので、それをざくざくやっつけていきました。

f:id:am1tanaka:20210323180546p:plain
LEGO Microgameのテンプレート

この当時は基本的な指示は日本語化されてましたが動画内は英語でした。操作は出ますし今どきはGoogleアプリとかで簡単に和訳できるので大丈夫だと思います。

動画をぼんやり聞いていたため肝心なところを聞き逃していて備忘録的にツイートしたら青木ととさんからお返事いただけました!ありがとうございました!!

LEGO Microgameで作った作品はunityroomにアップできないということで、習作を1週間ゲームジャムに、という野望は潰えました。今回はLEGOを触りたかったのでこちらのコンテストに専念です。

2/19にLEGO Microgameの組み込みチュートリアルとUnity LearnのLEGO® Microgame - Unity Learnは完了。チュートリアルでは分からなかった実行時にブロックをくっつけたり離したりができるかと、プレイヤーやカメラの制御を追加で調査。

一通り把握できたところで、マウスでクリックした場所に歩かせたり、カメラの操作を試作しはじめました。

この時に作ったカメラのシステムをGet the Ship Back!に採用しています。操作の方は動くブロックに乗り降りする操作などが難しそうだったので、元のLEGO Microgameの操作で進めることにしました。

経験を積んでいるうちに良い設定を発見。Hierarchyは荒れますが細かく調整する場合はこの設定は重宝しました。あとブロックの色を変えるパネルが出たり出なかったりしたのはプレハブの解除が必要でした。チュートリアルでプレハブの解除をしていたのはあったのですがその時はピンと来ておらず、試行錯誤しているうちに再発見しました。

こんな問題も発生しました。そのため予定外のものもStudioで組み立てることになりましたが、これがまた楽しくなってしまって時間が溶けました。

ストーリーや設定を導入のムービーとかで伝えたいけど時間が・・・ということで、なんとなくそういう感じのタイトル画面を作って解決!したことにしました。

最後の最後にこんな不具合も。

1つだけWebGLだとエラーになるステージがあって、その原因がこれでした。staticで軽くできるかと思ったのが仇に・・・。

以下のも最終日に発生したやつ。

「エネルギークリスタルを全て取っていたら、レーザー砲に触れるとクリアできる」という条件を作りたいのだけど、トリガーのネストができないのです。追加の条件はVariableで与えられるのでそちらでやったら、なぜか別のステージに前のステージの条件が表示される。なんでだ!?となったやつでした。

以上で公開しました。LEGO Microgameの事前調査2日+企画&制作3週間ぐらいの楽しいLEGO生活でした^^

間に合わなかった要素

時間がものすごくギリギリになってしまったので、いくつか思いついていた要素を省きました。

  • クリアまでのタイムアタックができるようにしたかった
  • 目標物のミニレーダーが欲しかった
  • カメラは上も見られるように調整した方がよかったかも
  • Stage7の4つの黄色スイッチは、押すごとに敵の足場を一つ一つ爆発させたかった
  • Stage7の敵を喋らせたかった
  • 最終ステージの高速化をしたかった

コンテストが終って手を入れてよくなったら追加するかも知れません。

ステージ紹介

あまり遊ばれないならせめてステージ紹介だけでも・・・。これを見て楽しそうに感じたら遊んでいただければ嬉しいです!!

Stage1

チュートリアルステージ。ほぼ死ぬ要素がない練習ステージ。

f:id:am1tanaka:20210325112358p:plain
ゲームスタート!

奥に見える赤い仕掛けのところの爆発に巻き込まれて死ぬ、という想定外の仕様上の死因以外はほぼ死にどころはありません。スイッチを押しながらずんずん進んでください。

f:id:am1tanaka:20210325113533p:plain
マウスホイールでズームアウトしてステージ全体を見る

クリアするとこんな感じで宇宙船のパーツが組み立てられていきます。

f:id:am1tanaka:20210325113440p:plain
最初のパーツを回収!

Stage2

順番がある、と気付くステージ。細いところを渡るスリルなんかもちょこっと入れました。

f:id:am1tanaka:20210325130112p:plain
ここもショートステージ

f:id:am1tanaka:20210325113455p:plain
でも何も考えてないと詰みます

f:id:am1tanaka:20210325113515p:plain
尾翼を回収!

Stage3

ここからが本番。お気に入りの回る足場から、レーザーを避けたり、仕掛けを組み合わせたり。

f:id:am1tanaka:20210325113724p:plain
タイミングよく渡ろう

f:id:am1tanaka:20210325113609p:plain
レーザーを避ける!

f:id:am1tanaka:20210325113638p:plain
左奥に辿り着くための足場をどうやって作ろうか・・・

Stage4

高台からステージ全体を見渡してから飛び降りて、一番下から登っていく高さを意識したステージです。途中の階段や回転足場がお気に入り。

f:id:am1tanaka:20210325114134p:plain
ステージを一望

Stage5

基地にたどり着け!このステージは回収するものがなく、攻撃をかいくぐってゴールを目指します!

f:id:am1tanaka:20210325114254p:plain
いきなりの砲撃!物陰に隠れてタイミングよく飛び出そう

f:id:am1tanaka:20210325114324p:plain
敵の猛攻!あと少しでゴール!!

Stage6

敵基地に潜入。高さ方向にエレベーター中心に作ったステージです。

f:id:am1tanaka:20210325114422p:plain
スタート地点から仕掛けを観察

f:id:am1tanaka:20210325114511p:plain
エレベーターをうまく使って移動しよう

Stage7

敵アジトの本部へ!

f:id:am1tanaka:20210325114619p:plain
レーザーは扉を閉めて遮断!

f:id:am1tanaka:20210325114657p:plain
怪しげな二人組!こいつらが今回の元凶

Stage8

最終ステージ。塔を登りながらクリスタルを集めて、最後のパーツのレーザー砲で巨大砲台を壊そう!

f:id:am1tanaka:20210325114937p:plain
あのどでかいレーザーに撃ち落された。あれを壊さないと同じ事に...

f:id:am1tanaka:20210325115140p:plain
塔を登りつつ、エネルギークリスタルを回収

f:id:am1tanaka:20210325115205p:plain
エネルギーが充填されたレーザー砲に辿り着いた!ついに...

さいごに

開発は3週間程度と思ったよりかかりましたが、ずっと楽しく作れました。実在のレゴブロックのモデルで組み立てられるツールStudio2.0でオブジェクトを作るのは楽しいですし、実在するブロックなので注文すれば実物を作れる可能性があるのも魅力です。

f:id:am1tanaka:20210328211501p:plain
BrickLinkのLEGO組み立てツールSTUDIO2.0

複雑なことをやろうとするとハマりポイントがありますが、シンプルな仕掛けならBehaviourBrickが充実しているので色々できます。カメラはCinemachineなので簡単に調整可能ですし、プレイヤーも調整用のパラメーターが多いですし外部のスクリプトからある程度の制御も可能です。

ちょっと残念だったのは継承が想定されていないクラスが結構あることでした。もとの動作がハードコーディングされていることがあったりして、その部分を変えたい時に難儀しました。もう一つの残念ポイントはUnity Playでしか公開できないことです。これはかなり痛い。ブロックを複雑に組み合わせることができたり、くっつけたブロックが持っている全ての動作を実行するなど手軽に使えるように工夫されていますが、その分、処理が重くWebGLだとパフォーマンス的に結構厳しいです。ネイティブでビルドできれば・・・とか、VRで使ってみたい、とか、可能性が大きそうなだけに発表先の自由度が低いのは残念です。軽量化されるか、発表先の自由度が増すか、今後の展開に期待しています。

テンプレートからプロジェクトを作ればチュートリアルを通して簡単な使い方が分かります。LEGOや積み木が好きな人は楽しめるのではないかと思います。今回は以上です。後日、作り方なども書いていきたいと思います。

ideas.lego.com

おまけ

無事に応募した記念に買ってしまいました。グローグーを組み立ててみましたが、ブロックがぱっちりハマる手応えは楽しいですし、色々なくっつけ方ができることにも驚きました。楽しいですね、LEGO

f:id:am1tanaka:20210326202953j:plain
ご褒美

f:id:am1tanaka:20210329172032p:plain
LEGOグローグー

関連URL