C++ #include <atlbase.h> is not found.
「C++ #include
DirectX12Raytracingのサンプルをビルドすると発生した。。。
■対応フロー
VisualStudioInstaller起動
↓
個別のコンポーネント
↓
「Spectreの軽減策を含む、v141ビルドツール用 C++ ATL (x86およびx64)」
「Spectreの軽減策を含む、最新のv142ビルドツール用 C++ ATL (x86およびx64)」
「Spectreの軽減策を含む、最新のv142ビルドツール用 C++ MFC (x86およびx64)」
「v141ビルドツール用 C++ ATL (x86およびx64)」
「最新のv142ビルドツール用 C++ ATL (x86およびx64)」
をインストール
↓
VisualStudio再起動してリビルド
↓
成功
yvals.hでcrtdbg.hが見つからないエラー
超絶久々にC++触ったら発生。
developercommunity.visualstudio.com
Windows 10 SDKをインストールでエラーは消えた。
developer.microsoft.com
DeviceSimulatorについて
blogs.unity3d.com
おぼえがきー
DeviceSimulatorとは
・Editor上で様々なモバイルデバイスの挙動と物理特性をシミュレートするための機能。
・セーフエリアの表示、画面解像度、Orientation、グラフィックスAPI変更など
・現在はPreview版
インストール方法
PackageManagerを開き「Show preview packages」にチェックを入れ検索するとヒットします。
1.2.0をインストールします。

使用方法

ここから開きます。
開くとこんな感じ

デバイススペック確認、セーフエリア表示、画面回転など制御できます。
現段階で用意されてるデバイスプリセットは以下の11つ
Apple iPad Pro 11
Apple iPad Pro 12.9(2018)
Apple iPhone 7
Apple iPhone 8
Apple iPhone XS Max
Google Pixel 2
Google Pixel 2 XL
Google Pixel 3
Motorola Moto G7 Power
Samsung Galaxy S10+
Samsung Galaxy S10e
com.unity.device-simulator/com.unity.device-simulator フォルダに
デバイス定義ファイル(.json)がありますが、今は追加出来ないみたいです。
今後カスタムデバイス定義を追加する方法が提供される予定とか。
シミュレートされたデバイス情報の取得
UnityEngine.ScreenとUnityEngine.SystemInfoから取得可能ですが
定義ファイルJSON内で未定義のパラメータはシミュレートされません。
例えば下記はiPhoneXSMaxの定義ファイルの一部ですが、
deviceModelは定義済なのでSystemInfo.deviceModelにこれが反映されます。
一方、deviceNameは未定義なのでSystemInfo.deviceNameには期待しない値が入ります。(動作環境?)

シミュレータを起動してSystemInfoとScreenの一部パラメータをLogするとこんな感じです。

(deviceNameがPC名になってる...)
また、DeviceとOrientationを変更するとこんな感じです。

Editor再生中にデバイスを変更することも可能なので、
縦横画面切り替わる系のゲーム開発では便利そう。
AdaptivePerformanceについて
blogs.unity3d.com
そういえば触ってなかったということで。
対応端末持っておらず動作確認取れていないので、
こんな感じで使うのかなーという自分へのメッセージ。
AdaptivePerformanceとは
モバイル端末の状態安定のため役立つ仕組みを提供するパッケージ。
現在はSamsung Galaxy S10のみサポート
出来ること
・端末状態変化をイベントとして受信(スロットリング発生,CPUバウンドなど)
・CPU/GPUの性能調整(スロットリング時除く)
例えば、サーマルスロットリング発生早期イベントを受信した際に
ゲーム中の表示物のLODを下げることで未然にそれを防いだり、
軽めの処理が多いシーンではCPU/GPU性能を抑えるなどが可能。
インストール方法
PackageManagerから「AP Sumsung Android」をインストールします。
依存してAdaptivePerformanceもインストールされます。

