الوحدة ، كمحرك ، لها عدد من العيوب ، والتي بفضل إمكانيات التخصيص وأدوات إنشاء الشفرات ، يمكن حلها.
سأخبرك الآن كيف كتبنا مكونًا إضافيًا لـ Unity بناءً على مشاريع ما بعد المعالجة ومولد كود CodeDom.
مشكلة
في Unity ، يتم تحميل المشاهد من خلال معرف سلسلة. إنه غير مستقر ، مما يعني أنه يمكن تغييره بسهولة دون عواقب واضحة. على سبيل المثال ، عندما تعيد تسمية مشهد ما ، فإن كل شيء سوف يطير ، لكن سيتم الكشف عنه فقط في نهاية مرحلة التنفيذ.
تظهر المشكلة بسرعة في المشاهد المستخدمة بشكل متكرر ، ولكن قد يكون من الصعب اكتشافها عندما يتعلق الأمر بالمشاهد المضافة الصغيرة أو المشاهد التي نادرًا ما يتم استخدامها.
القرار
عند إضافة مشهد إلى مشروع ، يتم إنشاء فئة بنفس الاسم باستخدام طريقة التحميل.
إذا أضفنا مشهد قائمة ، فسيتم إنشاء فئة القائمة في المشروع وفي المستقبل يمكننا بدء المشهد على النحو التالي:
Menu.Load();نعم ، الطريقة الثابتة ليست أفضل تخطيط. لكن بدا لي تصميمًا مقتضبًا ومريحًا. يحدث الإنشاء تلقائيًا ، الكود المصدري لهذه الفئة:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IJunior.TypedScenes
{
public class Menu : TypedScene
{
private const string GUID = "a3ac3ba38209c7744b9e05301cbfa453";
public static void Load()
{
LoadScene(GUID);
}
}
}
بطريقة ودية ، يجب أن تكون الفئة ثابتة ، حيث لا يُفترض أن يتم إنشاء مثيل لها منها. هذا خطأ سنصلحه. كما ترون من هذا الجزء ، الكود لا نتمسك بالاسم ، ولكن بالمشهد GUID ، وهو أكثر موثوقية. تبدو الفئة الأساسية نفسها كما يلي:
namespace IJunior.TypedScenes
{
public abstract class TypedScene
{
protected static void LoadScene(string guid)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
SceneManager.LoadScene(path);
}
protected static void LoadScene<T>(string guid, T argument)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
UnityAction<Scene, Scene> handler = null;
handler = (from, to) =>
{
if (to.name == Path.GetFileNameWithoutExtension(path))
{
SceneManager.activeSceneChanged -= handler;
HandleSceneLoaders(argument);
}
};
SceneManager.activeSceneChanged += handler;
SceneManager.LoadScene(path);
}
private static void HandleSceneLoaders<T>(T loadingModel)
{
foreach (var rootObjects in SceneManager.GetActiveScene().GetRootGameObjects())
{
foreach (var handler in rootObjects.GetComponentsInChildren<ISceneLoadHandler<T>>())
{
handler.OnSceneLoaded(loadingModel);
}
}
}
}
}- .
- ( , ), .
, .
, Game , .
.
using IJunior.TypedScenes;
using System.Collections.Generic;
using UnityEngine;
public class GameLoadHandler : MonoBehaviour, ISceneLoadHandler<IEnumerable<Player>>
{
public void OnSceneLoaded(IEnumerable<Player> players)
{
foreach (var player in players)
{
//make avatars
}
}
}, .
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IJunior.TypedScenes
{
public class Game : TypedScene
{
private const string GUID = "976661b7057d74e41abb6eb799024ada";
public static void Load(System.Collections.Generic.IEnumerable<Player> argument)
{
LoadScene(GUID, argument);
}
}
}. .. N , N . - .
, , , .
N?
YouTube .
. , , , .
, ?
. :
public class GameArguments
{
public IEnumerable<Player> Players { get; set; }
}, , , .
, : , . , .
ID .
PlayerPerfs
. , PlayerPrefs . , , .
ASPNet
- View ASPNet Core. ViewData ViewModel. Unity - .
Unity , - , View ASPNet. Additive ( , , ), .
, , , , .
Proof-of-concept. , .
مستودع جيثب - https://github.com/HolyMonkey/unity-typed-scenes
إذا كنت مهتمًا ، فسأطلب من فلاديسلاف في المقالة التالية إخبارك بكيفية عمله مع Code Dom في Unity وكيفية العمل مع المعالجة اللاحقة باستخدام مثال ما ناقشناه اليوم.