20210909のUnityに関する記事は5件です。

unityで2台のカメラを切り替え

 Unityで複数のカメラを設置して、切り替えながら使いたい時のサンプル。例えば、一人称視点と三人称視点を切り替えたい時に使える。1台のカメラでも出来なくはないが、一時的な座標の保存などが発生するので、使いにくいだろう。手動なら、インスペクタで一番上のチェックを操作すれば良いが、実行中は、プログラムが必要。  以下は、スペースキーでカメラを切り替えるサンプル。プログラムをアタッチした後に、mainCameraとsubCameraに割り当てが必要。 cameraChange.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class cameraChange : MonoBehaviour{ public Camera mainCamera; public Camera subCamera; void Start(){ mainCamera.enabled = true; subCamera.enabled = false; } void Update(){ if (Input.GetKeyDown(KeyCode.Space)) { mainCamera.enabled = !mainCamera.enabled; subCamera.enabled = !subCamera.enabled; } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VContainer入門(6) - LifetimeScopeの親子関係

この記事について 前回に引き続きVContainerの説明をしていきます。 今回はLifetimeScopeの親子関係を制御する方法を紹介します。 親子関係を通して依存関係の範囲を階層構造で管理できます。 目次ページ: VContainer入門 親子関係を試してみる とりあえず使ってみます。 サンプルとしてLogger、Calculatorクラスと、その2つに依存するCalculatorTestクラスを用意します。 using UnityEngine; using VContainer; using VContainer.Unity; // 先頭に[Logger]を付けてログ出力するクラス public sealed class Logger { public void Log(string message) => Debug.Log("[Logger] " + message); } // 足し算するだけのクラス public sealed class Calculator { public int Add(int a, int b) => a + b; } // LoggerとCalculatorに依存するクラス public sealed class CalculatorTest : IInitializable { private Logger logger; private Calculator calculator; [Inject] public CalculatorTest(Logger logger, Calculator calculator) { this.logger = logger; this.calculator = calculator; } // クラスがインスタンス化された直後に呼ばれる public void Initialize() { Calculate(1, 2); } private void Calculate(int a, int b) { int result = calculator.Add(a, b); logger.Log($"{a} + {b} = {result}"); } } このCalculatorTestの依存関係を解決するために、次のParentLifetimeScopeとChildLifetimeScopeを用意します。 ParentLifetimeScope.cs public class ParentLifetimeScope : LifetimeScope { protected override void Configure(IContainerBuilder builder) { builder.Register<Logger>(Lifetime.Singleton); } } ChildLifetimeScope.cs public class ChildLifetimeScope : LifetimeScope { protected override void Configure(IContainerBuilder builder) { builder.Register<Calculator>(Lifetime.Singleton); builder.RegisterEntryPoint<CalculatorTest>(); } } 実際の親子関係はインスペクタ上で設定できます。 下の画像のようにParentLifetimeScopeとChildLifetimeScopeを配置して、ChildLifetimeScopeのParentの部分にParentLifetimeScopeを設定します。 実行すると「1 + 2 = 3」と表示されてCalculatorTestが生成されていることを確認できます。 親のLifetimeScopeの探索 インスペクタのParentで指定すると、ロード中のシーン全体からそのLifetimeScopeを探索します。 なのでParentのLifetimeScopeはシーンのどこかに配置しておく必要があります。 親子関係があるLifetimeScopeの依存性解決 LifetimeScopeの親子関係は依存解決の順番に影響します。 具体的には、子のLifetimeScopeから親に向かって見つかるまで順番に探索されます。 例えば、先ほどのCalculatorTestの場合はCalculatorとLoggerに依存しています。 CalculatorはChildLifetimeScopeの中でRegisterされているのが見つかります。 LoggerはChildLifetimeScopeの中では見つからないので、親のParentLifetimeScopeでRegisterされているのが見つかります。 もし一番上の親まで見つからなければ例外が発生します。 RootLifetimeScope 全てのLifetimeScopeの親となる、ルートのLifetimeScopeを設定できます。 次の手順で設定できます。 Unityメニューの「Assets > Create > VContainer > VContainer Settings」でVContainerSettingsを作る 空のPrefabを作る PrefabにルートにしたいLifetimeScopeをアタッチする 作成したPrefabをVContainerSettingsのRootLifetimeScopeに設定する 親子関係を設定する インスペクタのParentに設定する以外でも親子関係を設定できます。 LifetimeScopeのスクリプトで親を設定する LifetimeScopeのAwakeでparentReference.Objectに親LifetimeScopeを直接設定できます。 public class ChildLifetimeScope : LifetimeScope { protected override void Awake() { var parentLifetimeScope = gameObject.AddComponent<ParentLifetimeScope>(); // 親にしたいLifetimeScopeを渡す parentReference.Object = parentLifetimeScope; // 必ずbase.Awake()を呼び出す base.Awake(); } } 親を設定してLifetimeScopeを生成する LifetimeScope.EnqueueParentを使うと、これから生成するLifetimeScopeの親を設定できます。 var parentLifetimeScope = gameObject.AddComponent<ParentLifetimeScope>(); using (LifetimeScope.EnqueueParent(parentLifetimeScope)) { // ここで生成されたLifetimeScopeの親はparentLifetimeScopeになる gameObject.AddComponent<ChildLifetimeScope>(); } ここではChildLifetimeScopeの親をparentLifetimeScopeにするのに使っています。 より実践的な使い道としては、usingのブロックの中でシーン読み込みやPrefab生成をすれば、そのシーンやPrefabの中の全てのLifetimeScopeの親を設定できます。 ただしLifetimeScope.EnqueueParentのネストは対応されていません。 LifetimeScope.EnqueueParentの中でLifetimeScope.EnqueueParentを使おうとするとおかしな動作になります。 親を設定してPrefabを生成する CreateChildFromPrefabを使うと、親を設定してPrefabを生成できます。 public sealed class TestMonoBehaviour : MonoBehaviour, ITestMonoBehaviour { [SerializeField] private LifetimeScope prefab; public void Start() { var parentLifetimeScope = gameObject.AddComponent<ParentLifetimeScope>(); LifetimeScope childLifetimeScope = parentLifetimeScope.CreateChildFromPrefab(prefab); } } CreateChildFromPrefabの引数にはPrefab内のLifetimeScopeを渡します。 渡したLifetimeScopeの親が設定された上でそのPrefabが生成されます。 Lifetime.SingletonとLifetime.Scoped Registerするときに指定するLifetime.Singleton/Scoped/Transientについて説明します。 protected override void Configure(IContainerBuilder builder) { builder.Register<A>(Lifetime.Transient); builder.Register<B>(Lifetime.Singleton); builder.Register<C>(Lifetime.Scoped); } Lifetime.TransientはResolveするたびに毎回新しいインスタンスが生成されます。 Lifetime.ScopedはLifetimeScopeごとに別々のインスタンスが生成され、その中だけで使い回されます。 つまりLifetimeScopeの親子関係があるときは、親と子で別のインスタンスが生成されます。 Lifetime.Singletonは親子間でも同じインスタンスが使い回されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Sorting Layerと3D Objectの関係

これはもともとは 自分のブログ に掲載していた記事なのだけど、まあ自分のブログは技術的な記事をドカドカ掲載するような場所でもないので、こちらにも並行して掲載しておく。 ある日、質問された。 「そういえば、unityでsorting layerと3D objectの関係ってどうなってるんでしょう?」 Sorting Layerは3D objectとどう影響しあうのか、検索してみたけれど見つからない。 「違うものだから挙動しない」なんて解説もあってが、テストした結果は違うw まあこんなのはテストしてみりゃいいやと思って、下のようなsceneを作ってテストしてみたら、抱腹絶倒というか「エー」な結果が得られたので、ちょっとブログに記事として残しておきたい。 さて。 sorting layerは以下のルールで動く。 リストの下の方が描画の優先度は高い。 同一優先度ならばカメラに近い方が「上」 またunityでは言うまでもなく3D Objectにはsorting layerはつかない。そこで空objectにspriteをぶら下げて、そいつにsorting layerをひっつけ、その下に3D Objectを配置するという暴挙に出てみる。 結論として言うと3D Objectにsorting layerは影響しないが、その前後を2Dobjectが動く時には、sorting layerはレンダリング結果に影響するという世にもキカイな挙動になるのである。 下は動かしたときに得られるレンダリング結果の一部。 テストをしたプロジェクトを下に置いておく。 なんの役に立つかは想像もつかないが、まあないよりはいいテストだろう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityにおけるThirdPesronCharactorのエラーに対策

ThirdPersonCharactorを使おう エラー内容 エラー文 ThirdPersonCharactorを使おうとしたところ次の様なエラーが出た。 Assets/Standard Assets/Utility/SimpleActivatorMenu.cs(11,16): error CS0619: 'GUIText' is obsolete: 'GUIText has been removed. Use UI.Text instead.' 詰まるところ、 GUITextが消去されたから、代わりにUI.Textを使えということの様だ。 エラー内容 実際にプログラムを見てみると、 using System; using UnityEngine; #pragma warning disable 618 namespace UnityStandardAssets.Utility { public class SimpleActivatorMenu : MonoBehaviour { // An incredibly simple menu which, when given references // to gameobjects in the scene public GUIText camSwitchButton; public GameObject[] objects; private int m_CurrentActiveObject; private void OnEnable() { // active object starts from first in array m_CurrentActiveObject = 0; camSwitchButton.text = objects[m_CurrentActiveObject].name; } 実際にはもっと続いているが、今回問題となる場所のみを取り出してきた。 次に、どこが問題なのかを調べた。 対処法 対処法を調べたところ、次のサイトに乗っていた。 要約すると、 上のプログラム中で、GUITextとなっている部分をTextに変えれば良いとのことだ。 また、それに付随して Using UnityEngine.UI; の一文も追加すると動いてくれるらしい。 using System; using UnityEngine; using UnityEngine.UI; #pragma warning disable 618 namespace UnityStandardAssets.Utility { public class SimpleActivatorMenu : MonoBehaviour { // An incredibly simple menu which, when given references // to gameobjects in the scene public Text camSwitchButton; public GameObject[] objects; private int m_CurrentActiveObject; private void OnEnable() { // active object starts from first in array m_CurrentActiveObject = 0; camSwitchButton.text = objects[m_CurrentActiveObject].name; } Unityの方を確認すると、確かにエラーが消えていることが分かる。 蛇足 Using UnityEngine.UI; の一文を追加しないと、 Assets/Standard Assets/Utility/SimpleActivatorMenu.cs(15,16): error CS0246: The type or namespace name 'Text' could not be found (are you missing a using directive or an assembly reference?) というエラーが出てくる。 つまり、Textが見つからないという感じなので、先の文を追加してあげる必要がある。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

定義が存在するのにビルド時に「error CS0117」と怒られる

今回は割とうっかりミスな気もしますが、とりあえず備忘録として残しておくことにしました。 (内容でPlayBillingLibraryって単語が出てきちゃってますが、根本的には関係ないですっ) (PlayBillingLibraryって単語で記事にきちゃった人、ごめんなさい...) 問題の概要 そもそも何をしようとしていたか Android用にPlayBillingLibrary3.0以上を実装しようとしていた。 (2021年11月までに対応しないとアプリのアップデートができないので) 問題の発生 1 : PlayBillingLibrary3.2.0のunitypackageをインストール (ここからDLした) 2 : 手順に従い競合の解決 3 : 特にエラーも出なかったのでApkのビルドを開始 結果下記のエラーが発生 Assets/GooglePlayPlugins/com.google.play.billing/Runtime/Scripts/Internal/GooglePlayBillingUtil.cs(27,44): error CS0117: 'Debug' does not contain a definition for 'unityLogger' 訳 : 「Debug ってクラスに unityLogger なんてものはないぞ」と。 問題の詳細 ビルド時に、下記の部分でエラーが発生。 GooglePlayBillingUtil.cs // クラスパス : Assets/GooglePlayPlugins/com.google/play.billing/Runtime/Scripts/Internal/GooglePlayBillingUtil.cs /*前略*/ using UnityEngine; public class GooglePlayBillingUtil : MonoBehaviour { private const string GooglePlayBillingLoggingTag = "Google Play Store: "; private readonly ILogger _logger = Debug.unityLogger; // <- こいつがエラー private static readonly List<Action> _callbacks = new List<Action>(); private static volatile bool _callbacksPending; /*後略*/ } ただ、ビルド前だとエラーは出ていないし、unityLoggerにカーソルを当てるときちんと定義にジャンプすることが可能だった。 問題の解決 原因 自前クラスにネームスペースを切ってないDebugクラスがあり、しかも#if !UNITY_EDITOR でクラス全体を覆っていたためでした。 ビルドするときだけ、Debugクラスが認識されるようになっており 結果「Debug.unityLogger」が指すDebugクラスがどれかわかなくなってしまってたようです。 対応内容 Debug.unityLogger に UnityEngineをつけてあげたところ、ビルドが通るようになった。 GooglePlayBillingUtil.cs // クラスパス : Assets/GooglePlayPlugins/com.google/play.billing/Runtime/Scripts/Internal/GooglePlayBillingUtil.cs /*前略*/ using UnityEngine; public class GooglePlayBillingUtil : MonoBehaviour { private const string GooglePlayBillingLoggingTag = "Google Play Store: "; //private readonly ILogger _logger = Debug.unityLogger; // <- こいつがエラー private readonly ILogger _logger = UnityEngine.Debug.unityLogger; // <- これでエラー回避できた private static readonly List<Action> _callbacks = new List<Action>(); private static volatile bool _callbacksPending; /*後略*/ } 本当は自前クラスにnamespaceをつけるなりするべきなのでしょうが、如何せん手間がかかっちゃうので今回はこのような対応で済ませることに。 最後に 今回は自前クラスが悪さをしていたわけですが、場合によっては外部ライブラリが似たような悪さをしないとも限らないので もしビルド時だけ「error CS0117」と怒られる箇所があった場合は、namespaceを指定して回避すると良いかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む