防止单例随场景销毁和跨场景两个物体脚本问题
通过泛型封装单例类
NormalSingleton.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//标准单例类
public class NormalSingleton<T> where T : class, new()
{
private static T _single;
public static T Singel
{
get
{
if (_single == null)
{
T t = new T();
if (t is MonoBehaviour)
{
Debug.LogError("Mono类请使用MonoSingleTon!");
return null;
}
_single = t;
}
return _single;
}
}
}
MonoSingleton.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Mono单例类
public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _singleton;
public static T SingleTon
{
get
{
if (_singleton == null)
{
_singleton = FindObjectOfType<T>();
if (_singleton == null)
{
Debug.LogError("场景中未找到类的对象,类名为:"+typeof(T).Name);
}
}
return _singleton;
}
}
private void Awake()
{
if (_singleton == null)
{
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}
通过物体路径 自动挂载脚本(游戏预制物体名字 和 脚本名字得一样)(方式一)
ILoader接口 给ResourceLoder 和 ABLoader实现
ILoader.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ILoader
{
/// <summary>
/// Resource方法加载物体
/// </summary>
/// <param name="path">加载物体的路径</param>
/// <param name="parent">指定父物体</param>
/// <returns></returns>
GameObject LoadPrefab(string path, Transform parent = null);
}
Resource加载器
ResourceLoader.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResourceLoader : ILoader
{
/// <summary>
/// Resource方法加载物体
/// </summary>
/// <param name="path">加载物体的路径</param>
/// <param name="parent">指定父物体</param>
/// <returns></returns>
public GameObject LoadPrefab(string path,Transform parent = null)
{
GameObject go = Resources.Load<GameObject>(path);
GameObject go2 = Object.Instantiate(go, parent);
return go2;
}
}
AB包加载器 (没有实现 共理清逻辑使用)
ABLoader.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ABLoader : ILoader
{
public GameObject LoadPrefab(string path, Transform parent = null)
{
throw new System.NotImplementedException();
}
}
LoadManager场景加载器
LoadManager.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//加载管理器
public class LoadManager : NormalSingleton<LoadManager>
{
[SerializeField]
private ILoader iLoader;
public LoadManager()
{
//Resource加载方式
iLoader = new ResourceLoader();
//AB包加载方式
// iLoader = new ABLoader();
}
//自动挂载脚本加载物体方式一(通过脚本与游戏物体同名)
public GameObject LoadPrefab(string path, Transform parent = null)
{
GameObject go = iLoader.LoadPrefab(path, parent);
//通过物体名 自动挂载脚本(游戏物体名字 和 脚本名字得一样)
Type type = Type.GetType(go.name.Remove(go.name.Length - 7));
go.AddComponent(type);
return go;
}
//自动挂载脚本加载物体方式二(通过反射特性)
// public GameObject LoadPrefab(string path, Transform parent = null)
// {
// GameObject go = iLoader.LoadPrefab(path, parent);
// Type type = BindUtil.GetType(path);
// go.AddComponent(type);
// return go;
// }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//加载管理器
public class LoadManager : NormalSingleton<LoadManager>
{
[SerializeField]
private ILoader iLoader;
public LoadManager()
{
//Resource加载方式
iLoader = new ResourceLoader();
//AB包加载方式
// iLoader = new ABLoader();
}
//自动挂载脚本加载物体方式一(通过脚本与游戏物体同名)
public GameObject LoadPrefab(string path, Transform parent = null)
{
GameObject go = iLoader.LoadPrefab(path, parent);
//通过物体名 自动挂载脚本(游戏物体名字 和 脚本名字得一样)
Type type = Type.GetType(go.name.Remove(go.name.Length - 7));
go.AddComponent(type);
return go;
}
//自动挂载脚本加载物体方式二(通过反射特性)
// public GameObject LoadPrefab(string path, Transform parent = null)
// {
// GameObject go = iLoader.LoadPrefab(path, parent);
// Type type = BindUtil.GetType(path);
// go.AddComponent(type);
// return go;
// }
}
启动游戏入口 需要挂在在游戏物体上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//启动游戏入口
public class LaunchGame : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
//通过反射特性 加载方式二
// InitCustermonAttribute initCustermonAttribute = new InitCustermonAttribute();
// initCustermonAttribute.init();
LoadManager.Singel.LoadPrefab("Prefab/StartView",transform);
}
}
启动入口挂载在Cavas上 加载的预制体 会做为其子物体
运行效果:
通过游戏物体路径 反射特性 自动加载预制体和脚本(方式二)
绑定物体特性
BindPrefab.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//绑定物体特性
[AttributeUsage(AttributeTargets.Class)]
public class BindPrefab : Attribute
{
public string Path { get; private set;}
public BindPrefab(string path)
{
Path = path;
}
}
加载物体同名脚本 通过路径反射
StartView.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//加载物体同名脚本 通过路径反射
[BindPrefab("Prefab/StartView")]
public class StartView : MonoBehaviour
{
}
绑定工具类
BindUtil.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
//绑定工具类
public class BindUtil : MonoBehaviour
{
public static Dictionary<string, Type> _Dictionary = new Dictionary<string, Type>();
public static void Bind(string path,Type type)
{
if (!_Dictionary.ContainsKey(path))
{
_Dictionary.Add(path,type);
}
else
{
Debug.LogError("当前数据已存在路径: "+path);
}
}
public static Type GetType(string path)
{
if (_Dictionary.ContainsKey(path))
{
return _Dictionary[path];
}
else
{
Debug.LogError("数据未包含路径:"+path);
return null;
}
}
}
初始化自定义特性
InitCustermonAttribute.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
//初始化自定义特性
public class InitCustermonAttribute : MonoBehaviour
{
public void init()
{
Assembly assembly = Assembly.GetAssembly(typeof(BindPrefab));
Type[] types = assembly.GetExportedTypes();
foreach (Type type in types)
{
foreach (Attribute attribute in Attribute.GetCustomAttributes(type,true))
{
if (attribute is BindPrefab)
{
BindPrefab data = attribute as BindPrefab;
BindUtil.Bind(data.Path,type);
}
}
}
}
}
加载管理器
LoadManager.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//加载管理器
public class LoadManager : NormalSingleton<LoadManager>
{
[SerializeField]
private ILoader iLoader;
public LoadManager()
{
//Resource加载方式
iLoader = new ResourceLoader();
//AB包加载方式
// iLoader = new ABLoader();
}
//自动挂载脚本加载物体方式一(通过脚本与游戏物体同名)
// public GameObject LoadPrefab(string path, Transform parent = null)
// {
// GameObject go = iLoader.LoadPrefab(path, parent);
// //通过物体名 自动挂载脚本(游戏物体名字 和 脚本名字得一样)
// Type type = Type.GetType(go.name.Remove(go.name.Length - 7));
// go.AddComponent(type);
// return go;
// }
//自动挂载脚本加载物体方式二(通过反射特性)
public GameObject LoadPrefab(string path, Transform parent = null)
{
GameObject go = iLoader.LoadPrefab(path, parent);
Type type = BindUtil.GetType(path);
go.AddComponent(type);
return go;
}
}
启动游戏入口
LaunchGame.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//启动游戏入口
public class LaunchGame : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
//通过反射特性 加载方式二
InitCustermonAttribute initCustermonAttribute = new InitCustermonAttribute();
initCustermonAttribute.init();
LoadManager.Singel.LoadPrefab("Prefab/StartView",transform);
}
}
运行效果:
加载器结构目录