423 Views
June 06, 17
スライド概要
講演者:大前 広樹(ユニティ・テクノロジーズ・ジャパン合同会社)
こんな人におすすめ
・アセットバンドルを使用するゲームの開発に関わっているプログラマーの方
・Unityで動的なコンテンツ配信を実現したいプログラマーの方
・アセットを使用するエディター拡張等を開発しているプログラマーの方
受講者が得られる知見
・アセットバンドルのツールやAPIが今後どう変化していくか
現在のアセットバンドルの課題がどう解決されていくか
新しいアセットバンドルの環境下で何をUnityが解決し、何をコンテンツ開発者が解決すべき問題となるか
講演動画:https://youtu.be/Aenne9hh2Mw
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
⥋ꂁخٝذٝ؝ז⹛涸ח孡鯪ה فحوس涪ٗ٦ה劢勻ךٕسٝغزحإ،
)JSPLJ0NBF 3FHJPOBM%JSFDUPS 6OJUZ
8"3/*/( "%7"/$&%4&44*0/ ")&"%
ַךז⡦佦"%7"/$&% גְ耀ّٝءحإךֿ ׇתזכחֲ״ַⴓָ⢪ְ倯ךٕسٝغزحإ، (陨デ8"3/*/(陨デ8"3/*/
湡涸ךّٝءحإךֿ պהֲֿג濼չ植朐 պהֿׅח㺁僒⪒㼎䘔彊חֹהֿչ㢌⻉ָ饯 պהֲֿג׃⸇חչ涪 (陨デ8"3/*/(陨デ8"3/*/
կׅת㢳ֻろⰻ㺁ך⚥涪כّٝءحإ הְֲⰻ㺁הպד׃חչְֲֲֿ괏 ְֲָⰻ㺁הպדװאׅחչְֲֲֿ괏 կׅתְגת⚕倯ろ (陨デ8"3/*/(陨デ8"3/*/
א ד׃
כחⴓ鿇ךպאչח暴 ׅתְג実ؙحغس٦؍ؿךֻׁךַׁ涺 ְֻׁ⸂⼿׀ח涪מ (陨デ8"3/*/(陨デ8"3/*/
問題を解決するときはいつも、もっとも抵抗の少 ない道を選んで行けばたやすく解決しそうに見え る。 しかして、その易しそうな道こそが最も過酷 で残酷なものに変質するのだ… -Winston Churchill
כהٕسٝغزحإ،
כהٕسٝغزحإ، ךזֲ״ך [JQشذٝ؝ׅ呓秛زؙؑآـؔ • ׁؔؤ؎ٓٔ،ءדي؎ة⥂䭯ծٓٝ䞔㜠ך嫣يؓ٦ؿزحٓف • زؙؑآـ ָ⳿勻הֿא䭯⤘⣛㶷ꟼךٕسٝغ • ; ꬊ㖇簭ծ-;."ծ-ָّ֮ٝءفؔך• 㖇簭 ָ֮珏겲ךאך⟃㢩ה˒٦ٝ欽ء• ˑ س؎ׅؖꟼחأ٦أהٕسٝغزحإ䗳铣،
⢪ְ麣 ֻׁׅ㼭ؤ؎؟ٕ٦زأ؎ٝךٔف، ׅ刿倜ח媮ꥡ涸أٖي٦ءخٝذٝ؝ךٔف، ׅ盖椚ח⿑㺘הًٌٔךي؎ةٓ؎ٝ ׅ䲿⣘زحإ،׃⻉剑黝חؙحلأךأ؎غر ֻׅ鸞ّٝءٖ٦ذ؎ծג׃何㊣儗سٕؽךٔف، • • • • •
˘ה鋅ג⢪ח㹋ꥷ
Unityプロジェクト 開発初週 - 直接参照
public class spawnCarFromDirectReference : MonoBehaviour
{
public GameObject carPrefab;
void Start ()
{
if(carPrefab != null)
GameObject.Instantiate(carPrefab, this.transform, false);
}
}
Unityプロジェクト,開発2週目 - Resources.Load
public class spawnCarFromResources : MonoBehaviour
{
public string carName;
void Start ()
{
var go = Resources.Load<GameObject>(carName);
if(go != null)
GameObject.Instantiate(go, this.transform, false);
}
}
Unityプロジェクト,開発3週目 - Resources.LoadAsync
public class spawnCarFromResourcesAsync : MonoBehaviour
{
public string carName;
IEnumerator Start ()
{
var req = Resources.LoadAsync(carName);
yield return req;
if(req.asset != null)
GameObject.Instantiate(req.asset, this.transform, false);
}
}
そして3ヶ月の時が流れた ... ַַָֺׅ儗ח⹛饯ךي٦ ְזⵖ䖴⳿勻גְגְֺׅ⢪ًٌٔח˘㹋遤儗 ˘ֲ״׃חٕسٝغزحإծ،ֲ
Resourcesからアセットバンドルへの変更
׆תծ،غزحإٕٝؽךٕس
زفؙٔأس剅ֻ
public class MyBuildProcess
{
...
[MenuItem("Build/Build Asset Bundles")]
public static void BuildAssetBundles()
{
var outputPath = bundleBuildPath;
if(!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
var manifest = BuildPipeline.BuildAssetBundles(outputPath,
BuildAssetBundleOptions.ChunkBasedCompression,
EditorUserBuildSettings.activeBuildTarget);
var bundlesToCopy = new List<string>(manifest.GetAllAssetBundles());
// Copy the manifest file
bundlesToCopy.Add(EditorUserBuildSettings.activeBuildTarget.ToString());
CopyBundlesToStreamingAssets(bundlesToCopy);
}
...
}
Resourcesからアセットバンドルへの変更
ג׃٦؝ךي٦س
⥜姻ג׃،غزحإٝ
ٕٗس٦חֲ״ׅس
剅ֹ䳔ְִֻג
public class spawnCarFromBuiltinAssetBundle : MonoBehaviour
{
public string carName;
public string carBundleName;
IEnumerator Start ()
{
if(!string.IsNullOrEmpty(carBundleName))
{
var bundleReq = AssetBundle.LoadFromFileAsync(carBundleName);
yield return bundleReq;
var bundle = bundleReq.assetBundle;
if( bundle != null)
{
var assetReq = bundle.LoadAssetAsync(carName);
yield return assetReq;
if(assetReq.asset != null)
GameObject.Instantiate(assetReq.asset, this.transform,
false);
}
}
}
}
そして3ヶ月後 ... ،؎ךٔفٝزأ٦ٕ㺁ꆀָ㣐ֹֺׅ ؐتٝٗ٦؝سٝذٝךخ㼎䘔ָ䗳銲זח
Asset BundlesをCDNからロードするよう書き換え
8FCַٗ٦חֲ״ׅس
剅ֹ䳔ִ䩛כ㼰˘ְז
public class spawnCarFromRemoteAssetBundle : MonoBehaviour
{
public string carName;
public string carBundleName;
public string remoteUrl;
IEnumerator Start ()
{
var bundleUrl = Path.Combine(remoteUrl, carBundleName);
var webReq = UnityWebRequest.GetAssetBundle(bundleUrl);
var handler = webReq.downloadHandler as DownloadHandlerAssetBundle;
yield return webReq.Send();
var bundle = handler.assetBundle;
if(bundle != null)
{
var prefab = bundle.LoadAsset<GameObject>(carName);
if(prefab != null)
GameObject.Instantiate(prefab, this.transform, false);
}
}
}
Loading Asset Bundles from CDN
˘ה䙼וֽ麩
،غزحإٕٝسכח⣛㶷
ꟼ⤘ָ֮
public class spawnCarFromRemoteAssetBundle : MonoBehaviour
{
public string carName;
public string carBundleName;
public string remoteUrl;
ゃ
ド
じ
IEnumerator Start ()
{
var bundleUrl = Path.Combine(remoteUrl, carBundleName);
var webReq = UnityWebRequest.GetAssetBundle(bundleUrl);
var handler = webReq.downloadHandler as DownloadHandlerAssetBundle;
yield return webReq.Send();
ー
コ
な !
ん !
こ 理
無
var bundle = handler.assetBundle;
if(bundle != null)
{
var prefab = bundle.LoadAsset<GameObject>(carName);
if(prefab != null)
GameObject.Instantiate(prefab, this.transform, false);
}
}
}
ֻ剅גלָ
public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour
{
// Simple class to handle loading asset bundles via UnityWebRequest
public class AssetBundleLoader
{
string uri;
string bundleName;
public AssetBundle assetBundle
{
get; private set;
}
public static AssetBundleLoader Factory(string uri, string bundleName)
{
return new AssetBundleLoader(uri, bundleName);
}
yield return manifestLoader.Load();
var manifestBundle = manifestLoader.assetBundle;
// Bail out if we can't load the manifest
if(manifestBundle == null)
{
Debug.LogWarning("Could not load asset bundle manifest.");
yield break;
}
var op =
manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
yield return op;
var manifest = op.asset as AssetBundleManifest;
var deps = manifest.GetAllDependencies(carBundleName);
foreach(var dep in deps)
{
Debug.LogFormat("Loading asset bundle dependency {0}", dep);
var loader = AssetBundleLoader.Factory(remoteUrl, dep);
yield return loader.Load();
}
private AssetBundleLoader(string uri, string bundleName)
{
this.uri = uri;
this.bundleName = bundleName;
}
public IEnumerator Load()
{
var bundleUrl = Path.Combine(this.uri, this.bundleName);
var webReq = UnityWebRequest.GetAssetBundle(bundleUrl);
var handler = webReq.downloadHandler as
DownloadHandlerAssetBundle;
yield return webReq.Send();
var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName);
yield return carLoader.Load();
if(carLoader.assetBundle != null)
{
op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName);
yield return op;
assetBundle = handler.assetBundle;
}
var prefab = op.asset as GameObject;
}
public
public
public
public
string
string
string
string
carName;
carBundleName;
manifestName;
remoteUrl;
IEnumerator Start ()
{
var manifestLoader = AssetBundleLoader.Factory(remoteUrl,
bundleManifestName);
if(prefab != null)
GameObject.Instantiate(prefab, this.transform, false);
}
}
}
さらに求められる、アセットバンドルに必要な配慮: • 一番効率的にアセットをバンドルに含める方法 • バンドル内のアセット重複回避 • バンドルに含まれているアセットの管理・確認 • バンドルのロードのメモリ管理
ךٕسٝغزحإ، ㉏겗挿
ٕسٝغزحإְ،غָֿֿَ ְկזַַך椚鍑⳿勻לֲ铣וְկ⡦غָَزًُٝؗس • חהֿׅٕ㼎䘔سٝغزحإ،ד穠卓ծꨜ㔲孡 ⵃ欽ח㹋ꥷדّٝءؙتٗفٕسٝغزحإկ،ֺׅٕكٖ• "1*ָ⡚ ְזזלֽזַ剅ֻׁس٦؝ָծ涪罏כחׅ ز٦رفح،הٔ٦غٔرךخٝذٝ؝ח暴 ז䗳銲חⵖ䖴ךسٗ٦ן״ֶُءحٍؗծسٕؽկֺׅٕكٖ• "1*ָ넝 ְկזָ磛䏝זⴓ⼧ ٦خ٦٥ة؍رؒז䗳銲חךٕسٝغزحإְկ،غָَ• 涪橆㞮 ְկזָٕ
T ٕ竲ֹسٝغزحإְ،غָֿֿَ ָⳢ椚儗ךسٗ٦ג״חيؓ٦ؿزحٓفְկغָَأٝوؓ٦ؿػ • Ⰻ搫麩ֲկ ְկז甧ח䕵דّٝءؙتٗفךְկ㹋ꥷغָَ• 7BSJBOU הֿךָ"TTFU#VOEMFسٕؽךٔفְկ،غְָَ堣腉זִ⢪ח• ♧筰 ַאָ鋅أؙٓז䗳銲ח儗سٗ٦גְ⸬ָ$PEF4USJQQJOHדךְזג鋅 ׅזֻז זזח罋דךְָ⡚؍ذؙٔؔךٕفٝ؟ְկغָَس٦؝ٕفٝ؟ • կֺׅ黝䔲أٝشذַًٝ׃ծ׃ְ ٥٥٥כ㉏겗ך剑㣐ג׃ַ׃ •
ˑ6OJUZ״ծぢֹさֲך ،غزحإٝכٕس剑ⴱַ⡦ַ ָ麩ְ˒˘חהְֲֿה ˑ-FUˏTGBDFJUVOJUZˊXIPMFBTTFUCVOEMFTUIJOHXBTNJTUBLFGSPNUIFCFHJOOJOH˒ - heszkeWmeszke
պֲ㣐♱㣗ָ勻ٖؔ˘זׇչ䖉
⚺滙挿ךي٦ثٕسٝغزحإ، ⥜姻ؚغה鍑寸ך⫈䪮遭涸頾 䲿⣘ךٕ٦خ٦ة؍رؒ ٕ٦م٦غؔ٦ך*ٓ؎ٝ"1ف؎ػسٕؽٕسٝغزحإ، 何㊣ך*"1ي؎ةٓٝךس،ٝٗ٦سٗ٦ 何㊣ך*ُ"1ءحٍؗ ⪒侭ךزًُٝؗس 䲿⣘ךزؙؑآٗفٕفٝ؟זח罋ד㹋 • • • • • • •
涪椚䙀ؔ٦فٝا٦דأ涪ׅ • (JUIVC#JUCVDLFUד鷲僇䚍֮ך涪ׅ • 鸞ְة٦ٝ،ٓؐٝس • 㢳ֻג㼭ְׁ،رفح٦ز • ؙٕٔف٥هؚٖغ٦חز㼎ׅ琎噰涸هأٖזٝأ
زأ؋٦ؿ涪椚䙀Ύ곁㹏 ُ٦ؽة䞔㜠❛䳔ծ؎ٝךֻ㢳הה• 涪罏 ⠓鑧ז琎噰涸ךדيٓؓ٦ؿ • ְֻגأ؎غس،ח琎噰涸חٓٝ涪罏麦ذكך⠓爡ي٦ • س٦نٔ٦ؠ؎غس،
䎃ך崞⹛ • • • • • 곁㹏؎ךפُٝؽة٦ծ㉏겗挿ך涪鋅ה侭椚 ㉏겗挿ך䱍䳢 ⥜ؚغ姻 ؎ٓف؎ػسٕؽٝ"1*ؔך٦غ٦م٦ٕ QSFWJFX ؒة؍ر٦خ٦ٕ䲿⣘ • "TTFU#VOEMFT#SPXTFS QSFWJFX • "TTFU#VOMEF(SBQI5PPM CFUB ד׃
䎃ך崞⹛ ًُؗسٝךز何㊣ "TTFU#VOEMF(SBQI5PPMٔٔ٦أ "TTFU#VOEMFT#SPXTFSٔٔ٦أ ꅾ銲⥜ؚغז姻 • TIBEFSWBSJBOUT㉏겗ך鍑寸BOEهؙحغח٦ ز • "TTFU#VOEMF.BOJGFTUَ؎ٖف٦חسٕؽ䭷㹀〳腉ח • ؓؿػ٦وٝأ何㊣ • %95ٍثأؙذ㖇簭鸞䏝ך何㊣ • ،غزحإٝٗךٕس٦س儗ך何㊣ • • • • ד׃
䎃2 • • • • • • • ؎ٓف؎ػسٕؽٝ"1*ؔך٦غ٦م٦ٕ CFUB 倜"ُءحٍؗ1* CFUB "TTFU#VOEMFT#SPXTFS CFUB "TTFU#VOEMF(SBQI5PPM 㸣✪ًٝشذٝأW ٗ٦ؓؿػس٦وٝךأ何㊣ Ⰻؓؿزحٓف٦ي㼎韋 "OESPJEַؓؿ٦ؕ أ ًُؗسٝךز何㊣㔐湡 ٓٝي؎ة欽넝ٖ"ٕك1*ך㹋鄲 • ٗٔزحم٦س • "EESFTTBCMF"TTFUT • 撑ؕؐٝز荈⹛ٗ٦س • ُٖىء٦ّءٌٝ٦س ד׃ א
䎃2։ 獳遤חأٝشذ٦ٕ 㸣✪ًٝم٦غؔ٦ךٓ؎ٝف؎ػسٕؽ 獳遤חأٝشذ"TTFU#VOEMFT#SPXTFS 㸣✪ًٝ ✪㸣ך⪒侭زًُٝؗس *"1ي؎ةְٓٝ׃倜 سٔٗ٦زحمהزٗ؎ًٝفرז넝鸞 QSFWJFXزؙؑآٗفٕفٝ؟ְ׃倜 ٦ QSFWJFXغ٦؟ؚٝ؍ذأمٕ欽سٝغزحإ، 何㊣ QSFWJFXך䕎䒭شذٝ؝ךٕسٝغزحإ، א • • • • • • • •
倜سٕؽ欽"1* Unity 2017.1b (experimental) UnityEditor.Experimental.Build.AssetBundle https://github.com/Unity-Technologies/AssetBundles-BuildPipeline ד׃
Bundle Build Pipeline Overhaul Sneak Peak ؎ٓف؎ػسٕؽٝؔך٦غ٦م٦ٕ public static AssetBundleBuildInput GenerateAssetBundleBuildInput( AssetBundleBuildSettings settings) { … } public struct AssetBundleBuildInput { public struct Definition { public string name; public string variant; public GUID[] assets; } * Input generated from asset importer meta Ⰵ⸂ח⢪ֲر٦ة圓鸡"TTFU#VOEMF#VJME*OQVUכ data or any other source (external tools, etc.) خ٦ٕדزفؙٔأװ⡲䧭կ⡦ד⡲ג葺ְկ public AssetBundleBuildSettings settings; public Definition[] bundles; }
Bundle Build Pipeline Overhaul Sneak Peak ؎ٓف؎ػسٕؽٝؔך٦غ٦م٦ٕ public struct AssetBundleBuildCommandSet { public struct Command { public AssetBundleBuildInput.Definition input; public ObjectIdentifier[] objectsToBeWritten; "TTFU#VOEMF#VJME*OQVUַ㹋ꥷך،غزحإٝךٕس } public static AssetBundleBuildCommandSet GenerateAssetBuildCommandSet( AssetBundleBuildInput buildInput) { … } חسٕؽ⢪欽ׁو؝ָٝزحإس⡲կ ֿֿד⣛㶷ꟼ⤘鍑寸ؾحٔزأךزؙؑآـؔװָؚٝ Command set generation gathers all 遤ծⰋָزأٔךزؙؑآـֹؔץׅ⸂⳿ךג⡲ dependencies, handles object stripping, and generates full list of objects to write. public AssetBundleBuildSettings settings; public Command[] commands; }
Bundle Build Pipeline Overhaul Sneak Peak ؎ٓف؎ػسٕؽٝؔך٦غ٦م٦ٕ public static void SaveAssetBundleOutput(AssetBundleBuildOutput output) { … } "TTFU#VOEMF#VJME0VUQVUָ⳿⸂ׁկֿײְכ植㖈ך.BOJGFTUך➿חկ Output can be serialized to JSON or any other 涪罏כ㥨ֹז䕎䒭⢽ִל+40/ַהٔءד،ٓ؎ג׃ؤ⢪ג葺ְկ format as required.
Bundle Build Pipeline Overhaul Sneak Peak ؎ٓف؎ػسٕؽٝؔך٦غ٦م٦ٕ public static void SaveAssetBundleOutput(AssetBundleBuildOutput output) { … } Ⰻ鿇穈さהׇ٥٥٥ Put it all together … // Default build pipeline SaveAssetBundleOutput(ExecuteAssetBuildCommandSet(GenerateAssetBuildComma ndSet(GenerateAssetBundleBuildInput(settings)))); ؎ٓف؎ػسٕؽךزٕؓؿرٝ
倜$BDIF欽"1* Unity 2017.1b ד׃
0ME$BDIF"1* • 888-PBE'SPN$BDIF0S%PXOMPBE • ַُٗءحٍؗ٦ַׅسծؐتלֽזٝٗ٦ُءحٍؗג׃س ⥂ח㶷ׅկ⥂חُءحٍؗ㶷⳿勻ٗלֽז٦ג׃س،غزحإٝ ٕس䰍גկ • $BDIJOH$MFBO$BDIF • ⥂㶷ׁⰋُءحְٍؗג鿇灶唱ׅկⰋ鿇˘Ⰻ鿇 • $BDIJOH*T7FSTJPO$BDIFE • 䭷㹀غך٦ّآְַָٝגׁُءحٍؗ然钠ֽׅ灶 唱כהֹד鎉ְזג
/FX$BIF"1* • ה稢ְַⵖ䖴 • 涺ׁך銲劄ח幐ג鏣鎘
/FX$BIF"1* • • • • • • • • • • "EE$BDIF $MFBS$BDIF $MFBS"MM$BDIFE7FSTJPOT $MFBS0UIFS$BDIFE7FSTJPOT (FU"MM$BDIF1BUIT (FU$BDIF"U (FU$BDIF#Z1BUI (FU$BDIFE7FSTJPOT *T$BDIF7FSTJPOFE .PWF$BDIF"GUFS.PWF$BDIF#FGPSF
/FX$BIF"1* • $BDIFؔزؙؑآـ • 醱侧ُءحٍؗך㜥䨽ָ䭯ג • FYQJSBUJPO%FMBZ荈⹛ꤐךדת儗 • NBYJNVN"WBJMBCMF4UPSBHF4QBDFٖزأ٦חآ⢪ִؤ؎؟ • QBUIأػךפُءحٍؗ • $BDIJOHDVSSFOU$BDIF'PS8SJUJOH • ُءحٍؗ䭷㹀ג׃888-PBE'SPN$BDIF0S%PXOMPBE • ⯓⮚ךُءحٍؗ䏝־♴־♳
*"1ي؎ة倜ٓٝ א
public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour
{
// Simple class to handle loading asset bundles via UnityWebRequest
public class AssetBundleLoader
{
string uri;
string bundleName;
public AssetBundle assetBundle
{
get; private set;
}
public static AssetBundleLoader Factory(string uri, string bundleName)
{
return new AssetBundleLoader(uri, bundleName);
}
yield return manifestLoader.Load();
var manifestBundle = manifestLoader.assetBundle;
// Bail out if we can't load the manifest
if(manifestBundle == null)
{
Debug.LogWarning("Could not load asset bundle manifest.");
yield break;
}
var op =
manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
yield return op;
var manifest = op.asset as AssetBundleManifest;
var deps = manifest.GetAllDependencies(carBundleName);
foreach(var dep in deps)
{
Debug.LogFormat("Loading asset bundle dependency {0}", dep);
var loader = AssetBundleLoader.Factory(remoteUrl, dep);
yield return loader.Load();
}
private AssetBundleLoader(string uri, string bundleName)
{
this.uri = uri;
this.bundleName = bundleName;
}
public IEnumerator Load()
{
var bundleUrl = Path.Combine(this.uri, this.bundleName);
var webReq = UnityWebRequest.GetAssetBundle(bundleUrl);
var handler = webReq.downloadHandler as
DownloadHandlerAssetBundle;
yield return webReq.Send();
var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName);
yield return carLoader.Load();
if(carLoader.assetBundle != null)
{
op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName);
yield return op;
assetBundle = handler.assetBundle;
}
var prefab = op.asset as GameObject;
}
public
public
public
public
string
string
string
string
carName;
carBundleName;
manifestName;
remoteUrl;
IEnumerator Start ()
{
var manifestLoader = AssetBundleLoader.Factory(remoteUrl,
bundleManifestName);
if(prefab != null)
GameObject.Instantiate(prefab, this.transform, false);
}
}
}
public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour
{
// Simple class to handle loading asset bundles via UnityWebRequest
public class AssetBundleLoader
{
string uri;
string bundleName;
public AssetBundle assetBundle
{
get; private set;
}
public static AssetBundleLoader Factory(string uri, string bundleName)
{
return new AssetBundleLoader(uri, bundleName);
}
yield return manifestLoader.Load();
var manifestBundle = manifestLoader.assetBundle;
// Bail out if we can't load the manifest
if(manifestBundle == null)
{
Debug.LogWarning("Could not load asset bundle manifest.");
yield break;
}
var op =
manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
yield return op;
ֿז醱꧟˘ְזָ׆כְְג֮ד
var manifest = op.asset as AssetBundleManifest;
var deps = manifest.GetAllDependencies(carBundleName);
foreach(var dep in deps)
{
Debug.LogFormat("Loading asset bundle dependency {0}", dep);
var loader = AssetBundleLoader.Factory(remoteUrl, dep);
yield return loader.Load();
}
private AssetBundleLoader(string uri, string bundleName)
{
this.uri = uri;
this.bundleName = bundleName;
}
ֲծ䨱
嚂ַ׃涪鹈湡˘ח
public IEnumerator Load()
{
var bundleUrl = Path.Combine(this.uri, this.bundleName);
var webReq = UnityWebRequest.GetAssetBundle(bundleUrl);
var handler = webReq.downloadHandler as
DownloadHandlerAssetBundle;
yield return webReq.Send();
var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName);
yield return carLoader.Load();
if(carLoader.assetBundle != null)
{
op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName);
yield return op;
assetBundle = handler.assetBundle;
}
var prefab = op.asset as GameObject;
}
public
public
public
public
string
string
string
string
carName;
carBundleName;
manifestName;
remoteUrl;
IEnumerator Start ()
{
var manifestLoader = AssetBundleLoader.Factory(remoteUrl,
bundleManifestName);
if(prefab != null)
GameObject.Instantiate(prefab, this.transform, false);
}
}
}
倜ٓٝ"ي؎ة1*ך湡垥ֿءךׁٕٝف笝䭯ׅ
public class spawnCarFromResourcesAsync : MonoBehaviour
{
public string carName;
IEnumerator Start ()
{
var req = Resources.LoadAsync(carName);
yield return req;
if(req.asset != null)
GameObject.Instantiate(req.asset, this.transform, false);
}
}
"EESFTTBCMF"TTFU
ٗ٦ؿؙٙ٦זٕفٝءְ׃倜 ٦وג׃הBEESFTTBCMFزحإְ،׃سٗ٦ג׃鸐أػ سٗ٦ג⢪أٖسծ،כزحإְ،׃سٗ٦ַأٖس، ׅ鏣㹀ַ$%/ׅ⥋ꂁة٦رַֿו سٕؽي٦ ծלָ֮䗳銲ׅفح،ח$%/ٕسٝغزحإ، سٗ٦فح،ח$%/ ⢪ֲ㜥さٕسٝغزحإָծ،س٦؝ׄず״ח*ずׄ"1דת➙ • ֻ⹛חֲ״ׄずְ㜥さז⢪ • • • • • א
椚䙀הٕ٦؞ ׁؚٝؗحػחٕسٝغزحإ،כخٝذٝ؝ךגץׅ • أػسٗ٦ך♧⽃ 遤ח鷲麓涸כسٗ٦ךַٕسٝغزحإ• ، ְז׃䠐陎ٕسٝغزحإ،כ涪罏 鎘חֹⰋ鿇葺גֻז׃חזָ涪罏כأإٗفسٕؽך• 鸐䌢 ֹדؤ؎وةأؕגⰋכ㜥さծ涪罏זٗ٦ָٕ䗳銲زٝ؝ • 麣זָ剑黝ְֿ麣ז㼰ך䫺䫑• 剑 א
أٖس،ךزحإ، 鏣㹀⳿勻ד鿪さך涪罏أٖس،ך• ⟣䠐 竰䪫أػٕ؎؋ؿך♴⟃"TTFUTכְ㜥さז׃• 鏣㹀 א
أٝ؛٦ءךسٗ٦ ך幥سٗ٦ג׃ח٦ؗأٖس،ךزحإ✓ 6OJUZָ، ׅ䱱أٝةأ؎ٝ ֲַׅ鍑寸וأٖسծ،לֽזָأٝةأ؎ٝך幥س✓ ٗ٦ ׇ㉏ְさחؙحغٕ٦؝ ַ瘝ךזַծ$%/ךזٕؕ㜥䨽 ٗ٦سٗ٦ךָ㹋ꥷؙحغٕ٦؝ ✓ ׅ鵤ח6OJUZ 竲遤سٗ٦ג䖞ח㜥䨽ך㹋ꥷָ✓ 6OJUZ א
ׅדךך⚥涪כ歗
زحإ، ؚٝ؍رٔٗ٦زحم א ד׃
★ #VJME3VO؝כٝذٝخろسٕؽ׆ ★ 6OJUZ&EJUPSָؔٝورٝ؝דسٝذٝخ䲿⣘
ׅ㢌刿آ؎ً٦سؙؚٓؐٝحغד٦ة؍رؒ ˘䭷⟀ָ饥ךز٦هⱄ؎ַٝة؍رؒծה
ٗ؎فرח澓儗חأ؎غرג׃ 䩛ָ♶銲ךוזسٗ٦فحⱄ،װسٕؽⱄ
ؙحغس٦؍ؿךׁ僽ꬊ涺 יג׃㔐瘶מز٦؛،ٝ