ランタイムに配置されたコンテンツを永続化のためにシリアライズする方法
この入門ガイドは以下を含みます:
- ランタイムにスポーンするプレハブを登録する
- 今後のセッションでコンテンツを復元するために、トランスフォームデータとステートデータを保存する
- 以前にシリアライズされたデータを更新する
この入門ガイドでは、人間が読みやすい形式でシリアライズのデモを行うために、手動で構築した冗長な文字列を使用しています。 適切なシリアライズを行うには、 [Serializable]
構造体 を使用し、具象構造にはJSONシリアライザー、コンパクトな保存にはバイナリーシリアライザーを使用することをお勧めします。
前提条件
Lightship ARを有効にしたUnityのプロジェクトが必要です。 詳細については、 ARDK 3.0 のインストール をご覧ください。
ランタイム・コンテンツのシリアライズに関する基本概念
リモートコンテンツオーサリング では、Unityシーンにおいて各 ARLocation
内に静的に配置されたオブジェクトが含まれますが、ランタイムコンテンツのシリアライズでは、プレイヤーが任意にコンテンツを配置し、その配置されたコンテンツを既知の形式にシリアライズすることで、後で再スポーンできるようにします。
プレイヤーが構築したシーンをシリアライズするには、以下の情報が必要です。
- コンテンツをアンカーするルートトランスフォーム(ARロケーション、イメージターゲットなど)
- これにより、将来的にデシリアライズされたコンテンツが同じ 場所に正しく配置されます。
- プレイヤーが配置したすべての
GameObject
- 各
GameObjects
の種類と状態(この例では、トランスフォームと色)。
このデータは、次回プレイヤーが同じ ARLocation
をトラッキングする際に取得できるように、文字列またはバイナリブロブに圧縮されます。
データをデシリアライズし、シーンを再構築する:
- シリアライズされたデータから各
GameObject
を取得してインスタンス化します。- 各
GameObject
は、同じルートトランスフォーム(ARLocation
)の下に配置され、同じの場所に表示されます。
- 各
- 各
GameObject
のステートデータ(トランスフォーム、色など)を適用します。
サンプルシーン「VpsSceneSerialization」が提供されており、この入門ガイドのスクリプトに沿って進めることができます。
シリアライズ用のプレハブを登録する
まずはじめに、プレイヤーが配置可能なすべてのプレハブのリストを収集することが重要です。 これは 将来、現場を再現するために必要なことである。
スクリプト PersistentObject.cs
では、 GetComponent
を使用してスポーン可能なプレハブを見つけ、各プレハブに PrefabId
を割り当てて識別します。
クリックしてPersistentObjectクラスを展開
using UnityEngine;
public class PersistentObject : MonoBehaviour
{
[SerializeField]
private long _prefabId;
public long PrefabId
{
get { return _prefabId; }
internal set
{
_prefabId = value;
}.
}
...// シリアライズコード
}.
「VpsSceneSerialization」サンプルでは、キューブと球体の2つの PersistentObject
プレハブがあり、それぞれに PrefabId
0と1が割り当てられています。 その後、これらの PersistentObjects
は、スポーン可能なオブジェクトの完全なリストを作成するために PersistentObjectManager
に登録されます。

