- 投稿日:2020-07-25T23:21:12+09:00
UnityでFirestoreを使いたい方へ
- 投稿日:2020-07-25T20:13:43+09:00
sora-unity-sdkがAndroidに正式対応したらしいのでサンプルを動かしてみた
株式会社時雨堂様が提供してくださっているsora-unity-sdkがAndroidに正式に対応したらしいので、サンプルを動かしてみました。
試した環境
sora-unity-sdk 2020.5
PC
Windows10
Unity2019.1.14f1スマホ
Android10
Motog81.サンプルの入手
GitHubから入手。
https://github.com/shiguredo/sora-unity-sdk-samplesREADMEに依ると
sora-unity-sdk のインストール
Windows の場合は install.bat を、macOS の場合は install.sh を実行して下さい。 これで各種サンプルを実行するために必要になる sora-unity-sdk をインストールできます。とのことなので
install.bat
を実行します。しかしこの実行ファイルの中身を見てみるとsora-unity-sdk v2020.4
をインストールする設定になっているようです。今回、試したいのは2020.5
だったのでinstall.ps1
の$SORAUNITYSDK_VERSIONを修正します。install.ps1$SORAUNITYSDK_VERSION = "2020.5"修正した上でコマンドプロンプトで
install.bat
を実行して、sora-unity-sdk v2020.5
をプロジェクトにインストールします。2.Sora Laboを使うように設定
とりあえず動かしてみたいので、時雨堂様が提供してくださっている
Sora Labo
を利用します。検証目的なら無償で利用できますが、商用利用はできないようです。簡単な利用規約があるのでよく確認してから利用しましょう。今回は検証目的なので大丈夫です。
https://sora-labo.shiguredo.jp/
サインアップしてログインしたらUnityに戻って設定していきます。
適当なサンプルシーンを開きます。今回は
multi_sendrecv
にします。
Scriptというオブジェクトにアタッチされている
Sora Sampleコンポーネント
にSora Laboに接続するための設定を記入していきます。Sora Laboのダッシュボードに記述してある
シグナリングURL
,シグナリングキー
をコピペしてUnityのSora Sampleコンポーネント
に貼り付けます。次に
Channel Id
を設定します。sora-laboのドキュメントに依るとチャネル ID を <自分の GitHub Username>@<好きな Room ID> のように指定してください
とのことなので適当に設定します。ここでは便宜上
<GITHUB_USERNAME>@sora-labo
とします。また、今回はUnityのカメラを送受信したいので、
Capture Unity Camera
のチェックを入れます。ここまでの設定でUnity Editor上で挙動を確認できるようになったはずです。Sora Laboに
マルチストリーム受信
というページがあるので、そこから確認してみます。Unityカメラの映像がブラウザから確認できるはずです。3.Androidで確認できるように設定
Android向けにビルドして実機で確認できるように設定していきます。まずビルドターゲットをAndroidに変更します。
- arm64-v8a のライブラリしか入れていないので armeabi-v7a の端末では動きません。
- libSoraUnitySdk.so のインスペクタ -> Platform settings -> Android の設定で CPU が ARM64 になっていることを確認して下さい。
- Player Settings -> Other Settings -> Target Architectures で ARM64 にチェックが入っていることを確認して下さい。
- Vulkan で動かす必要があります。
- Player Settings -> Other Settings の Graphics APIs で Vulkan が先頭にあることを確認して下さい。
- OpenGLES モードでの動作は未確認です。
- 最低でも API LEVEL 24 (Android 7.0)が必要です。
- Pixel 3 で解像度が 16 の倍数じゃない時に映像が乱れる問題があります。
とのことなので、書いてある通りに設定していきます。
まず
Assets\Plugins\SoraUnitySdk\android\arm64-v8a\libSoraUnitySdk.so
のTarget ArchitecturesをARM64に変更します。変更したら忘れずにApplyしましょう。次にPlayer Settingsの設定を変更していきます。Other SettingsのTarget ArchitecturesをARM64に。Graphics APIsのAuto Graphics APIのチェックをはずしてVulkanに設定します。さらにMinimum API LevelをAPI LEVEL 24にしておきましょう。
4.オブジェクトが映らない問題
一応、以上で設定はできたはずなんですが、私の環境だと問題が発生しました。Unityのカメラにオブジェクトが映らないという問題です。
本来なら球体が映らはずだけど、映らない。この問題はAndroidの実機だけじゃなくてUnity Editor上でも発生しました。
結論から言うと、Project Settings->Graphics->Tier SettingsのUser DafaultsのチェックをはずしてUSE HDRのチェックを入れると解決します。
この問題が起こった理由は特定できていませんが、検証してみた結果、ShaderのRenderTargetがOpaqueのオブジェクトが映らないという症状のようです。RenderTargetを
Transparent
にすると映るようになりました。まだBuild Settingsで対象プラットフォームをPCにしても治るようです。たぶんVulkan関連の何かが原因な気がします。何か必要な設定を忘れていたのか、自分の実行環境の問題なのか、よく分かりません。
なんか描画順とか、Unityのカメラをキャプチャしてテクスチャにする処理とかに何かヒントがある気がします。WaitForEndOfFrameのタイミングでUnityのカメラの映像をVulkanを直接叩いてキャプチャするっていう実装になっているようなんですが、これでなんで映らないのか謎です。WaitForEndOfFrameは描画系の処理の最後に実行されるようなので、キャプチャするタイミングとしては適切な気がします。
原因を探るならたぶんこの辺のキャプチャする仕組みがどうなってるのか見る必要がある気がするんですが、Vulkanとか低レイヤーのことは門外漢なので、私にはよく分からなかったです。今回はとりあえずUSE HDRのチェックを入れたら写ったので良しとしました。
https://github.com/shiguredo/sora-unity-sdk/blob/develop/src/unity_camera_capturer_vulkan.cpp5.結果
ということでsora-unity-sdkをAndroidで使うことができました。
使っているスマホはMotog8というローエンド端末なんですが、想像以上にヌルヌル動きます。遅延もほとんどないと言っていいんじゃないでしょうか。すごいですね。
6.最後に
先日、NDI SDKをAndroidで使うっていう記事を書きました。NDIはローカルネットワーク上で映像や音声の送信を行うのに対してsora-unity-sdkはSoraを介してどこからでもアクセスできます。
またNDI SDKのAndroid実装は送信にしか対応してませんでしたが、こちらは送信も受信もできます。ただSoraを商用利用するにはお金がかかります。(NDI SDKは無料だったはず)
NDIもWebRTCも使うなら、表面的な理解だけでは駄目で、チューニングして軽量化したりする必要がありますね。
- 投稿日:2020-07-25T19:59:44+09:00
Unityで作成したアプリにおいて、ネットワーク接続を確認する場合に使うメソッド「Application.internetReachability」!
筆者の環境:OS:Windows10, Unity 2019.3.5f1 使用言語:C#
利用Asset:DOTween,Destructible2D
筆者のプログラミング歴:2020年1月よりUnity上でC#の勉強を開始。ネットワークに接続しているかどうかを確認してくれる「Application.internetReachability」
初制作ゲームにて、Admob広告を掲載したのですがその際に、
『広告のLoadを待たずにゲームを開始すると、バナー広告の操作が上手くいかず、消すべき時に消せない。』
という不具合が出たので、広告のLoadが完了するまで、スタートボタンを表示させない、という無理やりな方法で
不具合を回避していました。
その為、インターネット接続していない端末はスタート出来ないので、それに対しての回避策を用意する、という更に面倒な事になっています。
今思えば、愚策中の愚策ですね。現在開発中のゲームでもランキングを搭載予定なのもあり、ネットワーク接続しているかどうかの確認が出来れば、この問題は簡単に解決出来ると思い、調べてみました!
すぐ見つかりました(というか、一度調べてました)。Application.internetReachabilityを使えば、ネットワーク接続しているかどうかの確認どころか、接続しているネットワークがWi-Fiなのかキャリアネットワーク(4Gとかですね)なのか?も、わかるそうです。
●NotReachable : インターネットに接続していない
●ReachableViaCarrierDataNetwork : キャリアネットワークで接続している
●ReachableViaLocalAreaNetwork : Wi-Fiでネットワークに接続している以下、実装例。
void CheckNetwork() { if (Application.internetReachability == NetworkReachability.NotReachable) { Debug.Log("ネットワーク接続無し"); } else if(Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork) { Debug.Log("キャリアネットワークに接続"); } else if((Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork) { Debug.Log("Wi-Fiネットワークに接続"); } }実際スマホアプリで使用する場合は、ネットワーク接続が無ければ、警告を表示するとかになりますね。
今回の筆者の場合は、スタートボタンは最初から表示しておいて、ボタンを押した時に広告Loadとネットワーク接続の確認をして、それぞれ処理を行う、って感じで実装する事になると思います。ここまで読んでいただき、ありがとうございました。
参考にさせていただいたサイト:エクスプラボ 様
https://ekulabo.com/network-reachability
- 投稿日:2020-07-25T19:59:44+09:00
Unityで作成したアプリにおいて、ネットワーク接続を確認する場合に使う「Application.internetReachability!」
筆者の環境:OS:Windows10, Unity 2019.3.5f1 使用言語:C#
利用Asset:DOTween,Destructible2D
筆者のプログラミング歴:2020年1月よりUnity上でC#の勉強を開始。ネットワークに接続しているかどうかを確認してくれる「Application.internetReachability」
初制作ゲームにて、Admob広告を掲載したのですがその際に、
『広告のLoadを待たずにゲームを開始すると、バナー広告の操作が上手くいかず、消すべき時に消せない。』
という不具合が出たので、広告のLoadが完了するまで、スタートボタンを表示させない、という無理やりな方法で
不具合を回避していました。
その為、インターネット接続していない端末はスタート出来ないので、それに対しての回避策を用意する、という更に面倒な事になっています。
今思えば、愚策中の愚策ですね。現在開発中のゲームでもランキングを搭載予定なのもあり、ネットワーク接続しているかどうかの確認が出来れば、この問題は簡単に解決出来ると思い、調べてみました!
すぐ見つかりました(というか、一度調べてました)。Application.internetReachabilityを使えば、ネットワーク接続しているかどうかの確認どころか、接続しているネットワークがWi-Fiなのかキャリアネットワーク(4Gとかですね)なのか?も、わかるそうです。
●NotReachable : インターネットに接続していない
●ReachableViaCarrierDataNetwork : キャリアネットワークで接続している
●ReachableViaLocalAreaNetwork : Wi-Fiでネットワークに接続している以下、実装例。
void CheckNetwork() { if (Application.internetReachability == NetworkReachability.NotReachable) { Debug.Log("ネットワーク接続無し"); } else if(Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork) { Debug.Log("キャリアネットワークに接続"); } else if((Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork) { Debug.Log("Wi-Fiネットワークに接続"); } }実際スマホアプリで使用する場合は、ネットワーク接続が無ければ、警告を表示するとかになりますね。
今回の筆者の場合は、スタートボタンは最初から表示しておいて、ボタンを押した時に広告Loadとネットワーク接続の確認をして、それぞれ処理を行う、って感じで実装する事になると思います。ここまで読んでいただき、ありがとうございました。
参考にさせていただいたサイト:エクスプラボ 様
https://ekulabo.com/network-reachability
- 投稿日:2020-07-25T18:52:53+09:00
UniRx 間隔の短いタップを検出する
概要
ポインターが押された時と離された時の間隔が一定以下のときだけ発火する物をUniRxで作成しました。
赤のエフェクトは押されたこと、青は離されたことを示します。その間隔が短いときだけLogが出力されてます。
プロジェクト全体はこちらから
https://github.com/Arihide/unirx-shorttap説明
短いのでソースコード丸ごと乗っけます。
using System; using UnityEngine; using UnityEngine.EventSystems; using UniRx; using UniRx.Triggers; public class ShortTap : UIBehaviour { protected override void Awake() { base.Awake(); const double shortTapThreshold = 200d; this.OnPointerUpAsObservable() .Timestamp() // 時間情報付与 .WithLatestFrom( // ポインターが離れたとき、最後に押された時の情報と合体させる this.OnPointerDownAsObservable().Timestamp(), (l, r) => new { up = l, down = r } ) // 押した時と離れたときの間隔が shortTapThreshold 以下のときだけ通す .Where(pair => (pair.up.Timestamp - pair.down.Timestamp) <= TimeSpan.FromMilliseconds(shortTapThreshold)) .Subscribe(_ => Debug.Log("Short Tap!")); } }やってることとしては、
- ポインターが離れたときに、最後にポインターが押されたときの情報とニコイチにする
- 押された時と離れたときの時刻を比較し、閾値以下なら通す
という感じですね。この方法は押されたときではなく、離れたときに発火するのがミソです。
また、条件式を調整すればロングタップなどにも対応できます。
- 投稿日:2020-07-25T15:49:59+09:00
【エディタ拡張】UI BuilderでC#コードを生成できるようにしてみる【UI Builder Extensions】
概要
UI Builder+UI Elementsでエディタ拡張(やランタイム)のUIを視覚的に実装できるようになりました。
UIBuilderではレイアウトの構造(UXML)とスタイル(USS)を生成できます。
- 構造=>UXML(UI Builderで生成可能)
- スタイル=>USS(UI Builderで生成可能)
- ロジック=>C#(UI Builder 未対応??)
今回
UI Builder Extensions
というものを作り、C#ロジックを生成できるようにしてみましたので紹介します。
環境
- Unity2019.4.1f1~
- UI Builder 1.0.0 preview
インストール
manifestに下記を追加してください。
{ "dependencies": { "com.t-macnaga.ui-builder-extensions": "https://github.com/t-macnaga/UIBuilderExtensions.git", } }コード生成
UI Builder Extensions
をインストールしますと、
UIBuilderにEventのインスペクターがあらわれます。
Eventsを開きますと、
ButtonならOnClick
、TextFieldやToggleならOnValueChanged
、といった具合に
イベント一覧があります。追加したいコールバックを ダブルクリック しますと、
そのUXMLと同じ階層にC# EditorWindow コードが作成される仕掛けとなっております。※ダブルクリックするまえに下記の注意点があります。
- VisualElementのNameを登録してください。
- Name`に登録したら、UXMLを保存してください。
生成されるコードサンプル
using UnityEngine; using UnityEngine.UIElements; using UnityEditor; using UnityEditor.UIElements; public partial class SampleWindow : EditorWindowBase { [MenuItem("Window/SampleWindow")] static void Init() { GetWindow<SampleWindow>(); } void OnEnable() { InitializeComponents(); } void OnClick_button1() { Debug.Log("button1 Clicked"); } }//AUTOGENERATED using UnityEngine; using UnityEngine.UIElements; using UnityEditor; using UnityEditor.UIElements; public partial class SampleWindow { protected override string TreeAssetPath => "Assets/Samples/Editor/SampleWindow.uxml"; protected override void RegisterCallbacks() { rootVisualElement.Q<Button>("button1").clicked += OnClick_button1; } }プロジェクトデータ
GitHubで公開しました。
https://github.com/t-macnaga/UIBuilderExtensionsまとめ
UIBuilder+UIElementsと、さらに今回作成のUIBuilderExtensionsを使えば
エディタ拡張ウィンドウのコード作成が楽になるかもです。参考記事
下記参考にさせていただきました。
* UIElements+UI BuilderでEditor拡張を作ろう
- 投稿日:2020-07-25T09:32:38+09:00
DOTween完全に理解するその5 Sequence編
今回解説するアニメーション
今回はDOTween最重要と言っても過言ではないSequenceについて解説します。
Tweenを繋げて1つのアニメーションとして連続実行させることができ、
複雑なアニメーションを作ることができます。開発環境
Unity:2019.4.0f1
DOTween:v1.2.335Append
var sequence = DOTween.Sequence(); //Sequence生成 //Tweenをつなげる sequence.Append(transform.DOMoveX(7, 1)) .Append(transform.DOMoveX(-7, 1)) .Append(transform.DOMoveX(0, 1));Sequenceの末尾にTweenを追加します。
前のTweenが終わり次第次のアニメーションが実行されます。
内部的にはTweenの終了を待っているわけではなく、
前のTweenが終わる時間までDelayしている感じですAppendInterval / AppendCollback
//TweenをつなげつつAppendIntervalとAppendCallbackを使う sequence.Append(transform.DOMoveX(7, 1)) .AppendInterval(0.25f) .AppendCallback(() => { targetRenderer.material.color = Color.yellow; }) .Append(transform.DOMoveX(-7, 1)) .AppendInterval(0.25f) .AppendCallback(() => { targetRenderer.material.color = Color.cyan; }) .Append(transform.DOMoveX(0, 1));Appendと同様に末尾に待機時間やコールバックを追加します。
Join
//Joinで並列動作するTweenを追加 sequence.Append(transform.DOMoveX(7, 1)) .Join(transform.DORotate(new Vector3(0, 180), 1.5f, RotateMode.WorldAxisAdd)) //0 ~ 1.5 .AppendInterval(0.25f) //1.5 ~ 1.75 .AppendCallback(() => { targetRenderer.material.color = Color.yellow; }) .Append(transform.DOMoveX(-7, 1)) .Join(transform.DORotate(new Vector3(0, 180), 1.5f, RotateMode.WorldAxisAdd)) //1.75 ~ 3.25 .AppendInterval(0.25f) //3.75 ~ 4 .AppendCallback(() => { targetRenderer.material.color = Color.cyan; }) .Append(transform.DOMoveX(0, 1)) .Join(transform.DORotate(new Vector3(0, 180), 1.5f, RotateMode.WorldAxisAdd)); //4 ~ 5.5直前のTweenと並行して動作するようにTween追加を行います。
Joinの後Appendした場合もっとも時間のかかったTweenの後に実行されます。
API アニメーション時間 開始時間〜終了時間 Append 5秒 0〜5秒 Join 10秒 0〜10秒 Append 5秒 10~15秒 Insert / InsertCallback
//Method2と同じ動きをInsertで行う sequence.Append(transform.DOMoveX(7, 1.5f)) //0 ~ 1.5 .AppendInterval(0.25f) //1.5 ~ 1.75 .Append(transform.DOMoveX(-7, 1.5f)) //1.75 ~ 3.25 .AppendInterval(0.25f) //3.25 ~ 3.5 .Append(transform.DOMoveX(0, 1.5f)); //3.5 ~ 5 sequence.Insert(0, transform.DORotate(new Vector3(0, 0, 1800), 5.5f, RotateMode.WorldAxisAdd)); sequence.InsertCallback(1.75f, () => { targetRenderer.material.color = Color.yellow; }); sequence.InsertCallback(3.5f, () => { targetRenderer.material.color = Color.cyan; });時間を指定して、Tweenerやコールバックを挿入します。
AppendやJoinとは異なり前後のTweenerなどに関係なく並列で動作します。Prepend / PrependCallback / PrependInterval
var sequence = DOTween.Sequence(); sequence.Append(transform.DOMoveX(7, 1)) .Append(transform.DOMoveX(-7, 1)) .Append(transform.DOMoveX(0, 1)); //前に追加する sequence.PrependInterval(0.5f); sequence.PrependCallback(() => { targetRenderer.material.color = Color.red; }); sequence.Prepend(transform.DORotate(new Vector3(0, 0, 180), 1, RotateMode.WorldAxisAdd));Sequenceの先頭にTweenerやコールバックを追加します。
先頭に追加されていくので、最後に追加したものから最初に実行されます。Sequence同士をSequenceで繋ぐ
//SequenceにSequenceに追加する var move = transform.DOMoveX(6, 0.5f) .SetRelative(true) .SetLoops(2, LoopType.Incremental); var rotate1 = transform.DORotate(Vector3.forward * 90, 0.5f, RotateMode.WorldAxisAdd); var sequenceA = DOTween.Sequence() .Append(move) .Join(rotate1); var scale = transform.DOScale(1, 0.5f); var rotate2 = transform.DORotate(Vector3.forward * 90, 0.5f, RotateMode.WorldAxisAdd) .SetRelative(true); var sequenceB = DOTween.Sequence() .Append(scale) .Insert(0.5f, rotate2) .SetLoops(2, LoopType.Yoyo); _tween = DOTween.Sequence() .Append(sequenceA) .Join(sequenceB); _tween = DOTween.Sequence() .Append(_tween) .Append(transform.DORotate(Vector3.forward * 180, 1f, RotateMode.WorldAxisAdd));SequenceもTweenerなので、Sequence同士をSequenceで繋ぐこともできます。
またSetLoops()をしたTweenerをSequenceに含めることもできますし
Sequence自体にSetLoops()をすることもできます。Sequenceを使用する際の注意点
無限ループが使えない
例えば以下のようなSequence内のTweenerが無限ループする設定は無視されます。
Sequenceが無限ループする場合は問題ありません。var move = transform.DOMoveX(1, 0.5f) .SetRelative(true) .SetLoops(-1, LoopType.Incremental); var sequence = DOTween.Sequence() .Append(move);無効化される設定
SetAutoKill(true)やSetSpeedBased(true)などの設定は、
Sequence追加時にfalseに設定されてしまいます。普通に考えればSeuqnceが終わっていない以上
PlayBackwordなどで実行済みのTweenを実行する必要が出てくるので
その際にKillされていたら困る為、設定が無効化されるのでしょう。SpeedBaseもSequence自体は全て時間ベースで追加や挿入が行われる為
設定が無効化されるのだと思われます。Sequenceに追加する前に設定を終わらせる
Tweenに対する設定はSequenceに追加する前に終わっている必要があります。
以下のようにSequence追加後のTweenへの設定は無視されます。
Sequence追加前に行った設定は正しく反映されます。(もちろん無効化されるもの以外)var move = transform.DOMoveX(1, 0.5f) .SetRelative(true); var sequence = DOTween.Sequence() .Append(move); move.SetDelay(3f); move.SetLoops(2, LoopType.Incremental); move.From(0);まとめ
Sequenceは作りが単純な分できることがかなり多い為、様々な場面で活躍します。
UnityはデフォルトではAnimator/Animationを使ってアニメーションを作ると思います。
ただ、Animatorの場合は固定化されたアニメーションを作るのには向いていますが
状況によって微妙に変化するアニメーションなど
コードから動きを細かく制御したい場合はSequenceが有効です。
Inspectorにアニメーション用のパラメータを出しておけば調整も簡単です。
あとこれは全てのTweenに該当しますがTimeScaleで個別に速度を変えられる点も強力だなぁと最近思いました。最後に最近作ったどこで使うかわからないアニメーションを置いておきます。ご査収ください。
どこで使うかわからないけどアニメーション作るの楽しい pic.twitter.com/KO2NrDwToc
— BEAT (@BEATnonanka) July 14, 2020
- 投稿日:2020-07-25T03:21:56+09:00
UnityでもRoslynで構文解析やコード評価したい
はじめに
RoslynはC#の構文解析やコード評価を行えるライブラリでC# 6以降のコンパイラでも使われています。Roslynを利用すると構文解析された結果を利用できるので文字列比較や正規表現と比べると解析漏れをなくせます。
RoslynのインストールはNuGetで使えますがUnityだと重複するdllがありそのままでは導入できません。それをUPMで簡単に導入する方法が分かったのでまとめてみました。
- UPM化されたRoslynのドキュメント Code Analysis
Unityでは以下のプロダクトでRoslynが使われています。
- UPMのImmediate Window
- Utf8JsonのUtf8Json.UniversalCodeGenerator
- MessagePack-CSharpのMessagePack.Generator
環境構築
Unity2018.3以上
- Package Managerから
Add package from git URL...
できるバージョンではcom.unity.code-analysis
を追加する- Package Managerから
Add package from git URL...
できないバージョンではPackages/manifest.json
に"com.unity.code-analysis": "0.1.2-preview",
を追加するインストールできると以下のようにPackage Managerに追加されます。
インストールだけではDLLを参照できないのでRoslynを使いたいスクリプトフォルダにアセンブリ定義を作り、以下の設定を変更します。
- 一般 > リファレンスをオーバーライドをチェック
- アセンブリ参照に
Microsoft.CodeAnalysis
で始まるdllを追加- エディタ拡張で使うならプラットフォームの
Editor
のみをチェック、アプリ内で使うならデフォルトの任意のプラットフォーム
のままでOKRoslynのサンプル
Scripting API SamplesとGetting Started C# Syntax Analysisを参考にサンプルを実行してみます。それぞれcode欄に実行または解析するコード、result欄にその結果を表示しています。また実行できるUnityプロジェクトは https://github.com/shiena/UnityRoslynSample にありメニューの
Tools > Roslyn Sample
を選択するとウインドウが開きます。Evaluate a C# expression
コードを実行します。
string code = "1 + 2"; var result = CSharpScript.EvaluateAsync(code);Evaluate a C# expression (strongly-typed)
ジェネリクスで結果の型を指定してコードを実行します。
string code = "1 + 2"; var result = CSharpScript.EvaluateAsync<int>(code);Parameterize a script
クラス定義したパラメータをコードに適用して実行します。
public class Globals { public int X; public int Y; } string code = "X+Y"; var globals = new Globals {X = 1, Y = 2}; var result = CSharpScript.EvaluateAsync<int>(code, globals: globals);Query Methods
コードを解析してMainメソッドの最初の引数を出力します。
string code = @"using System; using System.Collections; using System.Linq; using System.Text; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine(""Hello, World!""); } } }"; SyntaxTree tree = CSharpSyntaxTree.ParseText(code); var root = (CompilationUnitSyntax) tree.GetRoot(); var firstMember = root.Members[0]; var helloWorldDeclaration = (NamespaceDeclarationSyntax) firstMember; var programDeclaration = (ClassDeclarationSyntax) helloWorldDeclaration.Members[0]; var mainDeclaration = (MethodDeclarationSyntax) programDeclaration.Members[0]; var argsParameter = mainDeclaration.ParameterList.Parameters[0]; var firstParameters = from methodDeclaration in root.DescendantNodes() .OfType<MethodDeclarationSyntax>() where methodDeclaration.Identifier.ValueText == "Main" select methodDeclaration.ParameterList.Parameters.First(); var argsParameter2 = firstParameters.Single();SyntaxWalkers
コードを解析してSystemまたはSystem.以外で始まるusingを出力します。
class UsingCollector : CSharpSyntaxWalker { public readonly List<UsingDirectiveSyntax> Usings = new List<UsingDirectiveSyntax>(); public override void VisitUsingDirective(UsingDirectiveSyntax node) { if (node.Name.ToString() != "System" && !node.Name.ToString().StartsWith("System.")) { this.Usings.Add(node); } } } string code = @"using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; namespace TopLevel { using Microsoft; using System.ComponentModel; namespace Child1 { using Microsoft.Win32; using System.Runtime.InteropServices; class Foo { } } namespace Child2 { using System.CodeDom; using Microsoft.CSharp; class Bar { } } }"; SyntaxTree tree = CSharpSyntaxTree.ParseText(code); var root = (CompilationUnitSyntax) tree.GetRoot(); var collector = new UsingCollector(); collector.Visit(root);参考リンク
- UPMのImmediate Window
- Utf8JsonのUtf8Json.UniversalCodeGenerator
- MessagePack-CSharpのMessagePack.Generator
- UPM化されたRoslynのドキュメント Code Analysis
- Unity Roslyn Sample