Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Unity. Асинхронная загрузка. Какой способ выбрать?

Unity. Асинхронная загрузка. Какой способ выбрать?

s3dworldПостоялецwww11 янв. 201813:57#0
Всем доброго дня!

Подошёл к вопросу асинхронной загрузки (до этого как-то не требовалось это делать). Собрал пример с двумя вариантами загрузки. На сцене создал два объекта: Square1 и Square2. На каждый повесил по разному скрипту. Каждый скрипт создаёт 4 вершины и объединяет их в два треугольника, а затем загружает материал из ресурсов. Вот так выглядит Square1:

+ Показать

А вот так Square2:

+ Показать

Всё это успешно работает. Но какой вариант лучше использовать? Для меня не видны преимущества того или иного варианта. Ну или какие ещё бывают варианты.

zlosПостоялецwww11 янв. 201817:12#1
AssetBundles
s3dworldПостоялецwww11 янв. 201817:16#2
zlos
> AssetBundles
На сколько я понимаю, это всего лишь способ для организации получения ресурсов, что снова подходит к тому, что и с ним можно использовать LoadAssetAsync() и будет опять два варианта (как выше).

Правка: 11 янв. 2018 17:16

patsanchik3Постоялецwww11 янв. 201818:01#3
если необходима информация о состоянии загрузки (например для индикации процесса) - то второй предпочтительнее
s3dworldПостоялецwww11 янв. 201818:17#4
patsanchik3
> если необходима информация о состоянии загрузки (например для индикации процесса) - то второй предпочтительнее
А разве я не могу в первом варианте взять resourceRequest и из него получить прогресс в любом месте?
patsanchik3Постоялецwww11 янв. 201818:34#5
s3dworld
> А разве я не могу в первом варианте взять resourceRequest и из него получить
> прогресс в любом месте?
можешь - но во втором случае у тебя уже крутится коротин а в первом надо больше кода - тот же коротин или апдейт - а многа кода в апдейте не гут
s3dworldПостоялецwww11 янв. 201819:10#6
patsanchik3
> можешь - но во втором случае у тебя уже крутится коротин а в первом надо больше кода - тот же коротин или апдейт - а многа кода в апдейте не гут
А по производительности если сравнить эти варианты?
alexzzzzПостоялецwww11 янв. 201820:07#7
Пока Unity не прикрутит авейтеры к своим асинхронным операциям, я бы использовал самописный, чтобы не размазывать по своим исходникам асинхронные колбеки:

public static class ResourceRequestExtensions
{
  public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest request) => new ResourceRequestAwaiter(request);

  public struct ResourceRequestAwaiter : INotifyCompletion
  {
    private readonly ResourceRequest request;

    public ResourceRequestAwaiter(ResourceRequest request) => this.request = request;
    public ResourceRequestAwaiter GetAwaiter() => this;
    public UnityEngine.Object GetResult() => request.asset;
    public bool IsCompleted => request.isDone;
    public void OnCompleted(Action action) => request.completed += _ => action();
  }
}

При наличии в проекте вышеприведённого кода, старая асинхронная лапша записывается в одну строку:

meshRenderer.material = (Material)await Resources.LoadAsync<Material>("Materials/Square");

Правка: 11 янв. 2018 20:07

s3dworldПостоялецwww12 янв. 201820:43#8
alexzzzz
> GetAwaiter
Его же добавили в C# 7, а в Unity недавно ввели поддержку только C# 6 (и то экспериментальную).
s3dworldПостоялецwww12 янв. 201820:47#9
А вообще можно как-то сделать по моему первому варианту, но только чтобы не выделять место под сохранение ResourceRequest в классе и не создавая функций для оповещения (onMaterialLoadCompleted)? В C++ я бы это сделал через лямбды (благо там я знаю как захватывать параметры по значению, по ссылке). А тут если я и указываю:
resourceRequest.completed+=p => { ... };

То внутри, через этот p я не могу добраться до самого материала и приходится хранить ResourceRequest.

patsanchik3Постоялецwww13 янв. 20181:01#10
по второму можно через экшон
 private IEnumerator loadMaterial(Action<Material> result)
    {
        var resourceRequest = Resources.LoadAsync<Material>("Materials/Square");
        yield return resourceRequest;
        if (result != null)
            result(resourceRequest.asset as Material);
    }

и анонимные делегаты - лучше с ними поосторожнее :)

alexzzzzПостоялецwww13 янв. 20184:52#11
s3dworld
> > GetAwaiter
> Его же добавили в C# 7, а в Unity недавно ввели поддержку только C# 6 (и то
> экспериментальную).

async/await появились в C# 5.0.

Правка: 13 янв. 2018 4:53

s3dworldПостоялецwww13 янв. 201810:49#12
alexzzzz
> async/await появились в C# 5.0.
Да, но GetAwaiter() появился в C# 7.
alexzzzzПостоялецwww15 янв. 201813:00#13
Если смущают стрелочки в expression-bodied методах, ну замени на фигурные скобки, разницы нет. В остальном этот код на C# 5.0.

PS
Вот без стрелочек. Строго C# 5.0.

+ Показать

Правка: 15 янв. 2018 17:38

alexzzzzПостоялецwww15 янв. 201813:20#14
s3dworld
> А тут если я и указываю:
> resourceRequest.completed+=p => { ... };
> То внутри, через этот p я не могу добраться до самого материала и приходится
> хранить ResourceRequest.

Класс ResourceRequest, у которого есть свойство asset, наследуется от AsyncOperation. А это p у тебя - это и есть ResourseRequest под видом базового AsyncOperation. Его можно скастовать к ResourseRequest и достать оттуда asset.

// ...

Resources.LoadAsync<Material>("Materials/Square").completed += asyncOp =>
{
  var request = (ResourceRequest)asyncOp;
  var material = (Material)request.asset;
  // ...
};

Правка: 15 янв. 2018 17:42

/ Форум / Программирование игр / Общее

2001—2018 © GameDev.ru — Разработка игр