へくれすブログ

UnityとC#中心の備忘録です

【Unity】【AssetStore】組織(企業/サークルなど)で購入したアセット管理のベストプラクティス

今回は技術ではなく権利まわりのお話です。
企業やサークルといった「組織」がAssetStoreでアセットを購入した場合の諸々についてです。

アセットをいくつ買えばいいの? とか
使っている人が退職した場合は? だとか
UnityProシートみたいに割り当てられないの? などなど

調べたり問い合わせたりしたので結果を書いていきます。

続きを読む

【Unity】コードから最新のYAMLクラスIDリファレンスを取得する方法

今回はYAMLクラスIDリファレンスを取得する方法についてです。
Unityの公式ドキュメントの情報が古いためリフレクションで強引に取得します。

f:id:hecres:20180317152302j:plain

YAMLクラスIDとは

YAML(ヤメル、ヤムル)はデータ形式の一種です。XMLやJSONなどの同類です。

そしてクラスIDとは、その名の通り各クラスに割り当てられたIDのことです。
GameObject=1、Component=2…といったように、Unity内の各クラスにはIDが割り振られています*1

どのクラスにどのIDが割り振られているかは、基本的にはUnity公式ドキュメントで公開されています。

currentドキュメント
YAML クラス ID リファレンス - Unity マニュアル

ちなみにversion 5.4以降のドキュメントはレイアウトが妙に見づらいので、
雰囲気を掴むには5.3のドキュメントのほうがお勧めです。

5.3ドキュメント
Unity - マニュアル: YAML クラス ID リファレンス

クラスIDが必要となる場面

PlayerSettings内のStrip Engine Codeをtrueにしている場合、クラスIDは非常に重要な情報です。

Strip Engine Codeとは、ビルド時にUnityエンジン側のコードを必要最低限のみ含める機能です。
使用されていないコードを除外することでビルドサイズの削減が見込め、特にWebGLでは影響が顕著に現れます。

しかし落とし穴もあり、この「必要最低限」にはAssetBundleが考慮されません。

あるコンポーネントが
「AssetBundle内で使用されている、かつ、アプリ本体側に含まれていない」場合
そのコンポーネントはビルドに含まれないため実行段階でエラーとなります。

エラーメッセージは「Could not produce class with ID 331」のような形式です。

この場合331=SpriteMaskがないぞと怒られているため、SpriteMaskをスプリット対象外に設定すれば解決できます。

指定クラスをスプリット対象外とするにはAssets直下にlink.xmlという名前のXMLファイルを作成します。

問題は冒頭で述べた通りUnity公式ドキュメントの情報が古く、
エラーメッセージで出たクラスIDが必ずしも載っているとは限らない点です。

SpriteMaskも本記事を書いている時点での最新版(2018.1ドキュメント)では記載されていません。

コードから最新のクラスIDを取得する方法

本題です。

クラスIDはUnityEditor.UnityTypesクラスが持っています。
UnityTypesクラスはinternal sealed定義となっているためリフレクションでアクセスします。

上記GetClassNameメソッドで指定したIDのクラス名が取得できます。

特定のIDを取得するのではなく、すべてをリストアップしたい場合は
上記メソッドをfor文で1200回ほど回してください。

Unity公式ドキュメントに記載されているIDは1120までなので
それだけ回せば全IDを取得できるはずです。

参考/関連

docs.unity3d.com
https://forum.unity.com/threads/yaml-class-id-reference.501959/

この記事でのバージョン

Version
Unity 2017.3.0p4
Unity/PlayerSettings/Scripting Runtime Version Experimental (.NET 4.6 Equivalent)

*1:なお、スクリプトで定義されたクラスはすべてMonoBehaviour=114のクラスIDが割り振られます。

【Unity】XcodeでのSimulatorビルドがクラッシュする問題について

以下のエラーメッセージに悩まされている方向けの記事です。
[UnityAppController renderingAPI] called before [UnityAppController selectRenderingApi]

f:id:hecres:20180316192302j:plain

現象

Target SDKをSimulator SDKに設定し、
Xcodeでシミュレーター向けのビルドを行うと

Uncaught exception: NSInternalInconsistencyException:
[UnityAppController renderingAPI] called before [UnityAppController selectRenderingApi]

とエラーが発生してクラッシュします。

実機ビルドやストア用のビルドでは正常に動作します。

原因と解決方法

Player Settings内のGraphics APIsにMetalのみ設定していることが原因のようです。
Graphics APIsにOpenGL ES 3などを追加するとシミュレーターモードでも動作します。

f:id:hecres:20180316190808j:plain

Metalのみ設定している場合にクラッシュするのは、調べた限りでは
XcodeのシミュレータがMetalをサポートしていないためのようです。

サポートしていない理由についてはAppleのデベロッパーフォーラムに
「シミュレータはエミュレータではなく、i386用に構築されたスタックを実行している」
という書き込みがありました。

つまりシミュレーターは32bitプロセッサ向けであり、
Metalは64bitプロセッサ用のグラフィックAPIなので対応できない?

iOS11で32bitアプリのサポートが終了したことですし、
シミュレーターも64bit向けに変わっていくのを期待したいところです。

参考/関連

answers.unity.com
forums.developer.apple.com

この記事でのバージョン

Version
Unity 2017.3.0p4
Unity/PlayerSettings/Scripting Runtime Version Experimental (.NET 4.6 Equivalent)

【Unity】【エディタ拡張】Project Settingsへのショートカット(ツールバー型)

2018/03/16追記

本記事を投稿した2日後に気が付いたのですが、 参考サイト様で既に完全上位互換のツールが公開されていました。

baba-s.hatenablog.com

baba-s.hatenablog.com

恥ずかしながら、記事作成時はまったく気が付いておりませんでした。

本記事のツールバーよりもコンパクトかつ汎用性に富んでいるため、
断然あちらのツールを使うべきです。

-----追記ここまで------------------------------

今回は各ProjectSettingsウィンドウ(とLightingウィンドウ)のショートカットを作ります。

f:id:hecres:20180310153142j:plain

ツールバー型です。

はじめは再生ボタンの左右に置こうかと思ったのですが、
あのスペースを活用するアセットもあるので普通のEditorWindowで作りました。

少し場所はとりますがそのほうが楽競合するリスクの回避を重視しました。

元ネタはこちら。
【Unity】Player Settingsを簡単に開けるようにするエディタ拡張 - コガネブログ
Project Settingsを簡単に開けるようにするエディタ拡張 - PanzerSoftのブログ

UnityのバージョンアップでEdit/Render Settingsが開けなくなっていたことと、
個人的に横長のツールバータイプが欲しかったので作りました。

成果物

どういった形で記事に載せるか迷ったのですが、とりあえず1ファイルにまとめてあります。

そのままプロジェクトに入れれば使えますが、
本来はnamespace=ディレクトリとして作成しています。

自分は結構細かくファイル・クラスを分割するタイプなので、ショートカット機能を実現するだけで6ファイルつくっています。
こういう書き方をするならGistではなくリポジトリを公開したほうがよいのかも……?

リポジトリを作ったらここに追記して載せておきます。

参考/関連

baba-s.hatenablog.com panzersoft.blog.fc2.com

この記事でのバージョン

Version
Unity 2017.3.0p4
Unity/PlayerSettings/Scripting Runtime Version Experimental (.NET 4.6 Equivalent)

【Unity】AudioSourceの同時再生による音割れを防ぐ方法

今回は音割れに関するTipsです。

f:id:hecres:20180310163842j:plain

音、特に効果音は複数/同一の音源を同時再生する機会が多いかと思います。
その際問題になるのが「同時再生の実現」と「音割れ」です。

同時再生はAudioSource.PlayOneShot(AudioClip clip);という便利なメソッドで実現できます。

しかし上記メソッドは音割れに関する考慮はされておらず、
そのまま音を重ねて鳴らすと波形が壊れて変質してしまいます。

効果音の同時再生数制御などを自作するのは結構面倒です。

なのでUnity側で吸収してほしいなぁ……と思っていたのですが、自分が知らないだけで普通にありました。

AudioMixerのエフェクトについて

音の管理にはAudioMixerが役に立ちます。
これがあれば自分で音声管理クラスを作らなくとも大抵のことは実現可能です。

音割れ防止にはAudioMixerのエフェクト機能を使用します。

グルーピングした範囲に対して一律でエフェクトを掛けられます。
各グループの下部にAdd..と書かれたボタンがあるので、クリックして追加したいエフェクトを選びます。

f:id:hecres:20180310170850j:plain

1グループに複数のエフェクトを追加することも可能です。

音をこもらせる。エコーを掛ける。ピッチを変更する。色々できます。
自分では試してませんが、ボイス再生時にBGMの音量を少し下げるといったこともできるみたいです。

音割れ防止エフェクト

対象のグループにNormalizeエフェクトを追加します。
以上です。

これにより名前通りNormalize(音量正規化)が掛かり、
音声データの最大音量をもとに、音が歪まない範囲で音量を最大化してくれます。

なぜ今まで気づかなかったのか

必要になったのが最近だからというのもありますが、
調べ方の問題もあったのかなと思います(「Unity 音割れ」とかでググっていました)。

AudioMixerとそのエフェクト機能はUnity5から提供されていたものですが、
音割れ防止機能と銘打たれているわけではありません。

なので音割れの原因である「デジタルクリップ」や
解決策である「ノーマライズ」「音量正規化」などの用語で調べれば
もっと早く答えに到達できたかもしれません。

参考/関連

その5 SEの同時発生数問題を考えてみる
magcat.php.xdomain.jp

この記事でのバージョン

Version
Unity 2017.3.0p4
Unity/PlayerSettings/Scripting Runtime Version Experimental (.NET 4.6 Equivalent)

【Unity】画面の縁を当たり判定のある壁にする方法

正確には撮影範囲をColliderで囲う方法についてです。
前提としてCamera.orthographicSizeを使用しますので2D専用のTipsです。

f:id:hecres:20180304210016j:plain

中央の白い四角が撮影範囲で、周りの緑の四角がBoxCollider2D×4です。
撮影範囲の各辺にBoxCollider2Dを隣接させています。

オブジェクトサイズ=画面サイズにする方法

ステップ1です。

RectTransformであればStretch機能を使って簡単に実現できますが、
素のTransformコンポーネントだとひと手間掛かります。

Camera.orthographicSizeを基にワールド座標系でのカメラ撮影範囲を算出しましょう。

上記処理をAwakeやStartで呼び出してみましょう。

空オブジェクトだとサイズが分かりにくいのでBoxCollider2Dをアタッチしてみてください。
撮影範囲の白い四角とColliderの緑の四角がぴったり重なっているのではないでしょうか。

レイアウトの確認で画面サイズを変えるなど、動的にフィットさせたい場合はUpdate内で呼び出してください。
(ただしその場合「衝撃でカメラが揺れる」などの演出にも追従します)

オブジェクトに沿ってColliderを配置する方法

ステップ2です。

ステップ1と比べて非常に簡単です。
コードを1行も書く必要がありません。

サイズを変化させるオブジェクトの子として
BoxCollider2DをアタッチしたTop、Bottom、Left、Rightの4オブジェクトを用意します。

そしてそれらのPositionを以下のように設定します。

f:id:hecres:20180304211513j:plain

以上です。

あとは親オブジェクトのスケールに合わせて変化するため、
画面サイズがどう変わっても上下左右綺麗に追従してくれます。

画面の縁=壁にしたいと考えたときはもっと苦労するかと思っていたのですが
思いのほか簡単に実装できました。

Unity様様です。

参考/関連

nn-hokuson.hatenablog.com

この記事でのバージョン

Version
Unity 2017.3.0p4
Unity/PlayerSettings/Scripting Runtime Version Experimental (.NET 4.6 Equivalent)