هل سبق لك أن فكرت في كيفية جعل إدارة المشهد في مشروعك أقل إيلامًا؟ عندما يكون لديك لعبة بسيطة إلى حد ما حيث لا يوجد سوى عدد قليل من المشاهد تسير واحدة تلو الأخرى ، فغالبًا ما يسير كل شيء بسلاسة. ولكن عندما ينمو عدد المشاهد وتصبح الانتقالات بينها أكثر تعقيدًا - يمكن تحميلها بترتيب مختلف ويجب أن يعتمد سلوك بعضها على معلمات الإدخال - تصبح المهمة أقل أهمية.
فيما يلي عدة طرق لحلها رأيتها كثيرًا:
- الملفات - عند الانتقال من مشهد إلى آخر ، تتم كتابة جميع البيانات الضرورية في ملف JSON / XML ، وعندما يتم تحميل المشهد التالي ، تتم قراءتها مرة أخرى. على الأقل ، إنه بطيء (التحدث عن القراءة والكتابة في ملف) ، وتصبح عملية التصحيح أقل ملاءمة.
- فئة ثابتة ضخمة تتعامل مع جميع انتقالات المشهد الممكنة. إنها تشبه إلى حد بعيد الأشياء الإلهية وغالبًا ما تسبب تسربًا للذاكرة ، وكذلك ألمًا في أسفل الظهر عندما يحاول مطور جديد فهم ما يحدث في هذه الألف سطر من التعليمات البرمجية الثابتة.
- DontDestroyOnLoad GameObject - يشبه هذا الأسلوب الأسلوب السابق ، ولكن يتم تقديم كائن GameObject في مشهد به مجموعة من الروابط في المفتش. في الواقع ، هذا واحد من هؤلاء الفرديين الذين شاهدهم كل واحد منا في معظم المشاريع ...
أريد أن أوضح لك النهج الذي كنت أستخدمه منذ سنوات. يساعد في جعل الانتقالات أكثر شفافية للمطور ، ويصبح من السهل فهم مكان وما يحدث ، وكذلك تصحيح الأخطاء.
في كل مشهد لدي SceneController. وهو مسؤول عن إعادة توجيه جميع الروابط الضرورية وتهيئة العناصر الرئيسية. بمعنى ما ، يمكن اعتباره نقطة دخول المشهد. I استخدام فئة لتمثيل الحجج، SceneArgsو كل مشهد له فئتها الخاصة التي تمثل حججها ويرث منه SceneArgs.
public abstract class SceneArgs
{
public bool IsNull { get; private set; }
}
, , SceneController.
public abstract class SceneController<TController, TArgs> : MonoBehaviour
where TController : SceneController<TController, TArgs>
where TArgs : SceneArgs, new()
{
protected TArgs Args { get; private set; }
private void Awake()
{
Args = SceneManager.GetArgs<Tcontroller, TArgs>();
OnAwake();
}
protected virtual void OnAwake() {}
}
. , params object[] args. . , . , , — , , ( ) , , . , IDE , . params object[] args , , , . ( ), . where, SceneController.
, name buildIndex , LoadScene() LoadSceneAsync() Unity API. , SceneControllerAttribute, . , buildIndex , , , .
[AttributeUsage(AttributeTargets.Class)]
public sealed class SceneControllerAttribute : Attribute
{
public string SceneName { get; private set; }
public SceneControllerAttribute(string name)
{
SceneName = name;
}
}
, MainMenu. , :
public sealed class MainMenuArgs : SceneArgs
{
// args' properties
}
[SceneControllerAttribute]
public sealed class MainMenuController : SceneController<MainMenuController, MainMenuArgs>
{
protected override void OnAwake()
{
// scene initialization
}
}
, ( , ). , . SceneManager. , , . . — . .
public static class SceneManager
{
private static readonly Dictionary<Type, SceneArgs> args;
static SceneManager()
{
args = new Dictionary<Type, SceneArgs>();
}
private static T GetAttribute<T>(Type type) where T : Attribute
{
object[] attributes = type.GetCustomAttributes(true);
foreach (object attribute in attributes)
if (attribute is T targetAttribute)
return targetAttribute;
return null;
}
public static AsyncOperation OpenSceneWithArgs<TController, TArgs>(TArgs sceneArgs)
where TController : SceneController<TController, TArgs>
where TArgs : SceneArgs, new()
{
Type type = typeof(TController);
SceneControllerAttribute attribute = GetAttribute<SceneControllerAttribute>(type);
if (attribute == null)
throw new NullReferenceException($"You're trying to load scene controller without {nameof(SceneControllerAttribute)}");
string sceneName = attribute.SceneName;
if (sceneArgs == null)
args.Add(type, new TArgs { IsNull = true });
return UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(sceneName);
}
public static TArgs GetArgs<TController, TArgs>()
where TController : SceneController<TController, TArgs>
where TArgs : SceneArgs, new()
{
Type type = typeof(TController);
if (!args.ContainsKey(type) || args[type] == null)
return new TArgs { IsNull = true };
TArgs sceneArgs = (TArgs)args[type];
args.Remove(type);
return sceneArgs;
}
}
. OpenSceneWithArgs() (TController) , , (TArgs) , , (sceneArgs). , SceneManager , TController SceneControllerAttribute. , , TController. sceneArgs . - , TArgs IsNull true. , Unity API LoadSceneAsyn() , SceneControllerAttribute.
Awake(). , SceneController, TController SceneManager.GetArgs(), , , .
, SceneManager, . , . . !