Table of Contents

6. Livrarea online a conținutului

Cerinte

Realizati un joc de curse simplu cu urmatoarele funcitonalitati:

Documentatie

In Unity principalele metode de a folosi continut gestionat extern sunt Unity AssetBundles si Addressables.

AssetBundles

AssetBundles sunt arhive binare generate de Unity care conțin asset-uri (texturi, prefabs, scene etc.) pentru o platformă țintă.

La ce ajută: livrare de conținut după instalare (patch/DLC), reducerea dimensiunii build-ului, streaming de conținut.

Cum funcționează:

Limitări: management manual pentru dependențe, caching, versioning, naming, update logic.

Addressables

Addressables un layer peste AssetBundles care oferă:

În spate: Addressables generează AssetBundles + catalog.

De ce sunt preferate: workflow mult mai simplu pentru patch/DLC:

Când folosești labels: pentru a grupa conținut (ex: track_winter, ads, skins_pack_01) și a descărca “pachetul”.

Exemple:

AssetBundle de pe disc și aplicarea unei texturi

using UnityEngine;
using System.Collections;
 
public class LoadTextureFromBundle : MonoBehaviour
{
    public string bundlePath;          // ex: Application.persistentDataPath + "/bundles/ads"
    public string textureAssetName;    // ex: "coke_start_tex"
    public Renderer targetRenderer;
 
    private IEnumerator Start()
    {
        var bundleCreateRequest = AssetBundle.LoadFromFileAsync(bundlePath);
        yield return bundleCreateRequest;
 
        var bundle = bundleCreateRequest.assetBundle;
        if (bundle == null)
        {
            Debug.LogError("AssetBundle load failed: " + bundlePath);
            yield break;
        }
 
        var texRequest = bundle.LoadAssetAsync<Texture2D>(textureAssetName);
        yield return texRequest;
 
        var tex = texRequest.asset as Texture2D;
        if (tex == null)
        {
            Debug.LogError("Texture not found in bundle: " + textureAssetName);
            bundle.Unload(false);
            yield break;
        }
 
        // aplică textura
        ApplyTexture(targetRenderer, tex);
 
        // bundle.Unload(false) păstrează asset-urile încărcate în memorie
        bundle.Unload(false);
    }
 
    private void ApplyTexture(Renderer r, Texture2D tex)
    {
        // material instanțiat ca să nu modifici sharedMaterial global
        var mat = r.material;
        mat.mainTexture = tex;
    }
}

AssetBundle din memorie (de ex. după download)

var req = AssetBundle.LoadFromMemoryAsync(downloadedBytes);
yield return req;
AssetBundle bundle = req.assetBundle;

Addressables

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System.Collections;
using System.Collections.Generic;
 
public class AddressablesDlcExample : MonoBehaviour
{
    public string dlcLabel = "track_winter";
    public string textureAddress = "ads/coke_start_tex";
    public Renderer targetRenderer;
 
    private IEnumerator Start()
    {
        // 1) verifică update catalog
        var check = Addressables.CheckForCatalogUpdates(false);
        yield return check;
 
        List<string> catalogs = check.Result;
        Addressables.Release(check);
 
        if (catalogs != null && catalogs.Count > 0)
        {
            var update = Addressables.UpdateCatalogs(catalogs, false);
            yield return update;
            Addressables.Release(update);
        }
 
        // 2) află dimensiunea de download pentru DLC
        var sizeOp = Addressables.GetDownloadSizeAsync(dlcLabel);
        yield return sizeOp;
        long bytes = sizeOp.Result;
        Addressables.Release(sizeOp);
 
        Debug.Log($"DLC size: {bytes / (1024f * 1024f):0.00} MB");
 
        // 3) descarcă dependențele (bundles) pentru label
        var download = Addressables.DownloadDependenciesAsync(dlcLabel, true);
        while (!download.IsDone)
        {
            Debug.Log($"Download progress: {download.PercentComplete:0.00}");
            yield return null;
        }
 
        if (download.Status != AsyncOperationStatus.Succeeded)
        {
            Debug.LogError("DownloadDependencies failed");
            Addressables.Release(download);
            yield break;
        }
        Addressables.Release(download);
 
        // 4) încarcă textura după address
        var loadTex = Addressables.LoadAssetAsync<Texture2D>(textureAddress);
        yield return loadTex;
 
        if (loadTex.Status == AsyncOperationStatus.Succeeded)
        {
            ApplyTexture(targetRenderer, loadTex.Result);
        }
        else
        {
            Debug.LogError("LoadAssetAsync failed: " + textureAddress);
        }
 
        // când nu mai ai nevoie de asset:
        // Addressables.Release(loadTex);
    }
 
    private void ApplyTexture(Renderer r, Texture2D tex)
    {
        var mat = r.material;
        mat.mainTexture = tex;
    }
}

Încărcare scenă Addressable (DLC track)

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement;
using System.Collections;
 
public class LoadSceneAddressable : MonoBehaviour
{
    public string sceneAddress = "Track_Winter";
 
    private IEnumerator Start()
    {
        var op = Addressables.LoadSceneAsync(sceneAddress, LoadSceneMode.Single, true);
        yield return op;
    }
}

Pentru gestiunea reclamelor, puteti folosi texturi gestionate/acutalizate din cod:

Renderer r = GetComponent<Renderer>();
Texture2D tex = /* încărcată din URL / bundle / addressables */;
r.material.mainTexture = tex;
 
 
var r = GetComponent<Renderer>();
var mat = r.material;
mat.SetTexture("_BaseMap", tex); // URP Lit
 
 
using UnityEngine.UI;
 
Texture2D tex = ...;
Sprite sp = Sprite.Create(tex, new Rect(0,0,tex.width, tex.height), new Vector2(0.5f,0.5f));
GetComponent<Image>().sprite = sp;