جعل لعبة Match-3 في بناء 2: القضاء على المباريات السابقة الصنع
Arabic (العربية/عربي) translation by Aeni Amalia (you can also view the original English article)
في البرنامج التعليمي السابق وأخيراً وصلنا لدينا تتحرك اللعبة وإضافة الحركة إلى كتل لدينا. علاوة على ذلك، أنشأنا نظاما صعوبة بدائية لجعل اللعبة أكثر صعوبة كما اللاعب يلعب أطول.
مع كل من هذه الميزات في اللعبة ، نحن على استعداد لتنفيذ النظام الذي سيزيل المباريات المعدة مسبقاً من اللوحة. على الرغم من أن هذه ليست المقالة الأخيرة في هذه السلسلة ، إلا أن هذا هو النظام الرئيسي الأخير الذي نحتاج إلى تنفيذه - لذا كن مرتاحًا ، لأننا نعمل من أجلنا.
عرض لعبة النهائي
هنا هو عرض للعبة ونحن نعمل نحو طوال هذه السلسلة:
إصلاحات سريعة
قبل أن نبدأ بالجزء الرئيسي من هذا البرنامج التعليمي، أريد أن يستغرق ذلك دقيقة لحل المسألتين اكتشفت في حين أنني كنت كتابة البرنامج التعليمي السابق.
مطابقة
والمسألة الأولى وأنا أشير إلى يأتي في السيناريو يمكنك أن ترى أدناه:

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

إذا أننا لا يصلح هذا، سوف تتلقى اللاعب الائتمان والنقاط لعدد من المباريات أنها تهدف إلى جعل ابدأ، ويمكن أيضا خلط حول لماذا تختفي كتل كثيرة بشكل غير متوقع.
لحسن الحظ ، هذه مشكلة بسيطة لإصلاحها. لحل هذه المشكلة ، سنقوم بإنشاء متغير عالمي جديد يسمى MatchesPossible
والذي سيحدد ما إذا كان من الممكن إجراء تطابقات ، وحدث جديد سيكتشف متى يكون "السقوط" وسيقوم بتعديل MatchesPossible
لجعله لا يمكن لأي تطابقات يتم إجراؤها أثناء حدوث ذلك.
أولاً فإننا سنضع "المتغير العالمي":
Global Variable: MatchesPossible Type = Number Initial Value = 1
المتغير الجديد الخاص بك يجب أن تبدو مثل هذا:



الآن سوف نجعل الحدث الذي سيتم الاستماع لعند هبوط كتلة:
Event: Condition: Invert: Block>Is overlapping at offset Object = Block Offset X = 0 Offset Y = 8 Condition: Block>Compare Y Comparison = Less or equal Y co-ordinate = SPAWNY Action: System>Set value Variable = MatchesPossible Value = 1
هذا الحدث يجعل من ذلك أنه عندما يتم العثور على مساحة فارغة تحتها ، يتم تعيين MatchesPossible على 1
، مما يعني أن التطابقات غير ممكنة. ستلاحظ أيضا أن يتحقق من موقف Y من الكتلة. هذا هو لضمان الكتلة ليست في صف أدنى من القطع التي سوف دائماً مساحة فارغة تحتها.
بعد ذلك ، نحتاج إلى حدث يقوم بتعيين MKatchesPossible مرة أخرى إلى 0 عندما لا تحتوي أي كتل على مساحة فارغة أسفلها. سيستند هذا الحدث الثاني إلى شرط آخر:
Event: Condition: System>Else Action: System>Set value Variable = MatchesPossible Value = 0
تأكد من أن هذا الحدث يتبع مباشرة الحدث الأول بحيث يتم استخدام العبارة Else بشكل صحيح.
يجب أن يظهر الحدثان الجديدان لديك على النحو التالي:



