问之前一个一起开发独游的哥们儿最近在忙啥。
答曰,
第一句:在北京一个XX公司混日子
第二句:私下和主程在搞一个独游
第三句:我们俩半年的成绩比公司30人的团队还快,也是醉了。
独立游戏开发,效率就是生命,一切都要以满足高效开发为第一要务。
但若不管不顾,怎么方便怎么来,又很容易导致项目后期资源关联混乱,做性能和内存优化无从下手。
基于下面,我大概总结一下,资源管理方案必须满足以下三个
1、方便编辑,方便编辑,方便编辑
2、方便打AB包
3、方便内存管理(加载/卸载)
满足方便编辑的最有效手段,是可以在U3D编辑器中查看,配置资源的相互引用。
因此,通过继承于ScriptableObject的Asset和MonoBehaviour的Prefab中,
通过GameObject或ScriptableObject进行各种资源引用配置,是最方便编辑的。
但ScriptableObject中引用的各种自定义Object或者GameObject,都是通过GUID在资源中直接引用的。
在手游上难以做到合理分包、延迟加载。从而内存优化也很难做,无法对不使用的资源进行卸载。
如下:
既要解耦,又不会影响编辑的方便性。核心是在实现一个ABObject<T>类,并在引用对象时,将写法做响应修改。
比如:public Sprite m_ItemIcon; 改为 public ABSprite m_ItemIcon2;
```
MDTest.cs
using System.Collections;using System.Collections.Generic;using UnityEngine;using IGMDFramework.Types;public class MDTest : MonoBehaviour{ //public Sprite m_ItemIcon; public ABSprite m_ItemIcon2; //public GameObject m_ItemGameObject; public ABGameObject m_ItemGameObject2; // Start is called before the first frame update void Start() { // var obj = Instantiate(m_ggjGameObject); var obj = Instantiate(m_ItemGameObject2.asset); //Debug.Log($"{m_ItemIcon.name}"); Debug.Log($"{m_ItemIcon2.asset.name}"); } // Update is called once per frame void Update() { }}
```
```
ABObject.cs
using UnityEngine;using Sirenix.OdinInspector;namespace IGMDFramework.Types{ public class ABObject<T> where T : UnityEngine.Object { [SerializeField] private string _ObjPath; #if UNITY_EDITOR [SerializeField] private T _RefObj; #endif public T asset { get { #if UNITY_EDITOR return _RefObj; #else // AssetBundle 通过_ObjPath进行加载 return AssetManager.GetGameObject(_ObjPath); #endif } } } [System.Serializable] public class ABSprite : ABObject<Sprite> { } [System.Serializable] public class ABGameObject : ABObject<GameObject> { }}
```
```
ABObjectDrawer.cs
using System.Reflection;using UnityEditor;using UnityEngine;using IGMDFramework.Types;namespace IGMDFramework.Editor{ public class ABObjectDrawer<T, N> : PropertyDrawer where T : ABObject<N> where N : Object { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var abs = fieldInfo.GetValue(property.serializedObject.targetObject) as T; // abs._RefObj = (N)EditorGUILayout.ObjectField(label, abs._RefObj, typeof(N), true); // abs._ObjPath = AssetDatabase.GetAssetPath(abs._RefObj); var objField = typeof(T).BaseType.GetField("_RefObj", BindingFlags.Instance | BindingFlags.NonPublic); var obj = objField.GetValue(abs) as N; obj = (N)EditorGUILayout.ObjectField(label, obj, typeof(N), true); objField.SetValue(abs, obj); var pathField = typeof(T).BaseType.GetField("_ObjPath", BindingFlags.Instance | BindingFlags.NonPublic); var path = AssetDatabase.GetAssetPath(obj); pathField.SetValue(abs, path); position.y += 16; EditorGUILayout.LabelField(path); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return base.GetPropertyHeight(property, label); } } [CustomPropertyDrawer(typeof(ABSprite))] public class ABSpriteDrawer : ABObjectDrawer<ABSprite, Sprite> {}; [CustomPropertyDrawer(typeof(ABGameObject))] public class ABGameObjectDrawer : ABObjectDrawer<ABGameObject, GameObject> { };}
```
由于PropertyDrawer不支持泛型,这里绕了好远。