31 KiB
بناء لعبة الفضاء الجزء الثالث: إضافة الحركة
فكر في ألعابك المفضلة – ما يجعلها جذابة ليس فقط الرسومات الجميلة، بل الطريقة التي تتحرك بها وتستجيب لأفعالك. في الوقت الحالي، لعبتك الفضائية تشبه لوحة جميلة، لكننا على وشك إضافة الحركة التي ستجعلها تنبض بالحياة.
عندما قام مهندسو ناسا ببرمجة الكمبيوتر التوجيهي لمهام أبولو، واجهوا تحديًا مشابهًا: كيف تجعل المركبة الفضائية تستجيب لإدخال الطيار مع الحفاظ تلقائيًا على تصحيحات المسار؟ المبادئ التي سنتعلمها اليوم تعكس نفس المفاهيم – إدارة الحركة التي يتحكم بها اللاعب جنبًا إلى جنب مع سلوكيات النظام التلقائية.
في هذا الدرس، ستتعلم كيفية جعل السفن الفضائية تنزلق عبر الشاشة، تستجيب لأوامر اللاعب، وتخلق أنماط حركة سلسة. سنقسم كل شيء إلى مفاهيم قابلة للإدارة تبني على بعضها البعض بشكل طبيعي.
بحلول النهاية، سيكون لديك لاعبون يحلقون بسفينة البطل الخاصة بهم حول الشاشة بينما تقوم سفن العدو بدوريات في الأعلى. والأهم من ذلك، ستفهم المبادئ الأساسية التي تشغل أنظمة حركة الألعاب.
اختبار ما قبل المحاضرة
فهم حركة الألعاب
تنبض الألعاب بالحياة عندما تبدأ الأشياء في التحرك، وهناك طريقتان أساسيتان لحدوث ذلك:
- الحركة التي يتحكم بها اللاعب: عندما تضغط على مفتاح أو تنقر بالماوس، يتحرك شيء ما. هذا هو الاتصال المباشر بينك وبين عالم اللعبة.
- الحركة التلقائية: عندما تقرر اللعبة نفسها تحريك الأشياء – مثل سفن العدو التي تحتاج إلى القيام بدوريات على الشاشة سواء كنت تفعل شيئًا أم لا.
تحريك الأشياء على شاشة الكمبيوتر أبسط مما تعتقد. هل تتذكر تلك الإحداثيات x و y من فصل الرياضيات؟ هذا بالضبط ما نعمل به هنا. عندما تتبع غاليليو أقمار المشتري في عام 1610، كان يقوم بنفس الشيء – رسم المواقع بمرور الوقت لفهم أنماط الحركة.
تحريك الأشياء على الشاشة يشبه إنشاء رسوم متحركة لكتاب تقليب – تحتاج إلى اتباع هذه الخطوات الثلاث البسيطة:
- تحديث الموقع – تغيير مكان الكائن (ربما تحريكه 5 بكسلات إلى اليمين)
- مسح الإطار القديم – تنظيف الشاشة حتى لا ترى آثارًا شبحية في كل مكان
- رسم الإطار الجديد – وضع الكائن في موقعه الجديد
افعل ذلك بسرعة كافية، وها أنت ذا! لديك حركة سلسة تشعر بأنها طبيعية للاعبين.
إليك كيف يمكن أن يبدو ذلك في الكود:
// Set the hero's location
hero.x += 5;
// Clear the rectangle that hosts the hero
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Redraw the game background and hero
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);
ما يفعله هذا الكود:
- يحدث إحداثيات x الخاصة بالبطل بمقدار 5 بكسلات لتحريكه أفقيًا
- يمسح منطقة اللوحة بالكامل لإزالة الإطار السابق
- يملأ اللوحة بلون خلفية أسود
- يعيد رسم صورة البطل في موقعه الجديد
✅ هل يمكنك التفكير في سبب يجعل إعادة رسم بطلك عدة إطارات في الثانية قد يؤدي إلى تكاليف أداء؟ اقرأ عن بدائل لهذا النمط.
التعامل مع أحداث لوحة المفاتيح
هنا نربط إدخال اللاعب بحركة اللعبة. عندما يضغط شخص ما على مفتاح المسافة لإطلاق الليزر أو ينقر على مفتاح السهم لتجنب الكويكب، تحتاج لعبتك إلى اكتشاف هذا الإدخال والاستجابة له.
تحدث أحداث لوحة المفاتيح على مستوى النافذة، مما يعني أن نافذة المتصفح بأكملها تستمع لهذه الضغطات. من ناحية أخرى، يمكن ربط نقرات الماوس بعناصر محددة (مثل النقر على زر). بالنسبة للعبة الفضاء الخاصة بنا، سنركز على التحكم بلوحة المفاتيح لأنه يمنح اللاعبين ذلك الشعور الكلاسيكي لألعاب الأركيد.
هذا يذكرني بكيفية اضطرار مشغلي التلغراف في القرن التاسع عشر إلى ترجمة إدخال شفرة مورس إلى رسائل ذات معنى – نحن نفعل شيئًا مشابهًا، نترجم ضغطات المفاتيح إلى أوامر اللعبة.
للتعامل مع حدث تحتاج إلى استخدام طريقة addEventListener() الخاصة بالنافذة وتزويدها بمعاملين. المعامل الأول هو اسم الحدث، على سبيل المثال keyup. المعامل الثاني هو الوظيفة التي يجب استدعاؤها نتيجة لحدوث الحدث.
إليك مثال:
window.addEventListener('keyup', (evt) => {
// evt.key = string representation of the key
if (evt.key === 'ArrowUp') {
// do something
}
});
تفصيل ما يحدث هنا:
- يستمع لأحداث لوحة المفاتيح على النافذة بأكملها
- يلتقط كائن الحدث الذي يحتوي على معلومات حول المفتاح الذي تم الضغط عليه
- يتحقق مما إذا كان المفتاح المضغوط يطابق مفتاحًا معينًا (في هذه الحالة، السهم العلوي)
- ينفذ الكود عندما يتم استيفاء الشرط
بالنسبة لأحداث المفاتيح، هناك خاصيتان على الحدث يمكنك استخدامهما لمعرفة المفتاح الذي تم الضغط عليه:
key- هذا هو التمثيل النصي للمفتاح المضغوط، على سبيل المثال'ArrowUp'keyCode- هذا هو التمثيل الرقمي، على سبيل المثال37، يتوافق معArrowLeft
✅ التلاعب بأحداث المفاتيح مفيد خارج تطوير الألعاب. ما الاستخدامات الأخرى التي يمكنك التفكير فيها لهذه التقنية؟
المفاتيح الخاصة: تنبيه!
بعض المفاتيح لها سلوكيات مدمجة في المتصفح يمكن أن تتداخل مع لعبتك. مفاتيح الأسهم تقوم بتمرير الصفحة ومفتاح المسافة يقفز للأسفل – سلوكيات لا تريدها عندما يحاول شخص ما قيادة سفينته الفضائية.
يمكننا منع هذه السلوكيات الافتراضية وترك لعبتنا تتعامل مع الإدخال بدلاً من ذلك. هذا مشابه لكيفية اضطرار مبرمجي الكمبيوتر الأوائل إلى تجاوز مقاطعات النظام لإنشاء سلوكيات مخصصة – نحن فقط نفعل ذلك على مستوى المتصفح. إليك الطريقة:
const onKeyDown = function (e) {
console.log(e.keyCode);
switch (e.keyCode) {
case 37:
case 39:
case 38:
case 40: // Arrow keys
case 32:
e.preventDefault();
break; // Space
default:
break; // do not block other keys
}
};
window.addEventListener('keydown', onKeyDown);
فهم كود المنع هذا:
- يتحقق من رموز المفاتيح المحددة التي قد تسبب سلوكًا غير مرغوب فيه في المتصفح
- يمنع الإجراء الافتراضي للمتصفح لمفاتيح الأسهم ومفتاح المسافة
- يسمح للمفاتيح الأخرى بالعمل بشكل طبيعي
- يستخدم
e.preventDefault()لإيقاف سلوك المتصفح المدمج
الحركة الناتجة عن اللعبة
الآن دعونا نتحدث عن الكائنات التي تتحرك دون إدخال اللاعب. فكر في سفن العدو التي تجوب الشاشة، الرصاص الذي يطير في خطوط مستقيمة، أو السحب التي تنجرف في الخلفية. هذه الحركة التلقائية تجعل عالم لعبتك يبدو حيًا حتى عندما لا يلمس أحد عناصر التحكم.
نستخدم المؤقتات المدمجة في JavaScript لتحديث المواقع على فترات منتظمة. هذا المفهوم مشابه لكيفية عمل الساعات البندولية – آلية منتظمة تؤدي إلى إجراءات متسقة وموقوتة. إليك مدى بساطة ذلك:
const id = setInterval(() => {
// Move the enemy on the y axis
enemy.y += 10;
}, 100);
ما يفعله كود الحركة هذا:
- ينشئ مؤقتًا يعمل كل 100 مللي ثانية
- يحدث إحداثيات y الخاصة بالعدو بمقدار 10 بكسلات في كل مرة
- يخزن معرف الفاصل الزمني حتى نتمكن من إيقافه لاحقًا إذا لزم الأمر
- يحرك العدو للأسفل على الشاشة تلقائيًا
حلقة اللعبة
إليك المفهوم الذي يربط كل شيء معًا – حلقة اللعبة. إذا كانت لعبتك فيلمًا، فإن حلقة اللعبة ستكون جهاز العرض السينمائي، تعرض إطارًا بعد إطار بسرعة بحيث يبدو كل شيء وكأنه يتحرك بسلاسة.
كل لعبة لديها واحدة من هذه الحلقات تعمل خلف الكواليس. إنها وظيفة تقوم بتحديث جميع كائنات اللعبة، تعيد رسم الشاشة، وتكرر هذه العملية باستمرار. هذا يتتبع بطلك، جميع الأعداء، أي أشعة ليزر تطير – حالة اللعبة بأكملها.
هذا المفهوم يذكرني بكيفية اضطرار رسامي الأفلام الأوائل مثل والت ديزني إلى إعادة رسم الشخصيات إطارًا بعد إطار لإنشاء وهم الحركة. نحن نفعل الشيء نفسه، فقط باستخدام الكود بدلاً من الأقلام.
إليك كيف يمكن أن تبدو حلقة اللعبة، معبرًا عنها بالكود:
const gameLoopId = setInterval(() => {
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawHero();
drawEnemies();
drawStaticObjects();
}
gameLoop();
}, 200);
فهم هيكل حلقة اللعبة:
- يمسح اللوحة بالكامل لإزالة الإطار السابق
- يملأ الخلفية بلون صلب
- يرسم جميع كائنات اللعبة في مواقعها الحالية
- يكرر هذه العملية كل 200 مللي ثانية لإنشاء رسوم متحركة سلسة
- يدير معدل الإطارات عن طريق التحكم في توقيت الفاصل الزمني
متابعة لعبة الفضاء
الآن سنضيف الحركة إلى المشهد الثابت الذي قمت ببنائه سابقًا. سنقوم بتحويله من لقطة شاشة إلى تجربة تفاعلية. سنعمل على ذلك خطوة بخطوة لضمان بناء كل جزء على الآخر.
احصل على الكود من حيث توقفنا في الدرس السابق (أو ابدأ بالكود الموجود في مجلد Part II- starter إذا كنت بحاجة إلى بداية جديدة).
إليك ما نبنيه اليوم:
- تحكم البطل: ستقود مفاتيح الأسهم سفينتك الفضائية حول الشاشة
- حركة العدو: ستبدأ تلك السفن الفضائية الغريبة في التقدم
لنبدأ في تنفيذ هذه الميزات.
الخطوات الموصى بها
حدد الملفات التي تم إنشاؤها لك في المجلد الفرعي your-work. يجب أن يحتوي على ما يلي:
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
ابدأ مشروعك في مجلد your-work عن طريق كتابة:
cd your-work
npm start
ما يفعله هذا الأمر:
- ينتقل إلى دليل المشروع الخاص بك
- يبدأ خادم HTTP على العنوان
http://localhost:5000 - يخدم ملفات لعبتك حتى تتمكن من اختبارها في المتصفح
سيبدأ ما سبق خادم HTTP على العنوان http://localhost:5000. افتح متصفحًا وأدخل هذا العنوان، في الوقت الحالي يجب أن يعرض البطل وجميع الأعداء؛ لا شيء يتحرك - حتى الآن!
إضافة الكود
-
أضف كائنات مخصصة لـ
heroوenemyوgame object، يجب أن تحتوي على خصائصxوy. (تذكر الجزء الخاص بـ الوراثة أو التركيب).تلميح: يجب أن يكون
game objectهو الذي يحتوي علىxوyوالقدرة على رسم نفسه على اللوحة.نصيحة: ابدأ بإضافة فئة جديدة
GameObjectمع منشئها كما هو موضح أدناه، ثم ارسمها على اللوحة:class GameObject { constructor(x, y) { this.x = x; this.y = y; this.dead = false; this.type = ""; this.width = 0; this.height = 0; this.img = undefined; } draw(ctx) { ctx.drawImage(this.img, this.x, this.y, this.width, this.height); } }فهم هذه الفئة الأساسية:
- تعرف الخصائص المشتركة التي تشترك فيها جميع كائنات اللعبة (الموقع، الحجم، الصورة)
- تتضمن علامة
deadلتتبع ما إذا كان يجب إزالة الكائن - توفر طريقة
draw()التي تعرض الكائن على اللوحة - تحدد قيمًا افتراضية لجميع الخصائص التي يمكن للفئات الفرعية تجاوزها
الآن، قم بتمديد هذا
GameObjectلإنشاءHeroوEnemy:class Hero extends GameObject { constructor(x, y) { super(x, y); this.width = 98; this.height = 75; this.type = "Hero"; this.speed = 5; } }class Enemy extends GameObject { constructor(x, y) { super(x, y); this.width = 98; this.height = 50; this.type = "Enemy"; const id = setInterval(() => { if (this.y < canvas.height - this.height) { this.y += 5; } else { console.log('Stopped at', this.y); clearInterval(id); } }, 300); } }المفاهيم الرئيسية في هذه الفئات:
- ترث من
GameObjectباستخدام الكلمة المفتاحيةextends - تستدعي منشئ الوالد باستخدام
super(x, y) - تحدد أبعادًا وخصائص محددة لكل نوع من الكائنات
- تنفذ الحركة التلقائية للأعداء باستخدام
setInterval()
-
أضف معالجات أحداث المفاتيح للتعامل مع التنقل بالمفاتيح (تحريك البطل لأعلى/أسفل يسار/يمين)
تذكر أنه نظام ديكارتي، أعلى اليسار هو
0,0. أيضًا تذكر إضافة كود لإيقاف السلوك الافتراضينصيحة: قم بإنشاء وظيفة
onKeyDownالخاصة بك واربطها بالنافذة:const onKeyDown = function (e) { console.log(e.keyCode); // Add the code from the lesson above to stop default behavior switch (e.keyCode) { case 37: case 39: case 38: case 40: // Arrow keys case 32: e.preventDefault(); break; // Space default: break; // do not block other keys } }; window.addEventListener("keydown", onKeyDown);ما يفعله معالج الأحداث هذا:
- يستمع لأحداث الضغط على المفاتيح على النافذة بأكملها
- يسجل رمز المفتاح لمساعدتك في تصحيح الأخطاء ومعرفة المفاتيح التي يتم الضغط عليها
- يمنع السلوك الافتراضي للمتصفح لمفاتيح الأسهم ومفتاح المسافة
- يسمح للمفاتيح الأخرى بالعمل بشكل طبيعي
تحقق من وحدة التحكم في المتصفح في هذه المرحلة، وشاهد ضغطات المفاتيح التي يتم تسجيلها.
-
تنفيذ نمط النشر والاشتراك، سيحافظ هذا على نظافة الكود الخاص بك أثناء متابعة الأجزاء المتبقية.
يساعد نمط النشر والاشتراك في تنظيم الكود الخاص بك عن طريق فصل اكتشاف الأحداث عن معالجة الأحداث. هذا يجعل الكود الخاص بك أكثر تنظيمًا وأسهل في الصيانة.
للقيام بهذا الجزء الأخير، يمكنك:
-
إضافة مستمع حدث على النافذة:
window.addEventListener("keyup", (evt) => { if (evt.key === "ArrowUp") { eventEmitter.emit(Messages.KEY_EVENT_UP); } else if (evt.key === "ArrowDown") { eventEmitter.emit(Messages.KEY_EVENT_DOWN); } else if (evt.key === "ArrowLeft") { eventEmitter.emit(Messages.KEY_EVENT_LEFT); } else if (evt.key === "ArrowRight") { eventEmitter.emit(Messages.KEY_EVENT_RIGHT); } });
ما يفعله نظام الأحداث هذا:
- يكتشف إدخال لوحة المفاتيح ويحولها إلى أحداث لعبة مخصصة
- يفصل اكتشاف الإدخال عن منطق اللعبة
- يجعل من السهل تغيير عناصر التحكم لاحقًا دون التأثير على كود اللعبة
- يسمح لأنظمة متعددة بالاستجابة لنفس الإدخال
-
إنشاء فئة EventEmitter لنشر الرسائل والاشتراك فيها:
class EventEmitter { constructor() { this.listeners = {}; } on(message, listener) { if (!this.listeners[message]) { this.listeners[message] = []; } this.listeners[message].push(listener); } -
إضافة الثوابت وإعداد EventEmitter:
const Messages = { KEY_EVENT_UP: "KEY_EVENT_UP", KEY_EVENT_DOWN: "KEY_EVENT_DOWN", KEY_EVENT_LEFT: "KEY_EVENT_LEFT", KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT", }; let heroImg, enemyImg, laserImg, canvas, ctx, gameObjects = [], hero, eventEmitter = new EventEmitter();
فهم الإعداد:
- يعرف ثوابت الرسائل لتجنب الأخطاء الإملائية وجعل إعادة الهيكلة أسهل
- يعلن عن متغيرات الصور، سياق اللوحة، وحالة اللعبة
- ينشئ مرسل أحداث عالمي لنظام النشر والاشتراك
- يبدأ مصفوفة تحتوي على جميع كائنات اللعبة
-
تهيئة اللعبة
function initGame() { gameObjects = []; createEnemies(); createHero(); eventEmitter.on(Messages.KEY_EVENT_UP, () => { hero.y -= 5; }); eventEmitter.on(Messages.KEY_EVENT_DOWN, () => { hero.y += 5; }); eventEmitter.on(Messages.KEY_EVENT_LEFT, () => { hero.x -= 5; });
-
-
إعداد حلقة اللعبة
قم بإعادة صياغة وظيفة
window.onloadلتهيئة اللعبة وإعداد حلقة اللعبة على فاصل زمني مناسب. ستضيف أيضًا شعاع ليزر:window.onload = async () => { canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); heroImg = await loadTexture("assets/player.png"); enemyImg = await loadTexture("assets/enemyShip.png"); laserImg = await loadTexture("assets/laserRed.png"); initGame(); const gameLoopId = setInterval(() => { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); drawGameObjects(ctx); }, 100); };فهم إعداد اللعبة:
- ينتظر حتى يتم تحميل الصفحة بالكامل قبل البدء
- يحصل على عنصر اللوحة وسياق العرض ثنائي الأبعاد الخاص بها
- يحمل جميع موارد الصور بشكل غير متزامن باستخدام
await - يبدأ تشغيل حلقة اللعبة على فواصل زمنية قدرها 100 مللي ثانية (10 FPS)
- يمسح ويعيد رسم الشاشة بأكملها في كل إطار
-
أضف الكود لتحريك الأعداء على فاصل زمني معين
قم بإعادة صياغة وظيفة
createEnemies()لإنشاء الأعداء ودفعهم إلى فئة gameObjects الجديدة:function createEnemies() { const MONSTER_TOTAL = 5; const MONSTER_WIDTH = MONSTER_TOTAL * 98; const START_X = (canvas.width - MONSTER_WIDTH) / 2; const STOP_X = START_X + MONSTER_WIDTH; for (let x = START_X; x < STOP_X; x += 98) { for (let y = 0; y < 50 * 5; y += 50) { const enemy = new Enemy(x, y); enemy.img = enemyImg; gameObjects.push(enemy); } } }ما يفعله إنشاء الأعداء:
- يحسب المواقع لتوسيط الأعداء على الشاشة
- إنشاء شبكة من الأعداء باستخدام الحلقات المتداخلة
- تعيين صورة العدو لكل كائن عدو
- إضافة كل عدو إلى مصفوفة الكائنات العالمية الخاصة باللعبة
ثم أضف دالة createHero() لتنفيذ عملية مشابهة للبطل.
```javascript
function createHero() {
hero = new Hero(
canvas.width / 2 - 45,
canvas.height - canvas.height / 4
);
hero.img = heroImg;
gameObjects.push(hero);
}
```
ما الذي تفعله عملية إنشاء البطل:
- وضع البطل في أسفل منتصف الشاشة
- تعيين صورة البطل لكائن البطل
- إضافة البطل إلى مصفوفة الكائنات الخاصة باللعبة ليتم عرضه
وأخيرًا، أضف دالة drawGameObjects() لبدء عملية الرسم:
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
فهم وظيفة الرسم:
- التكرار عبر جميع الكائنات في المصفوفة
- استدعاء طريقة
draw()لكل كائن - تمرير سياق اللوحة حتى يتمكن الكائن من عرض نفسه
يجب أن يبدأ الأعداء بالتقدم نحو مركبة البطل الفضائية!
}
}
```
and add a `createHero()` function to do a similar process for the hero.
```javascript
function createHero() {
hero = new Hero(
canvas.width / 2 - 45,
canvas.height - canvas.height / 4
);
hero.img = heroImg;
gameObjects.push(hero);
}
```
وأخيرًا، أضف دالة drawGameObjects() لبدء عملية الرسم:
```javascript
function drawGameObjects(ctx) {
gameObjects.forEach(go => go.draw(ctx));
}
```
يجب أن يبدأ الأعداء بالتقدم نحو مركبة البطل الفضائية!
تحدي GitHub Copilot Agent 🚀
إليك تحدٍ لتحسين جودة لعبتك: إضافة حدود وتحكم سلس. حاليًا، يمكن للبطل الطيران خارج الشاشة، وقد تبدو الحركة غير سلسة.
مهمتك: اجعل مركبتك الفضائية تبدو أكثر واقعية من خلال تنفيذ حدود الشاشة وحركة سلسة. هذا مشابه لكيفية منع أنظمة التحكم في الطيران التابعة لناسا المركبات الفضائية من تجاوز حدود التشغيل الآمنة.
ما الذي يجب بناؤه: قم بإنشاء نظام يحافظ على مركبة البطل الفضائية داخل الشاشة، واجعل التحكم سلسًا. عندما يضغط اللاعبون على مفتاح السهم، يجب أن تنزلق المركبة باستمرار بدلاً من التحرك بخطوات منفصلة. فكر في إضافة تأثير بصري عندما تصل المركبة إلى حدود الشاشة – ربما تأثير بسيط يشير إلى حافة منطقة اللعب.
تعرف على المزيد حول وضع الوكيل هنا.
🚀 التحدي
تصبح تنظيم الكود أكثر أهمية مع نمو المشاريع. ربما لاحظت أن ملفك أصبح مزدحمًا بالوظائف والمتغيرات والفئات المختلطة معًا. هذا يذكرني بكيفية تنظيم المهندسين لكود مهمة أبولو لإنشاء أنظمة واضحة وقابلة للصيانة يمكن للفرق المتعددة العمل عليها في وقت واحد.
مهمتك:
فكر كمهندس برمجيات. كيف يمكنك تنظيم الكود الخاص بك بحيث بعد ستة أشهر من الآن، يمكنك (أو زميلك) فهم ما يحدث؟ حتى لو بقي كل شيء في ملف واحد الآن، يمكنك إنشاء تنظيم أفضل:
- تجميع الوظائف ذات الصلة معًا باستخدام عناوين تعليق واضحة
- فصل المهام - اجعل منطق اللعبة منفصلًا عن العرض
- استخدام تسميات متسقة للمتغيرات والوظائف
- إنشاء وحدات أو مساحات أسماء لتنظيم الجوانب المختلفة للعبة
- إضافة توثيق يشرح الغرض من كل قسم رئيسي
أسئلة للتفكير:
- ما هي الأجزاء الأكثر صعوبة في فهمها عند العودة إلى الكود؟
- كيف يمكنك تنظيم الكود لجعله أسهل لشخص آخر للمساهمة؟
- ماذا سيحدث إذا أردت إضافة ميزات جديدة مثل تعزيزات القوة أو أنواع مختلفة من الأعداء؟
اختبار ما بعد المحاضرة
المراجعة والدراسة الذاتية
لقد قمنا ببناء كل شيء من الصفر، وهو أمر رائع للتعلم، ولكن إليك سر صغير – هناك بعض أطر عمل JavaScript المذهلة التي يمكنها التعامل مع الكثير من العمل الشاق نيابةً عنك. بمجرد أن تشعر بالراحة مع الأساسيات التي غطيناها، من المفيد استكشاف ما هو متاح.
فكر في الأطر مثل امتلاك صندوق أدوات مجهز جيدًا بدلاً من صنع كل أداة يدويًا. يمكنها حل العديد من تحديات تنظيم الكود التي تحدثنا عنها، بالإضافة إلى تقديم ميزات قد تستغرق أسابيع لبنائها بنفسك.
أشياء تستحق الاستكشاف:
- كيف تنظم محركات الألعاب الكود – ستندهش من الأنماط الذكية التي يستخدمونها
- حيل الأداء لجعل ألعاب اللوحة تعمل بسلاسة فائقة
- ميزات JavaScript الحديثة التي يمكن أن تجعل الكود الخاص بك أنظف وأكثر قابلية للصيانة
- طرق مختلفة لإدارة الكائنات في اللعبة وعلاقاتها
الواجب
إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة ناتجة عن استخدام هذه الترجمة.