وأخيرًا ، سنضيف شرطًا جديدًا إلى CheckMatches حتى يطلع على MatchesPossible لتحديد ما إذا كان من الممكن إجراء مطابقة. إضافة هذا الشرط إلى استدعاء الدالة الأولي من الأحداث CheckMatches.
Condition: System>Compare variable Variable = MatchesPossible Comparison = Equal to Vale = 0
عند إضافة الشرط ، يجب أن يظهر حدث CheckMatches الآن بالشكل التالي:



خلافا لمعظم المسائل التي واجهناها حتى هذه النقطة، تظهر هذه المشكلة على أساس غير متسقة إلى حد ما. وهذا يعني أننا لا نستطيع اختبار ما إذا كنا قد أصلحنا المشكلة أم لا ، يمكننا فقط اختبار ما إذا كنا قد تسببنا في أي مشاكل أخرى. إذا كنت تلعب اللعبة الآن ، يجب أن ترى أنه لم تحدث أي مشاكل جديدة بسبب هذا الشرط.
نقاط
المسألة الثانية التي أردت إصلاحها قبل إضافة أي شيء جديد تتعلق بنظام النقاط.
أثناء العمل في مشروع هذا البرنامج التعليمي ، لاحظت أن شيئًا قد تسببت في تصرف نظام Points بشكل غريب وإعطاء اللاعب أربعة أو خمسة أضعاف النقاط التي يجب أن يحصل عليها كل مباراة. على الرغم من أنني لم أتمكن من تحديد التغيير الذي قمت به ، فقد أدى ذلك إلى حدوث ذلك ، ووجدت أن سبب المشكلة هو أن وظيفة GivePoints قد تم الاتصال بها عدة مرات منذ عدم تدمير الكتل على الفور. لحسن الحظ ، مثل هذه القضية الأخيرة ، يمكن إصلاح هذا بسهولة.
لإصلاح هذا ، سنقوم بإنشاء متغير جديد سيخبر النظام ما إذا كان يمكنه إعطاء النقاط. وبعد ذلك ، عندما نكون على وشك استخدام وظيفة GivePoints ، سنقوم أيضًا بتعديل المتغير لضمان تنشيط الحدث مرة واحدة فقط. أخيرا، متى أعطيت النقاط أننا سوف تغيير المتغير مرة أخرى حيث أنه لن تكون هناك مشكلة في المرة القادمة ونحن في محاولة لإعطاء نقاط.
أولاً ، قم بإنشاء متغير عالمي يسمىin PotsGiven:
Global Variable: PointsGiven Type = Number Initial Value = 0
يجب أن يكون المتغير الخاص بك كما يلي:

بعد ذلك ، سنقوم بتعديل جزء وظيفة FindMatches التي تعطي النقاط بالفعل بإضافة شرط جديد وإجراءين جديدين.
Condition: System>Compare variable Variable = PointsGiven Comparison = Equal to Value = 0
الآن أضف هذا الإجراء إلى بداية قائمة الإجراء:
Action: System>Set value Variable = PointsGiven Value = 1
أخيرًا ، أضف هذا الإجراء إلى نهاية قائمة الإجراء:
Action: System>Set value Variable = PointsGiven Value = 0
يجب أن يظهر الحدث الآن على النحو التالي:



مع هذه التغييرات ، قمنا بعملها بحيث لا يتم تشغيل الحدث الذي يستدعي نقاط GivePoints إلا عندما يكون المتغير PointsGiven هو 0.
وبما أننا نقوم بتعيين القيمة فوراً إلى 1 ع
ند بدء الحدث ، فهذا يمنع الحدث من إطلاق أكثر من مرة ويضمن سيحصل اللاعب على العدد الصحيح من النقاط.
إذا قمت بتشغيل اللعبة عند هذه النقطة يجب أن تتلقى العدد الصحيح للنقاط لكل مباراة تجريها، حتى ولو كان عدم وجود هذه المشكلة لتبدأ.
إلغاء مباريات مسبقة الصنع
مع هذه التغييرات ، قمنا بعملها بحيث لا يتم تشغيل الحدث الذي يستدعي نقاط GivePoints إلا عندما يكون المتغير PointsGiven هو 0. وبما أننا نقوم بتعيين القيمة فوراً إلى 1 عند بدء الحدث ، فهذا يمنع الحدث من إطلاق أكثر من مرة ويضمن سيحصل اللاعب على العدد الصحيح من النقاط.......
المشكلة التي لدينا الآن أنه، نظراً للألوان كتلة عشوائية تماما، ليس من غير المألوف لتتمكن من بدء تشغيل اللعبة وانظر الحصول على الفور من حفنة من المباريات. هذا مشكلة لأنه يمكن جعل الثواني القليلة الأولى من اللعبة مربكة جداً بالنسبة لشخص الذي لم يلعب أمام، ونظرا لأنها تعطي نقاط لاعب لا يحصلون عليه.
لحل هذه المسألة، سوف نقوم بإنشاء دالة التي سوف ننظر في كل كتلة ومن ثم معرفة ما إذا كان هذا الكتلة نفس لون أي من جيرانها. إذا كان نفس اللون كأحد جيرانها، سوف تواصل تغيير لون تلك الكتلة حتى أنه لم يعد يطابق أي من الكتل المحيطة به.
ولجعل هذا النظام يعمل ، سيتعين علينا أيضًا إنشاء وظائف دعم متعددة والأحداث بالإضافة إلى إضافة متغير مثيل جديد إلى كائن الحظر.
مما يجعل من العمل
أولاً، قم بإنشاء متغير مثيل جديد لهذا الكائن من كتلة:
Instance Variable: BlockID Type = Number Initial value = 0
هذا المتغير هو ما سنستخدمه لتحديد كتلة بسهولة حتى نتمكن من إخبار بعض الوظائف التي سنقوم بعملها بالضبط ما نريد أن ننظر إليه ، بغض النظر عن موقعه.
قبل الانتقال ، نحتاج أيضًا إلى البدء في استخدام هذا المتغير. انتقل إلى "بدء تشغيل" الحدث "تخطيط" الذي يقوم بإنشاء الكتل وإضافة إجراء جديد قبل الإجراء الذي يزيد NumBlocks:
Action:Block>Set value Instance variable = BlockID Value = NumBlocks
يجب أن يكون حدث حظر التفريخ الآن كما يلي:



القادم نحن بحاجة لجعل دالة التي سوف تتخذ في موقف كتلة X و Y ويقول لنا ما هو اللون الذي منع:
Event: Condition: Function>On function Name = "GetBlockColor" Sub-Event: Condition: Block>Compare X Comparison = Equal to X co-ordinate = Function.Param(0) Condition: Block>Compare Y Comparison = Equal to Y co-ordinate = Function.Param(0) Action: Function>Set return value Value = Block.Color Sub-Event: System>Else Action: Function>Set return value Value = -1
يجب أن تبدو الدالة مثل هذا عند الانتهاء من ذلك:



