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

Unityでの開発において、車を扱うアプリで指定したルート上でイベント処理を行う

プログラマーの大角です。Unityで車を扱ったVRアプリ開発を行った際の実装の一部をご説明させて頂きます。

概要

車を扱う際に様々な機能が有るかと思いますが、今回は決められたルートを走る車が指定したポイントに来た時に様々なイベント処理をする為の実装方法について説明します。

前提

まずは決められたルートを車が走るようにする為に使用するのはUnityStandardAssetsのWaypointProgressTrackerを使用します。WaypointProgressTrackerはWaypointCircuitとセットで使用しますが、この2つのクラスの詳細は割愛させて頂きます。

実装工程(1)

実装の準備としまして、WaypointProgressTrackerから取得したい値はcircuitとprogressStyleになりますのでスコープ変更する際にプロパティを定義します。

WaypointProgressTracker.cs

     // A reference to the waypoint-based route we should follow
        [SerializeField] private WaypointCircuit circuit;
        protected WaypointCircuit Circuit { get { return circuit; } }

     // whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.
        [SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
        protected ProgressStyle ProgressStyleProperty { get { return progressStyle; } }

実装工程(2)

WaypointProgressTrackerを継承したWayPointProgressTrackerAuxiliaryForMainCarを作成します。
指定したポイントに来た時に様々なイベント処理をする為にはWaypointProgressTracker内で処理されている値を取得する必要が有ります。

その値はルートのポイントの進行を管理しているprogressNumになります。

WayPointProgressTrackerAuxiliaryForMainCar内にprogressNumの替わりとなるProgressNumForMainCarを定義し、進行に合わせて値の整合性を合わせる為に記述したものが下記になります。

WayPointProgressTrackerAuxiliaryForMainCar.cs

using UnityEngine;
using UnityStandardAssets.Utility;

namespace Common {

    /// <summary>
    /// WaypointProgressTrackerの補助機能
    /// 
    /// Autor 大角
    /// </summary>
    public class WayPointProgressTrackerAuxiliaryForMainCar : WaypointProgressTracker {

        /// <summary> ルートのポイントの更新判定専用のターゲットポジション </summary>
        Vector3 m_targetPositionForProgressCountUp;

        /// <summary> プレイヤーの車 </summary>
        [SerializeField] Transform m_car = null;

        /// <summary>スタート時に設定するWaypoint.nullの時は初期位置からスタート</summary>
        [SerializeField] GameObject m_startWayPoint = null;

        /// <summary> メインカー専用でルートの進行管理 </summary>
        public static int ProgressNumForMainCar { get; private set; }

        protected override void Start () {
            base.Start ();
            m_targetPositionForProgressCountUp = target.position;
            ProgressNumForMainCar = 0; // SetInitCarPositionAndTargetより前にリセット
            SetInitCarPositionAndTarget ();
        }

        protected override void Update () {
            base.Update ();
            UpdatePointProgress ();
        }

        /// <summary>
        /// SmoothAlongRouteの時にProgressNumを更新
        /// </summary>
        void UpdatePointProgress () {
            if (ProgressStyleProperty == ProgressStyle.PointToPoint) {
                return;
            }

            Vector3 targetDelta = m_targetPositionForProgressCountUp - transform.position;
            const float POINT_TO_POINT_THRESHOLD = 8f;

            if (targetDelta.magnitude < POINT_TO_POINT_THRESHOLD) {
                ProgressNumForMainCar = (ProgressNumForMainCar + 1) % Circuit.Waypoints.Length;
            }

            m_targetPositionForProgressCountUp = Circuit.Waypoints[ProgressNumForMainCar].position;
        }

        /// <summary>
        /// 車の初期位置とTargetの初期値を設定
        /// </summary>
        void SetInitCarPositionAndTarget() {
            int wayPointIndex = 0;
            if (m_car != null
                && m_startWayPoint != null) {
                foreach (Transform transform in Circuit.Waypoints) {
                    if (m_startWayPoint.name == transform.name) {
                        // 車のスタート位置
                        m_car.position = m_startWayPoint.transform.position;

                        // 車の向き
                        int nextWayPointIndex = wayPointIndex + 1;
                        if (nextWayPointIndex < Circuit.Waypoints.Length) {
                            m_car.LookAt(Circuit.Waypoints[nextWayPointIndex]);
                        }
                        break;
                    }

                    wayPointIndex++;
                }
            }

            // スタート時の車の位置
            ProgressDistance = Circuit.Distances[wayPointIndex];
            ProgressNumForMainCar = wayPointIndex;
        }
    }
}

あとがき

今回はルート上の何処を走っているかを取得する部分に焦点を当てました、ルート上のポイントとアプリ内の進行との紐付けに関する実装は後日記述したいと思います。

最後まで見て頂き有難う御座いました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GfxDriveメモリリークに注意しろ

今回の主な話題:UGUI Android 「前髪」スクリーンの適応、UWA GOT Monoテスト スタック、Unityで作成したメッシュの頂点カラーをクリアする方法、MeshBakerの適用性。


メモリ

Q1: Unity 2017.2.0バージョンを使用しています。PCエディターで、ProfilerにGfxDriverが増加していることが示されています。調査した結果、Canvasにある一つのゲームオブジェクトが原因であります。このゲームオブジェクトのコンポーネントは次のとおりです。
1.png
このゲームオブジェクトを閉めると、GfxDriverはすぐに増加を停止します。この方法でアニメーションを作成するとメモリリークが発生し、このバージョンのUnityに問題があると思っています。だからこのゲームオブジェクトを空きシーンに入れましたが、GfxDriverは増加していませんでした。ここまで、問題をさらにトラブルシューティングする方法がわかりません。

これはUnity2017のUGUIのバグです。Unity2017.1のEditorバージョンでもReleaseバージョンでもこのリークが発生します。
Releaseバージョンは2017.2以降に修復されますが、Editorバージョンは2017.4.1まで修復されません。
実機バージョンに対して、現在のバージョンでは心配する必要がありません。メモリが大きすぎるためにEditorバージョンが常にクラッシュすることが心配な場合は、2017.4.1以降にアップグレードしてみてください。


UI制作

Q2:誰かがUGUI Android前髪スクリーン(Honor 10など)の適応を行った人はいますか?何かシェアできる経験はありますか?

簡単な解決策を挙げます。iPhone Xを例とすれば。
1)launch imageを準備して、iPhone Xの両側にあるデフォルトの黒い辺をオフにします。(Unity 2017以降、xのスプラッシュ画面イメージを直接提供できますから、この手順はスキップできます)

