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

Unityで簡単なSoundManager

めちゃ久しぶりの投稿です。(最近私用で忙しい、、、) 今後まだ改良予定ですがUnityでSoundManagerを製作しました。 まだ簡単な実装なので今後は3D対応、フェードイン、アウトの対応をする予定です。 SoundList.cs アセットのセット用 namespace GameSound { public class SoundList : MonoBehaviour { [SerializeField] AudioClip[] audioClipList; [SerializeField] string[] tagClipList; Dictionary<string, AudioClip> _audioClipList = null; void Start() { SetDictionary(); } void SetDictionary() { _audioClipList = new Dictionary<string, AudioClip>(); for (int i = 0; i < audioClipList.Length; i++) { if (tagClipList.Length <= i) break; _audioClipList.Add(tagClipList[i], audioClipList[i]); } } public Dictionary<string, AudioClip> GetDictionary() { return _audioClipList; } } } SoundManager.cs using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace GameSound { //使用するサウンドの種類 public enum UsingSoundTyp { None, SE, //効果音 BGM, //BGM SE_3D, //3D(今後実装予定) } //サウンドの再生方法 public enum PlaySoundTyp { None, Single, //一回再生する Loop, //一定条件が来るまでループ LoopNum, //指定回数ループ } /// <summary> /// サウンドの通知 /// </summary> public class SoundInfo { public SoundInfo() { } //サウンドのタイプ public UsingSoundTyp m_usingSoundTyp; //念のためつけてるけど現在の使用用途は謎 //サウンドの再生方法 public PlaySoundTyp m_playSoundTyp; //使用するサウンドの文字列 public string m_usingSound; //使用するサウンドがLoopだった際に何回繰り返すか public int m_loopNum = -1; //サウンド終了時に呼ばれる関数の登録 public Func<bool> m_endFunc; //サウンドを一時停止させるかの確認用関数の登録 //trueでストップ public Func<bool> m_pauseFunc; //一時停止させたサウンドをPlayするかの確認用関数の登録 //trueでPlay public Func<bool> m_unpauseFunc; //SoundPlayerを終了させる //trueで終了 public Func<bool> m_stopFunc; } /// <summary> /// サウンドを再生するためのクラス /// </summary> public class SoundPlayer { public SoundPlayer(SoundInfo _soundInfo, AudioSource _audioSource, int _index) { m_soundInfo = _soundInfo; m_audioSource = _audioSource; m_index = _index; Inst(); } //通知データ public SoundInfo m_soundInfo = null; //使用しているAudioSource public AudioSource m_audioSource = null; //使用中のindex public int m_index = -1; int m_loopCount; bool m_playFlg = true; /// <summary> /// 初期化 /// </summary> void Inst() { m_loopCount = 0; m_playFlg = true; m_audioSource.PlayDelayed(0); } /// <summary> /// SoundPlayerの終了 /// </summary> void ReleaseAudioSource() { if (m_soundInfo.m_endFunc != null) m_soundInfo.m_endFunc(); SoundManager.Instance.ReleaseAudioSource(m_index, this); } /// <summary> /// サウンド終了後の処理 /// </summary> void SoundEnd() { switch(m_soundInfo.m_playSoundTyp) { case PlaySoundTyp.Single: //1回のみ ReleaseAudioSource(); break; case PlaySoundTyp.Loop: //ループ m_audioSource.PlayDelayed(0); break; case PlaySoundTyp.LoopNum: //指定回数ループ m_loopCount++; if (m_loopCount >= m_soundInfo.m_loopNum) { ReleaseAudioSource(); } else { m_audioSource.PlayDelayed(0); } break; default: ReleaseAudioSource(); break; } } /// <summary> /// 更新 /// </summary> public void Update() { //一時停止 if(m_soundInfo.m_pauseFunc != null&& m_playFlg) { if(m_soundInfo.m_pauseFunc()) { m_audioSource.Pause(); m_playFlg = false; } } //再開 if (m_soundInfo.m_unpauseFunc != null && !m_playFlg) { if (m_soundInfo.m_unpauseFunc()) { m_audioSource.UnPause(); m_playFlg = true; } } //SoundPlayerの終了 if (m_soundInfo.m_stopFunc != null) { if (m_soundInfo.m_stopFunc()) { m_audioSource.Stop(); m_playFlg = false; ReleaseAudioSource(); } } //サウンド終了時 if (!m_audioSource.isPlaying && m_playFlg) { SoundEnd(); } } } public class SoundManager : Singleton<SoundManager> { [Header("SoundManagerは常にHierarchy下になるようにする")] [SerializeField] SoundList _soundList = null; //オブジェクトプール [SerializeField] AudioSource[] _audioSourceList = null; List<bool> _audioSourceListFlg = null; //サウンドリスト Dictionary<string, AudioClip> _audioClipList = null; //通知リスト public List<SoundInfo> _soundInfosList { get; private set; } = null; //再生しているサウンドのリスト public List<SoundPlayer> _soundPlayerList { get; private set; } = null; //SoundPlayerリストの解放予定のリスト List<SoundPlayer> _releasesoundPlayerList = null; void Start() { Inst(); } void Update() { InfoListCheck(); SoundUpdate(); } /// <summary> /// 初期化 /// </summary> public void Inst() { //AudioClipDictionaryの取得 _soundInfosList = new List<SoundInfo>(); if (_soundList != null) { _audioClipList = _soundList.GetDictionary(); } else { Debug.LogError("Could not get 'SoundList'"); return; } //AudioSourceListの準備 if (_audioSourceList != null) { _audioSourceListFlg = new List<bool>(); for (int i = 0; i < _audioSourceList.Length; i++) { _audioSourceListFlg.Add(false); } } else { Debug.LogError("There is no 'AudioSourceList'"); return; } if(_soundPlayerList == null) _soundPlayerList = new List<SoundPlayer>(); if (_releasesoundPlayerList == null) _releasesoundPlayerList = new List<SoundPlayer>(); } /// <summary> /// 通知チェック /// </summary> void InfoListCheck() { if (_soundInfosList.Count <= 0) return; foreach(var info in _soundInfosList) { if(!_audioSourceListFlg.Contains(false)) { Debug.LogError("No 'AudioSource' available"); continue; } if (!_audioClipList.ContainsKey(info.m_usingSound)) { Debug.LogError($"No '{info.m_usingSound}' AudioClip"); continue; } AudioClip audioClip = _audioClipList[info.m_usingSound]; int index = 0; for (int i = 0; i < _audioSourceListFlg.Count; i++) { if (!_audioSourceListFlg[i]) { index = i; _audioSourceListFlg[i] = true; break; } } _audioSourceList[index].clip = audioClip; SoundPlayer soundPlayer = new SoundPlayer(info, _audioSourceList[index], index); _soundPlayerList.Add(soundPlayer); } _soundInfosList.Clear(); } /// <summary> /// 通知を取得 /// </summary> /// <param name="_soundInfo"></param> public void SetInfo(SoundInfo _soundInfo) { _soundInfosList.Add(_soundInfo); } /// <summary> /// 使用中のAudioSourceの解放 /// </summary> /// <param name="_index"></param> public void ReleaseAudioSource(int _index, SoundPlayer _soundPlayer) { _audioSourceList[_index].clip = null; _audioSourceListFlg[_index] = false; _releasesoundPlayerList.Add(_soundPlayer); } /// <summary> /// 解放予定リストの確認 /// </summary> void ReleaseCheck() { //解放予定があれば解放 if (_releasesoundPlayerList.Count > 0) { foreach (var _soundPlayer in _releasesoundPlayerList) { _soundPlayerList.Remove(_soundPlayer); } _releasesoundPlayerList.Clear(); } } /// <summary> /// サウンドの更新 /// </summary> void SoundUpdate() { if (_soundPlayerList == null) return; foreach(var _soundPlayer in _soundPlayerList) { _soundPlayer.Update(); } ReleaseCheck(); } } } 使用例 void Update() { if(Input.GetKeyDown(KeyCode.P)) { SoundInfo soundInfo = new SoundInfo() { m_usingSoundTyp = UsingSoundTyp.SE, m_playSoundTyp = PlaySoundTyp.LoopNum, m_loopNum = 3, m_usingSound="SE", m_endFunc = TestEnd, }; SoundManager.Instance.SetInfo(soundInfo); } if (Input.GetKeyDown(KeyCode.O)) { SoundInfo soundInfo = new SoundInfo() { m_usingSoundTyp = UsingSoundTyp.BGM, m_playSoundTyp = PlaySoundTyp.Single, m_usingSound = "BGM", m_endFunc = TestEnd, }; SoundManager.Instance.SetInfo(soundInfo); } if(Input.GetKeyDown(KeyCode.J)) { SoundInfo soundInfo = new SoundInfo() { m_usingSoundTyp = UsingSoundTyp.BGM, m_playSoundTyp = PlaySoundTyp.Loop, m_usingSound = "BGM", m_endFunc = TestEnd, m_pauseFunc = Pause, m_unpauseFunc = UnPause, m_stopFunc = Stop, }; SoundManager.Instance.SetInfo(soundInfo); } } bool TestEnd() { Debug.Log("End"); return true; } bool Pause() { if (Input.GetKeyDown(KeyCode.I)) { return true; } return false; } bool UnPause() { if (Input.GetKeyDown(KeyCode.U)) { return true; } return false; } bool Stop() { if (Input.GetKeyDown(KeyCode.Y)) { return true; } return false; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】効率よく開発するためのTips

基本 ?検索力 ?AssetStore ?ショートカットキー ?インテリセンス ?コードスニペット ?プログラミングフォント ?️拡張機能 ?️SOLID原則 Unity ?基本 ?プレハブバリアント ?DoTween ✨Attribute ?UnityPackage ?Unityのショートカットキー よく使うショートカットキーを紹介します。 全般 ショートカットキー 内容 Ctrl + D 複製 Ctrl + Shift + C コンソール表示 Shift + Space 全画面表示 Ctrl + F / Ctrl + K 検索 / 広範囲に検索 Ctrl + P 再生 / 停止 Ctrl + Shift + P 一時停止 Alt + フォルダやオブジェクトをクリック 全ての階層を展開/全ての階層を折りたたむ Sceneビュー ショートカットキー 内容 右クリック + WASD 視点を前後左右に移動 右クリック + Shift + WASD 視点を前後左右に素早く移動 QWERTY ツールの切り替え Ctrl + 移動 / 回転 / 拡大 グリッドしながら移動 / 回転 / 拡大 Edit -> ShortCuts からショートカットキーの閲覧と編集が可能です。 ?️プリセット プリセットとは、コンポーネントの設定値を保存して再利用可能にする機能です。コンポーネント設定の手間が省け、ミスも防げます。 インスペクタの右上にある、調整バーのアイコンをクリックすると、コンポーネントの値をプリセットとして読み込んだり書き出したりできます。プリセットは画像や音声のインポート設定、Project Settings の設定値など、色々なもので作れます。 画像をインポートした時やコンポーネントを追加した時に、プリセットを自動で適応したい場合は、プリセットのインスペクタにある「Add to 〇〇 default」ボタンをクリックして下さい。プリセットが Project Settings -> Preset Manager に追加されます。 ?️Editor拡張 Unity Editor はスクリプトでカスタマイズできます。Unity Editor を不便に感じたときは、Editor拡張をネットで検索してみてください。色々なEditor拡張が配布されています。 ContextMenu や MenuItem、OnValidate() といったEditor拡張であれば簡単に作れます。 ⏯️Script Changes While Playing Editorでゲーム実行中にスクリプトを変更した際の挙動を変えて、無駄な待ち時間を減らせます。 変更は Unity -> Preferences -> General -> Script Changes While Playing から行えます。 項目 内容 Recompile And Continue Playing コンパイル後、ゲームを再開します(大抵、エラーが出てまともに動きません) Recompile After Finished Playing ゲーム終了後、コンパイルします Stop Playing And Recompile 自動でゲームを終了して、コンパイルします ⚠️注意が必要なもの Editor の挙動に影響が出るため、扱う際は機能を理解して忘れないようにしましょう。 ⏩Enter Play Mode Settings Editor上でゲームの再生をするときに行われる初期化処理を省略して、ゲームの起動時間を圧倒的に短縮します。 使う際は Edit -> Project Settings -> Editor -> Enter Play Mode Settings -> Enter Play Mode Options を有効にして下さい(static な変数が自動で初期化されなくなる等の副作用があるので注意)。 ?Auto Refrech ファイルのインポートや変更後のリフレッシュ処理を手動化する事で、望まない処理待ちを防げます。 使う際は Edit -> Preferences -> Asset Pipeline -> Auto Refresh を無効にして下さい。手動のリフレッシュ処理は Ctri + R で行えます。 エディタ再生前にリフレッシュするスクリプトを追加すれば、リフレッシュ忘れを防げます。 ?CompileLocker スクリプト書き換え後のコンパイル処理を手動化する事で、望まない処理待ちを防げます。 Auto Refresh を無効にする必要があります。 CompileLocker には、ショートカットキーの重複問題があります。ショートカットの変更は Editor -> ShortCuts から行える他、スクリプトから直接変更も可能です。私は Compile に「#&c (Shift + Alt + c)」、ForceCompile に「%#&c (Ctrl + Shift + Alt + c)」を割り当てています。 CompileLocker クラスに追加する事で便利になるコードを紹介します。 // コンパイル忘れ防止 [InitializeOnLoadMethod] private static void InitReloadAssemblies() { EditorApplication.playModeStateChanged += (PlayModeStateChange state) => { if (state == PlayModeStateChange.ExitingEditMode) ReloadAssemblies(); }; } //コンパイル後に再生 [MenuItem(MenuItemPath + "Compile And Play #&p", false)] private static void CompileAndPlay() { ReloadAssemblies(); EditorApplication.isPlaying = true; } ?️Assembly Definition Assembly Definition(asmdef)とは、プログラムのコンパイル範囲を区切って、コンパイル処理を削減する機能です。大規模プロジェクトやライブラリ向けの機能です。 asmdef の作成は、Project ビューにあるフォルダを右クリック -> Create -> Assembly Definition から行えます。 asmdef はアセンデフと読みます(非公式)。 詳細 asmdef 以下の階層にあるスクリプトは、その asmdef に属します。 asmdef に属したスクリプトは、asmdef に属していないスクリプトを参照できません。 Auto Referenced を無効にすると、コンパイル処理から除外されますが、asmdef に属していないスクリプトが参照できなくなります。 Auto Referenced を有効にすると、常にコンパイル処理に含まれるようになりますが、asmdef に属していないスクリプトが参照できるようになります。 Assembly Definition References に参照したい asmdef を追加すれば、参照可能になります。 小手先テクニック ?ゲームスピード キー入力でゲームスピードを変えられる便利コンポーネントを用意すれば、テストプレイにかかる時間を短縮できます。 ?便利コンポーネント 振動するだけのコンポーネントや、シーン移動するだけのコンポーネントなどを作っておくと、単純な実装箇所を楽に実装できます。 ?ディレクトリ 画像のようなフォルダを用意して、新規プロジェクトにD&Dすれば、フォルダを生成する手間が減らせます。 ⚙️初期値変更 Tools -> Demigiant -> DOTween Utility Panel から、DoTween のデフォルトの Easing や LoopType を変更できます。 Project Settings -> TextMeshPro -> Settings から、TextMeshPro 生成時のフォントやサイズを変更できます(Preset でも可)。 Visual Studio の便利機能 機能 使い方 メソッドやif文などを折り畳む・展開する Ctrl + M, Ctrl + M メソッドやif文などを全て折り畳む・展開する方法 Ctrl + M, Ctrl + L クイックアクションとリファクタリング 右クリック, クイックアクションとリファクタリング 変数やメソッドの定義へ移動 右クリック, 定義へ移動 変数やメソッドの実装に移動 右クリック, 実装に移動 変数やメソッドのすべての参照を検索 右クリック, 全ての参照を検索 定義へ移動 などはF12でも実行できますが、私は手を大きく動かすのが面倒なのでマウス操作で行っています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RectTransformに合わせてラインを引く

UGUIを組んでいると、RectTransformに対して線を引きたい場合が有ります。 例えばガイドラインだったり、例えばカーソルだったり。 そんな時に利用できるRectLineコンポーネントを作りました。 RectLine.cs using System; using UnityEngine; using UnityEngine.UI; namespace ScreenPocket.UI { /// <summary> /// RectLineのブレンドモード /// </summary> public enum RectLineBlendMode { /// <summary> /// 乗算 /// </summary> Multiply, /// <summary> /// 加算 /// </summary> Additive, /// <summary> /// 減算 /// </summary> Subtract, } /// <summary> /// ライン位置 /// 内側か、中間か、外側か /// </summary> public enum RectLinePositionType { /// <summary> /// 矩形の内側 /// </summary> Inside, /// <summary> /// 矩形の中間 /// </summary> Middle, /// <summary> /// 矩形の外側 /// </summary> Outside } /// <summary> /// Rectに合わせた線を引く /// </summary> [RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(CanvasRenderer))] public sealed class RectLine : MaskableGraphic { /// <summary> /// テクスチャ(一応) /// </summary> [SerializeField] private Texture2D _texture; /// <summary> /// アウトラインの太さ /// </summary> [SerializeField] private float _size; [SerializeField] private Color _inColor = Color.white; [SerializeField] private Color _outColor = Color.white; [SerializeField] private RectLineBlendMode _blendMode = RectLineBlendMode.Multiply; [SerializeField] private RectLinePositionType _positionType = RectLinePositionType.Middle; public override Texture mainTexture => _texture != null ? _texture : Texture2D.whiteTexture; protected override void OnPopulateMesh(VertexHelper vh) { var r = GetPixelAdjustedRect(); var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height); var inLength = _positionType switch { RectLinePositionType.Inside => _size * Mathf.Sqrt(2f), RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f, RectLinePositionType.Outside => 0f, _ => throw new ArgumentOutOfRangeException() }; var outLength = _positionType switch { RectLinePositionType.Inside => 0f, RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f, RectLinePositionType.Outside => _size * Mathf.Sqrt(2f), _ => throw new ArgumentOutOfRangeException() }; //ローカル関数 //合成した色を返す Color32 GetColor(Color target) { var ret = _blendMode switch { RectLineBlendMode.Multiply => target * color, RectLineBlendMode.Additive => target + color, RectLineBlendMode.Subtract => target - color, _ => throw new ArgumentOutOfRangeException() }; //アルファはcolorの物を使う(扱いやすいので) ret.a = color.a; return ret; } var inColor = GetColor(_inColor); var outColor = GetColor(_outColor); vh.Clear(); var lb = new Vector3(v.x, v.y); var lt = new Vector3(v.x, v.w); var rt = new Vector3(v.z, v.w); var rb = new Vector3(v.z, v.y); var lbIn = lb + new Vector3(inLength, inLength); var lbOut = lb + new Vector3(-outLength, -outLength); vh.AddVert(lbIn, inColor, new Vector2(0f, 0f)); vh.AddVert(lbOut, outColor, new Vector2(0f, 1f)); vh.AddVert(lt + new Vector3(inLength,-inLength), inColor, new Vector2(1f, 0f)); vh.AddVert(lt + new Vector3(-outLength,outLength), outColor, new Vector2(1f, 1f)); vh.AddVert(rt + new Vector3(-inLength,-inLength), inColor, new Vector2(2f, 0f)); vh.AddVert(rt + new Vector3(outLength,outLength), outColor, new Vector2(2f, 1f)); vh.AddVert(rb + new Vector3(-inLength,inLength), inColor, new Vector2(3f, 0f)); vh.AddVert(rb + new Vector3(outLength,-outLength), outColor, new Vector2(3f, 1f)); vh.AddVert(lbIn, inColor, new Vector2(4f, 0f)); vh.AddVert(lbOut, outColor, new Vector2(4f, 1f)); vh.AddTriangle(0, 1, 2); vh.AddTriangle(2, 1, 3); vh.AddTriangle(2, 3, 4); vh.AddTriangle(4, 3, 5); vh.AddTriangle(4, 5, 6); vh.AddTriangle(6, 5, 7); vh.AddTriangle(6, 7, 8); vh.AddTriangle(8, 7, 9); } } } 太さの調整 テクスチャを指定可能(内側がv0、外側がv1各辺が0~1、1~2とタイリング可能) 矩形の内側、中間、外側で位置を調整可能 内周色、外周色を指定可能 内周/外周色とGraphicのColorのブレンド方法を選択可能 となっているのでソコソコ多機能かな?と。 MaskableGraphic派生なので、当然マスク対象にもできるし、Maskコンポーネントと組み合わせれば、ライン部分のみマスクをかける事も可能です。 次作るゲームのカーソルはコレで作ろうかな。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RectTransformのRectに沿ったラインを引く

UGUIを組んでいると、RectTransformに対して線を引きたい場合が有ります。 例えばガイドラインだったり、例えばカーソルだったり。 そんな時に利用できるRectLineコンポーネントを作りました。 RectLine.cs using System; using UnityEngine; using UnityEngine.UI; namespace ScreenPocket.UI { /// <summary> /// RectLineのブレンドモード /// </summary> public enum RectLineBlendMode { /// <summary> /// 乗算 /// </summary> Multiply, /// <summary> /// 加算 /// </summary> Additive, /// <summary> /// 減算 /// </summary> Subtract, } /// <summary> /// ライン位置 /// 内側か、中間か、外側か /// </summary> public enum RectLinePositionType { /// <summary> /// 矩形の内側 /// </summary> Inside, /// <summary> /// 矩形の中間 /// </summary> Middle, /// <summary> /// 矩形の外側 /// </summary> Outside } /// <summary> /// Rectに合わせた線を引く /// </summary> [RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(CanvasRenderer))] public sealed class RectLine : MaskableGraphic { /// <summary> /// テクスチャ(一応) /// </summary> [SerializeField] private Texture2D _texture; /// <summary> /// アウトラインの太さ /// </summary> [SerializeField] private float _size; [SerializeField] private Color _inColor = Color.white; [SerializeField] private Color _outColor = Color.white; [SerializeField] private RectLineBlendMode _blendMode = RectLineBlendMode.Multiply; [SerializeField] private RectLinePositionType _positionType = RectLinePositionType.Middle; public override Texture mainTexture => _texture != null ? _texture : Texture2D.whiteTexture; protected override void OnPopulateMesh(VertexHelper vh) { var r = GetPixelAdjustedRect(); var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height); var inLength = _positionType switch { RectLinePositionType.Inside => _size * Mathf.Sqrt(2f), RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f, RectLinePositionType.Outside => 0f, _ => throw new ArgumentOutOfRangeException() }; var outLength = _positionType switch { RectLinePositionType.Inside => 0f, RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f, RectLinePositionType.Outside => _size * Mathf.Sqrt(2f), _ => throw new ArgumentOutOfRangeException() }; //ローカル関数 //合成した色を返す Color32 GetColor(Color target) { var ret = _blendMode switch { RectLineBlendMode.Multiply => target * color, RectLineBlendMode.Additive => target + color, RectLineBlendMode.Subtract => target - color, _ => throw new ArgumentOutOfRangeException() }; //アルファはcolorの物を使う(扱いやすいので) ret.a = color.a; return ret; } var inColor = GetColor(_inColor); var outColor = GetColor(_outColor); vh.Clear(); var lb = new Vector3(v.x, v.y); var lt = new Vector3(v.x, v.w); var rt = new Vector3(v.z, v.w); var rb = new Vector3(v.z, v.y); var lbIn = lb + new Vector3(inLength, inLength); var lbOut = lb + new Vector3(-outLength, -outLength); vh.AddVert(lbIn, inColor, new Vector2(0f, 0f)); vh.AddVert(lbOut, outColor, new Vector2(0f, 1f)); vh.AddVert(lt + new Vector3(inLength,-inLength), inColor, new Vector2(1f, 0f)); vh.AddVert(lt + new Vector3(-outLength,outLength), outColor, new Vector2(1f, 1f)); vh.AddVert(rt + new Vector3(-inLength,-inLength), inColor, new Vector2(2f, 0f)); vh.AddVert(rt + new Vector3(outLength,outLength), outColor, new Vector2(2f, 1f)); vh.AddVert(rb + new Vector3(-inLength,inLength), inColor, new Vector2(3f, 0f)); vh.AddVert(rb + new Vector3(outLength,-outLength), outColor, new Vector2(3f, 1f)); vh.AddVert(lbIn, inColor, new Vector2(4f, 0f)); vh.AddVert(lbOut, outColor, new Vector2(4f, 1f)); vh.AddTriangle(0, 1, 2); vh.AddTriangle(2, 1, 3); vh.AddTriangle(2, 3, 4); vh.AddTriangle(4, 3, 5); vh.AddTriangle(4, 5, 6); vh.AddTriangle(6, 5, 7); vh.AddTriangle(6, 7, 8); vh.AddTriangle(8, 7, 9); } } } 太さの調整 テクスチャを指定可能(内側がv0、外側がv1各辺がu0~1、u1~2、u2~3、u3~4とタイリング) 矩形の内側、中間、外側で位置を調整可能 内周色、外周色を指定可能 内周/外周色とGraphicのColorのブレンド方法を選択可能 となっているのでソコソコ多機能かな?と。 MaskableGraphic派生なので、当然マスク対象にもできるし、Maskコンポーネントと組み合わせれば、ライン部分のみマスクをかける事も可能です。 次作るゲームのカーソルはコレで作ろうかな。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】Unity2019.4のURP環境下にてPost Processingが動作しなかった話

先日、Unity2019.4.28f1上で制作していたプロジェクトにおいてうまくPost Processing(ポストプロセッシング/ポストプロセス)を適応することができず、ネットなどで調べてみても解決しなかった(検索の仕方が原因でうまく見つからなかった)問題を解決することができたので備忘録を兼ねて記録することにしました。 検証/再現環境 〇 Unity2019.4.28f1 〇 Universal Render Pipeline Version 7.3.1(Package Managerよりインストール)→ 以後URPと記述 〇 Post Processing Version 3.1.1 (Package Managerよりインストール) 簡単にまとめると 〇 Unity2019.3以降より、URPの中に標準でポストプロセッシングのためのシステムが組み込まれるようになり、以前のようにPackage Managerから導入する必要が無くなっていた。  →そのため、前の情報を頼りに設定するだけでは動作しないようになっている。 ↑ URPに付属されているポストプロセス(Volume)のコンポーネント 〇 2019.3以前のポストプロセッシングは「Post Processing Stack v2」という名前だったが、URPに搭載されているものはその後継バージョンとなっており、Unityとしてはこちらを推奨していく方針の模様。 (調べてみたところ、既にUnity2019.4までの互換性となっており、Unity2020.1以降では互換性が打ち切られている模様。) ↑ Post Processing Stack V2のポストプロセス(Volume)のコンポーネント 〇以前までポストプロセッシング用として使われていたパッケージは、URPやHDRP(High Definition Render Pipeline)を使用しないBRP(Built-in Render Pipeline)やSRP(Scriptable Render Pipeline)向けとなった。 〇URPで「Post Processing Stack v2」が使えないかというとそういうわけではなく、利用する手段はある。次の項目にて簡単に手段について記しておきます。 (HDRPの方でも同じことができるのか試そうとしましたが、設定項目的に出来ない可能性が高かったので今回は検証していません。ご了承ください。) URP環境下での「Post Processing Stack v2」使用方法 ①Package ManagerからPost Processingをダウンロードする。 プレビューパッケージなどには設定されてないのでAdvanced設定はしなくても見つかると思われます。 ②Project Settingから現在適応されているURPの設定を確認する。 [Edit]→[Project Settings]→[Graphics]→[Scriptable Render Pipeline Settings]の中のファイル名をクリックするとProjectにファイルの場所が表示されるので選択してください。 ③URPの設定から使用するPost Processingの種類を変更する。 URPの設定内にある[Post-processing]のメニューの中の[Fuature Set]を変更することによって、どの種類のポストプロセッシングを利用するか決めることができます。 Integratedを選択することでURPに付属しているポストプロセスが反映されるようになり、Post Processing Stack v2を選択することでPackage Managerから導入した方のポストプロセスが反映されるようになります。 この項目はPost ProcessingのPackageを入れているときのみしか表示されないようです。 (選択すると「UnityはそのうちURPでのPostProcessingV2のサポートをやめるので積極的に使わないでね」というニュアンスの警告文が出ます。) これで、Post Processing Stack v2のコンポーネントを用いたポストプロセスが可能になります。これを実際に使う人がどれくらいいるかはわかりませんが、URPでのポストプロセスの使用にあたって躓いてしまったところなので、備忘録かねて記述しました。 参考にしたサイト 〇Unity公式のURPでのポストプロセッシングのリファレンス https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.3/manual/integration-with-post-processing.html 〇Unity公式のHDRPでのポストプロセッシングのリファレンス(参考) https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@13.0/manual/Post-Processing-Main.html 〇Unity公式のPost Processing Stack v2のリファレンス(動作環境の話を見ればすぐ解決したような…?) https://docs.unity3d.com/Packages/com.unity.postprocessing@3.1/manual/index.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityのテストコードについて

初めてUnityでのテストコードを学びましたので、備忘録として残します。 Unityプロジェクトの作成 テスト開発するためにUnityプロジェクトを新規作成します。 Unity Test Ruuner の活用 Unityの標準で搭載されているテストツールです。 Unityのメニュー画面からWindow>General>Test Runnerで開くことが出来ます。 テスト方法には2つの方法があります。 Playモード:実際にバックグラウンドでアプリを起動しながらテストします。 Editモード:別途Editモード用のファイルを追加してテストできます。 テスト時のアプリ起動はしません。 テストするファイルを作成 テストしたいファイルを用意しておきます。 using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoundManager : MonoBehaviour { public static SoundManager instance; private void Awake() { if(instance == null) { instance = this; DontDestroyOnLoad(this.gameObject); } else { Destroy(this.gameObject); } } //--シングルトン終わり-- public AudioSource audioSourceBGM; //BGMのスピーカー public AudioClip[] audioClipsBGM; //BGMの素材 (0:Title, 1:Town, 2:Quest, 3:Battle) public AudioSource audioSourceSE; //SEのスピーカー public AudioClip[] audioClipsSE; //ならす素材 private string v; public SoundManager(string v) { this.v = v; } public void StopBGM() { audioSourceBGM.Stop(); } public void StopSE() { audioSourceSE.Stop(); } // Start is called before the first frame update void Start() { PlayBGM("Title"); } public void PlayBGM(string sceneName) { audioSourceBGM.Stop(); switch (sceneName) { default: case "Title": audioSourceBGM.clip = audioClipsBGM[0]; break; case "Town": audioSourceBGM.clip = audioClipsBGM[1]; break; case "Quest": audioSourceBGM.clip = audioClipsBGM[2]; break; case "Battle": audioSourceBGM.clip = audioClipsBGM[3]; break; } audioSourceBGM.Play(); } public void PlaySE(int index) { audioSourceSE.PlayOneShot(audioClipsSE[index]); //SEを一度鳴らす this.count = 0; } public int count { get; private set; } public int GetName() { return this.count; } } バックグランドBGMの設定やボタンクリック時に音が鳴る設定をしています。 ボタンが鳴るときにPlaySEが起動するのですが、その時にカウントに0を代入するようにしています。 テストコードの作成 テストするためのコードを記述します。 TestRunnerの画面からTestsフォルダを作成してテストファイルを作成します。 using System.Collections; using System.Collections.Generic; using NUnit.Framework; using UnityEngine; using UnityEngine.TestTools; namespace Tests { public class NewTestScript { // A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use // `yield return null;` to skip a frame. [UnityTest] public IEnumerator SoundManagerTest() { var x = new SoundManager("count"); //start() Assert.AreEqual(0,x.GetName()); yield return null; } } } countの値と予測値を比べて正しければテストが通るようにしています。 テスト テストコードを記述したら、テストします。 今回はPlayモードで実行しています。 左上のRun Allでテストを実行します。 結果が正しければすべて緑のチェックがつきます。 まとめ Unityでテスト開発するための手順を書きました。 PlayモードとEditモードの選択ができるので、必要に応じて使い分けてください。 テストするファイルの用意とテストコードを用意する必要があります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む