الآن أن لدينا دالة التي يمكن أن يقول لنا لون أي كتلة، سنقوم بإنشاء الدالة التي سوف ننظر في كتلة الواقع وتحديد ما إذا كانت أي كتل المجاورة التي هي بنفس اللون.
الطريقة التي سوف تعمل هذه الدالة بسيط جداً.
- أولاً ، سنمرر على BlockID في الوظيفة.
- إذا كانت هناك كتلة مع هذا الـ BlockID حاليًا ، ستنظر الدالة إلى الكتل الأربعة المجاورة ، وستحدد ما إذا كانت الكتلة التي ينظر إليها هي نفس اللون مثل أي من جيرانها.
- إذا وجد أن هناك جاره من نفس اللون، أنها سوف تبدأ في تغيير لون الكتلة أنها تبحث في، وأنها سوف تواصل تغيير اللون حتى يصبح الكتلة لون مختلف من جميع جيرانها.
قبل أن يمكننا أن نجعل هذا الحدث، علينا جعل "المتغيرات العالمية" الجديدة. في الدالة سوف نستخدم حين تنفيذ حلقة مستمرة لتحديد ما إذا كان لون الكتلة يحتاج إلى تغيير. هو المتغير نحن على وشك إنشاء المتغير حلقة While سوف تستخدم لتحديد ما إذا كان من الضروري مواصلة تشغيل:
Global Variable: HasMatchingNeighbor Type = Number Initial Value = 0
تلميح: يحتوي الحدث الذي سنقوم بإنشائه على حدث Or-based. إذا لم تقم أبدًا بإنشاء إحدى مجموعات الأحداث التي تحتوي على سمة "أو" ، فكل ما عليك فعله هو جعل "منع الأحداث" كما تفعل عادة ، ثم النقر بزر الماوس الأيمن فوق الحظر بالكامل واختيار "أو" حظر. وخلافا "كتلة الحدث" القياسية التي تتطلب كافة الشروط الواجب ملؤها قبل أن كان سيتم إطلاق النار، النار كتلة أو إذا يتم استيفاء أي شرط.
لذا، دعونا نجعل الحدث:
Event: Condition: Function>On function Name = "RemoveSpawnedMatches" Sub-Event: Condition: Block>Compare instance variable Instance variable = BlockID Comparison = Equal to Value = Function.param(0) Action: System> Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition: System> While Condition: System>Compare variable Variable = HasMatchingNeighbor Comparison = Equal to Value = 1 Sub-Event: Condition: Block>Compare instance variable Instance variable = Color Comparison = Equal to Value = Function.Call("GetBlockColor", Block.X - (Block.Width + 2), Block.Y) Action: Block>Set value Instance variable = Color Value = floor(Random(1,7)) Action: System>Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition: System>Else Condition: Block>Compare instance variable Instance variable = Color Comparison = Equal to Value = Function.Call("GetBlockColor", Block.X + (Block.Width + 2), Block.Y) Action: Block>Set value Instance variable = Color Value = floor(Random(1,7)) Action: System>Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition: System>Else Condition: Block>Compare instance variable Instance variable = Color Comparison = Equal to Value = Function.Call("GetBlockColor", Block.X, Block.Y - (Block.Width + 2)) Action: Block>Set value Instance variable = Color Value = floor(Random(1,7)) Action: System>Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition: System>Else Condition: Block>Compare instance variable Instance variable = Color Comparison = Equal to Value = Function.Call("GetBlockColor", Block.X, Block.Y + (Block.Width + 2)) Action: Block>Set value Instance variable = Color Value = floor(Random(1,7)) Action: System>Set value Variable = HasMatchingNeighbor Value = 1 Sub-Event: Condition: System>Else Action: System>Set value Variable = HasMatchingNeighbor Value = 0
الحدث الخاص بك ينبغي أن تبدو مثل هذا:



فكيف يعمل هذه الوظيفة بالضبط؟
أول شيء يفعله هو التحقق من وجود كتلة مع BlockID الذي تم تمرير النظام إليه. عندما يحدد موقع ذلك الحظر يقوم بتعيين قيمة HasMatchingNeighbors إلى 1
ثم يتم تشغيل حلقة While.
نظرًا لأن حلقة While سيتم تشغيلها فقط عندما يكون HasMatchingNeighbors هو 1 ، فذلك هو القيمة التي تعيّنها. أثناء حلقة While ، يتم اختبار لمعرفة ما إذا كان هناك كتلة مجاورة إلى اليسار أو اليمين أو فوق أو أسفل هذا هو نفس لون الكتلة التي ننظر إليها. إذا عثرت على كتلة مطابقة في أي من هذه المواضع ، فإنها تقوم بتعيين لون جديد إلى الكتلة بشكل عشوائي ثم تقوم بتشغيل الاختبار مرة أخرى من خلال التأكد من تعيين HasMatchingNeighbors على 1
. عندما يجد لونًا للحجر الذي لا يتطابق مع أي لون. من جيرانه ، فإنه يغير قيمة HasMatchingNeighbors إلى 0 بحيث ينتهي حلقة While ويمكن للبرنامج الانتقال
الآن نحن بحاجة لتنفيذ هذه الوظيفة في اللعبة؛ للقيام بذلك ونحن ستكون لدينا لإنشاء متغيرات جديدة اثنين واثنين من وظائف جديدة. دعونا نبدأ مع المتغيرات.
Global Variable: CheckStartingMatches Type = Number Value = 0
Global Variable: CheckNewestRow Type = Number Value = 0
المتغيرات الخاصة بك يجب أن تبدو مثل هذا:

