20211012のUnityに関する記事は6件です。

ScriptからSortingLayerを追加する

オレオレライブラリ、と言うかオレオレ開発環境を構築する上で、SortingLayerを自動的に設定したい場合が有ります。 そのための手順を調べたのでメモしておきます。 ScriptからSortingLayerを追加するテスト。Qiitaの記事用に動画を張り付け。 pic.twitter.com/YRx4EQKcjr— MIYAKE (@ScreenPocket) October 12, 2021 先に参考資料を貼っておきます ↑の記事にあるコードと、コメントにある修正部分を参照してメソッドを用意します SettingWindow.csの一部 /// <summary> /// SortingLayerの準備 /// </summary> private static void SetupSortingLayer() { string[] sortingLayerNames = {"UI","SystemUI"};//←追加したいSortingLayerをご自由に foreach (var sortingLayerName in sortingLayerNames) { CreateSortingLayer(sortingLayerName); } } /// <summary> /// SoringLayerを追加 /// </summary> /// <param name="layerName">追加したいSortingLayerの名前</param> private static void CreateSortingLayer(string layerName) { var serializedObject = new SerializedObject(AssetDatabase.LoadMainAssetAtPath("ProjectSettings/TagManager.asset")); var sortingLayers = serializedObject.FindProperty("m_SortingLayers"); for (var i = 0; i < sortingLayers.arraySize; i++) { if (sortingLayers.GetArrayElementAtIndex(i).FindPropertyRelative("name").stringValue.Equals(layerName)) { Debug.LogWarning($"Already Exists SortingLayer! name:{layerName}"); return; } } sortingLayers.InsertArrayElementAtIndex(sortingLayers.arraySize); var newLayer = sortingLayers.GetArrayElementAtIndex(sortingLayers.arraySize - 1); newLayer.FindPropertyRelative("name").stringValue = layerName; newLayer.FindPropertyRelative("uniqueID").intValue = (int)System.DateTime.Now.Ticks; serializedObject.ApplyModifiedProperties(); } という事でSerializedObject経由でFindPropertyを使って設定できるようです。 uniqueIDの設定方法が少々癖があるっぽいですね。 上記コードは参考資料のコメントのまま記載しましたが、 オレオレライブラリ内でSortingLayerを継続利用したい場合はuniqueIDを名前とワンセットで揃えておいた方が良いかもしれませんね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UniRx でGameObjectを点滅させる方法 (Unity)

デモ 解説 パラメータについて private float blinkingLimitTime = 5.0f; // 点滅開始後にオブジェクトが消滅するまでの時間 private float blinkInterval = 0.033f * 15; // Renderer のenabled が trueになっている時間 private float disappearingTime = 0.033f * 3; // Renderer のenabled が falseになっている時間 private bool isBlinking = false; // 点滅が開始しているかどうか private float objectRemainingTime = float.MaxValue; // オブジェクトが消える予定の時間 private float nextBlinkTime = float.MinValue; // 次の点滅する時間 private Renderer rend; // アタッチしたオブジェクトのRenderer Start で各パラメータの状況による処理を購読させる void Start() { rend = this.GetComponent<Renderer>(); // 点滅させる間隔を制御 this.UpdateAsObservable() .Where(_ => { return isBlinking; }) .Where(_ => { return nextBlinkTime < Time.time; }) .Subscribe(_ => { Blink(); }); this.UpdateAsObservable() .Where(_ => { return objectRemainingTime < Time.time; }) .Subscribe(_ => { Destroy(this.gameObject); }); // 出現と同時に点滅フラグ着火 isBlinking = true; objectRemainingTime = Time.time + blinkingLimitTime; } 点滅処理を実行させる /* 点滅の制御 */ private void Blink() { rend.enabled = !rend.enabled; // 反転する nextBlinkTime = Time.time; if (rend.enabled) { nextBlinkTime += blinkInterval; } else { nextBlinkTime += disappearingTime; } } 補足 点滅を同期したい場合 点滅の同期については、点滅開始可能フレームを共有することで可能だと思います。 各パラメータを共通化することで自然に見えるでしょう。 float.maxValue , float.minValue について 時間を始め一方通行なパラメータについては、1次元的に考えることで初期値を考慮する必要がなくなります。 private float objectRemainingTime = float.MaxValue; // オブジェクトが消える予定の時間 // this.UpdateAsObservable() .Where(_ => { return objectRemainingTime < Time.time; }) // 値が変更されるまで必ずfalse であることが担保される .Subscribe(_ => { Destroy(this.gameObject); }); // 出現と同時に点滅フラグ着火 isBlinking = true; objectRemainingTime = Time.time + blinkingLimitTime; 記事について ソースに関しては、抜粋のためコピペでは動作しない可能性があります。 コメント、補足、LGTM大歓迎です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityのOnCollisionEnter、OnTriggerEnter終止符

