UnityでResourceをLazy(遅延)ロードしたい

  • 8
    いいね
  • 0
    コメント

あらまし

  • Resourcesのリソースをインスタンス変数として持ちたい(AudioClipとか、Prefabとか)
  • でもResources.Loadはランタイムにしか呼べない
  • その変数が使われる時はランタイムであることが保証されている(StartとかUpdateとか)
  • なんかLazyないっぽい?

=> よし、Lazy作ろう

結論

こんな感じのLazyクラスを作ればよい

using System;
using UnityEngine;

namespace Hexat
{
    // Basic
    public class Lazy<TParam, TOut>
    {
        protected TParam param;
        protected TOut value;
        protected Func<TParam, TOut> provider;

        public Lazy(TParam param, Func<TParam, TOut> provider)
        {
            this.param = param;
            this.provider = provider;
        }

        public TOut Value
        {
            get { return value != null ? value : (value = provider(param)); }
        }
    }

    // Without initialization params
    public sealed class LazyObject<T> : Lazy<object, T>
    {
        public LazyObject(Func<T> provider) : base(null, o => provider())
        {
        }
    }

    // Resource
    public sealed class LazyResource<T> : Lazy<string, T> where T : UnityEngine.Object
    {
        public LazyResource(string path) : base(path, Resources.Load<T>)
        {
        }
    }
}

使い方

音を鳴らす感じのクラス


using System;
using System.Collections.Generic;
using UnityEngine;

namespace Hexat
{
    public sealed class SoundManager : MonoBehaviour
    {
        private static LazyResource<AudioClip> LazyAudio(string name)
        {
            return new LazyResource<AudioClip>(name);
        }
        private Dictionary<string, LazyResource<AudioClip>> _clips = new Dictionary<string, LazyResource<AudioClip>>()
        {
            {Sounds.SE_PLAYER_CRASH, LazyAudio("Sounds/crash")},
            {Sounds.SE_PLAYER_JUMP, LazyAudio("Sounds/jump")},
            {Sounds.SE_PLAYER_EQUIP, LazyAudio("Sounds/equip")}
        };
        private Dictionary<int, AudioSource> _channels = new Dictionary<int, AudioSource>();
        private AudioSource GetChannel(int channel)
        {
            if (_channels.ContainsKey(channel)) return _channels[channel];
            return _channels[channel] = gameObject.AddComponent<AudioSource>();
        }

        private AudioClip GetClip(string clip)
        {
            return _clips[clip].Value;
        }

        public void Play(string key, int channel = 0)
        {
            var cnl = GetChannel(channel);
            var clp = GetClip(key);
            cnl.clip = clp;
            cnl.Play();
        }
    }
}