سيتم استخدام المتغيرين اللذين أجرينا للتو للتوصل إلى الحدثين اللذين نحن بصدد إنشاءهما. سيتم استخدام الأحداث نفسها للتكرار خلال الكتل مباشرة بعد إنشائها وإرسال كل كتلة في وظيفة RemoveSpawnedMatches.
السبب في أننا لا ندعو الدالة RemoveSpawnedMatches بعد إنشاء الكتلة مباشرة ، لأن شبكة الكتلة يجب أن تكون كاملة لكي تعمل الدالة بشكل صحيح. لذلك ، بدلاً من مجرد استدعاء الوظيفة مباشرة عند إنشاء الكتل ، سنقوم بدلاً من ذلك بتشغيل حدث يمكن أن يمر عبر الكتل واستدعاء الدالة على نفسها بعد إنشاء الشبكة.
سيكون الحدث الأول على وجه التحديد للتكرار من خلال المجموعة الأولى من كتل:
Event: Condition: System>Compare variable Instance variable = CheckStartingMatches Comparison = Equal to Value = 1 Condition: System>For Name = "Blocks" Start index = 0 End index = NumBlocks-1 Action: Function>Call function Name = "RemoveSpawnedMatches" Parameter 0 = loopindex("Blocks") SubEvent: Condition: System>Compare two values First value = loopindex("Blocks") Comparison = Equal to Second value = NumBlocks-1 Action: System>Set variable Instance variable = CheckStartingMatches Value = 0
وهذا ما ينبغي أن تبدو وكأنها الحدث الخاص بك:



والحدث الثاني سيكون خصيصا للتحقق من صفوف جديدة من كتل عندما أنها مصنوعة:
Event: Condition: System>Compare variable Instance variable = CheckNewestRow Comparison = Equal to Value = 1 Condition: System>For Name = "Blocks" Start index = NumBlocks-9 End index = NumBlocks-1 Action: Function>Call function Name = "RemoveSpawnedMatches" Parameter 0 = loopindex("Blocks") SubEvent: Condition: System>Compare two values First value = loopindex("Blocks") Comparison = Equal to Second value = NumBlocks-1 Action: System>Set variable Instance variable = CheckNewestRow Value = 0
وهذا ما ينبغي أن تبدو وكأنها الحدث الثاني:



تنفيذ
مع كل من هذه الوظائف في مكانها نحن الآن بحاجة فقط إلى تنفيذها. انتقل إلى الحدث الأولي الذي يجعل الكتل ، في بداية الحدث المخطط. سنقوم بإضافة حدث فرعي إلى هذا الأمر الذي سيُعلم بتنشيط حدث CheckStartingMatches.
Sub-Event: Condition: System>Compare two values First value = loopindex("X") Comparison Second value: 7 Condition: System>Compare two values First value = loopindex("Y") Comparison Second value: 3 Action: System>Set value Instance variable = CheckStartingMatches Value = 1
الآن يجب أن تبدو الحدث الخاص بك مثل هذا:



يستمع الحدث الفرعي الخاص به عندما تنتهي حلقة For المتداخلة ، ثم يغير قيمة المتغير CheckStartingMatches لتنشيط الحدث المناسب.
سنقوم الآن بإجراء نفس الحدث الفرعي نفسه وإرفاقه بوظيفة SpawnNewBlocks.
Sub-Event: Condition: System>Compare two values First value = loopindex("X") Comparison Second value: 7 Action: System>Set value Instance variable = CheckNewestRow Value = 1
الآن يجب أن تبدو سباونيوبلوكس كما يلي:



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