っしゃす。 なんか衝突でヒットする記事だいたい間違ってるので、自分のために検証して残しておきます。 検証内容・結果は最後に回します。暇な人は見てください。 結論 衝突検知にはRigidBodyが必要だが、どちらかについてれば良い。 誰ですか、「両方RigidBodyが必要」とか言ってる人は。 衝突検知の際には動いてるかに関わらず、両方のコールバックが呼び出される。 2つともisTriggerがfalseの場合はOnCollisionEnter、それ以外はOnTriggerEnterが呼び出される。 なるべく動く方にRigidBodyを付ける(結果の表の注参照) ところで、Colliderは衝突を検知するためのコンポーネントだが、RigidBodyは動くためのコンポーネントであるため、ステージの「動かない壁」などに用いるのはお勧めしない。ただし衝突検知にはRigidBodyが必要となる。 追記 衝突判定はColliderの空間にRigidBodyが含まれる場合に呼び出される。オブジェクトの速度が速すぎてCollider空間に入るフレームがない場合、呼び出されない。 例えばtフレームでcolliderの寸前まで来ていたオブジェクトがt+1フレームでColliderより奥に移動した場合、衝突は発生しない。 銃弾のような速さのオブジェクトの場合、1フレームの移動量分のRaycastで近似することでのみ衝突検知が可能で、自作した方が早い。 検証環境 Unity2020.3.1f1 RigidBodyのCollisionDetectionはContinuousSpeculative。 コード ColliderTest.cs using UnityEngine; public class ColliderTest : MonoBehaviour { private void OnTriggerEnter(Collider other) { Debug.Log("OnTriggerEnterが起きたよ", gameObject); } private void OnCollisionEnter(Collision collision) { Debug.Log("OnCollisionEnterが起きたよ", gameObject); } } シーン この表の前提 ここでは二つのオブジェクトA、Bとする。 動くオブジェクトは片方のみか、両方の場合がある。どちらも動かない場合衝突しない。 Colliderは当たり前だが、2つともついてるとする。 RigidBody列の〇はRididbodyあり、×はなし。 isTrigger列は〇はisTrigger=true、×はfalse。 コールバック列はOnTriggerEnterが呼び出される場合T、OnCollisionEnterが呼び出される場合C、いずれも呼び出されない場合×。 結果 動くオブジェクト RigidBody(A) RigidBody(B) isTrigger(A) isTrigger(B) コールバック(A) コールバック(B) A × × × × × × A × × 〇 × × × A × × × 〇 × × A × × 〇 〇 × × A 〇 × × × C C A 〇 × 〇 × T T A 〇 × × 〇 T T A 〇 × 〇 〇 T T A × 〇 × × C△ C△ A × 〇 〇 × T T A × 〇 × 〇 T T A × 〇 〇 〇 T T A 〇 〇 × × C C A 〇 〇 〇 × T T A 〇 〇 × 〇 T T A 〇 〇 〇 〇 T T A、B × × × × × × A、B × × 〇 × × × A、B × × × 〇 × × A、B × × 〇 〇 × × A、B 〇 × × × C C A、B 〇 × 〇 × T T A、B 〇 × × 〇 T T A、B 〇 × 〇 〇 T T A、B × 〇 × × C C A、B × 〇 〇 × T T A、B × 〇 × 〇 T T A、B × 〇 〇 〇 T T A、B 〇 〇 × × C C A、B 〇 〇 〇 × T T A、B 〇 〇 × 〇 T T A、B 〇 〇 〇 〇 T T 注)結果のうち△は非常に稀にコールバックが確認された。使うべきではない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rider 2021.3 EAP3 でファイル保存時のコード整形が標準機能になったらしい

