Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming

خلق الحياة: لعبة كونواي للحياة

by
Difficulty:IntermediateLength:LongLanguages:

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

في بعض الأحيان حتى مجموعة بسيطة من القواعد الأساسية يمكن أن تعطيك نتائج مثيرة للاهتمام للغاية. سنقوم في هذا البرنامج التعليمي ببناء المحرك الأساسي لعبة Conway's Life of the up.

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


المقدمة

لعبة Conway's of Life هي عبارة عن إنسان خلوي تم تصميمه في السبعينيات بواسطة عالم رياضي بريطاني يدعى جون كونواي.

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

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

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


خلق الخلايا

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

لا تتحرك الخلايا ، فهي تؤثر ببساطة على جيرانها استنادًا إلى حالتها الحالية.

الآن ، فيما يتعلق ببرمجة وظائفهم ، هناك ثلاثة سلوكيات نحتاجها لمنحهم:

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

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


الشبكة وقواعدها

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

القواعد بسيطة إلى حد ما:

  1. تموت أي خلية حية تضم أقل من جارين حيين ، كما لو كان ذلك بسبب نقص عدد السكان.
  2. يعيش أي خلية حية مع اثنين أو ثلاثة من الجيران الحي على الجيل القادم.
  3. تموت أي خلية حية تضم أكثر من ثلاثة جيران أحياء ، كما لو كانت بسبب الاكتظاظ.
  4. أي خلية ميتة مع ثلاثة من الجيران الحيين بالضبط تصبح خلية حية ، كما لو كانت عن طريق التكاثر.

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

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

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

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


تحديث الشبكة في خطوات زمنية منفصلة

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

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

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

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


رسم الشبكة

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

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

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


مضيفا منطق لعبة عالية المستوى

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

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

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

لذا ، دعونا نضيف بعض التعليمات البرمجية لإيقاف اللعبة مؤقتًا عند الضغط على مفتاح المسافة ، ومسح الشاشة إذا تم الضغط على backspace:

سيساعدنا أيضًا إذا أوضحنا بوضوح أن اللعبة متوقفة مؤقتًا ، لذلك عندما نكتب طريقة Draw الخاصة بنا ، دعنا نضيف بعض الشفرات لجعل الخلفية باللون الأحمر ، وكتابة 'متوقفة مؤقتًا' في الخلفية:

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


إضافة تحسينات

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

ابدأ بتعريف معدل التحديث و framerate بشكل منفصل في الفصل الرئيسي:

الآن ، عند تهيئة اللعبة ، استخدم framerate (FPS) لتحديد السرعة التي ستقرأ بها إدخال الماوس ورسمها ، والتي يجب أن تكون 60 FPS سلسًا على أقل تقدير:

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

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


اختتام

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

شكرا على القراءة ، آمل أن تكون قد تعلمت بعض الأشياء المفيدة اليوم!

Advertisement
Advertisement
Advertisement
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.