クリックしてPersistentObjectManagerクラスを展開
using System.Collections.Generic;
using System.Collections.ObjectModel;
public class PersistentObjectManager : MonoBehaviour
{
[SerializeField]
private List<PersistentObject> _persistentObjects = new List<PersistentObject>();
public ReadOnlyCollection<PersistentObject> PersistentObjects => _persistentObjects.AsReadOnly();
...// シリアライズおよび検証コード
}.
ランタイム・コンテンツの配置
「VpsSceneSerialization」サンプルには、 PersistentContentDemoManager.cs
と PersistentObjectPlacementBehaviour.cs
の2つのスクリプトが含まれています。 これらのスクリプトでは、プレイヤーが平面や既存の GameObject
をタップするたびに、 Cube
や Sphere
のスポーンと破壊を管理します。 各ゲームにはオブジェクトのスポーンや破壊に関する独自のルールがあるため、この入門ガイドではこれらのスクリプトの詳細については説明しません。
次のコード行は重要な点を実装しています。生成されたすべてのオブジェクトは、インスタンス化後に必ず ARLocation
の子オブジェクトにしなければなりません。 独自のアプリケーションを作成する際には、必ずこの点を守ってください。
// _rootは、現在追跡されているARLocationへの参照
spawned.transform.SetParent(_root.transform, true);
生成オブジェクトのシリアライズと保存
プレイヤーがシーンを構築し、それをシリアライズして保存する準備ができたら、まずスポーンされたすべての GameObject
のリストを作成する必要があります。 これを行う方法はいくつかあり、各 GameObject
を List
に保持する方法や、このサンプルで用いられているように、ルート GameObject
に対して GetComponent<PersistentObject>
を使用する方法が考えられます。
クリックして、更新後のPersistentObjectManagerスクリプトを表示
public class PersistentObjectManager : MonoBehaviour
{
[SerializeField]
private List<PersistentObject> _persistentObjects = new List<PersistentObject>();
private const char Delimiter = ';';
private readonly Dictionary<long, PersistentObject> _validObjects =
new Dictionary<long, PersistentObject>();
public string SerializeObjectsToString(GameObject rootGo = null)
{
var root = rootGo ? rootGo.transform : this.transform;
var serializedObjects = new List<string>();
ValidateAndRefreshPersistentObjectList();
foreach (var child in root)
{
var persistentObject = ((Transform)child).GetComponent<PersistentObject>();
if (persistentObject)
{
if (!_validObjects.Keys.ToList().Contains(persistentObject.PrefabId))
{
continue;
}
serializedObjects.Add(persistentObject.SerializeObjectToString());
}.
}
return string.Join(Delimiter, serializedObjects.ToArray());
}.
...// デシリアライズと検証コード
} ...
簡潔さを重視して、このサンプルでは、すべてのプレハブが同じルートの子であり、入れ子になったプレハブがないことを前提としています。 実際のアプリケーションでは、Hierarchy内でのプレハブのトラッキングと処理がさらに高度になる場合があります。
PersistentObjects
の List
を収集した後、各 PersistentObject
は自分自身のシリアライズを文字列に変換します。 その後、これらの文字列は一つの文字列に結合され、保存されます。
クリックして、更新後のPersistentObjectスクリプトを表示
public class PersistentObject : MonoBehaviour
{
[SerializeField]
private long _prefabId;
public long PrefabId
{
get { return _prefabId; }
internal set
{
_prefabId = value;
}
}
public virtual string SerializeObjectToString()
{
return SimpleObjectToString();
}
protected string SimpleObjectToString()
{
var stringFormat = $"PrefabId: {_prefabId}, Position: {SerializeVector3(transform.localPosition)}, " +
$"Rotation: {SerializeQuaternion(transform.localRotation)}, Scale: {SerializeVector3(transform.localScale)}";
return stringFormat;
}
private string SerializeVector3(Vector3 vector)
{
return string.Format("{0},{1},{2}", vector.x, vector.y, vector.z);
}
private string SerializeQuaternion(Quaternion quat)
{
return string.Format("{0},{1},{2},{3}", quat.x, quat.y, quat.z, quat.w);
}
... // デシリアライズコード
}
シリアライズを行うと、将来的にシーンを再構築するために必要な情報を含む文字列が返ります。 この例では、次のような文字列になります。
PrefabId: 0, Position: 0,0,0, Rotation: 0,-0.2323422,0,0.9726341, Scale: 1,1,1; PrefabId: 1, Position: 0,0,-1.689, Rotation: 0,0,0,1, Scale: 1,1,1
シリアライズされた文字列は、将来の取得に備えてバックエン ドやサービスに保存することができます。 このサンプルでは、文字列はローカルに PlayerPrefs
に保存され、 ARLocation
アンカーの名前でインデックスが付けられています。
// コンテンツをシリアライズして格納する
var serializedString = PersistentObjectManager.SerializeObjectsToString(_root);
// _locationStringはpersistentAnchor.nameだけ
PlayerPrefs.SetString(_locationString, serializedString);
より多くの状態を格納するためのPersistentObjectの拡張
「VpsSceneSerialization」サンプルでは、キューブと球体は基本の PersistentObject
ではなく、 ColorfulPersistentObjects
です。 ここでは、基本的なトランスフォームに加えて、さらにカスタムのステートデータをシリアライズする方法を示すために、基本クラスを拡張しています。
クリックしてColorfulPersistentObjectクラスを表示
using UnityEngine;
public class ColorfulPersistentObject : PersistentObject
{
public override string SerializeObjectToString()
{
Color color;
if (!Application.isPlaying)
{
// マテリアルを漏らさないためには、編集モードでsharedMaterialを使用する必要があります。
// これは、マテリアル(デフォルト)を共有するすべてのゲームオブジェクトが同じ色を持つことを意味します
color = GetComponent<Renderer>().sharedMaterial.color;
}
else
{
color = GetComponent<Renderer>().material.color;
}
var colorStr = SerializeColor(color);
return $"{base.SerializeObjectToString()}, Color: {colorStr}";
}
private string SerializeColor(Color color)
{
return $"{color.r},{color.g},{color.b},{color.a}";
}.
...// デシリアライズコード
}.