إدارة الحالة والأحداث بين المكونات في GameObject
رابط للمشروعكما يعلم الجميع أو أكثر أو أقل دراية بمنصة Unity ،
يتكون كل كائن لعبة
GameObject من مكونات (مدمجة أو مخصصة ، والتي عادة ما تسمى "البرنامج النصي"). ترث المكونات من الفئة الأساسية
MonoBehavior .

وعادة ، بشكل جيد أو في كثير من الأحيان ، يتم إنشاء رابط مباشر لربط المكونات.

أي في أحد المكونات ، للحصول على البيانات من مكون آخر ، نحصل على هذا الأخير باستخدام الأسلوب
GetComponent <...> () ، على سبيل المثال مثل هذا:

في هذا المثال ، سيتم وضع إشارة إلى مكون من النوع
SomeComponent في المتغير
someComponent .
من خلال هذا النهج "المقترن بإحكام" ، خاصةً عندما يكون هناك عدد كبير من المكونات ، من السهل جدًا الخلط والحفاظ على سلامة مثل هذا الاتصال. على سبيل المثال ، إذا تغير اسم خاصية أو أسلوب في مكون واحد ، فسيتعين عليك إصلاحه في جميع المكونات التي تستخدم هذا. وهذا هو النزيف.
تحت خفض الكثير من الصورإنشاء حل يعتمد على "الترابط القوي" للمكونات
سننشئ مشروعًا فارغًا لإعادة إنتاج الموقف المعتاد عندما يكون لدينا بعض المكونات ويشير كل منها إلى الآخر ، لتلقي البيانات أو التحكم فيها.

أضفت
نصين ،
FirstComponent و
SecondComponent ، والذي سيتم استخدامه كمكونات في كائن اللعبة:

الآن سأحدد بنية بسيطة لكل مكون من العناصر اللازمة للتجارب.


الآن تخيل موقفًا نحتاج فيه إلى الحصول على قيم حقول
state1 من مكون
FirstComponent واستدعاء أسلوب
ChangeState (...) في مكون
SecondComponent . للقيام بذلك ، تحتاج إلى الحصول على ارتباط للمكون وطلب البيانات اللازمة في المكون
SecondComponent :

بعد أن نبدأ اللعبة في وحدة التحكم ، سيتبين أننا تلقينا بيانات من
FisrtComponent من
SecondComponent وقمنا بتغيير حالة الأول

الآن ، بنفس الطريقة تمامًا ، يمكننا الحصول على البيانات وفي الاتجاه المعاكس من مكون
FirstComponent للحصول على بيانات المكون
SecondComponent .

بعد بدء اللعبة ، سيكون من الواضح أيضًا أننا نتلقى البيانات ويمكننا التحكم في مكون
SecondComponent من
FirstComponent .

كان هذا مثالًا بسيطًا إلى حد ما ، ولكي نفهم نوع المشكلة التي أريد وصفها ، سيكون من الضروري تعقيد هيكل وعلاقات جميع المكونات إلى حد كبير ، ولكن المعنى واضح. الآن الاتصال بين المكونات كما يلي:


سيكون توسيع كائن حتى لعبة واحدة بمكونات جديدة ، إذا احتاج إلى التفاعل مع العناصر الموجودة ، أمرًا معتادًا. وخاصة إذا تغير ، على سبيل المثال ، اسم حقل الحالة 1 في مكون
FirstComponent ، على سبيل المثال ، إلى
state_1 وعليك تغيير الاسم حيث يتم استخدامه في جميع المكونات. أو عندما يحتوي المكون على عدد كبير جدًا من الحقول ، يصبح من الصعب للغاية التنقل فيها.
إنشاء حل يستند إلى "الحالة العامة" بين المكونات
تخيل الآن أننا لن نحتاج إلى الحصول على رابط لكل عنصر من عناصر الاهتمام والحصول على البيانات منه ، ولكن سيكون هناك كائن معين يحتوي على حالات وبيانات جميع المكونات في كائن اللعبة. في المخطط ، سيبدو كما يلي:

كائن الحالة العامة أو الحالة العامة (SharedState) هو أيضًا مكون يلعب دور مكون الخدمة ويخزن حالة جميع مكونات كائن اللعبة.
سأقوم بإنشاء مكون جديد وتسميته SharedState:

وسأحدد رمز هذا المكون العالمي. سيتم تخزين قاموس مفهرس وفهرس مغلقين للعمل الأكثر ملاءمة مع قاموس المكون ، وسيكون أيضًا مغلفًا ولن يعمل مباشرة مع القاموس من مكونات أخرى.

يجب الآن وضع هذا المكون على كائن اللعبة حتى تتمكن المكونات الأخرى من الوصول إليه:

بعد ذلك ، تحتاج إلى إجراء بعض التغييرات على مكونات
FirstComponent و
SecondComponent حتى يستخدموا مكون
SharedState لتخزين حالتهم أو بياناتهم:


كما ترون من رمز المكون ، لم نعد نخزن الحقل ، بل نستخدم الحالة العامة ونستطيع الوصول إلى بياناته باستخدام المفتاح "state1" أو "العداد". الآن لا ترتبط هذه البيانات بأي مكون ، وإذا ظهر مكون ثالث ، فسيتمكّن من الوصول إلى SharedState من الوصول إلى جميع هذه البيانات.
الآن ، لشرح تشغيل هذا النظام ، تحتاج إلى تغيير أساليب التحديث في كلا المكونين. في
FisrtComponent :

وفي المكون
الثاني المكون:

الآن لا تعرف المكونات أصل هذه القيم ، أي قبل أن تتحول إلى مكون معين للحصول عليها ، والآن يتم تخزينها ببساطة في مساحة مشتركة ويمكن لأي عنصر الوصول إليها.
بعد بدء اللعبة ، يمكنك أن ترى أن المكونات تحصل على القيم المطلوبة:

الآن بعد أن عرفنا كيف تعمل ، يمكننا استنباط البنية التحتية الأساسية للوصول إلى الحالة العامة في الفئة الأساسية ، حتى لا نفعل كل شيء في كل مكون على حدة:
وسأجعلها مجردة ، حتى لا يتم إنشاء مثيل لها عن طريق الخطأ ... وينصح أيضًا بإضافة سمة تشير إلى أن هذا المكون الأساسي يتطلب مكون
SharedState :

أنت الآن بحاجة إلى تغيير مكونات
FirstComponent و
SecondComponent بحيث
يرثونها من
SharedStateComponent وإزالة كافة
العناصر غير الضرورية:


حسنا ماذا عن طرق الاتصال؟ يُقترح القيام بذلك أيضًا بشكل غير مباشر ، ولكن من خلال نموذج الناشر-المشترك. المبسطة.
لتنفيذ ذلك ، تحتاج إلى إضافة مكون مشترك آخر ، على غرار المكون الذي يحتوي على البيانات ، فيما عدا أن هذا المكون سوف يحتوي على اشتراكات فقط
وسيُطلق عليه
SharedEvents :

المبدأ هو على النحو التالي. المكون الذي يريد استدعاء بعض الأساليب على مكون آخر لن يقوم بذلك مباشرة ، ولكن عن طريق استدعاء حدث ، بالاسم فقط ، حيث نحصل على بيانات من الحالة العامة.
يشترك كل مكون في بعض الأحداث التي يكون جاهزًا لتتبعها. وإذا أدرك هذا الحدث ، فإنه ينفذ المعالج ، والذي تم تعريفه في المكون نفسه.
إنشاء مكون
SharedEvents :

وسوف نحدد الهيكل اللازم لإدارة الاشتراكات والمنشورات.

لتبادل البيانات بين الاشتراكات والمنشورات ، يتم تعريف فئة أساسية ، وسيتم تحديد واحدة محددة لمؤلف كل حدث بشكل مستقل ، ثم سيتم تحديد عدة أمثلة:

تحتاج الآن إلى إضافة مكون جديد إلى كائن اللعبة:

قم بتوسيع الفئة الأساسية
SharedStateComponent قليلاً ثم قم بإضافة شرط أن يحتوي الكائن على
SharedEvents

بالإضافة إلى كائن الحالة العامة ، يجب الحصول على كائن الاشتراك العام من كائن اللعبة:


الآن نحدد اشتراك حدث ، والذي سنقوم
بمعالجته في
FisrtComponent وفئة لنقل البيانات من خلال هذا النوع من الأحداث ،
ونقوم أيضًا بتغيير
SecondComponent بحيث يتم نشر حدث هذا الاشتراك:


لقد اشتركنا الآن في أي حدث يسمى "writesomedata" في مكون
FirstComponent وقم ببساطة
بطباعة رسالة إلى وحدة التحكم عند حدوثها. وينشأ في هذا المثال عن طريق استدعاء نشر حدث باسم "writesomedata" في مكون
SecondComponent ونقل بعض المعلومات التي يمكن استخدامها في المكون الذي يمسك بالأحداث بهذا الاسم.
بعد بدء اللعبة في 5 ثوانٍ ، سنرى نتيجة معالجة الحدث في
FirstComponent :

ملخص
الآن ، إذا كنت بحاجة إلى توسيع مكونات كائن اللعبة هذا ، والتي ستستخدم أيضًا الحالة العامة والأحداث العامة ، فأنت بحاجة إلى إضافة فئة
ورثها ببساطة من
SharedStateComponent :
استمرار الموضوع