# بناء لعبة فضاء الجزء السادس: النهاية وإعادة التشغيل كل لعبة رائعة تحتاج إلى شروط نهاية واضحة وآلية إعادة تشغيل سلسة. لقد قمت ببناء لعبة فضاء مذهلة تتضمن الحركة والقتال وتسجيل النقاط - والآن حان الوقت لإضافة القطع النهائية التي تجعلها تبدو مكتملة. لعبتك حالياً تعمل بلا نهاية، مثل مسبارات "فوياجر" التي أطلقتها ناسا في عام 1977 - ولا تزال تسافر عبر الفضاء بعد عقود. بينما هذا مناسب لاستكشاف الفضاء، تحتاج الألعاب إلى نقاط نهاية محددة لتوفير تجربة مرضية. اليوم، سنقوم بتنفيذ شروط الفوز والخسارة بشكل صحيح ونظام إعادة التشغيل. بنهاية هذا الدرس، سيكون لديك لعبة مصقولة يمكن للاعبين إكمالها وإعادة لعبها، تماماً مثل ألعاب الأركيد الكلاسيكية التي شكلت هذا المجال. ## اختبار ما قبل المحاضرة [اختبار ما قبل المحاضرة](https://ff-quizzes.netlify.app/web/quiz/39) ## فهم شروط نهاية اللعبة متى يجب أن تنتهي لعبتك؟ هذا السؤال الأساسي شكل تصميم الألعاب منذ عصر الأركيد الأول. تنتهي لعبة "باك مان" عندما يتم الإمساك بك من قبل الأشباح أو عند تنظيف جميع النقاط، بينما تنتهي لعبة "غزاة الفضاء" عندما تصل الكائنات الفضائية إلى الأسفل أو عندما تدمرها جميعاً. بصفتك منشئ اللعبة، يمكنك تحديد شروط النصر والهزيمة. بالنسبة للعبة الفضاء الخاصة بنا، إليك بعض الأساليب المثبتة التي تخلق تجربة لعب ممتعة: - **تدمير `N` سفن العدو**: من الشائع تقسيم اللعبة إلى مستويات مختلفة حيث تحتاج إلى تدمير `N` سفن العدو لإكمال المستوى. - **تدمير سفينتك**: هناك بالتأكيد ألعاب تخسر فيها إذا تم تدمير سفينتك. نهج شائع آخر هو وجود مفهوم "الحياة". في كل مرة يتم تدمير سفينتك، يتم خصم حياة. بمجرد فقدان جميع الأرواح، تخسر اللعبة. - **جمع `N` نقاط**: شرط نهاية شائع آخر هو جمع النقاط. كيفية الحصول على النقاط يعتمد عليك، ولكن من الشائع تخصيص نقاط لأنشطة مختلفة مثل تدمير سفينة العدو أو جمع العناصر التي تسقطها السفن عند تدميرها. - **إكمال مستوى**: قد يتضمن ذلك عدة شروط مثل تدمير `X` سفن العدو، جمع `Y` نقاط، أو ربما جمع عنصر معين. ## تنفيذ وظيفة إعادة تشغيل اللعبة تشجع الألعاب الجيدة على إعادة اللعب من خلال آليات إعادة تشغيل سلسة. عندما يكمل اللاعبون اللعبة (أو يواجهون الهزيمة)، غالباً ما يرغبون في المحاولة مرة أخرى على الفور - سواء لتحسين درجاتهم أو أدائهم. لعبة "تيتريس" مثال مثالي على ذلك: عندما تصل الكتل إلى الأعلى، يمكنك بدء لعبة جديدة فوراً دون الحاجة إلى التنقل عبر قوائم معقدة. سنقوم ببناء نظام إعادة تشغيل مشابه يعيد ضبط حالة اللعبة بشكل نظيف ويعيد اللاعبين إلى العمل بسرعة. ✅ **تأمل**: فكر في الألعاب التي لعبتها. ما هي الظروف التي تنتهي فيها، وكيف يتم تحفيزك لإعادة التشغيل؟ ما الذي يجعل تجربة إعادة التشغيل سلسة مقابل محبطة؟ ## ما الذي ستبنيه ستقوم بتنفيذ الميزات النهائية التي تحول مشروعك إلى تجربة لعبة مكتملة. هذه العناصر تميز الألعاب المصقولة عن النماذج الأولية الأساسية. **إليك ما سنضيفه اليوم:** 1. **شرط الفوز**: دمر جميع الأعداء واحصل على احتفال مناسب (لقد استحققت ذلك!) 2. **شرط الهزيمة**: نفاد الأرواح ومواجهة الهزيمة مع شاشة الهزيمة 3. **آلية إعادة التشغيل**: اضغط على Enter للعودة مباشرة - لأن لعبة واحدة لا تكفي 4. **إدارة الحالة**: بداية جديدة في كل مرة - لا أعداء متبقين أو أخطاء غريبة من اللعبة السابقة ## البدء لنقم بإعداد بيئة التطوير الخاصة بك. يجب أن تكون جميع ملفات لعبة الفضاء الخاصة بك من الدروس السابقة جاهزة. **يجب أن يبدو مشروعك شيئاً مثل هذا:** ```bash -| assets -| enemyShip.png -| player.png -| laserRed.png -| life.png -| index.html -| app.js -| package.json ``` **ابدأ خادم التطوير الخاص بك:** ```bash cd your-work npm start ``` **هذا الأمر:** - يشغل خادم محلي على `http://localhost:5000` - يقدم ملفاتك بشكل صحيح - يقوم بالتحديث تلقائياً عند إجراء تغييرات افتح `http://localhost:5000` في متصفحك وتأكد من أن لعبتك تعمل. يجب أن تكون قادراً على التحرك، إطلاق النار، والتفاعل مع الأعداء. بمجرد التأكد، يمكننا المضي قدماً في التنفيذ. > 💡 **نصيحة احترافية**: لتجنب التحذيرات في Visual Studio Code، قم بتعريف `gameLoopId` في أعلى ملفك كـ `let gameLoopId;` بدلاً من تعريفه داخل وظيفة `window.onload`. هذا يتبع أفضل الممارسات الحديثة لتصريح المتغيرات في JavaScript. ## خطوات التنفيذ ### الخطوة 1: إنشاء وظائف تتبع شروط النهاية نحتاج إلى وظائف لمراقبة متى يجب أن تنتهي اللعبة. مثل أجهزة الاستشعار في محطة الفضاء الدولية التي تراقب الأنظمة الحرجة باستمرار، ستقوم هذه الوظائف بفحص حالة اللعبة بشكل مستمر. ```javascript function isHeroDead() { return hero.life <= 0; } function isEnemiesDead() { const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead); return enemies.length === 0; } ``` **ما الذي يحدث خلف الكواليس:** - **التحقق** إذا كانت حياة البطل قد انتهت (يا للأسف!) - **العد** لعدد الأعداء الذين لا يزالون على قيد الحياة - **الإرجاع** بـ `true` عندما يكون ساحة المعركة خالية من الأعداء - **الاستخدام** لمنطق بسيط يعتمد على صحيح/خطأ للحفاظ على الأمور واضحة - **التصفية** عبر جميع كائنات اللعبة للعثور على الناجين ### الخطوة 2: تحديث معالجات الأحداث لشروط النهاية الآن سنقوم بربط هذه الفحوصات بنظام الأحداث في اللعبة. في كل مرة يحدث تصادم، ستقوم اللعبة بتقييم ما إذا كان يؤدي إلى شرط نهاية. هذا يخلق ردود فعل فورية للأحداث الحرجة في اللعبة. ```javascript eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => { first.dead = true; second.dead = true; hero.incrementPoints(); if (isEnemiesDead()) { eventEmitter.emit(Messages.GAME_END_WIN); } }); eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => { enemy.dead = true; hero.decrementLife(); if (isHeroDead()) { eventEmitter.emit(Messages.GAME_END_LOSS); return; // loss before victory } if (isEnemiesDead()) { eventEmitter.emit(Messages.GAME_END_WIN); } }); eventEmitter.on(Messages.GAME_END_WIN, () => { endGame(true); }); eventEmitter.on(Messages.GAME_END_LOSS, () => { endGame(false); }); ``` **ما الذي يحدث هنا:** - **تصادم الليزر مع العدو**: يختفي كلاهما، تحصل على نقاط، ونتحقق إذا كنت قد فزت - **تصادم العدو معك**: تخسر حياة، ونتحقق إذا كنت لا تزال على قيد الحياة - **ترتيب ذكي**: نتحقق من الهزيمة أولاً (لا أحد يريد الفوز والخسارة في نفس الوقت!) - **ردود فعل فورية**: بمجرد حدوث شيء مهم، تعرف اللعبة بذلك ### الخطوة 3: إضافة ثوابت رسائل جديدة ستحتاج إلى إضافة أنواع رسائل جديدة إلى كائن الثوابت `Messages`. هذه الثو --- **إخلاء المسؤولية**: تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي [Co-op Translator](https://github.com/Azure/co-op-translator). بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.