概要 Rider 2021.3 EAP3 からファイル保存時にコード整形を行う設定が追加されました。 従来はマクロを使用して ⌘S のショートカットを上書きするなどしてファイル保存時のコード整形を行なっていましたが、今回のアップデートで簡単に設定できるようになったようです。 設定方法 File | Settings | Tools | Actions on Save で Reformat and Cleanup Code を有効にします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityのインスペクター上で列挙型リストを動的に表示する

Dictionaryに追加されたKeyや要素をインスペクター上に"列挙型"として表示するためのスクリプトです。DictionaryはSeiralizeできないので、インスペクター上で内容を確認することはできません。 ただ内容を表示するだけならDebug.logで構わないのですが、要素にdelegate型等を指定して「keyに応じたなにかしらの動作のチェックを行いたい」場合、インスペクターにGUILayout.Buttonで全てのkeyを書くのは非常に大変です。 そこでDictionaryの内容を列挙型で取得できたら非常に便利なんじゃないかと組んでみました。 InspectorEnumPopup.cs using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEditor; public class InspectorEnumPopup : MonoBehaviour { public Dictionary<string, string> Dic = new Dictionary<string, string>(); void Start() { Dic.Add("Hello", "こんにちわ"); Dic.Add("Bye", "さようなら"); } } #if UNITY_EDITOR //CustomEditor [CustomEditor(typeof(InspectorEnumPopup))] public class InspectorEnumPopupCustom : Editor { private string[] EnumList = new string[] { "None" }; private int Idx = 0; private InspectorEnumPopup Content; public void EnumUpdate() { EnumList = Content.Dic.Keys.ToArray(); } public override void OnInspectorGUI() { Content = target as InspectorEnumPopup; base.OnInspectorGUI(); Idx = EditorGUILayout.Popup("List", Idx, EnumList); if (GUILayout.Button("Enum.Update")) { if (Application.isPlaying) { EnumUpdate(); } } if (GUILayout.Button("Check Dictionary")) { if (Application.isPlaying) { Debug.Log("Key:" + EnumList[Idx] + " Element:" + Content.Dic[EnumList[Idx]]); } } } } #endif ここではDictionaryの内容を表示しているだけですが、本来の目的はエディターでの動作確認を簡単にする為のスクリプトです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

unity basic unitask async await with Process and Stream

unity と外部プログラムを連携したときの基本的な非同期のやり方 unity using System.Collections; using System.Collections.Generic; using System; using UnityEngine; using System.Diagnostics; using System.IO; using Cysharp.Threading.Tasks; using Debug = UnityEngine.Debug; public class TestUniTask : MonoBehaviour { // Start is called before the first frame update private string pyExePath = @"C:\meganebu\venv\Scripts\python.exe"; private ProcessStartInfo processStartInfo; private Process process; private StreamReader streamReader; private string processResult; // Basic async await with Process(ex python) async void Start() { Debug.Log("Start1"); var result = await TestFunc(); Debug.Log(result); Debug.Log("Start4"); } private UniTask<string> TestFunc() { Debug.Log("Start2"); return UniTask.Run(() => { processStartInfo = new ProcessStartInfo() { FileName = pyExePath, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, Arguments = @"C:\meganebu\test.py" }; process = Process.Start(processStartInfo); streamReader = process.StandardOutput; processResult = streamReader.ReadLine(); process.WaitForExit(); process.Close(); Debug.Log(processResult); Debug.Log("Start3"); return processResult; }); } // Update is called once per frame void Update() { } } 大事な箇所だけ、説明 private string pyExePath = @"C:\meganebu\venv\Scripts\python.exe"; ここで、あらかじめインストールしておいたpythonを指定 Arguments = @"C:\meganebu\test.py" 次に、ここで、実際に実行したいpythonを指定。 var result = await TestFunc(); 実際には、ここで実行。すると、TestFunc内が実行され、pythonが実行され、pythonからの戻り、print(1)の1を受け取って、resultに入る。 ので場合よっては、python側で、処理分岐し、0、1で成否、その戻りをunityで受けてUI上に表示するとか、が良いかも。 python import sys import time time.sleep(5) print(1) time.sleep(5) ここは、確認用にわかりやすく入れているsleep処理。unityから呼び出した後、ちゃんと5秒待って、戻りが戻ってくる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む