使用例
端末温度管理
using UnityEngine;
using UnityEngine.AdaptivePerformance;
public class ApThermalStatusTest : MonoBehaviour
{
// AdaptivePerformanceのインターフェース
private IAdaptivePerformance m_ap = null;
void Awake()
{
// インスタンス取得。Instanceは再生開始時にPackage側で自動生成される
m_ap = Holder.Instance;
if (!m_ap.Active)
return;
// 温度に関するイベント
m_ap.ThermalStatus.ThermalEvent += (metrics) =>
{
switch (metrics.WarningLevel)
{
// スロットリングの危険はありません
case WarningLevel.NoWarning:
// 通常品質へ
break;
// スロットリングが発生しそうです
case WarningLevel.ThrottlingImminent:
// 品質下げてスロットリング回避する
break;
// スロットリング中です
case WarningLevel.Throttling:
// 品質下げてスロットリング回避する
break;
}
};
}
void Update()
{
// ThermalStatusに温度関連情報が詰まってる。ThermalMetricsから取得する
var tm = m_ap.ThermalStatus.ThermalMetrics;
// TemparatureLevelは正規化された温度で0~1の値をとる.
// 1は最大温度に達した状態でスロットリングが発生している
Debug.Log("温度レベル:" + tm.TemperatureLevel);
// TemperatureTrendは正規化された温度の上昇下降傾向で-1~1の値をとる
// +値は温度上昇、-値は温度下降
Debug.Log("温度傾向:" + tm.TemperatureTrend);
}
}
端末性能操作
using UnityEngine;
using UnityEngine.AdaptivePerformance;
public class ApDevicePerformanceControlTest : MonoBehaviour
{
private IAdaptivePerformance m_ap = null;
void Awake()
{
m_ap = Holder.Instance;
if (!m_ap.Active)
return;
var dpc = m_ap.DevicePerformanceControl;
// true:AutoPerformanceLevelControllerに制御を任せる
// false:自分で制御する
dpc.AutomaticPerformanceControl = false;
// Cpu性能レベルを最低に設定
dpc.CpuLevel = 0;
// Gpu性能レベルを最低に設定
dpc.GpuLevel = 0;
// Cpu性能レベルを最大に設定
dpc.CpuLevel = dpc.MaxCpuPerformanceLevel;
// Gpu性能レベルを最大に設定
dpc.GpuLevel = dpc.MaxGpuPerformanceLevel;
}
}
端末性能状態の管理
using UnityEngine;
using UnityEngine.AdaptivePerformance;
public class ApPerformanceStatusTest : MonoBehaviour
{
// AdaptivePerformanceのインターフェース
private IAdaptivePerformance m_ap = null;
void Awake()
{
// インスタンス取得。Instanceは再生開始時にPackage側で自動生成される
m_ap = Holder.Instance;
if (!m_ap.Active)
return;
// CPU,GPU,フレームレートのバウンド発生でイベント受信
m_ap.PerformanceStatus.PerformanceBottleneckChangeEvent += (ev) =>
{
switch (ev.PerformanceBottleneck)
{
// CPUバウンド
case PerformanceBottleneck.CPU:
break;
// GPUバウンド
case PerformanceBottleneck.GPU:
break;
// フレームレートバウンド
case PerformanceBottleneck.TargetFrameRate:
break;
// 不明
case PerformanceBottleneck.Unknown:
break;
}
};
// 性能レベル変更イベント
m_ap.PerformanceStatus.PerformanceLevelChangeEvent += (ev) =>
{
Debug.Log("CPUレベル:" + ev.CpuLevel);
Debug.Log("GPUレベル:" + ev.GpuLevel);
Debug.Log("CPUレベル差分:" + ev.CpuLevelDelta);
Debug.Log("GPUレベル差分:" + ev.GpuLevelDelta);
};
}
void Update()
{
var metrics = m_ap.PerformanceStatus.PerformanceMetrics;
Debug.Log("CPUレベル:" + metrics.CurrentCpuLevel);
Debug.Log("GPUレベル:" + metrics.CurrentGpuLevel);
Debug.Log("性能ボトルネック:" + metrics.PerformanceBottleneck);
var frameTiming = m_ap.PerformanceStatus.FrameTiming;
Debug.Log("現在フレーム時間:" + frameTiming.CurrentFrameTime);
Debug.Log("平均フレーム時間:" + frameTiming.AverageFrameTime);
Debug.Log("現在CPUフレーム時間:" + frameTiming.CurrentCpuFrameTime);
Debug.Log("平均CPUフレーム時間:" + frameTiming.AverageCpuFrameTime);
Debug.Log("現在GPUフレーム時間:" + frameTiming.CurrentGpuFrameTime);
Debug.Log("平均GPUフレーム時間:" + frameTiming.AverageGpuFrameTime);
}
}
所感
いやこれ個人的に非常に便利。GalaxyS10でのみサポートって勿体ない。
Unityも公式ブログで対応デバイス増やすと言ってるし今後に期待・・・!
クラスメンバのメンバのSerializedProperty取得方法
UnityのEditorInspector拡張作業時に詰まったのでメモ。
// 疑似コード
[Serializable]
public class SomethingData : ScriptableObject
{
[Serializable]
public class InnerData
{
public int value; // <- これ
}
public InnerData inner = new InnerData();
}上記のようなクラスがあったとして、「value」のSerializedPropertyを取得する方法。
// 疑似コード
[CustomEditor(typeof(SomethingData))]
public class SomethingDataEditor : Editor
{
public override void OnInspectorGUI()
{
/*~いろいろ処理~*/
SerializedProperty property = serializedObject.FindProperty("inner").FindPropertyRelative("value");
/*~いろいろ処理~*/
}
}FindProperty()とFindPropertyRelative()を段階的に使用して取得。
同期した位置の線形補間
ネットワークマルチなどで表示物の位置を同期する際、クライアントがサーバーから受信した位置をそのまま使用すると、ラグや低同期レートなどが原因でその表示物の動作がカックカクになるが、これを軽減するために同期フレームとその前のフレームの位置を線形補間しようよってやつ。ベタ中のベタ。予測同期と併せてUnityがまだメジャーになる10数年前に初めて出会い使用しそれっきりだったが、最近ネットワーク同期について調べる機会がありそこで目にしたがやっぱり今でも活用されていて、超簡単、手軽だし書いてみた。回転補間付。
コード
public class TransformInterpolator : MonoBehaviour
{
private Vector3 m_fromPos;
private Vector3 m_toPos;
private Quaternion m_fromRotation;
private Quaternion m_toRotation;
private float m_diffTime;
private float m_lastTime;
private float m_elapsedTime;
public void SetTransform(Vector3 newPos,Quaternion newRot)
{
m_fromPos = transform.position;
m_toPos = newPos;
m_fromRotation = transform.rotation;
m_toRotation = newRot;
m_diffTime = Time.time - m_lastTime;
m_lastTime = Time.time;
m_elapsedTime = 0.0f;
}
void LateUpdate()
{
if (m_diffTime <= 0)
return;
m_elapsedTime += Time.deltaTime;
float ratio = m_elapsedTime / m_diffTime;
if (ratio >= 1.0f)
ratio = 1.0f;
transform.position = Vector3.Lerp(m_fromPos, m_toPos, ratio);
transform.rotation = Quaternion.Lerp(m_fromRotation, m_toRotation, ratio);
}
}
使用例
※疑似コード
public class SyncObject : MonoBehaviour
{
private TransformInterpolator m_transformInterpolator;
void Awake()
{
// クライアント側のみに追加
m_transformInterpolator = gameObject.AddComponent<TransformInterpolator>();
}
// サーバーからスナップショットを受信したら呼ばれる
void OnReceiveSnapshot(Snapshot snapshot)
{
m_transformInterpolator.SetTransform(snapshot.newPos,snapshot.newRot);
}
}
他にも補間手法はありますが、開発中のゲームに組み込んでみると相性が悪くて思ったような挙動にならずそのプロジェクト独自の補間手法(や、サーバー側でのクラ位置管理手段)を模索することになることが多かったが、線形補間はとりあえず実装出来て効果もそこそこ、プロトレベルでは十分なのでコスパよい印象。
Photon BOLT サンプル起動まで覚書
Photon BOLTのサンプル動かすところまでの覚書。
自分が理解出来ればOK状態なので
詳細知りたい人は公式やQiitaで適当な記事を漁ってください。
Photon BOLT
- 状態、Mecanim,シーンロードの同期有
- エンティティの優先順位付
- ラグ補正有
- 当たり判定記録有
- 専用サーバーとして使用可能(DGS)
- マッチメイキング可(サンプル有)
- リレー
- マルチプラットフォーム対応
詳しい機能は公式参照
doc.photonengine.com
環境
- Unity : Unity 2019.2.3f1
- OS : Windows 10 Home
手順
Photonのアカウントを作成
↓
PhotonBOLTをUnityにインポート
↓
Serverアプリ作成
↓
Clientアプリ作成
↓
ServerアプリをHeadlessModeで起動
↓
ClientアプリをServerへ接続して操作
Photonのアカウントを作成
dashboard.photonengine.com
既に持っていたら必要なし。
持ってない場合アカウント登録。
(PhotonBOLTをUnityへインストールした後にAppIDの設定が求められる。)
登録したメールアドレスに届くメールので、パスワードを入力しアカウントを作成。
その後、クーポンIDなどの適用が求めらるが、持っていないのでスキップ。
アプリ作成時「Photonの種別」「アプリケーション名」のみ設定し次へ。
PhotonBOLTをUnityにインポート
UnityのアセットストアからPhotonBOLTをインポート。
検索したら出てくる。