cp -R "../yourPorject/Assets/ArtResources/SplashScreen/iphonex_h.png" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/iphonex_h.png"
cp -R "../yourPorject/Assets/ArtResources/SplashScreen/iphonex_v.png" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/iphonex_v.png"
cp -R "../yourPorject/Assets/ArtResources/SplashScreen/Contents.json" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/Contents.json"

2)UGUI Rootの下に、すべてのUIの祖先レイヤーとして、desktopの概念があります。水平方向と垂直方向の両方をstretchに設定し、Topを88に、Bottomを-88に設定します。 (88は最小間隔、132は公式に推奨される安全間隔です)。2番目のステップは他のUIユーザーに対して透過的であり、意味のないUI画像が両側に表示されるため、UIの作成にはほとんど影響しません。全体的な改造プロセスは非常に短いので、試してみることをお勧めします。

PS:iPhoneXのバーは考慮されていません。

一つ簡単な解決策があります。それは、上部インターフェースに対して水平と垂直方向に自動的に伸びるRectTransformを配置することです。それがiPhoneXであることを検出したら、インターフェースコードを開き、Left Top RightBottomを自動的に44に設定します。この解決策は雨松で見ましたが、非常に簡単な方法です。もちろん、場所によっては微調整が必​​要な場合もあります。


アセット

Q3:Unityで作成したメッシュはなぜ頂点カラーが付けてありますか?どうすればつけていないメッシュを作成できますか?またはどうすればUnityに頂点カラーを消去できますか?

以下の方法はもう試しました。
1)mesh.color = null、mesh.colors32 = null。役に立ちません。
2)再びに一つ頂点カラーを付けていないMeshをnewします。役に立ちません。
3)objに変換してUnityに入れてみると、意外に頂点カラーはまだ付けています。ただし、objをMaxに入れてみると付けていませんでした。FBXに転換してプロジェクトに入れると、再びに付けました。

