重要: UNet は非推奨のソリューションになり、現在、新しい Multiplayer とネットワーキングソリューション (Netcode for GameObjects) が開発中です。詳細は、GameObjects Web サイトの Unity Netcode を参照してください。 |
DownloadHandlers
にはさまざまなタイプがあります。
DownloadHandlerBuffer
は簡易なデータストレージとして使用されます。DownloadHandlerFile
は少ないメモリフットプリントでファイルをダウンロードし、ディスクに保存するために使用されます。DownloadHandlerTexture
は画像をダウンロードするために使用されます。DownloadHandlerAssetBundle
はアセットバンドルをフェッチするために使用されます。DownloadHandlerTexture
はオーディオ ファイルをダウンロードするために使用されます。DownloadHandlerMovieTexture
はビデオファイルのダウンロードに使用されます。 MovieTexture (ムービーテクスチャ) は非推奨であるため、ビデオのダウンロードとムービーの再生には VideoPlayer を使用することをお勧めします。DownloadHandlerScript
は特殊クラスです。それ自体では何も行いません。ただし、このクラスはユーザー定義のクラスによって継承が可能です。 このクラスは UnityWebRequest システムからコールバックを受け取り、ネットワークからデータを取得したときに完全にカスタム処理するために使用します。API は DownloadHandlerTexture
のインターフェースに似ています。
UnityWebRequest
には disposeDownloadHandlerOnDispose
というプロパティがあります。このデフォルトは true です。このプロパティが true の場合、UnityWebRequest オブジェクトが破棄されると、添付されたダウンロードハンドラーで Dispose() も呼び出され、レンダリングを無効にします。ダウンロードハンドラーへの参照を UnityWebRequest への参照より長く保持している場合は、disposeDownloadHandlerOnDispose を false に設定する必要があります。
このダウンロードハンドラーは最も簡単で、たいていのケースを処理できます。このハンドラーは受け取ったデータをネイティブコードバッファーに格納します。ダウンロードが終了すると、バイト配列またはテキスト文字列で、バッファーされたデータにアクセスできます。
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetText());
}
IEnumerator GetText() {
UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
Debug.Log(www.error);
}
else {
// 結果をテキストで表示
Debug.Log(www.downloadHandler.text);
// または、結果をバイナリデータで取得
byte[] results = www.downloadHandler.data;
}
}
}
これは大きなファイル用の特別なダウンロードハンドラです。ダウンロードされたバイトを直接ファイルに書き込むので、ダウンロードするファイルのサイズに関係なくメモリの使用量は少なくなります。他のダウンロードハンドラとの違いは、このデータは取り出すことができず、すべてのデータはファイルに保存されます。
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class FileDownloader : MonoBehaviour {
void Start () {
StartCoroutine(DownloadFile());
}
IEnumerator DownloadFile() {
var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
uwr.downloadHandler = new DownloadHandlerFile(path);
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
Debug.LogError(uwr.error);
else
Debug.Log("File successfully downloaded and saved to " + path);
}
}
DownloadHandlerBuffer
を使用して画像ファイルをダウンロードし、それから Texture.LoadImage
を使用して生のバイトからテクスチャを作成する代わりに、DownloadHandlerTexture
を使用する方が効率的です。
このダウンロードハンドラーは、受信したデータを UnityEngine.Texture
に格納します。ダウンロードが完了すると、JPEG と PNG を有効な UnityEngine.Texture
オブジェクトにデコードします。各 DownloadHandlerTexture
オブジェクトごとに 1 つのUnityEngine.Texture
だけしか作成されません。ですから、ガベージコレクションによるパフォーマンスの低下を軽減します。ハンドラーは、バッファリング、解凍、テクスチャの作成をネイティブコードで実行します。さらに、解凍とテクスチャの作成を、メインスレッドでなくワーカースレッドで実行するため、大きなテクスチャを読み込むときにフレーム時間を向上させます。
最後に、DownloadHandlerTexture
は、最終的にテクスチャ自体を作成するときにのみマネージドのメモリを割り当てます。このため、スクリプトでバイトからテクスチャへの変換を実行する際のガベージコレクションのオーバーヘッドを排除します。
以下の例では、PNG ファイルをインターネットからダウンロードし、スプライトに変換し、画像 に割り当てます。
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;
[RequireComponent(typeof(Image))]
public class ImageDownloader : MonoBehaviour {
Image _img;
void Start () {
_img = GetComponent<UnityEngine.UI.Image>();
Download("https://www.mysite.com/myimage.png");
}
public void Download(string url) {
StartCoroutine(LoadFromWeb(url));
}
IEnumerator LoadFromWeb(string url)
{
UnityWebRequest wr = new UnityWebRequest(url);
DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);
wr.downloadHandler = texDl;
yield return wr.SendWebRequest();
if (wr.result == UnityWebRequest.Result.Success) {
Texture2D t = texDl.texture;
Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
Vector2.zero, 1f);
_img.sprite = s;
}
}
}
この特化したダウンロードハンドラーの利点は、Unity のアセットバンドルシステムにデータをストリーミングできることです。アセットバンドルシステムが十分なデータを受け取ると、アセットバンドルはUnityEngine.AssetBundle
オブジェクトとして利用できます。UnityEngine.AssetBundle
オブジェクトのコピーは 1 つだけ作成されます。これにより、ランタイムメモリの割り当てと、アセットバンドルの読み込みによるメモリへの影響が大幅に軽減されます。また、完全にダウンロードされていないときにアセットバンドルを部分的に使用することができます。ですから、アセットをストリーミングすることができます。
すべてのダウンロードと解凍はワーカースレッドで行われます。
アセットバンドルは、DownloadHandlerAssetBundle
オブジェクトをとおしてダウンロードされます。このオブジェクトには、アセットバンドルを取得する特別な assetBundle
プロパティがあります。
アセットバンドルシステムの仕組みにより、すべてのアセットバンドルには関連付けられたアドレスが必要です。一般的には、これはアセットバンドルが位置する名目上の URL (リダイレクト前のURL ) です。ほとんどの場合、UnityWebRequest に渡したのと同じ URL を渡す必要があります。高レベル API (HLAPI) を使用する場合、これは本人の判断で行ってください。
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class MyBehaviour : MonoBehaviour {
void Start() {
StartCoroutine(GetAssetBundle());
}
IEnumerator GetAssetBundle() {
UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);
www.downloadHandler = handler;
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
Debug.Log(www.error);
}
else {
// AssetBundle を取得
AssetBundle bundle = handler.assetBundle;
}
}
}
このダウンロードハンドラーは、オーディオファイルをダウンロードするために最適化されています。 DownloadHandlerBuffer
を使用して生のバイトをダウンロードしてから AudioClip
を作成する代わりに、このダウンロードハンドラーを使用してより便利に処理できます。
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class AudioDownloader : MonoBehaviour {
void Start () {
StartCoroutine(GetAudioClip());
}
IEnumerator GetAudioClip() {
using (var uwr = UnityWebRequestMultimedia.GetAudioClip("https://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success) {
Debug.LogError(uwr.error);
yield break;
}
AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
// オーディオクリップを使用
}
}
}
ダウンロードしたデータの処理を完全に制御する必要があるユーザのために、Unity はDownloadHandlerScript
クラスを提供します。
デフォルトでは、このクラスのインスタンスは何も行いません。ただし、DownloadHandlerScript
から独自のクラスを派生させる場合、特定の関数をオーバーライドして、ネットワークからデータが到着するときコールバックを受け取るためにその関数を使用します。
注意 実際のダウンロードはワーカースレッド上で行われますが、すべての DownloadHandlerScript
コールバックはメインスレッド上で動作します。 これらのコールバック中に負荷の高い計算操作を行なわないでください。
protected void ReceiveContentLength(long contentLength);
この関数は、Content Length ヘッダーが受信されたときに呼び出されます。UnityWebRequest の処理中にサーバーが 1つ以上のリダイレクト応答を送信すると、このコールバックは複数回発生することがあります。
protected void OnContentComplete();
この関数は UnityWebRequest がサーバーからすべてのデータを完全にダウンロードし、それを ReceiveData コールバックに転送したときに呼び出されます。
protected bool ReceiveData(byte[] data, long dataLength);
この関数は、リモートサーバーからデータを受領した後に、フレームごとに 1 回呼び出されます。 data
引数には、リモートサーバーから受信した生のバイトが含まれます。また、 dataLength
はデータ配列内の新しいデータの長さを示します。
事前に割り当てられたデータバッファを使用しない場合、システムはこのコールバックを呼び出すたびに新しいバイト配列を作成し、dataLength
は常に data.Length
と等しくなります。 事前に割り当てられたデータバッファを使用する場合は、データバッファが再利用され、更新されたバイト数を見つけるために dataLength
を使用する必要があります。
この関数には、true または false のいずれかの戻り値が必要です。false を返すと、システムは直ちに UnityWebRequest を中止します。true を返すと、処理は正常に続行されます。
もっと上級レベルの Unity ユーザーの多くは、ガベージコレクションのために CPU スパイクを減らすことを気にかけています。これらのユーザのために、UnityWebRequest システムは、ダウンロードされたデータを DownloadHandlerScript のReceiveData
コールバックに配信するために使用されるマネージドのコードのバイト配列の事前割り当てを許可します。
この関数を使用すると、DownloadHandlerScript 派生クラスを使用してダウンロードしたデータを取得するときに、マネージドのコードのメモリ割り当てを完全に排除します。
DownloadHandlerScript
をあらかじめ割り当てられたマネージバッファで動作させるには、バイト配列を DownloadHandlerScript
のコンストラクタに渡します。
注意 バイト配列のサイズは、各フレームで ReceiveData コールバックに渡されるデータ量を制限します。データがゆっくりと、多くのフレームにわたって到着した場合、バイト配列が小さすぎる可能性があります。
using UnityEngine;
using UnityEngine.Networking;
public class LoggingDownloadHandler : DownloadHandlerScript {
// 標準のスクリプトされたダウンロードハンドラー。各 ReceiveData コールバックにメモリを割り当てます。
public LoggingDownloadHandler(): base() {
}
// 事前に割り当てられたスクリプトされたダウンロードハンドラーは、
//提供されたバイト配列を再利用してデータを配信します。
//メモリ割り当てを排除します。
public LoggingDownloadHandler(byte[] buffer): base(buffer) {
}
// DownloadHandler 基本クラスに必須。 'bytes' プロパティを示すときに呼び出されます。
protected override byte[] GetData() { return null; }
// ネットワークからデータを受信すると、フレームごとに 1 回呼び出されます。
protected override bool ReceiveData(byte[] data, int dataLength) {
if(data == null || data.Length < 1) {
Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");
return false;
}
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));
return true;
}
// すべてのデータがサーバーから受信され、ReceiveData を介して配信されるときに呼び出されます。
protected override void CompleteContent() {
Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
}
// Content-Length ヘッダーをサーバーから受信したときに呼び出されます。
protected override void ReceiveContentLengthHeader(ulong contentLength) {
Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
}
}