- 投稿日:2021-01-13T23:48:53+09:00
Unityを始める - Unityちゃんライブステージの構造理解 -
はじめに
以前、「 Unityを始める - Unityインストールからプロジェクト作成 - 」で、Unityを触ったことがないという人でも気軽に始められるように、Unityで開発を始める場合に必要な事をまとめました。
公開されているUnityちゃんライブステージのプロジェクトを見て、Unityのプロジェクトを学んだので備忘録としてまとめました。
ユニティちゃんライブステージ! -Candy Rock Star-
- ダウンロードURL : https://unity-chan.com/download/releaseNote.php?id=CandyRockStar
- 動画 : ユニティちゃん Candy Rock Star ライブステージ!
- 最新バージョン : 1.0
- 最終リリース日 : 2014.11.05
- カテゴリー : 3D, SOUND
- 形式 : zip
この作品はユニティちゃんライセンス条項の元に提供されています参考にした本
動作確認
ユニティちゃんライブステージのダウンロード
下記のページからダウンロードしてください。
https://unity-chan.com/download/releaseNote.php?id=CandyRockStarダウンロードしたプロジェクトをUnityで開く
フォルダを展開後、 unitychan-crs-master/Assets/Scenes/Main.unity を開くとライブシーンを確認する事ができます。実装
Unityちゃんライブステージの構造理解するために以下の手順で一から実装してみました。
- 新しいシーンの作成
- ステージの作成
- ミュージックの作成
- ユニティちゃんを配置する
- バックスクリーンの作成
- カメラワークの設定
参考にしたサイト
まとめ
今回のUnityのプロジェクトの改修が初回ということもあり、うまくいかないことなどの課題は多くありましたが、このサンプルを知る事で、簡単に学習して進む事が出来ます。
ライブの面白さはアーティストとの距離が近いことだけではありません。アーティストや他のファンと同じ場を共有し、一体感を高めることで盛り上がるところにあります。バーチャルアイドルのライブも、実際のライブの中継もその一体感をいかに高めるかがポイントになってくるでしょう。 Oculus Quest 2 を持っている人はぜひ試して、どの程度の一体感が得られるように出来るのか試してみてはいかでしょうか。
今後、本格的なVR向けの開発に今後取り組む予定です。
- 投稿日:2021-01-13T19:11:01+09:00
Nreal Light でキャラクター表示
はじめに
2020年12月1日に発売されたスマートグラス、NrealLight(エンリアルライト)
今回はそこにUnityを使用してキャラクターを表示するまでのことを書いていきます。
↓NrealLight越しに見たままキャプチャーする方法が分からないので、ちょっと見え方が違う…
NrealLightとは?
詳しくはこちらを見て頂けると…
https://news.kddi.com/kddi/corporate/newsrelease/2020/11/10/4778.html大雑把に言うと、スマートフォンに接続してXR技術を楽しめるスマートグラスです。
ミラーリングモードを使えばYoutubeなどを空間上に映し出して見ることも可能なので電車などで周りを気にせず動画を楽しむことも出来ます。
ケーブルがあるのでちょっとあやしい感じに見えますが…(笑)
※ 対応しているスマートフォンには注意が必要です。開発環境
・Windows10
・Unity2019.4.16f1
・Android SDK 8.0(APIレベル26)
・NRSDKForUnity_1.4.8
・NrealLight(Developer Kitではないものです)
・Xperia 5 II SOG02(Nreal Lightを使用するには、ビルド番号58.0.C.11.142以降が必須)流れ
NrealLight DeveloperKitとUnityでの開発手順は公式サイトに書いてありますので
それを参考にしながら進めていきます。
https://developer.nreal.ai/develop/unity/android-quickstart基本的な下準備
Android開発は初めてという人向けの簡単な説明になります。(Unityはある程度使える前提)
Unityのインストール、Android SDKのインストール、UnityのAndroidSDKパス設定、Android Debug Bridge(adb)コマンドのパスを設定、Androidの開発モード設定 に触れています。
そんなの必要ないという人も多いと思うので別記事での説明になります。
https://qiita.com/yambowcto/private/918f6eefd103d09f5e1bUnityプロジェクト設定
・テンプレートを3Dにしてプロジェクトを新規作成します。
・メニューのFile > Build Settings で Build Settings ウィンドウを開きます。
・Platform で Android を選択し Switch Platform で変更します。
・同ウィンドウ内の Player Settings ボタンを押して Project Settings ウィンドウを開きます。
・Project Settings ウィンドウ内の Player 設定を変更します。
※ Target API Level は level 26~29 で設定する必要があり、Android 11は現時点で非対応。
また、Android 10の場合はAndroidManifest.xmlを変更する必要があると書かれてます。
キャプチャー機能等使わなければ変更しなくても大丈夫かな?・Project Settings ウィンドウ内の Quality 設定を変更します。
※ Skin Weights はデータ次第ですが、大抵は4 Bonesにしてあげないと破綻します。NRSDKForUnityパッケージのインポート
公式サイトからNRSDKForUnity_1.4.8をダウンロードして、ダブルクリックするなりしてインポートします。
https://developer.nreal.ai/downloadユニティーちゃんのインポート
Unity公式サイトからユニティーちゃんのモデルデータをダウンロードしてインポートします。
https://unity-chan.com/contents/guidelineもし、error CS0234: The type or namespace name 'Policy' does not exist in the namespace 'System.Security' (are you missing an assembly reference?)のようなエラーが出ていたら AutoBlink.csを開いて
using System.Security.Policy;
を削除するか(使用してないので)、Project Settings > Player > Other Settings > Api Compatibility Level* を.Net 4.x
に変更すれば大丈夫です。シーンの作成
メニューのFile > New Scene で新規シーンを作ります。
ProjectウィンドウのAssets > NRSDK > Prefabs にあるNRCameraRig
とNRInput
を Hierarchyに追加します。
Assets > UnityChan > Prefabs にあるunitychan
も Hierarchyに追加します。
HierarchyにあるMain Camera
は必要ないので削除しましょう。
unitychanの座標はPosition Y:-0.94 Z:2.56
Rotation Y:180
としておきます。
名前を付けてシーンを保存しておきます。
ビルド準備
さて、実際に作ったアプリをスマートフォンにインストールする簡単な方法としては、スマートフォンをUSBケーブルでPCに繋いで Build And Run を実行することですが、今回はNreal Lightをスマートフォンに接続しないと動かないアプリなので作業のたびにケーブルの付け替えを行う必要が出てしまいます。なので、Wi-Fi経由でインストールできる準備をしましょう。
下準備のadbコマンドのためのパス設定をしていることを前提に進めます。
まずはandroidスマートフォンをUSBケーブルでPCに繋ぎます。
※ 開発者向けオプションのUSBデバッグをONにするのを忘れずに!
また、スマートフォンに対して何かしようとすると許可
の確認が結構でるので
移行の作業で出た場合には内容を確認しつつ基本的にOKします。コマンドプロンプトを起動し、
adb tcpip 5555
を打ち込みEnterを押します。
スマートフォンのIPアドレスを確認(自分のだと、設定 > デバイス情報で見れます)してから
adb connect IPアドレス
を打ち込みEnterを押します。
自分の場合Enter押した後に失敗と出ますが、スマートフォン側に許可の確認が出てるので許可をすると大丈夫です。
最後にスマートフォンとPCの接続を外してadb devices
と打ち、認識できていればOK。
スマートフォンにNebulaをインストール
NrealLightアプリを動かすためにはNebulaのインストールが必要です。(違ったらゴメンナサイ)
なので、Google PlayからNebulaをインストールします。(↓のやつです、同名のアプリに注意)
nebula nreal で検索すると上の方にくると思います。
スマートフォンのソフトウェアのバージョンが条件を満たしていないとNreal Lightを接続したときのNebulaの挙動がおかしくなってしまうので注意してください。(自分はそこで詰まりました…)Nebulaを起動してセットアップを行います。
言われるがまま許可をしながら進めていきます。すると最後にグラスを付けた時のチュートリアルに進みます。ビルド
いよいよビルドです。
メニューのFile > BuildSettings でビルド設定を開きます。
Wi-Fi接続が上手くいっていれば、Run DeviceにIP名が入ったデバイスがあるはずです。なければRefreshで情報を更新します。
あとはBuild And Runボタンを押すとビルドが開始され、続いてインストールされます。
※ Nebulaが起動してなければPlease connect your Nreal Light Glasses.
と出ます。
インストールしたアプリはNebulaのメニューから起動することができます。
これでキャラクターを表示することが出来ます。
操作方法はAPPボタン長押しでポインターリセット、ホームボタン長押しで終了になります。
以上、お疲れさまでした。おまけ
ここからはシーンにもうちょっとだけ機能を加えてみたいと思います。
まず、HierarchyにCreateEmptyでGameObjectを作成し、その子供にunitychanを移動。
この時、GameObjectのTransformの値はリセットしておきます。
DemoにあるTargetModelDisplayCtrl
を改良した以下のスクリプトをAddComponentでGameObjectに追加します。TargetModelDisplayCtrlEx.csusing NRKernal; using UnityEngine; namespace Test { public class TargetModelDisplayCtrlEx : MonoBehaviour { public Transform modelTarget; private Vector3 m_AroundLocalAxis = Vector3.down; private float m_TouchScrollSpeed = 10000f; private float correctZ = 0.01f; private Vector2 m_PreviousPos; void Start() { ResetModel(); } private void Update() { if (NRInput.GetButtonDown(ControllerButton.TRIGGER)) { m_PreviousPos = NRInput.GetTouch(); } else if (NRInput.GetButton(ControllerButton.TRIGGER)) { UpdateScroll(); } else if (NRInput.GetButtonUp(ControllerButton.TRIGGER)) { m_PreviousPos = Vector2.zero; } } private void UpdateScroll() { if (m_PreviousPos == Vector2.zero) return; Vector2 deltaMove = NRInput.GetTouch() - m_PreviousPos; m_PreviousPos = NRInput.GetTouch(); float x = Mathf.Abs(deltaMove.x); float y = Mathf.Abs(deltaMove.y); if (x > y) modelTarget.Rotate(m_AroundLocalAxis, deltaMove.x * m_TouchScrollSpeed * Time.deltaTime, Space.Self); else { Vector3 v = modelTarget.localPosition; v.z += deltaMove.y * m_TouchScrollSpeed * Time.deltaTime * correctZ; modelTarget.localPosition = v; } } public void ResetModel() { modelTarget.localRotation = Quaternion.Euler(0.0f, 180.0f, 0.0f); } } }InspectorでそのコンポーネントのModel Targetにunitychanを設定します。
これにより、アプリ中の操作で上下にスライドするとキャラクターが前後に移動、左右にスライドするとY軸回転を行うようになります。おわりに
説明があまり上手くないかもしれませんが、いかがでしたか?
物凄く大雑把に言うと、動作環境を満たす、Nebulaを入れる、適切なプロジェクト設定、NRSDKForUnityを使う というところだけ注意すればOKだと思います。さて、2021年に入って新たなスマートグラスの情報なども出てきています。
値段がもっとお手軽になって、街中でスマートグラスをしてても違和感がない時代が来るといいですね。ユニティちゃんライセンスについて
この作品はユニティちゃんライセンス条項の元に提供されています
ユニティちゃんを使用する際は、上記ライセンスをよく読んで使用しましょう。
- 投稿日:2021-01-13T19:10:08+09:00
Nreal Lightでキャラクター表示(準備編)
はじめに
ここではNrealLightでキャラクターを表示する下準備として、Unityを使ったAndroid開発のためのセットアップについて説明を行います。Unityに関してはある程度は使える前提で進めます。
本編はこちらです。
https://qiita.com/yambowcto/private/a973252e25cb9e5d44d7Unityのインストール
Nreal Developer の説明にあるように Unity2019.4 LTS をインストールします。
ここでは2019.4.16f1をインストールしました。
また、インストール時には Android Build Support にチェックを入れて下さい。
Android SDK & NDK Tools と OpenJDK にもチェックが入っていると次に説明するAndroid SDK をインストールしなくても自動的にインストールされパスも設定してくれます。
ただし、指定したいTarget API LevelのSDKバージョンが入っていない場合は別途必要になるので、次に説明するAndroid Studioを入れた方が自分的には分かりやすいと思ってます。Android SDKをインストール
まずは公式サイトからAndroid Studioをダウンロードします。
https://developer.android.com/studio?hl=ja
基本的にはデフォルトのままで進めていけばOKですが、Android SDKの場所がちょっと深いので分かりやすい場所にした方がいいかもしれません。(ここではデフォルトのままでの説明となります)Android Studioのインストールが終わったら起動して、右下辺りにある Configure > SDK Manager を選択します。
Android SDK の必要なバージョンにチェックを入れてインストールします。
※ NrealLightの開発にはAndroid SDK 8.0(APIレベル26)以上が必要です。
UnityのAndroidSDKパス設定
メニューのEditからPreferencesを選択、ExternalToolsのAndroid SDK Tools Installed with Unityのパスを変更します。
Android Debug Bridge(adb)コマンドのパスを設定
adbコマンドを使用するためのパスの設定を行います。
これは必須というわけではないですが、NrealLightをスマートフォンに接続したままUnityで作成したapkファイルをWi-fiでインストール出来るので便利です。まず、コントロールパネルのシステムを開きます。(ショートカット:Windowsキー + Pause)
次にシステムの詳細設定を開いて環境変数ウィンドウを表示します。
Pathを選択し、編集、新規でパスを追加します。
追加するパスはAndroidSDKのパスにplatform-tools
を付け加えたものになります。
コマンドプロンプトからadbと入力して決定、エラーが出なければOKです。
コマンドプロンプトはWindows10の場合は検索ボックスでcmdと打つと出てきます。あるいは、スタートメニュー > Windowsシステムツール からでも見つけられます。よく使うのでタスクバーにピン止めしておきましょう。Android端末の設定
Android端末の開発向けオプションを有効にします。
この設定を表示するには、端末やOSのバージョン等によって違いがあると思うので分からない場合は検索してみて下さい。
Xperia 5ⅡSOG02 (Android 10)の場合だと、設定 > デバイス情報 > ビルド番号を7回タップすると表示されます。
表示される場所は、設定 > システム > 詳細設定 > 開発者向けオプション となりますので、その設定内のUSBデバッグを有効にしてください。許可するか表示されるのでOKを押します。
※ USBデバッグを有効にしたままにすると動作しないアプリなどありますので、必要ない場合は無効にしましょう。おわりに
一部手かなり抜きな説明ですが、以上が基本的なUnityでAndroidアプリを開発するための下準備になります。
- 投稿日:2021-01-13T16:52:52+09:00
Oculus Integration/Unity2020
環境
Unity 2020.2.0f1
VS2019 free
OS windows10 proビルド
[Unity]
Vulkanの削除
Android6.0
ネットワークパーミッションOculus Integrationのインストール
→リップシンクとAvatorは不要で重いのでチェックを外すSwich Platform (10分くらいかかる)
ビルド2
XR Plugin Management
→ コンフリクトが発生する
けど、無視してAndroidのapkを作る事はできる。Unity2019との違い
Oculus XRとOculus Android は明示的にインストールしなくてもよい
XRインタラクションツールキット/XR Interaction Toolkit
https://note.com/npaka/n/n7b99fac6b5fa
Unity2019.4
パッケージマネージャ横のpreview版を表示するにチェックを入れる。
ご参考
この記事群はわりと役に立つ
https://note.com/npaka/n/nc18d61e25c85Oculus Developer Hub/Android Logcat/Controler/Locamotionなどの解説がある。
「Oculus Developer Hub」と「Android Logcat」同時には使えません。
★「Not starting debugger since process cannot load the jdwp agent.」
がでるんやが...
あとコントローラー認識できない。OculusIntegration必要?
↓
OculusIntegrationインストールの後に、「Build And Run」の後に本体を頭にかぶるとOKUnity + Oculus Quest 2 開発メモ(framesynthesis
- 投稿日:2021-01-13T09:59:55+09:00
ゲーミングtoio - toio SDK for UnityでLEDを操る
概要
toio SDK for UnityでLEDを操ります。フルカラーLEDといえばレインボー(ゲーミングPC風)
GitHub repository
https://github.com/zurachu/toio-rainbow-led/
WebGL sample
toioキューブが必要です。
https://zurachu.github.io/toio-rainbow-led/動画(Twitter)
ゲーミング #toio pic.twitter.com/SY7y8FkjLZ
— ヅラChu (@zurachu) January 12, 2021技術情報
UnityEngine.Colorをtoioランプ制御で使うカラー値に変換するUtility
前回のかるたでもそうでしたが、キューブの接続順(どのキューブがプレイヤー1か?2か?)を認識するために画面表示とLEDの色を合わせるのは、良くある手な気がします。
ToioLedUtility.csusing UnityEngine; using toio; public static class ToioLedUtility { public static void TurnLedOn(Cube cube, Color color, int durationMs, Cube.ORDER_TYPE order = Cube.ORDER_TYPE.Strong) { cube.TurnLedOn(ColorByteValue(color.r), ColorByteValue(color.g), ColorByteValue(color.b), durationMs, order); } public static Cube.LightOperation LightOperationOf(Color color, int durationMs) { return new Cube.LightOperation(durationMs, ColorByteValue(color.r), ColorByteValue(color.g), ColorByteValue(color.b)); } public static byte ColorByteValue(float value) { return (byte)Mathf.Clamp(value * 255, 0, 255); } }レインボーグラデーション
#ff0000
→#ffff00
→#00ff00
→#00ffff
→#0000ff
→#ff00ff
→#ff0000
のグラデーションするUnityEngine.Color配列を作ってから、先ほどのCube.LightOperationに変換して、キューブに送信します。
Cube.TurnOnLightWithScenarioに一度に送れるLightOperationの上限が29
https://toio.github.io/toio-spec/docs/ble_light#operation-%E3%81%AE%E6%95%B0
なので、4<(29÷6)<5より、1色のグラデーションを4段階かけて行います。SampleScene.cspublic async void OnClickConnect() { var cube = await cubeManager.SingleConnect(); if (cube == null) { return; } var colors = new List<Color>(); colors.AddRange(Gradation(Color.red, Color.yellow, 4)); colors.AddRange(Gradation(Color.yellow, Color.green, 4)); colors.AddRange(Gradation(Color.green, Color.cyan, 4)); colors.AddRange(Gradation(Color.cyan, Color.blue, 4)); colors.AddRange(Gradation(Color.blue, Color.magenta, 4)); colors.AddRange(Gradation(Color.magenta, Color.red, 4)); cube.TurnOnLightWithScenario(0, colors.ConvertAll(_color => ToioLedUtility.LightOperationOf(_color, 100)).ToArray()); } private List<Color> Gradation(Color fromColor, Color toColor, int division) { var colors = new List<Color>(); for (var i = 0; i < division; i++) { colors.Add(Color.Lerp(fromColor, toColor, (float)i / division)); } return colors; }
- 投稿日:2021-01-13T08:55:54+09:00
【Unity シェーダー】グラデーションに巨大な値を足すと諧調が落ちる話
はじめに
巨大な値を使った際にグラデーションの諧調が落ちるという現象に遭遇したので、まとめたいと思います。
本記事は、簡潔さを重視した内容となっているため、情報の正確さに欠ける面があるかもしれません。
環境
Unity 2020.2.0f1
Universal RP 10.2.2事の発端
シェーダーグラフにて、巨大な数を使うとグラデーションの諧調が減るという不可解な現象に遭遇しました。
今回はfloat(浮動小数点数)の視点から、階調が減る現象について検証していきたいと思います。
検証ではShaderLabを使用します。検証 その1 : UV.xを画面に出す
ShaderLabでUVのxだけを返すようなフラグメントシェーダーを書いてみます。
fixed4 frag (v2f i) : SV_Target { return i.uv.x; }結果
検証 その2 : UV.xに巨大な整数を足す
次に、
0.001
という小数を足して、frac
で小数部分だけを返すようにしてみます。fixed4 frag (v2f i) : SV_Target { return frac(i.uv.x + 0.001); }結果
同じく滑らかなグラデーションが表示されます。
ここまでは、問題ないかと思います。
検証 その3 : 10^6を足してみる
10^6
という巨大な数を足してから、frac
で小数部分だけを返すようにしてみます。fixed4 frag (v2f i) : SV_Target { return frac(i.uv.x + 1e6 + 0.001); }結果
整数を足しているだけだから、滑らかなグラデーションが表示されるのでは?と思ってしまいそうですが、
結果は以下のようなカクカクしたグラデーションになります。この現象は、float(浮動小数点数) が関係していると考えられます。
floatの内部表現
シェーダーのfloat は 32bit float(単精度浮動小数点数) というもので、
0.3や0.7といった実数を32ケタの2進数で表現します。ビット列から実数を計算する
符号部を $sign$ (0か1) 、指数部を $e$ (0 ~ 255の整数)、仮数部のビット列を $b_1, b_2, b_3, ... , b_{23} $ と置きます。
この時、floatが表現する実数 $value$ は以下の計算式で求めることができます。(IEEE754規格)value = (-1)^{sign} \cdot (1 + \sum_{i=1}^{23}b_{i}2^{-i} ) \cdot 2^{e - 127}クイズ
以下のようなビット列が表す実数 $value$ はどんな値になるでしょうか?
答え
符号部 : $sign = 0$
指数部 : 8桁目のビット列が1になっているので、$e = 2^7 = 128$
仮数部のビット列 : $b_1 = 1, b_4 = 1, b_5 = 1$ビット列が表す値$value$は以下のようになります。
\begin{align} value &= (-1)^0 \cdot (1 + 2^{-1} + 2^{-4} + 2^{-5}) \cdot 2^{128- 127} \\ \\ &= (1 + 0.5 + 0.0625 + 0.03125) \cdot 2 \\ \\ &= 3.1875 \end{align}本題
さて、ここからが本題です。
以下のようなフラグメントシェーダーを書いた場合、グラデーションがカクカクしてしまいます。float4 frag (v2f i) : SV_Target { return frac(i.uv.x + 1e6 + 0.001); }カクカクしてしまうのは、
i.uv.x + 1e6 + 0.001
という計算に原因があります。
桁数が大きく異なる数を足し合わせると、小さい方の数の情報が落ちてしまうためです。1e6のビット列
i.uv.x + 1e6 の計算
次に、
i.uv.x + 1e6
を計算します。uv.x = 0.3の場合
i.uv.x = 0.3
の時、ビット列は以下のようになります。
そして、
0.3 + 10^6
のビット列は以下のようになります。
10^6
の仮数はそのままですが、0.3
の仮数はだいぶ下の方にズレてしまいました。
0.3
のビット列の大部分が欠損しています。このような現象は情報落ちと呼ばれます。
uv.x = 0.9の場合
i.uv.x = 0.9
の場合を考えてみます。
0.9 + 10^6
のビット列は以下のようになります。
仮数の下4ケタを0.9
の仮数(だったもの)が埋めています。uv.x = 1.0 の場合
i.uv.x = 1.0
の場合を考えてみます。
1.0 + 10^6
のビット列は以下のようになります。
仮数の下5ケタを
1.0
の仮数(だったもの)が埋めています。i.uv.x + 1e6 のUVデータ制度
i.uv.x + 1e6
を計算した場合、グラデーションの表現に使える領域は 4 ~ 5ビット程度になりそうです。カクカクしたグラデーションを見てみると、グラデーションの諧調は16段階になっていますね
おまけ : さらに大きい数を足してみる
これまでは1e6を足していましたが、2倍の2e6を足してみます。
float4 frag (v2f i) : SV_Target { return frac(i.uv.x + 2e6 + 0.001); }結果
諧調数が半分の
8
になります。おまけ2 : 0.001を外す
0.001を外して以下のようなフラグメントシェーダーを書くと、グラデーションがなめらかになります。
float4 frag (v2f i) : SV_Target { return frac(i.uv.x + 2e6); }知識不足で理由がよくわからないのですが、シェーダーコンパイラが良い感じに最適化してくれているのかもしれません。
関連
【Unity】【シェーダ】小数点の精度と型の使い分けについて(float / half / fixedの話)
https://light11.hatenadiary.com/entry/2018/06/01/001008地味にヤバい、シェーダ変数の精度について
https://techblog.kayac.com/unity-shader-parameters-precision
- 投稿日:2021-01-13T03:03:51+09:00
Unity 2020.1から、自動実装プロパティのバッキングフィールドにSerializeField属性をつけた時のEditor上の表示が良くなったが、シリアライズ名的に使ってはいけない
前提
- Unityのフィールドに付与するSerializeField属性がわかる
- C#のプロパティ、自動実装プロパティ、バッキングフィールドがわかる
- C# 7.3から、自動実装プロパティに属性をつけられるようになったことを知っている
以上の内容は、自分の『C# 7.3から自動実装プロパティのバッキングフィールドに属性をつけられるようになった。UnityでSerializeFieldとそれをいい感じに使いたかった』で説明してます。
本題
次のようなコードを、自動実装プロパティのバッキングフィールドにSerializeField属性をつけて、シリアライズを試みます。
using UnityEngine; public class Player : MonoBehaviour { [field: SerializeField] public int Level { get; private set; } }Unity 2019.4までで、自動実装プロパティのバッキングフィールドにSerializeField属性をつけた時のEditor上の表示はこんな感じ。
そして.unityファイル中(YAMLファイル)などでのシリアライズはこんな感じ。
「
<Level>k__BackingField
」!これは自動実装プロパティのバッキングフィールドの名前です。ILとしては有効でも、C#のフィールド名としては不正な名前です。
この名前でEditor上で表示され、そしてシリアライズされます。
ここまではUnity 2019.4までの話。
ここからはUnity 2020.1以降の話。
Unity 2020.1以降では、先のコンポーネントのUnity Editor上の表示はこんな感じになります。
なんと表示が変わっています。「Level」という表示になりました。断定はできませんが内部実装で
UnityEditor.ObjectNames.NicifyVariableName
を使っている可能性があります。// Levelと表示された Debug.Log(ObjectNames.NicifyVariableName("<Level>k__BackingField"));さぁ、ではUnity 2020.1では、どんな名前でシリアライズされるのでしょうか?
残念ながら以前と変わらず、ILとしては有効でも、C#のフィールド名としては不正な「
<Level>k__BackingField
」っていう名前でシリアライズされるようです。
自動実装プロパティのバッキングフィールドに対してSerializeFieldをつけた時の、Unity 2019.4 => Unity 2020.1の仕様変更は・・・
- Unity Editor上の表示は変更(プロパティ名になり、簡潔になった。)
- .unityや.prefabなどでシリアライズされている名前は変わらず
となります。
さて、タイトルが自分の主張なのですが、「Unity 2020.1から、自動実装プロパティのバッキングフィールドに、SerializeField属性をつけた時のEditor上の表示は良くなったが、シリアライズ名的に使ってはいけない」です。
ぱっと見のUnity Editor上の表示は良い感じに見えます。しかし、シリアライズは「
<Level>k__BackingField
」という名称で行われます。そのため、自動実装プロパティのバッキングフィールドに、SerializeField属性を単純につけることは、避けることを強くおすすめします。自分は「シリアライズされる名前」・「シリアライズされたり、永続化される際のデータフォーマット」というのは非常に重要と考えています。コードを変更するコストに比べて、シリアライズ・永続化されたデータのフォーマットを変更するというのは、影響範囲が広く、過去・未来のことを考慮する必要があり、非常に面倒だからです。
<Level>k__BackingField
という自動実装プロパティのバッキングフィールドの名前は
- 冗長
- 扱いにくい
- C#のフィールド名として不正
- C#の自動実装プロパティのバッキングフィールドの命名が仕様化されていない
という欠点があります。そのため、自分は「シリアライズされる名前」・「シリアライズされたり、永続化される際のデータフォーマット」として不適切だと考えています。
多少冗長になりますが、こんな感じで書くことをおすすめします。
using UnityEngine; public class Player : MonoBehaviour { [SerializeField] private int level; public int Level => level; }こんなことができればよかったのに
2017年から主張しているけれど、「Unityでシリアライズ名を指定する機能が欲しい」。
SerializeFieldが引数をとって、シリアライズ名を指定できればよかったのに・・・
public class Player : MonoBehaviour { // こんなことができればよかったのに [field: SerializeField("field")] public int Level { get; private set; } }FormerlySerializedAsAttributeってのがあるけれど、残念ながらこれはダメ。「以前シリアライズされていた名前を指定するもの」だから。
ちなみにもし、「自動実装プロパティのバッキングフィールドにSerializeFieldをつけた時の名前が、勝手に良い感じになれば良いのにー」って思った人がいたら、それはNot Goodだと思います。「SerializeFieldをつけた時のシリアライズされる名前はフィールド名で」っていう原則が崩れちゃうので。(自動実装プロパティのバッキングフィールドもフィールドだから)
やっぱり必要なのは明示的にシリアライズする名前を指定する方法。(Unity 2020.1やUnity 2020.2の時点でそんな方法はない、ですよね?あったら教えてください。)
- 投稿日:2021-01-13T02:20:05+09:00
Unityでオブジェクトの複製と動的削除
クリックすると、Cubeが生成され、積み上がるサンプルです。Cubeはprefab化し、Asset内に保持してあり、クリックによりInstantiate命令が実行され、シーンに追加されます。下方には、こぼれ落ちたCubeを削除するための平面とスクリプトが設置されています。
0、Edit>ProjectSetting>PhysicsのGravityのyを-50にする
1、sceneにCubeを作成する
2、Cubeにrigidbodyを追加する
3、AssetsにResourcesフォルダを作成する
4、CubeをResourcesフォルダにドラッグ&ドロップし、prefab化する
5、sceneのCubeは削除してしまう
6、Planeで地面groundを作成する
7、新規にスクリプトaddBox.csを作成し、groundに追加する
8、groundからこぼれるCubeを消すため、Planeでdelを作成する
9、新規にスクリプトdelObj.csを作成し、delに追加するaddBox.csusing System.Collections; using System.Collections.Generic; using UnityEngine; public class addBox : MonoBehaviour { void Update(){ if (Input.GetMouseButtonDown(0)){ Shot(); } } void Shot () { GameObject dup = (GameObject)Resources.Load ("Cube"); Vector3 pos = new Vector3( Random.Range(-1f,1f), 5, Random.Range(-1f,1f)); Instantiate (dup, pos, Random.rotation); } }delObj.csusing System.Collections; using System.Collections.Generic; using UnityEngine; public class delObj : MonoBehaviour { void OnCollisionEnter(Collision c) { Destroy(c.gameObject); } }