インポートが完了するとこんなダイアログが出てくる。

「Photon Bolt App ID or Email」にAppIDを入力して「Next」
「Samples」の矩形をクリックして、サンプルをインポートし「Next」

Nextし続けるとセットアップ完了ダイアログが出るのでYes。
Unityのコンパイルが走る。
Serverアプリ作成
Unityで新規プロジェクト作成し、BoltHeadlessServerシーンを開く。
HerarchyのHeadlessServerHolderゲームオブジェクトを選択し
inspectorのMapの値をLevel1からTutorial1に変更する。
※デフォルト設定のLevel1がHeadlessModeで再生するとエラーを吐くためTutorial1を代用する。
RoomIDも変更しておくと後でクライアントがルームリスト参照する際にわかりやすい。
空の場合はランダムで作られる。

BuildSettings->Scenes In Buildに以下のシーンを追加
BoltHeadlessServer : 0 (起動シーン)
Tutorial1 : 1
シーン追加後、メニューバーからBolt->Compile Assemblyを実行
Unityを再生。
ここまで上手く進めばこの画面が出来上がる。
WSDAキーで画面上の箱が動く。

何事もなければビルドする。
アプリ名は「PhotonBoltServerTest」
Clientアプリ作成
Unityで新規プロジェクト作成し、Serverと同じようにPhotonBOLTをインポート。
完了後、BuildSettings->Scenes In Buildで以下シーンを追加。
MainMenu : 0 (起動シーン)
Tutorial1 : 1
追加したらビルドする。
アプリ名は「PhotonBoltClientTest」
ここまででServerとClientのアプリが完成。
ServerアプリをHeadlessModeで起動
作成済のServerアプリをHeadlessModeで起動
PhotonBoltServerTest.exe -batchmode -nographics -map Tutorial1
Windowsのプロセス一覧に表示されたら成功。
ClientアプリをServerへ接続して操作
PhotonBoltClientTest.exeを起動し画面に表示されている「Client」をクリックするとルームIDが表示される。

クリックすると
部屋に入れる。

クライアント複数起動&接続で操作可能

裏でサーバープロセスが動いている。
