21 KiB
بناء لعبة فضاء الجزء الثاني: رسم البطل والوحوش على اللوحة
تُعد واجهة برمجة التطبيقات الخاصة بـ Canvas واحدة من أقوى ميزات تطوير الويب لإنشاء رسومات ديناميكية وتفاعلية مباشرة في متصفحك. في هذا الدرس، سنحوّل عنصر HTML <canvas> الفارغ إلى عالم لعبة مليء بالأبطال والوحوش. فكر في اللوحة كلوحة فنية رقمية حيث يتحول الكود إلى صورة.
نحن نبني على ما تعلمته في الدرس السابق، والآن سنتعمق في الجوانب البصرية. ستتعلم كيفية تحميل وعرض صور اللعبة، وضع العناصر بدقة، وإنشاء الأساس البصري للعبة الفضاء الخاصة بك. هذا يربط بين صفحات الويب الثابتة والتجارب الديناميكية والتفاعلية.
بنهاية هذا الدرس، سيكون لديك مشهد لعبة كامل مع سفينة البطل في موقعها الصحيح وتشكيلات الأعداء جاهزة للمعركة. ستفهم كيف تقوم الألعاب الحديثة بعرض الرسومات في المتصفحات وستكتسب مهارات لإنشاء تجارب بصرية تفاعلية خاصة بك. دعونا نستكشف رسومات اللوحة ونُحيي لعبة الفضاء الخاصة بك!
اختبار ما قبل المحاضرة
اللوحة
ما هو بالضبط عنصر <canvas>؟ إنه حل HTML5 لإنشاء رسومات ديناميكية ورسوم متحركة في متصفحات الويب. على عكس الصور أو الفيديوهات العادية التي تكون ثابتة، تمنحك اللوحة التحكم على مستوى البكسل في كل ما يظهر على الشاشة. هذا يجعلها مثالية للألعاب، التصورات البيانية، والفن التفاعلي. فكر فيها كسطح رسم قابل للبرمجة حيث يصبح JavaScript فرشاة الرسم الخاصة بك.
بشكل افتراضي، يظهر عنصر اللوحة كأنه مستطيل فارغ وشفاف على صفحتك. لكن هنا تكمن الإمكانيات! تظهر قوتها الحقيقية عندما تستخدم JavaScript لرسم الأشكال، تحميل الصور، إنشاء الرسوم المتحركة، وجعل الأشياء تستجيب لتفاعلات المستخدم. يشبه ذلك الطريقة التي كان رواد الرسومات الحاسوبية في مختبرات Bell في الستينيات يبرمجون كل بكسل لإنشاء الرسوم المتحركة الرقمية الأولى.
✅ اقرأ المزيد عن واجهة برمجة التطبيقات الخاصة باللوحة على MDN.
هكذا يتم عادةً إعلانها كجزء من جسم الصفحة:
<canvas id="myCanvas" width="200" height="100"></canvas>
ما الذي يفعله هذا الكود:
- يحدد خاصية
idحتى تتمكن من الإشارة إلى هذا العنصر المحدد في JavaScript - يحدد العرض بالبكسل للتحكم في حجم اللوحة الأفقي
- يحدد الارتفاع بالبكسل لتحديد أبعاد اللوحة العمودية
رسم أشكال هندسية بسيطة
الآن بعد أن تعرفت على عنصر اللوحة، دعنا نستكشف كيفية الرسم عليه! تستخدم اللوحة نظام إحداثيات قد يبدو مألوفًا من دروس الرياضيات، ولكن هناك نقطة مهمة تختلف عن الرسومات الحاسوبية.
تستخدم اللوحة إحداثيات ديكارتية مع محور x (أفقي) ومحور y (عمودي) لتحديد موضع كل ما ترسمه. ولكن هنا الفرق الرئيسي: على عكس نظام الإحداثيات في الرياضيات، تبدأ نقطة الأصل (0,0) في الزاوية العلوية اليسرى، مع زيادة قيم x عند التحرك يمينًا وزيادة قيم y عند التحرك للأسفل. هذا النهج يعود إلى شاشات الكمبيوتر المبكرة حيث كانت أشعة الإلكترون تمسح من الأعلى إلى الأسفل، مما يجعل الزاوية العلوية اليسرى نقطة البداية الطبيعية.
الصورة من MDN
لترسم على عنصر اللوحة، ستتبع نفس العملية المكونة من ثلاث خطوات التي تشكل أساس جميع رسومات اللوحة. بمجرد القيام بذلك عدة مرات، يصبح الأمر طبيعيًا:
- الحصول على مرجع لعنصر اللوحة الخاص بك من DOM (مثل أي عنصر HTML آخر)
- الحصول على سياق الرسم ثنائي الأبعاد – هذا يوفر جميع طرق الرسم
- ابدأ الرسم! استخدم الطرق المدمجة في السياق لإنشاء رسوماتك
هكذا يبدو ذلك في الكود:
// Step 1: Get the canvas element
const canvas = document.getElementById("myCanvas");
// Step 2: Get the 2D rendering context
const ctx = canvas.getContext("2d");
// Step 3: Set fill color and draw a rectangle
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 200, 200); // x, y, width, height
دعونا نوضح هذا خطوة بخطوة:
- نحن نحصل على عنصر اللوحة باستخدام معرفه ونخزنه في متغير
- نحن نحصل على سياق الرسم ثنائي الأبعاد – هذا هو صندوق الأدوات المليء بطرق الرسم
- نحن نخبر اللوحة أننا نريد ملء الأشياء باللون الأحمر باستخدام خاصية
fillStyle - نحن نرسم مستطيلًا يبدأ من الزاوية العلوية اليسرى (0,0) بعرض وارتفاع 200 بكسل
✅ تركز واجهة برمجة التطبيقات الخاصة باللوحة بشكل أساسي على الأشكال ثنائية الأبعاد، ولكن يمكنك أيضًا رسم عناصر ثلاثية الأبعاد على موقع ويب؛ لهذا، قد تستخدم واجهة برمجة تطبيقات WebGL.
يمكنك رسم العديد من الأشياء باستخدام واجهة برمجة التطبيقات الخاصة باللوحة مثل:
- الأشكال الهندسية، لقد أظهرنا بالفعل كيفية رسم مستطيل، ولكن هناك المزيد مما يمكنك رسمه.
- النصوص، يمكنك رسم نص بأي خط ولون ترغب فيه.
- الصور، يمكنك رسم صورة بناءً على أصل صورة مثل .jpg أو .png على سبيل المثال.
✅ جربها! تعرف كيفية رسم مستطيل، هل يمكنك رسم دائرة على الصفحة؟ ألقِ نظرة على بعض الرسومات المثيرة للاهتمام باستخدام اللوحة على CodePen. إليك مثال مثير للإعجاب.
تحميل ورسم أصل صورة
رسم الأشكال الأساسية مفيد للبدء، ولكن معظم الألعاب تحتاج إلى صور فعلية! الصور الرمزية، الخلفيات، والقوام هي ما يمنح الألعاب جاذبيتها البصرية. يختلف تحميل وعرض الصور على اللوحة عن رسم الأشكال الهندسية، ولكنه بسيط بمجرد فهم العملية.
نحتاج إلى إنشاء كائن Image، تحميل ملف الصورة الخاص بنا (يحدث هذا بشكل غير متزامن، بمعنى "في الخلفية")، ثم رسمه على اللوحة بمجرد أن يكون جاهزًا. يضمن هذا النهج عرض الصور بشكل صحيح دون تعطيل التطبيق أثناء تحميلها.
تحميل الصور الأساسي
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// Image loaded and ready to be used
console.log('Image loaded successfully!');
};
ما الذي يحدث في هذا الكود:
- نحن ننشئ كائن صورة جديد تمامًا لحفظ الصورة الرمزية أو القوام
- نحن نخبره أي ملف صورة يجب تحميله عن طريق تحديد مسار المصدر
- نحن نستمع لحدث التحميل حتى نعرف بالضبط متى تكون الصورة جاهزة للاستخدام
طريقة أفضل لتحميل الصور
إليك طريقة أكثر قوة للتعامل مع تحميل الصور يستخدمها المطورون المحترفون عادةً. سنقوم بتغليف منطق تحميل الصور في وظيفة تعتمد على الوعد – هذا النهج، الذي أصبح شائعًا عندما أصبحت وعود JavaScript معيارًا في ES6، يجعل الكود الخاص بك أكثر تنظيمًا ويتعامل مع الأخطاء بشكل أنيق:
function loadAsset(path) {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = path;
img.onload = () => {
resolve(img);
};
img.onerror = () => {
reject(new Error(`Failed to load image: ${path}`));
};
});
}
// Modern usage with async/await
async function initializeGame() {
try {
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Images are now ready to use
} catch (error) {
console.error('Failed to load game assets:', error);
}
}
ما الذي قمنا به هنا:
- غلفنا كل منطق تحميل الصور في وعد حتى نتمكن من التعامل معه بشكل أفضل
- أضفنا معالجة الأخطاء التي تخبرنا فعليًا عندما يحدث خطأ ما
- استخدمنا بناء الجملة الحديث async/await لأنه أكثر وضوحًا للقراءة
- أدرجنا كتل try/catch للتعامل بشكل أنيق مع أي مشاكل في التحميل
بمجرد تحميل الصور الخاصة بك، فإن رسمها على اللوحة يكون في الواقع بسيطًا جدًا:
async function renderGameScreen() {
try {
// Load game assets
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Get canvas and context
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// Draw images to specific positions
ctx.drawImage(heroImg, canvas.width / 2, canvas.height / 2);
ctx.drawImage(monsterImg, 0, 0);
} catch (error) {
console.error('Failed to render game screen:', error);
}
}
دعونا نوضح هذا خطوة بخطوة:
- نحن نحمل صور البطل والوحش في الخلفية باستخدام await
- نحن نحصل على عنصر اللوحة ونحصل على سياق الرسم ثنائي الأبعاد الذي نحتاجه
- نحن نضع صورة البطل في المنتصف باستخدام بعض الرياضيات السريعة للإحداثيات
- نحن نضع صورة الوحش في الزاوية العلوية اليسرى لبدء تشكيل الأعداء
- نحن نلتقط أي أخطاء قد تحدث أثناء التحميل أو العرض
الآن حان الوقت لبدء بناء لعبتك
الآن سنجمع كل شيء معًا لإنشاء الأساس البصري للعبة الفضاء الخاصة بك. لديك فهم قوي لأساسيات اللوحة وتقنيات تحميل الصور، لذا فإن هذا القسم العملي سيرشدك خلال بناء شاشة لعبة كاملة مع صور موضوعة بشكل صحيح.
ما الذي ستبنيه
ستقوم ببناء صفحة ويب تحتوي على عنصر لوحة. يجب أن تعرض شاشة سوداء 1024*768. لقد وفرنا لك صورتين:
الخطوات الموصى بها لبدء التطوير
حدد ملفات البداية التي تم إنشاؤها لك في مجلد your-work. يجب أن يحتوي هيكل المشروع الخاص بك على:
your-work/
├── assets/
│ ├── enemyShip.png
│ └── player.png
├── index.html
├── app.js
└── package.json
ما الذي تعمل عليه:
- صور اللعبة موجودة في مجلد
assets/حتى يبقى كل شيء منظمًا - ملف HTML الرئيسي الخاص بك يجهز عنصر اللوحة ويجهز كل شيء
- ملف JavaScript حيث ستكتب كل سحر عرض اللعبة الخاص بك
- ملف package.json الذي يجهز خادم تطوير حتى تتمكن من الاختبار محليًا
افتح هذا المجلد في Visual Studio Code لبدء التطوير. ستحتاج إلى بيئة تطوير محلية مع Visual Studio Code، NPM، وNode.js مثبتة. إذا لم يكن لديك npm مثبتًا على جهاز الكمبيوتر الخاص بك، إليك كيفية تثبيته.
ابدأ خادم التطوير الخاص بك بالتنقل إلى مجلد your-work:
cd your-work
npm start
هذا الأمر يقوم ببعض الأشياء الرائعة:
- يبدأ خادمًا محليًا على
http://localhost:5000حتى تتمكن من اختبار لعبتك - يخدم جميع ملفاتك بشكل صحيح حتى يتمكن متصفحك من تحميلها بشكل صحيح
- يراقب ملفاتك للتغييرات حتى تتمكن من التطوير بسلاسة
- يوفر لك بيئة تطوير احترافية لاختبار كل شيء
💡 ملاحظة: سيعرض متصفحك صفحة فارغة في البداية – هذا متوقع! أثناء إضافة الكود، قم بتحديث متصفحك لرؤية التغييرات. هذا النهج التطويري التكراري مشابه للطريقة التي بنت بها ناسا كمبيوتر التوجيه الخاص بأبولو – اختبار كل مكون قبل دمجه في النظام الأكبر.
إضافة الكود
أضف الكود المطلوب إلى your-work/app.js لإكمال المهام التالية:
-
رسم لوحة بخلفية سوداء
💡 كيف: ابحث عن TODO في
/app.jsوأضف سطرين فقط. قم بتعيينctx.fillStyleإلى الأسود، ثم استخدمctx.fillRect()بدءًا من (0,0) بأبعاد اللوحة الخاصة بك. سهل! -
تحميل قوام اللعبة
💡 كيف: استخدم
await loadAsset()لتحميل صور اللاعب والعدو. قم بتخزينها في متغيرات حتى تتمكن من استخدامها لاحقًا. تذكر – لن تظهر حتى تقوم برسمها فعليًا! -
رسم سفينة البطل في المركز السفلي
💡 كيف: استخدم
ctx.drawImage()لوضع البطل. بالنسبة للإحداثي x، جربcanvas.width / 2 - 45لتوسيطه، وبالنسبة للإحداثي y استخدمcanvas.height - canvas.height / 4لوضعه في المنطقة السفلية. -
رسم تشكيل 5×5 من سفن الأعداء
💡 كيف: ابحث عن وظيفة
createEnemiesوقم بإعداد حلقة متداخلة. ستحتاج إلى القيام ببعض الرياضيات للتباعد والتموضع، ولكن لا تقلق – سأريك بالضبط كيف!
أولاً، قم بتحديد الثوابت لتخطيط تشكيل الأعداء بشكل صحيح:
const ENEMY_TOTAL = 5;
const ENEMY_SPACING = 98;
const FORMATION_WIDTH = ENEMY_TOTAL * ENEMY_SPACING;
const START_X = (canvas.width - FORMATION_WIDTH) / 2;
const STOP_X = START_X + FORMATION_WIDTH;
دعونا نوضح ما تفعله هذه الثوابت:
- نحن نحدد 5 أعداء لكل صف وعمود (شبكة جميلة 5×5)
- نحن نحدد مقدار المسافة بين الأعداء حتى لا يظهروا مزدحمين
- نحن نحسب عرض التشكيل بالكامل
- نحن نحدد مكان البدء والتوقف حتى يبدو التشكيل مركزيًا
ثم، قم بإنشاء حلقات متداخلة لرسم تشكيل الأعداء:
for (let x = START_X; x < STOP_X; x += ENEMY_SPACING) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
ما الذي تفعله هذه الحلقة المتداخلة:
- الحلقة الخارجية تتحرك من اليسار إلى اليمين عبر تشكيلنا
- الحلقة الداخلية تذهب من الأعلى إلى الأسفل لإنشاء صفوف مرتبة
- نحن نرسم كل صورة عدو عند الإحداثيات x,y التي حسبناها
- كل شيء يبقى متباعدًا بشكل متساوٍ حتى يبدو احترافيًا ومنظمًا
النتيجة
يجب أن تبدو النتيجة النهائية كما يلي:
الحل
يرجى محاولة حلها بنفسك أولاً ولكن إذا واجهت صعوبة، يمكنك الاطلاع على الحل
تحدي GitHub Copilot Agent 🚀
استخدم وضع الوكيل لإكمال التحدي التالي:
الوصف: قم بتحسين لوحة لعبة الفضاء الخاصة بك عن طريق إضافة تأثيرات بصرية وعناصر تفاعلية باستخدام تقنيات واجهة برمجة التطبيقات الخاصة باللوحة التي تعلمتها.
المهمة: قم بإنشاء ملف جديد يسمى enhanced-canvas.html يحتوي على لوحة تعرض نجومًا متحركة في الخلفية، شريط صحة نابض لسفينة البطل، وسفن الأعداء التي تتحرك ببطء نحو الأسفل. قم بتضمين كود JavaScript يرسم نجومًا متلألئة باستخدام مواقع عشوائية وشفافية، ينفذ شريط صحة يتغير لونه بناءً على مستوى الصحة (أخضر > أصفر > أحمر)، ويقوم بتحريك سفن الأعداء للنزول على الشاشة بسرعات مختلفة.
تعرف على المزيد حول وضع الوكيل هنا.
🚀 التحدي
لقد تعلمت عن الرسم باستخدام واجهة برمجة التطبيقات الخاصة باللوحة ثنائية الأبعاد؛ ألقِ نظرة على واجهة برمجة التطبيقات الخاصة بـ WebGL، وحاول رسم كائن ثلاثي الأبعاد.
اختبار ما بعد المحاضرة
المراجعة والدراسة الذاتية
تعرف على المزيد حول واجهة برمجة التطبيقات الخاصة باللوحة من خلال قراءتها.
الواجب
العب مع واجهة برمجة التطبيقات الخاصة باللوحة
إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الرسمي. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.



