20210411のUnityに関する記事は9件です。

【Unity】できるだけ簡単にScrollViewでセルを再利用して一覧表示したい

参考 次の参考を元にしています。k7a様に感謝します。 やりたいこと 縦スクロール セルの再利用 実行中の一覧の総数変更 任意タイミングで全体再描画 手順 Scroll Viewの追加 StaticScrollViewコンポーネントを追加 StaticScrollViewを制御するコンポーネントを作成 になります。 uGUIの配置 GameObject>UI>Scroll ViewからScrollViewを追加 追加した"Scroll View"を目的の位置とサイズに設定 項目(セル)となるオブジェクトをContent下に作成し、RectTransformの項目を設定 ・アンカーはLeft-Top(画像左上) ・Widthは"Scroll View"の"Content" に合わせ、Heightは自由 ・PivotはX:0,Y:1 ※このセルの子になるようにTextなどUIを追加してください 3で作成したセルをプレハブ化 コンポーネントの追加 次のセル再利用コンポーネントを"Scroll View"にアタッチしてInspectorからContentを指定 using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class StaticScrollView : MonoBehaviour { public RectTransform content; public float spacing = 5; private ScrollRect scrollRect; private IStaticScrollViewController controller; //--- int cellCount; float cellSize; int maxVisibleCellCount; int renderedStartIndex; private LinkedList<StaticScrollViewCell> cells = new LinkedList<StaticScrollViewCell>(); private void Awake() { scrollRect = GetComponent<ScrollRect>(); } public void Setup(IStaticScrollViewController controller,float cellsize) => StartCoroutine(_Setup(controller,cellsize)); private IEnumerator _Setup(IStaticScrollViewController controller,float cellsize) { yield return null; UnityAction<Vector2> update = UpdateCell; scrollRect.onValueChanged.AddListener(update); this.cellSize = cellsize; this.controller = controller; Reload(); for (int i = cells.Count; i < maxVisibleCellCount; i++) { var cell = controller.InitCell(); cell.transform.SetParent(content, false); var visibleCell = new StaticScrollViewCell(cell.GetComponent<RectTransform>(), cell); cells.AddLast(visibleCell); if(i<cellCount) controller.UpdateCell(i, cell); SetCellPosition(i, visibleCell.transform); cell.gameObject.SetActive(i < cellCount); } } public void Reload() { cellCount = controller.StaticScrollViewCellCount; content.sizeDelta = new Vector2(content.sizeDelta.x, (cellSize + spacing) * cellCount); maxVisibleCellCount = Mathf.CeilToInt(scrollRect.viewport.rect.height / (cellSize + spacing)) + 2; renderedStartIndex = 0; int visibleCellsCount = cells.Count; for (int i = 0; i < visibleCellsCount;i ++) { var visibleCell = cells.First(); cells.RemoveFirst(); if(i<cellCount) controller.UpdateCell(i, visibleCell.cell); SetCellPosition(i, visibleCell.transform); cells.AddLast(visibleCell); visibleCell.transform.gameObject.SetActive(i < cellCount); } scrollRect.verticalNormalizedPosition = 1.0f; } public void UpdateCell(Vector2 scrolledBar) { if ( cellCount == 0) return; var startIndex = GetStartIndex(content.localPosition.y); var cellIndex = 0; if (startIndex > renderedStartIndex) { cellIndex = System.Math.Max(startIndex, renderedStartIndex + maxVisibleCellCount); while (cellIndex < startIndex + maxVisibleCellCount) { var visibleCell = cells.First(); cells.RemoveFirst(); if(cellIndex<cellCount) controller.UpdateCell(cellIndex, visibleCell.cell); cells.AddLast(visibleCell); SetCellPosition(cellIndex,visibleCell.transform); visibleCell.transform.gameObject.SetActive(cellIndex < cellCount); cellIndex++; } } else if (cellIndex < renderedStartIndex) { cellIndex = System.Math.Min(renderedStartIndex + maxVisibleCellCount - 1, renderedStartIndex - 1); while (cellIndex >= startIndex) { var visibleCell = cells.Last(); cells.RemoveLast(); if(cellIndex < cellCount) controller.UpdateCell(cellIndex, visibleCell.cell); cells.AddFirst(visibleCell); SetCellPosition(cellIndex,visibleCell.transform); visibleCell.transform.gameObject.SetActive(cellIndex < cellCount); cellIndex--; } } renderedStartIndex = startIndex; } private int GetStartIndex(float scrolledHeight) =>(int)System.Math.Truncate((scrolledHeight) / (cellSize + spacing)); private void SetCellPosition(int index,RectTransform t) => t.localPosition = new Vector2(0,-index *(cellSize + spacing)); class StaticScrollViewCell { public StaticScrollViewCell(RectTransform transform, Component cell) { this.transform = transform; this.cell = cell; } public RectTransform transform; public Component cell; } } public interface IStaticScrollViewController { int StaticScrollViewCellCount { get; } Component InitCell(); void UpdateCell(int index, Component cell); } ※補足:Scroll RectのOnValueChangedにInspectorからUpdateCellを登録する必要はありません 2.新しくScrollView制御コンポーネントを作成し、作成したコンポーネントにIStaticScrollViewControllerを実装してアタッチ public class TestScrollViewController : MonoBehaviour,IStaticScrollViewController {...} (次のメソッドを追加するように求められます) int StaticScrollViewCellCount { get; } //一覧の数 Component InitCell(); //生成したセル void UpdateCell(int index, Component cell);) //一覧更新時処理 3.実行開始時(Start以降)にGetComponentなどから1のStaticScrollViewを取得してSetup(this,セルの高さ)を呼ぶ 4. 一覧の総数が変わったり、再描画したい場合は、Reloadを呼ぶ(Setup時は不要) 以下2から4のサンプル ※ItemCellは無視してください(セルのUI管理用に使用していました) using System.Collections; using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif public class TestScrollViewController : MonoBehaviour,IStaticScrollViewController { public GameObject prefab; public int cellCount = 15; //表示総数 // Start is called before the first frame update void Start() { GetComponent<StaticScrollView>().Setup(this, prefab.GetComponent<RectTransform>().sizeDelta.y); } //InitCellで指定したコンポーネントがセルごとに渡されます public void UpdateCell(int index, Component cell) { var c = cell as ItemCell; c.text.text = index.ToString() + ",max:" + cellCount; } //任意のコンポーネントを渡すことができます public Component InitCell() { return Instantiate(prefab).GetComponent<ItemCell>(); } //表示総数 public int StaticScrollViewCellCount { get => cellCount; } } //Inspector表示用なので気にしないでください #if UNITY_EDITOR [CustomEditor(typeof(TestScrollViewController))] public class ControllerEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); if (GUILayout.Button("Reload")) { var t = target as TestScrollViewController; t.GetComponent<StaticScrollView>().Reload(); } } } #endif  おわりに 恐らく多々改善点がある(もしかしたら根本的に作り直す必要がある)と思いますのでぜひコメントでご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】できるだけ簡単にScrollViewでセルを再利用して一覧表示する

参考 次の参考を元にしています。k7a様に感謝します。 やりたいこと 縦スクロール セルの再利用 実行中の一覧の総数変更 任意タイミングで全体再描画 想定していないこと 横スクロール セルごとに異なる高さ設定 手順 uGUIの配置 GameObject>UI>Scroll ViewからScrollViewを追加 追加した"Scroll View"を目的の位置とサイズに設定 項目(セル)となるオブジェクトをContent下に作成し、RectTransformの項目を設定 ・アンカーはLeft-Top(画像左上) ・Widthは"Scroll View"の"Content" に合わせ、Heightは自由 ・PivotはX:0,Y:1 ※このセルの子になるようにTextなどUIを追加してください 3で作成したセルをプレハブ化 コンポーネントの追加 次のコンポーネントを"Scroll View"にアタッチしてInspectorからContentを指定 using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; public class StaticScrollView : MonoBehaviour { public RectTransform content; public float spacing = 5; private ScrollRect scrollRect; private IStaticScrollViewController controller; //--- int cellCount; float cellSize; int maxVisibleCellCount; int renderedStartIndex; private LinkedList<StaticScrollViewCell> cells = new LinkedList<StaticScrollViewCell>(); private void Awake() { scrollRect = GetComponent<ScrollRect>(); } public void Setup(IStaticScrollViewController controller,float cellsize) => StartCoroutine(_Setup(controller,cellsize)); private IEnumerator _Setup(IStaticScrollViewController controller,float cellsize) { yield return null; UnityAction<Vector2> update = UpdateCell; scrollRect.onValueChanged.AddListener(update); this.cellSize = cellsize; this.controller = controller; Reload(); for (int i = cells.Count; i < maxVisibleCellCount; i++) { var cell = controller.InitCell(); cell.transform.SetParent(content, false); var visibleCell = new StaticScrollViewCell(cell.GetComponent<RectTransform>(), cell); cells.AddLast(visibleCell); if(i<cellCount) controller.UpdateCell(i, cell); SetCellPosition(i, visibleCell.transform); cell.gameObject.SetActive(i < cellCount); } } public void Reload() { cellCount = controller.StaticScrollViewCellCount; content.sizeDelta = new Vector2(content.sizeDelta.x, (cellSize + spacing) * cellCount); maxVisibleCellCount = Mathf.CeilToInt(scrollRect.viewport.rect.height / (cellSize + spacing)) + 2; renderedStartIndex = 0; int visibleCellsCount = cells.Count; for (int i = 0; i < visibleCellsCount;i ++) { var visibleCell = cells.First(); cells.RemoveFirst(); if(i<cellCount) controller.UpdateCell(i, visibleCell.cell); SetCellPosition(i, visibleCell.transform); cells.AddLast(visibleCell); visibleCell.transform.gameObject.SetActive(i < cellCount); } scrollRect.verticalNormalizedPosition = 1.0f; } public void UpdateCell(Vector2 scrolledBar) { if ( cellCount == 0) return; var startIndex = GetStartIndex(content.localPosition.y); var cellIndex = 0; if (startIndex > renderedStartIndex) { cellIndex = System.Math.Max(startIndex, renderedStartIndex + maxVisibleCellCount); while (cellIndex < startIndex + maxVisibleCellCount) { var visibleCell = cells.First(); cells.RemoveFirst(); if(cellIndex<cellCount) controller.UpdateCell(cellIndex, visibleCell.cell); cells.AddLast(visibleCell); SetCellPosition(cellIndex,visibleCell.transform); visibleCell.transform.gameObject.SetActive(cellIndex < cellCount); cellIndex++; } } else if (cellIndex < renderedStartIndex) { cellIndex = System.Math.Min(renderedStartIndex + maxVisibleCellCount - 1, renderedStartIndex - 1); while (cellIndex >= startIndex) { var visibleCell = cells.Last(); cells.RemoveLast(); if(cellIndex < cellCount) controller.UpdateCell(cellIndex, visibleCell.cell); cells.AddFirst(visibleCell); SetCellPosition(cellIndex,visibleCell.transform); visibleCell.transform.gameObject.SetActive(cellIndex < cellCount); cellIndex--; } } renderedStartIndex = startIndex; } private int GetStartIndex(float scrolledHeight) =>(int)System.Math.Truncate((scrolledHeight) / (cellSize + spacing)); private void SetCellPosition(int index,RectTransform t) => t.localPosition = new Vector2(0,-index *(cellSize + spacing)); class StaticScrollViewCell { public StaticScrollViewCell(RectTransform transform, Component cell) { this.transform = transform; this.cell = cell; } public RectTransform transform; public Component cell; } } public interface IStaticScrollViewController { int StaticScrollViewCellCount { get; } Component InitCell(); void UpdateCell(int index, Component cell); } ※補足:Scroll RectのOnValueChangedにInspectorからUpdateCellを登録する必要はありません 2.新しいコンポーネントを作成し、作成したコンポーネントにIStaticScrollViewControllerを実装してアタッチ public class TestScrollViewController : MonoBehaviour,IStaticScrollViewController {...} (次のメソッドを追加するように求められます) int StaticScrollViewCellCount { get; } //一覧の数 Component InitCell(); //生成したセル void UpdateCell(int index, Component cell);) //一覧更新時処理 3.実行開始時(Start以降)にGetComponentなどから1のStaticScrollViewを取得してSetup(this,セルの高さ)を呼ぶ 4. 一覧の総数が変わったり、再描画したい場合は、Reloadを呼ぶ(Setup時は不要) 以下2から4のサンプルです ※ItemCellは無視してください(セルのUI管理用に使用していました) using System.Collections; using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif public class TestScrollViewController : MonoBehaviour,IStaticScrollViewController { public GameObject prefab; public int cellCount = 15; //表示総数 // Start is called before the first frame update void Start() { GetComponent<StaticScrollView>().Setup(this, prefab.GetComponent<RectTransform>().sizeDelta.y); } //InitCellで指定したコンポーネントがセルごとに渡されます public void UpdateCell(int index, Component cell) { var c = cell as ItemCell; c.text.text = index.ToString() + ",max:" + cellCount; } //任意のコンポーネントを渡すことができます public Component InitCell() { return Instantiate(prefab).GetComponent<ItemCell>(); } //表示総数 public int StaticScrollViewCellCount { get => cellCount; } } //Inspector表示用なので気にしないでください #if UNITY_EDITOR [CustomEditor(typeof(TestScrollViewController))] public class ControllerEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); if (GUILayout.Button("Reload")) { var t = target as TestScrollViewController; t.GetComponent<StaticScrollView>().Reload(); } } } #endif
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityとGitHubActionsを使って自動でunitypackageをエクスポートする

はじめに 最終的に仕上がったものは以下のリポジトリで公開してあります。 分からないことがあったときは参考にしてみてください。 手順 UnityとGitHub Actionsを使ってunitypackageのエクスポートを行う手順です。 1. パッケージをエクスポートするC#を記述する GitHub Actions上でパッケージを出力するためのC#スクリプトを追加します。 プロジェクトリポジトリのEditorフォルダ下に、UnityPackageExporter.cs(名前はなんでもいい)を追加し、以下のように記述します。(パッケージ名などの定数はプロジェクトに合わせてください) UnityPackageExporter.cs using System.IO; using UnityEditor; namespace ExportPackageExample.Editor { public static class UnityPackageExporter { // 出力するunitypackageの名前 const string k_PackageName = "ExportPackageExample"; // `Assets/`フォルダ下にあるパッケージのパス const string k_PackagePath = "ExportPackageExample"; // エクスポート先のパス const string k_ExportPath = "Build"; public static void Export () { ExportPackage($"{k_ExportPath}/{k_PackageName}.unitypackage"); } public static string ExportPackage (string exportPath) { // Ensure export path. var dir = new FileInfo(exportPath).Directory; if (dir != null && !dir.Exists) { dir.Create(); } // Export AssetDatabase.ExportPackage( $"Assets/{k_PackagePath}", exportPath, ExportPackageOptions.Recurse ); return Path.GetFullPath(exportPath); } } } かなり簡潔に書いたものなので、もし「もっと細かくパッケージをカスタマイズしたい」という場合は、公式のドキュメントを参考にしてください。 https://docs.unity3d.com/ScriptReference/AssetDatabase.ExportPackage.html 2. ULFファイルを入手する GitHub Actions上でUnityライセンスをアクティベートするためのULFファイルを入手します。 この手順に関しては別の記事として書かせてもらいました。(GUIのみで簡単にできます) 3. ULFファイルをSecretsに登録する プロジェクトリポジトリのSettings > Secretsメニューを選択する。 New repository secretボタンをクリックする。 Nameに"UNITY_LICENSE"と入力し、ValueにULFファイルの中身をコピペする。 Add secretボタンをクリックする。 これでULFファイルの中身は非公開のまま、環境変数として扱うことができます。 4. GitHub ActionsでunitypackageをエクスポートするYAMLを記述する リポジトリの.github/workflows/下にpackage.yamlファイルを追加します。 package.yamlに以下のように記述します。 package.yaml name: Export Package on: pull_request: {} push: { branches: [main] } env: UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} jobs: build: name: Build UnityPackage runs-on: ubuntu-latest steps: # Checkout - name: Checkout repository uses: actions/checkout@v2 with: lfs: true # Cache - name: Cache uses: actions/cache@v2 with: path: Library key: Library restore-keys: Library- # Build - name: Build .unitypackage uses: game-ci/unity-builder@v2 with: unityVersion: 2020.3.1f1 # Secretsに登録したULFのUnityバージョン buildMethod: ExportPackageExample.Editor.UnityPackageExporter.Export # 名前空間を含むエクスポート関数の名前 # Upload - name: Upload .unitypackage uses: actions/upload-artifact@v2 with: name: Unity Package path: Build 5. エクスポートしてみる リポジトリにPush及びPull Requestを行うことで、unitypackageをエクスポートするワークフローが走ります。 以下のように✔マークが表示されていれば成功です。出力されたunitypackageは右上のArtifactsから入手できます。 さいごに 最終的に仕上がったリポジトリです。詰まったときは参考にしてみてください。 CIは初めてであまり詳しくないので、間違えているところがあれば教えてもらえると幸いです。 参考 Github Actions で UnityPackage をビルドしたら快適だった話 GameCI - Builder
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[脱初心者への道]AndroidのリモートデバッグではまるCommandInvokationFailure

謎のエラーでリモート実行できない UnityでAndroid向けにBuildしてリモートで実行しようとすると、以下のようなエラーが出ることがあります。 : Unable to install APK to device. Please make sure the Android SDK is installed and is properly configured in the Editor. See the Console for more details. ただ、この後にBuildが成功しているメッセージは出ていて、Buildは失敗して無さそうだし、SDKも入ってる。という場合の対処方法を以下に示します。 原因1:同じアプリが既に入っている 一番、単純な話ですが、入れようとしているアプリが既にストア等からインストールされているとエラーになってインストールできません。 https://www.crossroad-tech.com/entry/UnityAndroidBuildFailure 原因2:Android側に空きがない これもあり得ます、エラーメッセージから推測しがたいです。 http://blog.lab7.biz/archives/21598575.html 原因3:ADBが邪魔している この現象もありました。 https://qiita.com/r-ngtm/items/13a09e33e6788be42eb8
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Oculus Quest2】クライアントのアカウントでVRコンテンツを納品するまで

後から振り返れば当たり前なことかもしれませんが、私がハマってしまった体験談を投稿したいと思います。もしかしたら同じことで困っている方がいて、この記事が少しでも参考になれば幸いです。 はじめてのVR開発案件が、Quest2にコンテンツをインストールして現物納品というものでした。その際、当然ながらデバイスの管理者アカウントはクライアントのものにしなければなりません。自分のデバイスに自分のアカウントでしか設定やインストールをした経験がなかった私は、漠然としか流れをイメージできていなかったのです。。 体験談を書く前に、結論から。 クライアントのアカウントでコンテンツをインストールするには クライアントのFacebookアカウントでFacebookにログイン Oculusの開発者としてOculusアカウントを作成(ここで、基本的にはFacebookアカウントとOculusアカウントが統合される) スマホのOculusアプリで、クライアントのFacebookアカウントでログイン 開発者モードにする (必要があれば)Quest2を出荷状態に戻す(リセット) 改めて通常通りの初期設定でQuest2をペアリング(これでクライアントのアカウントで設定される) コンテンツをインストール 以上です。 書いていることは当たり前ですよね...。しかし、ここに行き着くまでの自分の思い違いからの試行錯誤と、参考になるかもしれないポイントを次に書いていきたいと思います。 最初は・・・ 新品のQuest2が届き、開発中は自分のアカウントでセットアップしました。ですから、環境は整っており、特に問題なくスマホのOculusアプリからペアリングできます。 クライアントからは、Facebookアカウントだけもらっていました。最初に考えたのは、開発者は自分で、すでにコンテンツのインストールはできているから、複数アカウントでクライアントのアカウントを追加し、その後自分のアカウントを削除する、というものでした。 がしかし、調べてみると管理者アカウントは削除できないらしい・・・。ということは、この方法は不可でした。 次に考えたのは・・・ 逆に、クライアントのFacebookアカウントでセットアップだけして、複数アカウントで自分を追加すればコンテンツをインストールできるのではないか?ということでした。 そのためには、まずクライアントのFacebookアカウントでOculusアプリにログインを...しようとしたところ、最初の壁に突き当たりました。 自分以外のFacebookアカウントでログインできない iPhoneのOculusアプリの画面からは、 Facebookでログイン Oculusアカウントをお持ちの場合 というボタンしかありません。 この、「Facebookでログイン」をクリックすると、「〇〇(自分の名前)として続行」しか選べません。Facebookアプリの方でクライアントのアカウントでログインし直していても、です。 一方、試せてはいないのですが、GooglePlayストアからダウンロードとしたアプリには、「別のFacebookアカウントにログイン」というボタンがあるようです。(こちらはネットで見つけた画像なので、AppStoreとGooglePlayストアのアプリで、デフォルトでこのような表示の違いがあるかは確証ありませんが) えー、、どうすればいいの?!となりました・・・ これは、もう一つのボタン Oculusアカウントをお持ちの場合 でしかできないのか...?と思い、(開発者として必要という認識ではなく単にログインしたいために)Oculusアカウントを作成することにしました。 Oculusアカウントを作成 しかし、Oculusアカウント作成でもトラブルが...。これはレアケースだと思われるので参考にはならないと思いますが、PCのOculusアプリからOculusアカウントを作成しようとしたところ、なぜか設定の途中で表示が固まり、パスワードの設定画面までいけません。アカウントができているかも不明です...。しかし、もう一度同じFacebookアカウントで作成しようとするとはじかれるので、とりあえず作成はされているようなのですが、パスワードが不明なまま...(泣) これでは、 Oculusアカウントをお持ちの場合 からも入れません・・・(大泣) 結局、Facebookアカウントでなんとか入れた 散々調べたり試行錯誤した結果、AppStoreからダウンロードしたアプリの画面で、一番下にある「アカウント登録」を選ぶと一旦自分のFacebookアカウントが自動検出されましたが、その画面からFacebookに移動してログアウト→別のアカウントでログイン後、再度Oculusアプリを開くと、ログインし直したFacebookアカウントが表示されました!(Facebookアプリの方から先にアカウント変更しても反映されなかったのに、、わかりにくい、、) ※注釈※ 一度認識?された後は、Facebookアプリの方から先にアカウント変更しても反映されたりしたので、タイミング的な問題などなのかも知れません。。 これでほっと一安心、Oculusアプリにログインさえできれば、あとは通常通りQuest2をセットアップすれば大丈夫。 しかし、私は、ここで最大の過ちを犯してしまいました・・・ Oculusアカウントの削除 そもそも、 クライアントのFacebookアカウントでセットアップだけして、複数アカウントで自分を追加すればコンテンツをインストールできるのではないか? という考えで、単にOculusアプリにログインしたいために作成したOculusアカウントだったので、入れてしまえば不要(むしろクライアントのアカウントを勝手に作成して置いておくのは良くない)と思い、「Oculusアカウントの削除」を実行してしまいました。 さっきまで入れていたのにまたログインができなくなった FacebookアカウントとOculusアカウントは別物、と思っていました。統合されているとはいえ、Oculusアカウントだけ削除してもFacebookアカウントは生きているのだから、ふつうにログインできるものと。。 しかし、Oculusアカウントを削除以降、Oculusアプリのログイン画面はグルグル読み込もうとするままで、入れなくなってしまいました。考えられる原因はもちろん、Oculusアカウントの削除です。 ようやくどうすればよかったのか分かった(遅い) そうです、Oculusアカウントは必要だったのです。 少なくとも、FacebookアカウントがOculusアカウントと統合された状態でOculusアプリにログインした場合は、Oculusアカウントを削除すると認識されなくなるようです。さらに、コンテンツのインストールも、冷静に考えれば管理者アカウントが開発者モードにできないと無理だと思われます。ですから、最初からクライアント用にOculusアカウントは必須だったのだと。。(そもそも私はその認識がありませんでした。クライアントのアカウントを開発者に登録する必要はないと勝手に思い込んでいたというか。また、「複数アカウントを登録できる」ということにも惑わされていましたが、そもそも複数アカウント自体が「テスト機能」となっていることからも正攻法でないのは明らかでした...) すべてに気づいたときには、もう納品前々日、とにかく出来得る措置をとり、あとは運を天に任せるしかありませんでした。。 Oculusサポートさま、ありがとう Oculusアカウント削除のキャンセル(復旧)は、サポートに連絡(※)して対応してもらうよりほかなく、とにかく翌日中に対応してくれることを祈りました。”問い合わせが増えており、できる限り2営業日中には対応します”とありましたが、実際には即日対応してくれました。「削除のキャンセル」という、機械的に対応できる種類の内容だったからというのもあるかもしれませんが、そのときの私には、サポートデスクの方が神様に思えました。。 (※)サポートのお問い合わせページから、「サポートチケットを送信する。」をクリック。「リクエストタイプ」等、的確に選択して、問い合わせ内容は明瞭に書く方が迅速に対応してもらえるような気がします。 こうして、無事納品に間に合いましたが、一時は本当にどうしようかと寿命が縮まる思いでした。 振り返ると、自分の考えの無さが恥ずかしいですが、そのときは必死で混乱してしまいました。このような経験でも、どなたかの役に立つことがあれば嬉しいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Fonts を使って TextMeshPro で日本語を表示する

Unity の TextMeshPro で Google Fonts のフォント利用しつつ、日本語を表示する方法をまとめました。 Google Fonts とは Google が提供してくれているフォントサービスです。基本的に無料で利用でき、日本語にも対応しているフォントがたくさんあります。もちろん非対応のフォントのほうが多いですが・・・。好きな書体があればすぐに使えるのがメリットだと思います。下の画像のようなフォントがたくさんあるので、まずは上のリンクからさっと見てみるとモチベーションが上がると思います。 手順 まずは普通にブラウザで Google Fonts から日本語が使えるフォントをダウンロードします。(例えば NotoSansJP を開き、Download Familyを押します。zip ファイルの中に otf が入っているはずなので、後でそれを使用します。) ここからはUnityです。TextMeshPro をインストールします。Window -> PackageManager を開き、検索ボックスに TextMeshPro をいれて探すのが楽かもしれません。 インストールするとウィンドウが開くので、Import TMP Essentials を押して閉じます。 Window -> TextMeshPro -> Font Asset Creator を起動します。 以下の値を設定して Generate Font Atlas を押します。登録する文字(※1)は Custom Characters を選択すると入力できる Custom Charcter List に貼り付けます。 出力までに時間がかかるので待ちます。(手軽にやるなら Packing Method を Fast にするとここの待ち時間が短くなります。) Save を押して Font Asset を保存します。 上で保存したファイルを TextMesh Pro の Font Asset に設定します。 ※1 漢字など第二水準までは UnityのText Mesh Proでほぼ全ての日本語を表示させる の記事がまとめてくれています。 第二水準まで全部入れようとすると、Atlas Resolution が 8192x8192 でないと入らないかもしれません。一度試しにやってみたところ 131MB というアホみたいなファイルサイズになりました。ちょっと無謀だと思うので、何かを削ることを考えないといけないかと思います。 上記リストの 哩 までが第一水準と信じて、それ以降を削除しつつ、Atlas Resolution を 4096 x 2048 にしたところ 18MB ぐらいまで減りました。この辺が妥協点なのではと思い、上記設定値はそうしてあります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityとGitHubActionsを使って自動テストを行う

はじめに 最終的に仕上がったものは以下のリポジトリで公開してあります。 分からないことがあったときは参考にしてください。 手順 以下、UnityとGitHub Actionsを使って自動テストを行う手順です。 1. プロジェクトを用意する 適当にテストが含まれるプロジェクトのリポジトリを用意します。 2. ULFファイルを入手する UnityライセンスをアクティベートするためのULFファイルを入手します。 この手順に関しては別の記事として書かせてもらいました。(GUIのみで簡単にできます) 3. ULFファイルをSecretsに登録する プロジェクトリポジトリのSettings > Secretsメニューを選択する。 New repository secretボタンをクリックする。 Nameに"UNITY_LICENSE"と入力し、ValueにULFファイルの中身をコピペする。 Add secretボタンをクリックする。 これでULFファイルの中身は非公開のまま、環境変数として扱うことができます。 4. テストを走らせるためのYAMLファイルを記述する .github/workflows/フォルダ下(例)にTest.yamlファイル(名前は何でもいい)を作成し、そこにテストを走らせるための処理を記述します。 Test.yaml name: Test on: [push, pull_request] jobs: test: name: ${{ matrix.testMode }} on ${{ matrix.unityVersion }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: projectPath: - . unityVersion: - 2020.3.1f1 # Secretsに登録したULFのUnityバージョンを記入 testMode: - playmode - editmode steps: # Checkout - uses: actions/checkout@v2 with: lfs: true # Cache - uses: actions/cache@v2 with: path: ${{ matrix.projectPath }}/Library key: Library-${{ matrix.projectPath }} restore-keys: | Library- # Test - uses: game-ci/unity-test-runner@v2 id: tests env: UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} with: projectPath: ${{ matrix.projectPath }} unityVersion: ${{ matrix.unityVersion }} testMode: ${{ matrix.testMode }} artifactsPath: ${{ matrix.testMode }}-artifacts checkName: ${{ matrix.testMode }} Test Results # Upload Artifact - uses: actions/upload-artifact@v2 if: always() with: name: Test results for ${{ matrix.testMode }} path: ${{ steps.tests.outputs.artifactsPath }} 5. GitHub Actionsでテストを走らせる 上記のTest.yamlの場合だと、PushまたはPull RequestをするたびにGitHub Actionsでテストが実行されます。 以下の画像のように✔マークがついていれば成功です。 さいごに 最終的に仕上がったリポジトリです。詰まったときは参考にしてみてください。 CIは初めてであまり詳しくないので、間違えているところがあれば教えてもらえると幸いです。 参考 【Unity】GitHub Actions v2でUnity Test Runnerを走らせて、結果をSlackに報告する【入門】 GitHub Actions を使った Unity の自動テスト UnityとGithubActionsを使って自動テストをセットアップする手順の備忘録
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHubActionsでUnityライセンスのアクティベーションを行うためのULFファイルを入手する(GUI操作のみ)

はじめに GitHubActionsでUnityTestRunnerを走らせる際に何度もUnityライセンスのアクティベーションを行う必要があったので、その作業を簡略化しました。 手順 UnityライセンスをアクティベートするためのALF及びULFファイルの入手の手順です。 1. ALFファイル生成用リポジトリをForkする GitHubActionsを介してALFファイルの生成を行うため、以下のリポジトリをForkします。 ALFファイルを生成するためのワークフローが含まれます。 2. Acquire activation file with GUIページを開く Forkして作成されたリポジトリのActionsタブからAcquire activation file with GUIページを開きます。 3. ALFファイルを生成する Run workflowドロップダウンをクリックします ALFファイルを取得したいUnityのバージョン(例:2019.4.0f1)を指定します。 Run workflowボタンをクリックします。 ワークフローが完了するまで待ちます。 4. ALFファイルを取得する 完成したワークフローページのアーティファクトからUnity_v20XX.X.XfX.alfファイルを取得します。 取得したzipファイルを解凍します。 5. ULFファイルを取得する Unityの手動アクティベーションページを開きます。(https://license.unity3d.com/manual) 取得したUnity_v20XX.X.XfX.alfファイルを使用してアクティベーションします。 Download license fileボタンをクリックしてULFファイルをダウンロードします。 以上の手順でULFファイルを取得できます。 もしうまくいかなかった場合は、以下のドキュメントを参考にしてみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHubActionsでUnityライセンスのアクティベーションを行うためのULFファイルを入手するツールを作った【GUI操作のみ】

はじめに GitHubActionsでUnityTestRunnerを走らせる際に何度もUnityライセンスのアクティベーションを行う必要があったので、その作業を簡略化しました。 手順 UnityライセンスをアクティベートするためのALF及びULFファイルの入手の手順です。 1. ALFファイル生成用リポジトリをForkする GitHubActionsを介してALFファイルの生成を行うため、以下のリポジトリをForkします。 ALFファイルを生成するためのワークフローが含まれます。 2. Acquire activation file with GUIページを開く Forkして作成されたリポジトリのActionsタブからAcquire activation file with GUIページを開きます。 3. ALFファイルを生成する Run workflowドロップダウンをクリックします ALFファイルを取得したいUnityのバージョン(例:2019.4.0f1)を指定します。 Run workflowボタンをクリックします。 ワークフローが完了するまで待ちます。 4. ALFファイルを取得する 完成したワークフローページのアーティファクトからUnity_v20XX.X.XfX.alfファイルを取得します。 取得したzipファイルを解凍します。 5. ULFファイルを取得する Unityの手動アクティベーションページを開きます。(https://license.unity3d.com/manual) 取得したUnity_v20XX.X.XfX.alfファイルを使用してアクティベーションします。 Download license fileボタンをクリックしてULFファイルをダウンロードします。 以上の手順でULFファイルを取得できます。 もしうまくいかなかった場合は、以下のドキュメントを参考にしてみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む