DontDestroyOnLoad 加载场景时不销毁游戏对象。对于保留全局对象以及角色切换场景来说是非常实用的方法,但是直接使用该方法有一个弊端,当返回创造对象的场景时,场景将会出现两个对象,即保留的对象和新生成的对象。这样就不符合我们的需求了。
(想直接得到答案请拉到最下端的结论)
网上有很多解决方案,大致分为三种:静态初始化、循环销毁、flag判断以及不再进入初始场景,但是三种方法多多少少会存在一些问题。
public class Global:MonoBehaviour
{
public static Globalinstance;
static Global()
{
GameObjectgo=newGameObject("Globa");
DontDestroyOnLoad(go);
instance=go.AddComponent();
}
}
作者:霸俊流年
链接:https://www.jianshu.com/p/57b339a79959
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
网上随便找了一段代码,这段代码使得Global对象的构造函数变为静态,这样该对象就会在游戏一开始时被创建,同时挂载DontDestroyOnLoad并成为单例,这样当再次进入该场景时不会被动态生成。这样做的好处是没有循环判断且不会再分配新的内存空间,效率高。但是弊端很明显,游戏对象必然在第一个场景被创建,在不想对象在第一个场景创建的时候就不能直接使用了。
基本原理是把需要保留的对象放在一个队列里,每次切换场景都循环判断一次场景中是否存在同名对象,若存在则销毁。很明显,该方法消耗性能极大,若把判断代码放在场景控制脚本中,那么耦合度又是一个头疼的问题,总之并不建议去尝试。
使用一个变量去判断场景中是否存在同一对象,如下面代码:
public static bool isClone;
public GameObject obj;
private GameObject cloneObj;
void Awake()
{
if(!isClone)
{
cloneObj =Instantiate(obj,obj.transform.position,obj.transform.rotation)as GameObject;
isClone = true;
}
DontDestoryOnLoad(cloneObj);
}
作者:Babybus_Unity
链接:https://www.jianshu.com/p/cd9cc1c3049f
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
结论自然是耦合度高、代码复杂、效率不高等等,其中还要预先封装预制体,也加大了开发难度。
使用一个场景来进行初始化,简单高效,也就多一个场景以及一个场景切换脚本而已。
接下来是我的解决方案,把所有需要保留的对象挂载在名为“Global”的空对象下,并设置tag为“Global”,再把一下代码脚本挂载在Global上,别害怕只有两句代码:
private void Awake()
{
if (GameObject.FindGameObjectsWithTag("Global").Length>1)
Destroy(this.gameObject);
else
DontDestroyOnLoad(this.gameObject);
}
这里使用了一个概念:立即销毁=限制创建,当然,这样描述是不正确的,因为对象的创建事实上发生了 ,所以对于需要保留的对象有一个限制,就是不能在Awake里写入对游戏有明显影响的代码。
这段代码只会在创建对象时调用,所以性能上完全是没有问题的,这样当再次进入第一个场景时,新生成的对象调用Awake函数,发现“Global”的数量大于1,于是立马销毁掉,在玩家看来基本上是看不出有任何问题的。当然你不能一上来就删几个对象或者生产几个对象这样子,作死多了肯定会露馅的。
效果如下,挂载后角色将不会再重复出现:
把“Global”做成空的预制体也可以,单独使用这段代码也可以,因为Destroy和DontDestroyOnLoad都是对整个继承树有效的。这样做的话无论是效率还是耦合度都能得到保障,只不过如果某个子类在Awake里有“特别的技巧”,那还是推荐其他方法吧。
综合一下上面的方法,可以使用下面的代码结合单例模式作为基类使用。原理是一样的借助静态变量origional 判断是否是最初的对象,在第一次创建对象后,origional 被置为false,之后的对象均会在Awake阶段就被Destroy掉。
private static T instance;
private static bool origional = true;
protected virtual void Awake()
{
if (origional) {
instance = this as T;
origional = false;
DontDestroyOnLoad(this.gameObject);
} else {
Destroy(this.gameObject);
}
}
另,如果有正在做或者想做独立游戏的小伙伴,希望可以加入我们的群,一起分享经验或者寻找同伴: