Advertisement
  1. Game Development
  2. Programming

استخدام نمط تصميم المركب لنظام سمات RPG

Scroll to top
Read Time: 13 min

Arabic (العربية/عربي) translation by Basrah (you can also view the original English article)

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

ملاحظة: على الرغم من كتابة هذا البرنامج التعليمي باستخدام Flash و AS3 ، يجب أن تكون قادرًا على استخدام نفس الأساليب والمفاهيم في أي بيئة تطوير ألعاب.


مقدمة

تُستخدم أنظمة السمات بشكل كبير في ألعاب RPGs لتحديد نقاط القوة والضعف والقدرات لدى الأشخاص. إذا لم تكن على دراية بها ، قم بقراءة صفحة ويكيبيديا للحصول على نظرة عامة لائقة.

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

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


ما هو النمط المركب؟

هذا القسم عبارة عن نظرة عامة على نمط التصميم المركب. إذا كنت تعرفه بالفعل ، فقد ترغب في تخطي 'نمذجة مشكلتنا'.

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

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

النموذج المركب هو المرشح المثالي لهذه الوظيفة. من خلال التعامل مع 'مجموعة من الرسومات' كرسومات بنفسه ، يمكن بسهولة إضافة أي رسم داخل هذه المجموعة ، وستظل المجموعة ككل تعتبر رسمًا واحدًا.

فيما يتعلق بالبرمجة ، سيكون لدينا طبقة أساسية واحدة ، الرسم ، والتي تحتوي على السلوكيات الافتراضية للرسم (يمكنك تحريكه ، تغيير الطبقات ، تدويره ، وهكذا) ، وأربع فئات فرعية ، مثلث ، مربع ، دائرة و مجموعة.

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

لأخذ هذا في تمثيل أفضل ، يمكننا عرض كل رسم كنقطة في شجرة. كل عقدة هي ورقة ، باستثناء العقد المجموعة ، والتي يمكن أن يكون لها أطفال - والتي هي بدورها رسومات داخل تلك المجموعة.


تمثيل مرئي للنمط

بالتمسك بمثال تطبيق الرسم ، هذا تمثيل مرئي لـ 'تطبيق الرسم' الذي فكرنا فيه. لاحظ أن هناك ثلاث رسومات في الصورة: مثلث ، مربع ومجموعة تتكون من دائرة ومربع:

Using the Composite Design Pattern for an RPG Attributes System

وهذا هو تمثيل الشجرة للمشهد الحالي (الجذر هو مرحلة تطبيق الرسم):

Using the Composite Design Pattern for an RPG Attributes System

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

Using the Composite Design Pattern for an RPG Attributes System

وهذا ما ستصبح الشجرة:

Using the Composite Design Pattern for an RPG Attributes SystemUsing the Composite Design Pattern for an RPG Attributes SystemUsing the Composite Design Pattern for an RPG Attributes System

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


نمذجة مشكلتنا

لكي نتمكن من تشكيل سماتنا في شجرة ، نحتاج إلى كسر كل سمة في أصغر الأجزاء التي نستطيعها.

نحن نعلم أن لدينا مكافآت ، والتي يمكن أن تضيف قيمة خام إلى السمة ، أو تزيدها بنسبة مئوية. هناك مكافآت تضيف إلى السمة ، والبعض الآخر الذي يتم حسابه بعد تطبيق كل تلك العلاوات الأولى (مكافآت من المهارات ، على سبيل المثال).

لذلك ، يمكننا الحصول على:

  • المكافآت الأولية (المضافة إلى القيمة الأولية للسمة)
  • المكافآت النهائية (إضافة إلى السمة بعد أن تم حساب كل شيء آخر)

المكافآت النهائية (إضافة إلى السمة بعد أن تم حساب كل شيء آخر) المكافآت النهائية (إضافة إلى السمة بعد أن تم حساب كل شيء آخر) هذا يعني أنه يمكننا الحصول على مكافأة تضيف 5 إلى القيمة وتزيد من السمة بنسبة 10٪. سيتم التعامل مع كل هذا في الكود.

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

ما زلنا لم نقم بإنشاء كيان يعمل كمجموعة. هذه الكيانات ستكون الصفات نفسها! سيكون تصنيف المجموعة في مثالنا ببساطة هو السمة نفسها. لذلك سيكون لدينا فئة سمة تتصرف مثل أي سمة.

هذه هي الطريقة التي يمكن أن تبدو بها شجرة السمات:

Using the Composite Design Pattern for an RPG Attributes SystemUsing the Composite Design Pattern for an RPG Attributes SystemUsing the Composite Design Pattern for an RPG Attributes System

والآن بعد أن تقرر كل شيء ، هل سنبدأ في شفرتنا؟


إنشاء الطبقات الأساسية

سنستخدم الإصدار ActionScript 3.0 كلغة البرمجية في هذا البرنامج التعليمي ، ولكن لا تقلق! سيتم التعليق الكامل على الكود بعد ذلك ، وسيتم شرح كل ما هو فريد للغة (ومنصة فلاش) وسيتم توفير البدائل - لذلك إذا كنت على دراية بأي لغة OOP ، فستتمكن من اتباع هذا البرنامج التعليمي دون مشاكل.

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

كما ترون ، الأمور بسيطة جداً في هذه الفئة الأساسية. نقوم فقط بإنشاء الحقول _value و _multiplier ، وتعيينها في المُنشئ ، وإنشاء طريقتَي getter ، واحدة لكل حقل.

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

RawBonus.as:

FinalBonus.as:

كما ترون ، هذه الفئات ليس لديها أي شيء فيها ولكن منشئ.


فئة السمة

ستكون فئة سمة مكافئة لمجموعة في نمط مركّب. يمكن أن يحمل أي مكافآت نهائية أو نهائية ، وسيكون لديه طريقة لحساب القيمة النهائية للسمة. نظرًا لأنه يمثل فئة فرعية من BaseAttribute ، سيكون حقل _baseValue للفئة هو قيمة البداية للسمة.

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

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

مع هذا الموضح ، دعونا نصل إلى الكود!

الأساليب addRawBonus () ، addFinalBonus () ، removeRawBonus () و removeFinalBonus () واضحة جدا. كل ما يفعلونه هو إضافة أو إزالة نوع المكافآت الخاص بهم إلى أو من المصفوفة التي تحتوي على جميع المكافآت من هذا النوع.

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

وننتهي مع الهيكل! تحقق من الخطوات التالية لمعرفة كيف تستخدمها وتمديدها.


سلوك إضافي: مكافآت موقوتة

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

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

من أجل القيام بذلك ، سنستخدم الفصل Timer. هذه الفئة هي أصلية من ActionScript 3.0 ، وكل ما يفعله هو تصرف مثل جهاز توقيت ، بدءا من 0 ثانية ثم استدعاء وظيفة محددة بعد فترة محددة من الوقت ، مع إعادة الضبط إلى 0 وبدء العد مرة أخرى ، حتى تصل إلى المحدد عدد التهم مرة أخرى. إذا لم تحددها ، فسيستمر تشغيل المؤقت حتى تقوم بإيقافه. يمكنك اختيار وقت بدء الموقت ومتى يتوقف. يمكنك تكرار سلوكه ببساطة عن طريق استخدام أنظمة توقيت اللغة الخاصة بك مع رمز إضافي مناسب ، إذا لزم الأمر.

دعونا نقفز إلى الشفرة!

في المنشئ ، الفرق الأول هو أن المكافآت النهائية تتطلب الآن معلمة زمنية ، والتي ستظهر إلى متى تستمر. داخل المُنشئ ، نقوم بإنشاء مؤقت لهذا القدر من الوقت (على افتراض أن الوقت بالمللي ثانية) ، وإضافة مستمع حدث إليه.

(المستمعون في الحدث هم أساسا ما سيجعل الموقت يستدعي الوظيفة الصحيحة عندما يصل إلى تلك الفترة الزمنية - في هذه الحالة ، الدالة المراد استدعاءها هي onTimerEnd ().)

لاحظ أننا لم نبدأ الموقت بعد. يتم ذلك في طريقة startTimer () ، والتي تتطلب أيضًا معلمة ، parent ، والتي يجب أن تكون سمة. تتطلب هذه الوظيفة السمة التي تضيف المكافأة لاستدعاء تلك الوظيفة لتنشيطها ؛ في المقابل ، يبدأ هذا الموقت ويخبر المكافأة التي يطلب منك حذف المكافأة عندما يصل الموقت إلى الحد الأقصى.

يتم إجراء جزء الإزالة في طريقة onTimerEnd () ، والتي ستطلب فقط من الوالد المحدد إزالته وإيقاف المؤقت.

الآن ، يمكننا استخدام المكافآت النهائية كمكافآت موقوتة ، مما يشير إلى أنها ستستمر لفترة زمنية محددة فقط.


سلوك إضافي: سمات تابعة

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

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

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

في Attribute.as:

كما ترون من خلال الخطوط المميزة ، كل ما قمنا به هو إنشاء applicationRawBonuses () و applyFinalBonuses () واستدعائهم عند حساب السمة النهائية في حساب VALUE (). نحن أيضا جعلنا محمية _finalValue ، حتى نتمكن من تغييرها في الفئات الفرعية.

الآن ، تم تعيين كل شيء بالنسبة لنا لإنشاء فئة DependantAttribute! هنا الرمز:

في هذه الفئة ، يجب أن تكون وظائف addAttribute () و removeAttribute () مألوفة لك. تحتاج إلى الانتباه إلى الدالة calculateValue () التي تم تجاوزها. هنا ، لا نستخدم السمات لحساب القيمة النهائية - تحتاج إلى القيام بذلك لكل سمة تابعة!

هذا مثال على كيفية القيام بذلك لحساب سرعة الهجوم:

في هذه الفئة ، نفترض أنك أضفت سمة البراعة بالفعل كطفل لـ AttackSpeed ​​، وأنه أول في صفيف _otherAttributes (يوجد الكثير من الافتراضات ؛ تحقق من الاستنتاج لمزيد من المعلومات). بعد استعادة البراعة ، نستخدمها ببساطة لإضافة المزيد إلى القيمة النهائية لسرعة الهجوم.


استنتاج

مع الانتهاء من كل شيء ، كيف تستخدم هذه البنية في اللعبة؟ الأمر بسيط للغاية: كل ما عليك فعله هو إنشاء سمات مختلفة وتعيين كل منها كمثال سمة. بعد ذلك ، يتعلق الأمر بإضافة وإضافة المكافآت إليه من خلال الأساليب التي تم إنشاؤها بالفعل.

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

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

مع أي نظام ، هناك دائما المزيد يمكنك إضافته. في ما يلي بعض التحسينات المقترحة التي يمكنك إجراؤها:

  • التعرف على السمات حسب الأسماء
  • قم بعمل نظام 'مركزي' لإدارة السمات
  • تحسين الأداء (تلميح: ليس عليك دائمًا حساب القيمة النهائية بالكامل)
  • تمكن بعض المكافآت من تخفيف أو تعزيز المكافآت الأخرى

Thanks for reading!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Game Development tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.