いくつか調べたところ、問題が見つかりました。Use Direct3D 11オプションをオフにして、Unityを再起動したら解決できます。Use Direct3D 11をオフにした後、メッシュを再作成し、この時点に頂点カラーはもう付けていません。Objファイルと頂点カラーのないFBXファイルを直接にプレビューすると、頂点カラーもありません。スイッチの位置:Edit>Project Settings>Player>Other Settings>Use Direct3D 11(PC)


Monoメモリ

Q4:MeshBakerを使用して動的にモデルをバッチ処理します。動的にモデルをバッチ続き時に大量のGCが生成されます。追加するほど、生成されるGCは多くなり、サイズは4MBになる可能性があります。これはどんな状況ですか?MeshBakerは動的モデルのバッチ処理には適していませんか?

そうです。Mesh Bakerプラグインは、上位層でメッシュデータを大量にバッチします。その間、多数のVertex Arrayを生成する必要はあり、大量のMonoメモリの割り当てを引き起こします。複雑なMMO、ARPGなどのMeshバッチ処理を大量に行う必要のあるプロジェクトに、一般的にMeshBakerプラグインはお勧めしません。
静的オブジェクトの場合、実際にはStatic Batchingを介して直接実行できます。通常、Mesh Bakerは、あるチームがゲームの実行時に動的にBatch Skinned Meshを行います。これは、数が多い場合はお勧めしません。


GOT

Q5:今日からGOTを使って始めました。Monoをデバッグすると、戦闘が始まったばかり時によくフリーズし、OverviewもAssetsもこのようにはならないです。この原因は何ですか?フリーズしたときに一部のアセットはロードされているはずだけど、これと関係ありますか?

これは、現時点でMonoメモリが超大量に割り当てられていることを示しており、UWA GOTは、これらの割り当てのMonoメモリ情報を記録するために多くの計算が必要です。さらに、アセットをロードする時にlogの出力も伴う場合、遅い程度を厳重化させる可能性もありますので、先にlog出力を閉じようとすることをお勧めします。


UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析最適化ソリューション及びコンサルティングサービスを提供している会社でございます。

UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[TIPS]Amazon S3とは?

Amazon S3とは

AWS(Amazon Web Services)の中のサービスの1つ、Amazon Simple Storage Serviceのことを指します。Sが3つだからS3ですね。
名前の通りクラウド型のストレージ機能を提供するサービスとなります。ただ、単なるストレージとしての機能だけではなく、バージョン管理やイベント機能もあるみたいです。

容量は無制限で、1GB使用する毎に料金が加算されていきます。つまりストレージにファイルを入れた分だけ課金されます。
記事執筆時点での料金は1GBあたり0.025ドル(東京リージョン、スタンダードストレージ)となっています。安い。

image.png (201.2 kB)

ウェブのどこからでもデータ格納と取得が可能のようです。データは動画や画像ファイルなど殆どのデータを預けることが可能で、ファイルそのものへのセキュリティも担保されています。各地にある物理的なデータセンターに分散して保存をしているので、障害にも強いようです。

他のAWSサービスとの連携も容易にできるので、AWS触ってる人はS3もガンガン使うのだろうと思います。

S3の機能(さらっと確認程度)

バージョン管理

バージョニングを有効にしておくことで、オブジェクト毎のバージョンを残すことができます。誤った操作しても元に戻すことができるsvnみたいな使い方ができそうですね。

ライフサイクル

オブジェクト毎にライフサイクルを設定でき、「一定期間経ったら削除・低価格帯のストレージに移動」ということができるようです。Jenkinsとかで使ったら便利そう。

ログ記録

svnみたいな感じだと思うんですが、ログを残せるみたいです。

イベント

オブジェクトに操作が行われた場合にイベントを発火させる機能があるみたいです。ここで言うイベントは多分データ分析とかですかね。

アクセス権限

デフォルトでは全オブジェクトのアクセス権がプライベートになっており、所有者+管理者以外はアクセスできません。ここに認証したユーザーのみ操作を許可するなど、細かく設定することができます。

暗号化

オブジェクトをS3に保存すると、データを暗号化しておくことができます。 サーバーサイド、クライアントサイド、それぞれの暗号化に対応しているらしいです。

オブジェクトへのアクセスツール

