使用单例为unity设计初始化

本文关键字:初始化 unity 单例 | 更新日期: 2023-09-27 18:05:56

我有一个ImageSequencePlayer脚本,它有一个字符串输入来选择从哪里加载图像。图像的Sprite[]数组现在是静态的,但我仍然将它们多次加载到同一个数组中。我使用这个工具制作了更多的预制件,例如一个角色,敌人,一些陷阱,火焰等等。如何使用Singletons创建一个体面的设计?这样,只要使用这个脚本的prefab有一个不同的位置,游戏管理器就会寻找它并加载精灵,然后把它给所有需要的人?如果不是这样,那又如何?

using UnityEngine;
using System.Collections;
public class ImageSequencePlayer : MonoBehaviour
{
    private int currentImageIndex;
    private SpriteRenderer spriteRenderer;
    private static Sprite[] spriteSheet;
    [Tooltip("The location of your main spritesheet.")]
    public string spritesLocation;
    public float frameRate = 24.0f;
    public enum PlayMode
    {
        order, random, uponNeeded
    }
    public PlayMode playMode = PlayMode.order;
    private bool updateEnabled = true;
    [Tooltip("Decides if the random playback can iterate. If no, it doesn't play, it is frozen.")]
    public bool canIterate = true; //if the random playback can iterate. if no, it doesn't play.
    [Tooltip("Is there some non looping animation before the loop? If so, right after it's done, it starts looping.")]
    public bool warmUp = false;
    [Tooltip("If you have a warmup sheet location, put it here.")]
    public string warmUpLocation = "";
    private static Sprite[] warmUpSprites;
void Start ()
{
    try
    {
        spriteSheet = null;
        spriteSheet = Resources.LoadAll<Sprite>(spritesLocation);
    }
    catch(MissingSpriteSheetException ex)
    {
        Debug.Log(ex.Message);
    }
    try
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }catch
    {
        spriteRenderer = GetComponentInChildren<SpriteRenderer>();
    }
    if(warmUp)
    {
        switch (this.gameObject.tag)
        {
            case "candleLight":
                warmUpSprites = null;
                warmUpSprites = Resources.LoadAll<Sprite>("warmUpFlames");
                break;
            default:
                warmUpSprites = null;
                warmUpSprites = Resources.LoadAll<Sprite>(warmUpLocation);
                break;
        }
        //meaning we do have something to warm up
    }else
    {
        //so if we did want some warmup, we load it,
        //if we didn't, we just free the memory.
        warmUpSprites = null;
        warmUpLocation = null;
    }
    if(playMode == PlayMode.uponNeeded)
    {
        //if we need it occasionally, we just disable everything else.
        warmUp = false;
        updateEnabled = false;
        warmUpLocation = null;
        warmUpSprites = null;
    }
}
void LateUpdate ()
{
    if (warmUp)
    {
        currentImageIndex = Mathf.RoundToInt(Time.time * frameRate);
        currentImageIndex = currentImageIndex % warmUpSprites.Length;
        spriteRenderer.sprite = warmUpSprites[currentImageIndex];
        if(currentImageIndex >= warmUpSprites.Length-1)
        {
            currentImageIndex = 0;
            warmUp = false;
            //now easing on the memory, not another warmup will happen of course:
            warmUpLocation = null;
            warmUpSprites = null;
        }
    }
    if (updateEnabled && !warmUp)
    {
        switch (playMode)
        {
            case PlayMode.order:
                currentImageIndex = Mathf.RoundToInt(Time.time * frameRate);
                currentImageIndex = currentImageIndex % spriteSheet.Length;
                spriteRenderer.sprite = spriteSheet[currentImageIndex];
                break;
            case PlayMode.random:
                updateEnabled = false;
                StartCoroutine(RandomizedPlay());
                break;
        } 
    }
}
IEnumerator RandomizedPlay()
{
    int oldIndex = 0;
    int currentIndex;
    int iterNumber = 0;
    while (canIterate)
    {
        currentIndex = Random.Range(0, spriteSheet.Length - 1);
        if(currentIndex == oldIndex)
        {
            while((currentIndex == oldIndex) && (iterNumber < 8))
            {
                currentIndex = Random.Range(0, spriteSheet.Length - 1);
                iterNumber++;
            }
        }
        spriteRenderer.sprite = spriteSheet[currentIndex];
        oldIndex = currentIndex;
        iterNumber = 0;
        yield return new WaitForSeconds(1.0f / frameRate);
    }
}
public void OccasionalAnimation(bool backWardsNeeded)
{
    StartCoroutine(OccasionalAnimEnum(backWardsNeeded));
}
public IEnumerator OccasionalAnimEnum(bool backWardsNeeded)
{
    currentImageIndex = 0;
    while (currentImageIndex < spriteSheet.Length)
    {
        //meaning while we do have anything to play
        spriteRenderer.sprite = spriteSheet[currentImageIndex];
        currentImageIndex++;
        yield return new WaitForSeconds(1.0f / frameRate);
    }
    if (backWardsNeeded)
    {
        //so we need to play the shit backwards as well, like in the book
        currentImageIndex = spriteSheet.Length - 2;//so we won't repeat the last again.
        while (currentImageIndex >= 0)
        {
            //meaning while we do have anything to play
            spriteRenderer.sprite = spriteSheet[currentImageIndex];
            currentImageIndex--;
            yield return new WaitForSeconds(1.0f / frameRate);
        }
    }
    //at the end it should be at the starting sprite.
    currentImageIndex = 0;
}
}

使用单例为unity设计初始化

在脚本开始处添加以下代码,使其成为单例:

private static ImageSequencePlayer _instance;
public static ImageSequencePlayer Instance
{
    get
    {
        if (_instance == null)
        {
            _instance = FindObjectOfType<ImageSequencePlayer>();
            if (_instance == null)
            {
                Debug.LogError("ImageSequencePlayer Instance is null");
            }
        }
        return _instance;
    }
}

现在你不需要做任何static .

从任意位置访问非静态精灵数组,如下所示:

ImageSequencePlayer.Instance.spriteSheet

和所有其他属性/字段。

使用Awake()方法从资源中加载图像:

void Awake()
{
    // populate sprites array here.
}
编辑:

单例脚本不应该在场景中出现在多个对象上。创建一个空对象并附加单例脚本。如果您有任何其他通用功能(如spritesheet),请将该代码移到单例中。确保你的其他脚本中没有Sprite加载代码,而这些代码要应用于所有对象。