WindowsならWinSCP、MacならCyberDuckが良さそう?

Unityでの活用方法

以下のスライドが参考になりそう
https://www.slideshare.net/UnityTechnologiesJapan002/unite-tokyo-2019aws-for-unity-developers

ゲーム内写真をアップロードしてサーバー側でサムネイル画像の作成が行われたり。

image.png

image.png

以下の記事も。

UnityからAmazon S3にファイルをアップロードし、公開状態にする

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] LayoutGroupの子要素のpositionを正しく参照できない

自作ゲームを作っているときにUIのpositionが思うように参照できず解決に時間がかかったので備忘録として残す

問題のシーン

現在選択されているUIを下のように黄色い枠で囲もうとしたところ
予想.PNG
実行時はこのようにずれてしまう
実際.PNG
コードは以下のようになっている。選択したいUIと同じpositionに黄色い枠を移動しているだけ

private void Start()
    {
        select.rectTransform.position = currentGauge.rectTransform.position;
    }

構成はこんな感じ
CyrinderにはLayoutGroupがついている。SelectをCyrinderの子要素であるRedやGreenの位置に動かしたい

オブジェクト構成.PNG

Cyrinder構成.PNG

参考になった記事

unityのフォーラムで同じような症状についてやりとりしていた

https://forum.unity.com/threads/positions-of-ui-elements-under-vertical-layout-group.266775/

どうやらLayoutGroupなどのUI関係のコンポーネントの位置計算はフレームの最後に働くためにstart時は正しいpositionを参照できないとのこと
  
  
そこでUpdate中に黄色い枠を動かしてみると
正常.PNG

正しく動いた

解決法

しかし最初のUpdate時のみ動かすみたいなことはしたくない
どうしたものかと調べたところ普通に公式リファレンスに書いてあった
https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/class-RectTransform.html

You can work around this by creating a Start() callback and adding Canvas.ForceUpdateCanvases() method to it. This will force Canvas to be updated not at the end of the frame, but when that method is called.

つまりCanvas.ForceUpdateCanvas()を呼ぶことでCanvasのUpdateをフレームの最後ではなく即時にすることができるらしい

private void Start()
    {
    Canvas.ForceUpdateCanvases();//追加
        select.rectTransform.position = currentGauge.rectTransform.position;
    }

これでstart時でも正しくpositionを参照できるようになった

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] LayoutGroupの子要素のpositionを正しく参照できない[解決]

自作ゲームを作っているときにUIのpositionが思うように参照できず解決に時間がかかったので備忘録として残す。

問題のシーン

現在選択されているUIを下のように黄色い枠で囲もうとしたところ
予想.PNG
実行時はこのようにずれてしまう
実際.PNG
コードは以下のようになっている。選択したいUIと同じpositionに黄色い枠を移動しているだけ。

private void Start()
    {
        select.rectTransform.position = currentGauge.rectTransform.position;
    }

構成はこんな感じ。
CyrinderにはLayoutGroupがついている。SelectをCyrinderの子要素であるRedやGreenの位置に動かしたい。

オブジェクト構成.PNG

Cyrinder構成.PNG

参考になった記事

unityのフォーラムで同じような症状についてやりとりしていた。

https://forum.unity.com/threads/positions-of-ui-elements-under-vertical-layout-group.266775/

どうやらLayoutGroupなどのUI関係のコンポーネントの位置計算はフレームの最後に働くためにstart時は正しいpositionを参照できないとのこと。
  
  
そこでUpdate中に黄色い枠を動かしてみると
正常.PNG

正しく動いた。

解決法

しかし最初のUpdate時のみ動かすみたいなことはしたくない。どうしたものかと調べたところ普通に公式リファレンスに書いてあった。
https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/class-RectTransform.html

You can work around this by creating a Start() callback and adding Canvas.ForceUpdateCanvases() method to it. This will force Canvas to be updated not at the end of the frame, but when that method is called.

つまりCanvas.ForceUpdateCanvas()を呼ぶことでCanvasのUpdateをフレームの最後ではなく即時にすることができるらしい。

private void Start()
    {
    Canvas.ForceUpdateCanvases();//追加
        select.rectTransform.position = currentGauge.rectTransform.position;
    }

これでstart時でも正しくpositionを参照できるようになった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む