The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.

ترجمة لدرس تعلّم البرمجة بلغة السي الخاص بموقع OpenClassrooms

Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by Hamza Abbad, 2017-08-03 11:01:25

تعلّم البرمجة بلغة C

ترجمة لدرس تعلّم البرمجة بلغة السي الخاص بموقع OpenClassrooms

‫إنشاء مشروع ‪(Xcode) Mac OS : SDL‬‬

‫الأيقونات في ‪ Mac OS‬هي بصيغة ‪ . .icns‬إن استعملت صيغة أخرى فستلاحظ أن الأيقونة لا تظهر‪.‬‬
‫إن أردت تحو يل صيغة صورة عادية إلى أيقونة استعمل برنامج ‪ .Icon Composer‬المتواجد في المجلد‬
‫‪ ، /Developer/Applications/Utilities‬يكفي أن تسحب الأيقونة إلى المربع المخصص لها‬

‫ثم تحفظها‪.‬‬
‫في المنطقة ‪ Info‬يمكننا أن نشير إلى العديد من المعلومات في البرنامج‪ ،‬يمكنك الإطلاع عليها أكثر من خلال‬
‫قراءة الملفات التوثيقية الخاصة بـ‪ .Apple‬الشيء الوحيد الذي يمكنك التعديل عليه هو ‪ Localization‬من‬

‫‪ en‬إلى ‪ ، fr‬كما يمكنك تعديل الـ ‪ Copyright‬و وضع ما تريد‪.‬‬
‫توجّه الآن إلى ‪ Build Phases‬و انقر على ‪ Copy Files / Add Build Phase‬في أسفل يمين‬
‫النافذة‪ ،‬اضغط على ‪ Copy Files‬و غي ّره إلى ‪ . Copy frameworks into app‬في ‪Destination‬‬
‫اختار ‪ Frameworks‬لتضيف الخاصة بك‪ ،‬قم بسحبها من التفرع الشجري اليساري و افلاتها في المنطقة‬

‫‪ ، Build phase‬كما يظهر بالصورة ‪:‬‬

‫أنصحك بترتيب كل الـ‪ frameworks‬الخاص بك في مجلد ‪ Framework‬و هذا لـكي يسهل عليك إيجادها‪.‬‬
‫و أيضا ًبالنسبة للشفرات المصدر ية‪ ،‬أنصحك بترتيبها في مجلدات ليسهل الوصول إليها‪ .‬لإنشاء مجلد انقر باليمين على‬

‫الشجرة اليسار ية و اختر ‪ New Group‬ثم اسحب الملفات إلى داخلها‪.‬‬
‫سنقوم الآن بإضافة الملفات ‪ SDLMain.h‬و ‪ ، SDLMain.m‬توجه إلى المجلد ‪ devel-lite‬المفتوح‬

‫مسبقا و قم بإضافة الملفين إلى المشروع‪ .‬إذا ظهرت لك نافذة تحديد خصائص النسخ‪ ،‬قم باختيار‬
‫)‪. Copy items into destination group’s folder (if needed‬‬

‫آخر شيء ‪ :‬أنشئ ملفا ‪ . main.c‬توجه إلى القائمة ‪ New File / New / File‬ثم إلى ‪، C and C++‬‬
‫اختار ‪ C File‬ثم ”‪ .”Next‬قم بتسمية الملف و هاقد أكملت‪.‬‬

‫‪301‬‬

‫الفصل ج‪ .1.‬ٺثبيت الـ‪SDL‬‬

‫ج‪ 5.1.‬إنشاء مشروع ‪(GNU/Linux) : SDL‬‬

‫لمن يستعملون بيئة تطوير ية من أجل الترجمة‪ ،‬فعليهم بتغيير خواص المشروع )فالعملية مشابهة لما كنت قد‬
‫شرحت(‪ .‬بالنسبة لمن يستعملون ‪ ،Code::Blocks‬فالطر يقة هي نفسها التي شرحتها سابقا ً‪.‬‬

‫ماذا عن الذين يقومون بترجمة الشفرات يدو يا ؟‬

‫قد يوجد بين القراء من اعتاد على ترجمة الشفرات يدو يا بالاستعانة بـ‪) Makefile‬ملف يساعد على عملية‬
‫الترجمة(‪.‬‬

‫إذا كانت هذه حالتك‪ ،‬فأدعوك لتحميل ‪ Makefile‬ال ّذي ي ُمكن أن ي ُستخدم لترجمة مشار يع الـ‪.SDL‬‬

‫‪http://www.siteduzero.com/uploads/fr/ftp/mateo21/makefile_sdl‬‬

‫الشيء الوحيد المختلف‪ ،‬هو إضافة المكتبة ‪ SDL‬إلى محر ّر الروابط ) ‪ .( LDFLAGS‬يجدر بك أن تكون قد‬
‫نزّلت المكتبة و ثب ّتها في مجل ّد ملفات المترجم‪ ،‬بنفس طر يقة الويندوز )المجلدان ‪ include/SDL‬و ‪.( lib‬‬

‫بعد ذلك يجب عليك أن تكتب الأوامر التالية في الـكونسول ‪:‬‬

‫‪make‬‬ ‫‪# To compile the project‬‬

‫‪make clean‬‬ ‫)‪# To delete compilation files (useless .o files‬‬

‫‪make mrproper # To delete all files except source ones‬‬

‫مل ّخص‬

‫• الـ‪ SDL‬مكتبة منخفضة المستوى‪ ،‬تسمح بإنشاء نوافذ و التعامل مع الرسوميات ‪.2D‬‬

‫• المكتبة ليست مس ّطبة تلقائيا في الحاسوب‪ ،‬يجب عليك أن تنزّلها بنفسك و تقوم بتخصيص البيئة التطوير ية‬
‫لتعمل معها‪.‬‬

‫• المكتبة حرة و مج ّانية‪ ،‬مما يسمح باستعمالها السر يع و الدائم‪.‬‬

‫• توجد آلاف المكتبات الأخرى‪ ،‬و كثير منها ذو جودة عالية جدا ً‪ .‬و قد تم اختيار المكتبة ‪ SDL‬لبقي ّة‬
‫هذا الدرس لأجل سهولتها‪ .‬لمن يريد بناء واجهات رسومية بنوافذ‪ ،‬أزرار و قوائم‪ ،‬فأنا أنصحه بالمكتبة‬

‫‪ GTK+‬مثلا‪.‬‬

‫‪302‬‬

‫الفصل ج‪2.‬‬

‫إنشاء نافذة و مساحات‬

‫في الدرس السابق‪ ،‬قمنا بالإلمام حول أهم المميزات التي تمنحها المكتبة ‪ .SDL‬يجدر بك أن تكون قد ثب ّت‬
‫المكتبة‪ ،‬و تعل ّمت كيفية إنشاء مشروع جديد يشتغل بشكل جيد‪ .‬على الرغم من أن ّه كان فارغا‪.‬‬

‫سندخل في مضمون موضوعنا في هذا الفصل‪ .‬سنقوم بتطبيق أساسيات لغة الـ‪ C‬مع ‪ .SDL‬كيف يتم تحميل‬
‫الـ‪ SDL‬؟ كيف يتم فتح نافذة بالأبعاد التي نريد ؟ كيف نرسم داخل النافذة ؟‬
‫لدينا أمور كثيرة لنعرفها‪ ،‬فهي ّا بنا !‬

‫ج‪ 1.2.‬تحميل و إيقاف الـ‪SDL‬‬

‫العديد من المكتبات المكتوبة بلغة الـ‪ ،C‬تستلزم أن يتم تحميلها ثم غلقها حين ننتهي منها‪ ،‬و ذلك لاستعمال‬
‫دوال محددة‪ .‬المكتبة ‪ SDL‬من بين هذه المكتبات‪.‬‬

‫بالفعل‪ ،‬فالمكتبة تحتاج أن يتم تحميل عدد معي ّن من المعلومات إلى الذاكرة العشوائية لتستطيع أن تشتغل‬
‫بشكل صحيح‪ .‬يتم هذا التحميل بشكل حيّ باستعمال الدالة ‪) malloc‬إ ّنها مهمّة ج ّدا هنا !(‪ .‬و كما تعلم فإن‬

‫قلت ‪ ، malloc‬سأقول كذلك ‪! free‬‬
‫يجب عليك تحرير الذاكرة التي حجزتها و لم تعد بحاجة إليها‪ .‬إن لم تفعل‪ ،‬فالبرنامج يمكن أن يأخذ حيّزا ً كبيرا ً من‬
‫الذاكرة بدون فائدة‪ ،‬و يمكن لذلك أحيانا أن يدرّ بنتائج كارثية‪ .‬تخي ّل القيام بحلقة غير منتهية من ‪malloc‬‬

‫دون قصد‪ ،‬في بضع ثوان ستس ّد ك ّل الذاكرة !‬
‫هاهما الدالتان الأولتان الخا ّصتان بالـ ‪ SDL‬اللتان يجب عليك أن تعرفهما ‪:‬‬
‫• ‪ : SDL_Init‬تحميل المكتبة في الذاكرة العشوائية )باستخدام الـ ‪.( malloc‬‬

‫• ‪ : SDL_Quit‬تحرير المكتبة من الذاكرة )باستعمال الـ ‪.( free‬‬

‫أي أن أ ّول شيء يجب أن تقوم به في البرنامج هو استدعاء ‪ ، SDL_Init‬و آخر شيء هو استدعاء‬
‫‪. SDL_Quit‬‬

‫‪303‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫‪ : SDL_Init‬تحميل المكتبة ‪SDL‬‬

‫الدالة ‪ SDL_Init‬تستقبل معاملا‪ .‬إذ يجب أن يتم تحديد أي جزء من المكتبة نريد تحميله‪.‬‬
‫آه ح ّقا ! هل الـ‪ SDL‬ٺتكون من كثير من الأجزاء ؟‬

‫نعم بالطبع ! فهناك جزء من المكتبة يتعامل مع الشاشة‪ ،‬و آخر يتعامل مع الصوت‪ ،‬إلخ‪.‬‬
‫توف ّر لنا المكتبة عددا ً من الثوابت التي تسمح لنا بتحديد اسم الجزء الذي نريد تحميله من المكتبة‪.‬‬

‫الشرح‬ ‫الثابت‬

‫تحميل الجزء الخاص بالعرض )الفيديو(‪ ،‬إنه الجزء الذي نحمله غالبا ً‪.‬‬ ‫‪SDL_INIT_VIDEO‬‬
‫تحميل الجزء الخاص بالصوت‪ ،‬هذا ما يسمح لك مثلا بتشغيل الموسيقى مثلا‪.‬‬ ‫‪SDL_INIT_AUDIO‬‬
‫‪SDL_INIT_CDROM‬‬
‫تحميل الجزء الخاص بقارئ القرص المضغوط‪ ،‬و ذلك للتحكم به‪.‬‬ ‫‪SDL_INIT_JOYSTICK‬‬
‫تحميل الجزء الخاص بجهاز التحكم ‪.Joystick‬‬

‫‪ SDL_INIT_EVERYTHING‬تحميل كل الأجزاء التي ذكرتها سابقا‪.‬‬

‫إذا استدعيت الدالة بهذا الشكل‬

‫;)‪1 SDL_Init(SDL_INIT_VIDEO‬‬

‫فإن نظام العرض سيتم تحميله في الذاكرة‪ ،‬فيمكنك أن تفتح نافذة و ترسم فيها‪ ،‬إلخ‪.‬‬
‫كل ما قمنا به هو إعطاء عدد إلى الدالة ‪ SDL_Init‬بالاستعانة بثابت‪ .‬أنت لا تعرف أي عدد هو‪ ،‬و هذا أمر‬

‫جيد‪ .‬إذ أنك غير مجـبر على حفظ العدد‪ ،‬بل التعبير عنه باسم الثابت فقط‪.‬‬

‫الدالة ‪ SDL_Init‬تقرأ العدد و هكذا تحدد الأنظمة الواجب تحميلها‪.‬‬

‫الآن لو تكتب ‪:‬‬

‫;)‪1 SDL_Init(SDL_INIT_EVERYTHING‬‬

‫ستقوم بتحميل كل أنظمة الـ‪ ،SDL‬لا تقم بهذا إلا في حالة كنت بالفعل تحتاج إلى ك ّل شيء‪ ،‬ليس جيدا ً‬
‫إثقال الحاسوب بوحدات لا فائدة منها‪.‬‬

‫ماذا لو أردت تحميل الصوت و الفيديو فقط‪ .‬هل يجدر بي استخدام ‪ SDL_INIT_EVERYTHING‬؟‬

‫لن تستعمل ‪ ، SDL_INIT_EVERYTHING‬من أجل تحميل وحدتين‪ ،‬هذا جنون ! لحسن الحظ‪ ،‬يمكننا‬
‫تجميع الخيارات بواسطة الرمز | ‪.‬‬

‫‪304‬‬

‫تحميل و إيقاف الـ‪SDL‬‬

‫‪1 // Loading the video and the audio‬‬
‫;)‪2 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO‬‬

‫كما يمكنك وضع ثلاثة دون مشاكل ‪:‬‬
‫‪1 // Loading the video, the audio and the timer‬‬
‫;)‪2 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER‬‬

‫هذه ”الخيارات” التي نبعثها للدالة ‪ SDL_Init‬نسميها بـالأعلام )‪ .(flags‬هذه الكلمة نستعملها كثيرا ً‬
‫في علوم الحاسوب‪.‬‬

‫تذكّر إذا أن الإشارة | خاصة بدمج الخيارات‪ .‬إنها تشبه الإضافة إلى ح ّد ما‪.‬‬

‫‪ : SDL_Quit‬إيقاف المكتبة ‪SDL‬‬

‫هذه الدالة سهلة الاستعمال لأنها لا تحتاج إلى أي معامل ‪:‬‬

‫;)(‪1 SDL_Quit‬‬

‫كل الأنظمة سيتم إيقافها و يتم تحرير الذاكرة‪.‬‬
‫باختصار‪ ،‬هذه الدالة أداة للخروج من المكتبة بشكل نظيف‪ ،‬و لنقل للخروج من برنامجك‪.‬‬

‫نموذج عن برنامج ‪SDL‬‬

‫باختصار‪ ،‬هذا ما يبدو عليه برنامج ‪ SDL‬في نسخته الأبسط ‪:‬‬

‫>‪1 #include <stdlib.h‬‬

‫>‪2 #include <stdio.h‬‬

‫>‪3 #include <SDL/SDL.h‬‬

‫‪4‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪5‬‬
‫{‬

‫‪6 SDL_Init(SDL_INIT_VIDEO); // Starting the SDL (Here we load‬‬

‫‪7‬‬ ‫)‪the video system‬‬
‫‪8‬‬ ‫‪SDL_Quit(); // Stopping the SDL (Freeing the memory).‬‬
‫}‪9‬‬ ‫;‪return 0‬‬

‫هذا نموذج عن برنامج بسيط‪ ،‬عبارة عن مخطط لبرامج ‪ SDL‬التي نكتبها‪ .‬في الواقع‪ ،‬البرنامج الحقيقي يكون‬
‫ممتلأ كثيرا إذ يحتوي ع ّدة استدعاءات لدوال‪ ،‬تقوم بدورها بمزيد من الاستدعاءات‪.‬‬

‫الأمر المه ّم في النهاية‪ ،‬هو أ ّن ‪ SDL‬يجب أن ت ُحم ّل في البداية و ت ُغلق عندما لا تصبح بحاجة إليها‪.‬‬

‫‪305‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫معالجة الأخطاء‬

‫الدالة ‪ SDL_Init‬تقوم بإرجاع قيمة ‪:‬‬

‫• ‪ : 1-‬في حال وجود خطأ‪.‬‬
‫• ‪ : 0‬في حالة عدم وجود أي خطأ‪.‬‬

‫لست مجـبرا ً‪ ،‬لـكن يمكنك اختبار القيمة الم ُرجعة‪ .‬قد تكون طر يقة جي ّدة لمعالجة الأخطاء في برنامجك‪ ،‬و‬
‫هذا ما سيساعدك على حل ّها‪.‬‬

‫لـكن كيف أقوم بإظهار الخطأ الحادث ؟‬

‫سؤال وجيه ! ليس لدينا كونسول الآن‪ ،‬كيف نخز ّن و نعرض رسائل الخطأ ؟‬
‫هناك حل ّان ‪:‬‬

‫• يمكننا التعديل على خاصيات المشروع‪ ،‬لـكي نسمح له باستعمال الـكونسول أيضا ً‪ .‬سنتم ّكن في هذه الحالة‬
‫من استخدام الدالة ‪،( printf‬‬

‫• أو نكتب الأخطاء في ملف‪ .‬تستخدم الدالة ‪. fprintf‬‬

‫لقد اخترت أن نكتب في ملف‪ .‬و بهذا فإن العمل على ملف يحتاج إلى فتح هذا الأخير بـ ‪ fopen‬و غلقه‬
‫بـ ‪ ، fclose‬و الأمر أق ّل سهولة من استعمال الـ ‪. printf‬‬

‫لحسن الحظ‪ ،‬هناك طر يقة أسهل و هي استعمال مخرج الأخطاء القياسي‪.‬‬

‫يوجد متغير ‪ stderr‬معر ّف في ‪ stdio.h‬يقوم بالتأشير نحو المنطقة التي ي ُمكن أن ي ُكتب فيها الخطأ‪.‬‬
‫غالبا في الويندوز‪ ،‬هذه المنطقة عبارة عن ملف يحمل الاسم ‪ . stderr.txt‬بينما في اللينكس فإن الأخطاء‬

‫غالبا ًما يتم إظهارها على الـكونسول‪ .‬هذا المتغير يتم إنشاؤه تلقائيّا في بداية البرنامج و يتم حذفه في نهايته‪ ،‬أي أنك‬

‫لست مجـبرا ً على استعمال ‪ fopen‬و ‪. fclose‬‬
‫يمكنك استعمال الدالة ‪ fprintf‬على ‪ stderr‬بدون استعمال ‪ fopen‬و ‪: fclose‬‬

‫>‪1 #include <stdlib.h‬‬

‫>‪2 #include <stdio.h‬‬

‫>‪3 #include <SDL/SDL.h‬‬

‫‪4‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪5‬‬
‫{‬

‫‪6 if (SDL_Init(SDL_INIT_VIDEO) == −1) // Starting the SDL, if‬‬

‫‪there’s an error :‬‬

‫{‪7‬‬

‫‪306‬‬

‫فتح نافذة‬

‫‪8‬‬ ‫”‪fprintf(stderr, ”Error while initializing SDL : %s\n‬‬
‫‪,‬‬
‫‪9‬‬
‫‪10‬‬ ‫‪SDL_GetError()); // Writing the error‬‬
‫‪11‬‬ ‫‪exit(EXIT_FAILURE); // We exit the program‬‬
‫‪12‬‬ ‫}‬
‫‪13‬‬ ‫;)(‪SDL_Quit‬‬
‫} ‪14‬‬ ‫;‪return EXIT_SUCCESS‬‬

‫ما الجديد في هذه الشفرة المصدر ية ؟‬

‫• لقد كتبنا الخطأ الذي وجدناه في ‪ . stderr‬الرمز ‪ %s‬يسمح للـ‪ SDL‬بالإشارة إلى تفاصيل الخطأ ‪:‬‬
‫الدالة ‪ SDL_GetError‬في الحقيقة تقوم بإرجاع آخر خطأ ‪.SDL‬‬

‫• نخرج باستعمال الـ )(‪ . exit‬لح ّد الآن لا يوجد شيء جديد مقارنة بما جرت العادة‪ ،‬ستلاحظ أنني‬
‫استعمل الثابت ‪ EXIT_FAILURE‬كقيمة يقوم البرنامج الرئيسي بإرجاعها‪ ،‬بينما استعملت في النهاية‬

‫الثابت ‪ EXIT_SUCCESS‬في مكان الـ‪.0‬‬
‫ما الذي قمت به ؟ لقد قمت بتحسين الطر يقة التي تعودنا أن نكتب بها الشفرة‪ .‬لقد استخدمت اسم الثابت‬
‫ال ّذي يعني ”خطأ” و الذي هو نفسه بالنسبة لجميع أنظمة التشغيل‪ .‬بينما الأعداد تختلف من نظام إلى آخر‪.‬‬

‫لهذا فإن الملف ‪ stdlib.h‬تسمح باستعمال ثابتتين )معر ّفي ‪: ( #define‬‬

‫– ‪ : EXIT_FAILURE‬قيمة يتم إرجاعها في حالة وجود خطأ ما في البرنامج‪.‬‬
‫– ‪ : EXIT_SUCCESS‬قيمة يتم إرجاعها في حالة عدم وجود أي خطأ‪.‬‬

‫باستعمال أسماء الثوابت بدلا ًمن قيمها‪ ،‬ستضمن بأنك قد بعثت القيمة الصحيحة‪.‬‬
‫لماذا ؟ لأن الملف ‪ stdlib.h‬يتغيّر حسب نظام التشغيل ال ّذي أنت عليه‪ ،‬لذا فقيم الثوابت ستتأقلم‬
‫مع النظام من دون أ ّن نحتاج إلى تغيير شيء ! و هذا ما يجعل لغة الـ‪ C‬متوافقة مع ك ّل أنظمة التشغيل‬

‫)بافتراض أن ّك تبرمج بالطر يقة الصحيحة باستخدام الأدوات المتوف ّرة‪ ،‬كما فعلنا هنا(‪.‬‬

‫استعمال أسماء الثوابت لا يعود علينا بكثير من النفع الآن‪ ،‬لـكن من الأحسن استعمالها‪ .‬سنقوم‬
‫بذلك انطلاقا ًمن الآن‪.‬‬

‫ج‪ 2.2.‬فتح نافذة‬

‫حسنا ً‪ ،‬لقد تم فتح و غلق المكتبة بنجاح‪ .‬الخطوة التالية التي يريد تعل ّمها الجميع هي كيفية فتح نافذة !‬
‫لـكي نبدأ‪ ،‬تأكد من أن لديك ‪ main‬تشبه هذه ‪:‬‬

‫‪307‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫‪1‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪2‬‬
‫{‬

‫)‪3 if (SDL_Init(SDL_INIT_VIDEO) == −1‬‬

‫{‪4‬‬

‫;)”‪5 fprintf(stderr, ”Error while initializing SDL‬‬

‫;)‪6 exit(EXIT_FAILURE‬‬

‫}‪7‬‬

‫;)(‪8 SDL_Quit‬‬

‫;‪9 return EXIT_SUCCESS‬‬

‫} ‪10‬‬

‫هذه هي حالتك لو اتبعت جيدا ً من بداية الفصل‪ .‬حالي ّا‪ ،‬ك ّل ما سنقوم بتحميله هو نظام العرض‬
‫) ‪ ،( SDL_INIT_VIDEO‬هذا ما يهمّنا‪.‬‬

‫إختيار وضع العرض‬

‫أول شيء نقوم به بعد ‪ ، SDL_Init‬هو تحديد وضع العرض الذي نريد استعماله‪ ،‬أي الدقة )‪،(resolution‬‬
‫عدد الألوان بالإضافة إلى خصائص أخرى‪.‬‬

‫من أجل هذا سنستعمل الدالة ‪ SDL_SetVideoMode‬التي تستقبل ‪ 4‬معاملات ‪:‬‬

‫• عرض النافذة التي نريدها )‪،(pixels‬‬
‫• طول النافذة التي نريدها )‪،(pixels‬‬

‫• عدد الألوان القابلة للعرض )‪،(bits/pixel‬‬
‫• الخيارات )الأعلام(‪.‬‬

‫لا أعتقد أن طول و عرض النافذة يحتاجان إلى شرح‪ ،‬بينما عدد الألوان و الأعلام هما المعاملان الأكثر‬
‫أهمي ّة‪.‬‬

‫• عدد الألوان ‪ :‬هو العدد الأقصى للألوان التي يمكن أن تظهر في النافذة‪ .‬إن كنت من عشاق ألعاب‬
‫الفيديو‪ ،‬ستكون معتادا ً على هذا الأمر‪ .‬فإن قيمة ‪ 32 bits/pixel‬تسمح بإظهار ملايير الألوان‪ ،‬بينما إنه‬
‫من الممكن أن نختار قيمة أقل كـ‪) 16 bits/pixel‬تسمح بعرض ‪ 65536‬لون( أو حتى ‪8 bits/pixel‬‬
‫)تسمح بعرض ‪ 256‬لون مختلف(‪ ،‬هذا الأمر مفيد حينما تريد برمجة تطبيقات من أجل جهاز بسيط‬

‫كالـ‪ PDA‬أو الهاتف المحمول‪.‬‬

‫• الخيارات ‪ :‬تماما مثل الـ ‪ ، SDL_Init‬علينا باستعمال أعلام من أجل تعر يف خصائص‪ .‬هذه أهم‬
‫الأعلام التي يمكنك استعمالها )يمكنك استعمال العديد منها‪ ،‬يتم التفر يق بينها باستعمال الرمز | ( ‪:‬‬

‫‪308‬‬

‫فتح نافذة‬

‫– ‪ : SDL_HWSURFACE‬المعطيات سيتم حفظها في في الذاكرة الرسومية للبطاقة ‪ .3D‬الشيء الجيد ‪:‬‬
‫إنها الذاكرة الأكثر سرعة‪ .‬الشيء الس ّيء ‪ :‬يصعب إيجاد مساحة شاغرة في هذا النوع من الذاكرة‬

‫مقارنة بالأخرى ) ‪.( SDL_SWSURFACE‬‬
‫– ‪ : SDL_SWSURFACE‬المعطيات يتم حفظها في ذاكرة النظام )أي في الـ‪ ،(RAM‬الشيء الجيد ‪:‬‬

‫يوجد الـكثير من المكان في هذه الذاكرة‪ .‬الشيء السيء ‪ :‬أقل سرعة و أقل كفاءة‪.‬‬
‫– ‪ : SDL_RESIZABLE‬ستصبح مقاييس أبعاد النافذة قابلة للتعديل‪ ،‬لأنها ليست كذلك تلقائيا‪.‬‬

‫– ‪ : SDL_NOFRAME‬لن يصبح للنافذة أية حواش أو شر يط علوي لكتابة عنوان النافذة‪.‬‬
‫– ‪ : SDL_FULLSCREEN‬نمط الشاشة الكاملة‪ .‬لن تستطيع رؤ ية أية نافذة أخرى لأن نافذة البرنامج‬

‫الحالي تهيمن على ك ّل الشاشة‪ ،‬مع تعديل دق ّة الشاشة في حالة الضرورة‪.‬‬
‫– ‪ : SDL_DOUBLEBUF‬وضع ‪ ،double buffering‬تقنية مستعملة بكثرة في برمجة الألعاب ثنائية‬
‫الأبعاد‪ .‬تقضي بأن يكون تحر ّك الأشياء على الشاشة مرنا ً‪ ،‬لأنه إن لم يكن كذلك‪ ،‬سيكون التحر ّك‬

‫سيئا ً‪ ،‬سأشرح هذا الأمر بالتفصيل لاحقا ً‪.‬‬

‫إذا كتبت الشفرة المصدر ية التالية ‪:‬‬
‫;)‪1 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫فإنه سيقوم بفتح نافذة ذات أبعاد ‪ ،640 × 480‬و بعدد ألوان ‪) 32 bits/pixel‬ملايير الألوان(‪ ،‬و ستم تحميل‬
‫النافذة على الذاكرة الرسومي ّة )إ ّنها الأسرع‪ ،‬لذلك نف ّضل استعمالها(‪.‬‬

‫كمثال آخر‪ ،‬لو نأخذ ‪:‬‬
‫| ‪1 SDL_SetVideoMode(400, 300, 32, SDL_HWSURFACE | SDL_RESIZABLE‬‬

‫;)‪SDL_DOUBLEBUF‬‬

‫هذه الشفرة تفتح نافذة مقاييس أبعادها قابلة للتعديل‪ ،‬بأبعاد ابتدائية ‪ ،400×300‬و بعدد ألوان ‪32 bits/pixel‬‬
‫كما أن تقنية ‪ double buffering‬مفعّلة‪.‬‬

‫هذه أ ّول شفرة مصدر ية بسيطة يمكنك تجريبها ‪:‬‬
‫>‪1 #include <stdlib.h‬‬
‫>‪2 #include <stdio.h‬‬
‫>‪3 #include <SDL/SDL.h‬‬
‫)][‪4 int main(int argc, char *argv‬‬
‫{‪5‬‬
‫;)‪6 SDL_Init(SDL_INIT_VIDEO‬‬
‫;)‪7 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬
‫;)(‪8 SDL_Quit‬‬
‫;‪9 return EXIT_SUCCESS‬‬
‫} ‪10‬‬

‫‪309‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫لقد اخترت أن أسحب معالجة الأخطاء لتبسيط الشفرة‪ ،‬لـكن بالنسبة لك‪ ،‬يجب عليك أن تكتب برامج كاملة‬
‫و أخذ ك ّل الاحتياطات اللازمة لمعالجة الأخطاء‪.‬‬

‫قم بتجريب الشفرة‪ .‬ما الذي يحصل ؟ تظهر النافذة و تختفي بسرعة البرق‪.‬‬
‫الحقيقة أن استدعاء الدالة ‪ SDL_SetVideoMode‬يليه مباشرة استدعاء الدالة ‪ SDL_Quit‬التي تقوم بإنهاء‬

‫ك ّل شيء‪.‬‬

‫توقيف البرنامج للحظات‬

‫ما العمل كي تقوم النافذة بالانتظار و لا تختفي مباشرة ؟‬

‫يجب أن نفعل ما تفعله جميع البرامج‪ ،‬سواء كانت ألعابا أو غير ذلك‪ ،‬حلقة تكرار ية غير منتهية‪ .‬في الواقع‪،‬‬
‫بمساعدة حلقة غير منتهية بسيطة سنمنع البرنامج من التوقف‪ .‬لـكن هذه الطر يقة فعالة ج ّدا لدرجة أن ّه لا يمكننا‬

‫إيقاف البرنامج )إلا إذا أجبرناه باستدعاء المعالج‪ ،‬لـكنّها تبقى طر يقة عنيفة لانهاء عمل برنامج(‪.‬‬

‫هذه شفرة تعمل‪ ،‬لـكن ّي أدعوك إلى عدم تجريبها‪ ،‬أعطيها لك فقط كشرح ‪:‬‬

‫‪1‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪2‬‬
‫{‬

‫;)‪3 SDL_Init(SDL_INIT_VIDEO‬‬

‫;)‪4 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫;)‪5 while(1‬‬

‫;)(‪6 SDL_Quit‬‬

‫;‪7 return EXIT_SUCCESS‬‬

‫}‪8‬‬

‫أنت تعرف الـ ;)‪ : while(1‬إ ّنها الحلقة التكرار ية غير المنتهية‪ .‬بما أن ‪ 1‬يساوي القيمة المنطقية ”صحيح”‬

‫)تذكّر المتغيرات المنطقية(‪ ،‬فإن الشرط صحيح دائما و بالتالي فستدور الحلقة إلى الأبد مع عدم وجود وسيلة‬

‫لإيقافها‪ .‬هذا ليس حل ّا جي ّدا‪.‬‬

‫لـكي نتمكن من توقيف النافذة كي لا تختفي فجأة بدون اللجوء إلى حلقة غير منتهية‪ ،‬سنستعمل دالتي ال ّتي‬

‫أنشأتها و سميتها ‪: pause‬‬

‫)(‪1 void pause‬‬
‫{‪2‬‬
‫;‪3 int cont = 1‬‬
‫;‪4 SDL_Event event‬‬
‫)‪5 while (cont‬‬
‫{‪6‬‬
‫;)‪7 SDL_WaitEvent(&event‬‬
‫)‪8 switch(event.type‬‬
‫{‪9‬‬

‫‪310‬‬

‫فتح نافذة‬

‫‪10 case SDL_QUIT:‬‬
‫;‪11 cont = 0‬‬
‫} ‪12‬‬
‫} ‪13‬‬
‫} ‪14‬‬

‫لن أشرح لك تفاصيل الدالة الآن‪ .‬فهذه الدال ّة تحتاج إلى ما نسميه بمعالجة الأحداث ال ّتي سأشرحها في‬
‫الفصل القادم‪ .‬فإن شرحت لك ك ّل شيء الآن فقد تختلط عليك الأمور ! ث ِق في دال ّتي الخا ّصة بالتوقيف‪،‬‬

‫ستتعرف على طر يقة عملها قريبا ً‪.‬‬

‫هذا مثال عن شفرة مصدر ية كاملة‪ ،‬يمكنك )أخيرا ً( تجريبها ‪:‬‬

‫>‪1 #include <stdlib.h‬‬

‫>‪2 #include <stdio.h‬‬

‫>‪3 #include <SDL/SDL.h‬‬

‫;)(‪4 void pause‬‬

‫‪5‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪6‬‬
‫{‬

‫‪7 SDL_Init(SDL_INIT_VIDEO); // We initialize the SDL‬‬

‫;)‪8 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫‪9 pause(); // We pause the program‬‬

‫‪10 SDL_Quit(); // We stop the SDL‬‬

‫‪11 return EXIT_SUCCESS; // We close the program‬‬

‫} ‪12‬‬

‫)(‪13 void pause‬‬

‫{ ‪14‬‬

‫;‪15 int cont = 1‬‬

‫;‪16 SDL_Event event‬‬

‫)‪17 while (cont‬‬

‫{ ‪18‬‬

‫;)‪19 SDL_WaitEvent(&event‬‬

‫)‪20 switch(event.type‬‬

‫{ ‪21‬‬

‫‪22 case SDL_QUIT:‬‬

‫;‪23 cont = 0‬‬

‫} ‪24‬‬

‫} ‪25‬‬

‫} ‪26‬‬

‫ستلاحظ أنني وضعت نموذج الدالة ‪ pause‬في أعلى البرنامج كي لا أضطر ّ لعرض أكثر من ملف‪.‬‬
‫لقد قمت باستدعاء الدالة ‪ pause‬و هي تقوم بالدخول في حلقة تكرار ية غير منتهية أذكى من السابقة‪ .‬هذه‬

‫الحلقة تنتهي حينما تنقر على الزر الأحمر ‪ X‬أعلى النافذة !‬

‫الصورة التالية هي عبارة عن النافذة التي نحصل عليها حين نترجم الشفرة المصدر ية السابقة )النافذة ذات‬
‫أبعاد ‪.(640 × 480‬‬

‫‪311‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫ها قد وصلنا !‬
‫إن أردت‪ ،‬قم بوضع الع َلم الذي يسمح بتعديل مقاييس النافذة‪ .‬للع ِلْم‪ ،‬في ألعاب الفيديو نف ّضل النوافذ ذات‬

‫الأبعاد الثابتة )لأنه يسهل التعامل معها(‪ ،‬إذا فلنترك النافذة ثابتة كما هي الآن‪.‬‬
‫إحذر من الع َل َم ‪ SDL_FULLSCREEN‬الخاص بوضع الشاشة الكاملة‪ ،‬و من الع َـلم ‪SDL_NOFRAME‬‬
‫الذي يقوم بإخفاء حواشي النافذة‪ .‬بما أن ّه لن يكون هناك شر يط للعنوان‪ ،‬فلن نكون قادرين على الخروج‬

‫من البرنامج‪ ،‬إلا بالاستعانة بالمعالج !‬
‫تريّث قليلا ًحتى نتعلّم معالجة الأحداث )في الفصول القادمة( و ستتمكن بعدها من الخروج من النافذة‬

‫بطر يقة أقل عنفا ًمن استدعاء المعالج‪.‬‬

‫تغيير عنوان النافذة‬

‫لح ّد الآن‪ ،‬النافذة أخذت عنوانا تلقائيا )و هو ‪ SDL_app‬في الصورة السابقة(‪.‬‬
‫هل تريد تغييره ؟‬

‫إن الأمر بسيط للغاية‪ ،‬يكفي استعمال الدالة ‪. SDL_WM_SetCaption‬‬
‫هذه الدالة تأخذ معاملين ‪ :‬المعامل الأول هو العنوان الذي تريد إعطاءه للنافذة‪ ،‬و المعامل الثاني هو العنوان‬

‫الذي تريد إعطاءه للأيقونة‪.‬‬
‫‪312‬‬

‫فتح نافذة‬

‫خلافا ً على ما يعتقده الجميع‪ ،‬تغيير اسم الأيقونة لا يعني تغيير صورة الأيقونة التي تظهر أعلى يسار النافذة‪.‬‬
‫هذا لا يعمل دائما )حسب معرفتي‪ ،‬قد يعطي نتائج على الـ‪ GNU/Linux‬في بيئة الـ‪ .(Gnome‬شخصيا ً‪ ،‬أنا أبعث‬
‫القيمة ‪ NULL‬إلى الدالة‪ .‬على أية حال‪ ،‬يمكننا تغيير شكل الأيقونة التي تظهر أعلى يسار النافذة‪ ،‬لـكننا سنتعلّم‬

‫ذلك في الفصل القادم‪ ،‬لأ ّن هذا الأمر ليس بمستواك بعد‪.‬‬

‫هذه نفس الـ ‪ main‬السابقة‪ ،‬مع إضافة الدالة ‪: SDL_WM_SetCaption‬‬

‫‪1‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪2‬‬
‫{‬

‫;)‪3 SDL_Init(SDL_INIT_VIDEO‬‬

‫;)‪4 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫;)‪5 SDL_WM_SetCaption(”My super SDL window !”, NULL‬‬

‫;)(‪6 pause‬‬

‫;)(‪7 SDL_Quit‬‬

‫;‪8 return EXIT_SUCCESS‬‬

‫}‪9‬‬

‫لاحظ بأنني استعملت القيمة ‪ NULL‬للمعاملات غير المهمة بشكل كبير‪ .‬بالنسبة للـ‪ ،C‬يجب أن يتم‬
‫إعطاء قيم لكل المعاملات التي تستقبلها الدوال‪ ،‬حتى لو كانت هذه المعاملات غير مهمة لك‪ ،‬فأعطها‬
‫‪ NULL‬كما فعلت أنا هنا‪ .‬بينما الـ‪ C++‬تسمح بألا نعطي أساسا ًقيمة لبعض المعاملات الاختيار ي ّة عندما‬

‫نستدعي الدوال‪.‬‬

‫للنافذة الآن عنوان‪.‬‬

‫‪313‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫ج‪ 3.2.‬التعامل مع المساحات‬

‫لحد الآن تم ّكنا من فتح نافذة ذات خلفي ّة سوداء‪ .‬ما نريد الآن هو أن نملأها ببعض الأشياء‪ ،‬أي أن ”نرسم”‬
‫فيها‪.‬‬

‫كما قلت لك في الفصل السابق‪ ،‬فإن المكتبة ‪ SDL‬هي مكتبة منخفضة المستوى‪ ،‬أي أنها لا توف ّر لنا سوى‬
‫دوال قاعدية‪ ،‬بسيطة جدا ً‪.‬‬

‫الصراحة هي أن الشكل الوحيد الذي تسمح لنا الـ‪ SDL‬برسمه هو المستطيل ! ك ّل ما سنقوم به هو جمع‬
‫بعض المستطيلات في نافذة‪ .‬نسمّي هذه المستطيلات بـالمساحات )‪ ،(Surfaces‬المساحة هي الوحدة الرسومية‬

‫القاعدية في الـ‪.SDL‬‬

‫إنه من الممكن أن نرسم أشياء أخرى‪ ،‬مثل الدوائر و المثلثات‪ ،‬إلخ‪ .‬و لـكن لـكي نفعل ذلك‪ ،‬يجب أن‬

‫نكتب بأنفسنا الدوال ال ّتي تم ّكن من فعل ذلك‪ ،‬برسم تلك الأشكال بيكسلا ببيكسل‪ ،‬و إما أن نستعمل‬

‫مكتبة أخرى إلى جانب الـ‪ .SDL‬الأمر مع ّقد نوعا ً ما‪ ،‬لـكن لا تقلق‪ ،‬ستجد بأننا لسنا بحاجة إلى ك ّل‬
‫هذا في التطبيق‪.‬‬

‫مساحتك الأولى ‪ :‬الشاشة‬

‫في كل برامج الـ‪ ،SDL‬توجد على الأقل مساحة عمل واحدة و هي ما نسميه بالشاشة )‪ ،(Screen‬و هي مساحة‬
‫توافق كل النافذة‪ ،‬أي ك ّل المساحة السوداء التي تظهر بالنافذة‪.‬‬

‫في الشفرة المصدر ية‪ ،‬كل مساحة يتم تخزينها في متغير من نوع ‪ . SDL_Surface‬نعم‪ ،‬إنه نوع بيانات تم‬
‫انشاؤه من طرف الـ‪) SDL‬هذا المتغير عبارة عن هيكل(‪.‬‬

‫بما أن أول مساحة ننشئها هي الشاشة‪ ،‬فهيا بنا ‪:‬‬

‫;‪1 SDL_Surface *screen = NULL‬‬

‫تلاحظ أنني قمت بإنشاء مؤش ّر‪ .‬لماذا أفعل هذا ؟ لأن الـ‪ SDL‬هي من ستقوم بحجز مكان في الذاكرة من‬
‫أجل مساحتنا‪ .‬المساحة بالفعل ليس لها بالضرورة دائما نفس الحجم و لهذا فعلى الـ‪ SDL‬أن تقوم بحجز حيّ من‬

‫أجلنا )هنا‪ ،‬هذا يعتمد على حجم النافذة التي فتحناها(‪.‬‬

‫لم أقل لك هذا من قبل‪ ،‬لـكن الدالة ‪ SDL_SetVideoMode‬تقوم بإرجاع قيمة ! ستقوم بإرجاع مؤش ّر‬
‫نحو المكان بالذاكرة المخصص لمساحة الشاشة‪.‬‬

‫ممتاز‪ ،‬يمكننا إذا استرجاع المؤش ّر في المتغير ‪: screen‬‬

‫;)‪1 screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫المؤشّر يمكن الآن أن يساوي قيمتين ‪:‬‬

‫‪314‬‬

‫التعامل مع المساحات‬

‫• ‪ : NULL‬المتغير ‪ screen‬سيساوي ‪ NULL‬إذا فشلت الدالة ‪ SDL_SetVideoMode‬في تحميل‬
‫أسلوب العرض الذي تم طلبه‪ .‬و هذا يحصل حينما يتم اختيار دقة جد عالية أو عدد كبير جدا ً من‬

‫الألوان‪ ،‬أكبر من أقصى عدد يتحمله جهازك‪.‬‬

‫• قيمة أخرى ‪ :‬إذا كانت القيمة مختلفة عن ‪ ، NULL‬فهذا يعني أن الـ‪ SDL‬قامت بحجز المكان‪ ،‬كل شيء‬
‫على ما يرام !‬

‫إنه من المستحسن هنا أن تتم معالجة الأخطاء‪ ،‬تماما مثلما فعلنا حينما أردنا تحميل الـ‪ ،SDL‬هاهي إذا الدالة‬

‫الكاملة بإضافة معالجة الأخطاء للـ ‪. SDL_SetVideoMode‬‬

‫)][‪1 int main(int argc, char *argv‬‬
‫{‪2‬‬
‫‪3 SDL_Surface *screen = NULL; // The pointer which stores the‬‬

‫‪surface of the screen‬‬

‫;)‪4 SDL_Init(SDL_INIT_VIDEO‬‬
‫‪5 screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE); // We‬‬

‫‪try to open the window‬‬

‫‪6 if (screen == NULL) // If we can’t, we note it and we exit.‬‬
‫{‪7‬‬
‫”‪8 fprintf(stderr, ”Impossible to load video mode :%s\n‬‬

‫‪9‬‬ ‫;))(‪, SDL_GetError‬‬
‫‪10‬‬ ‫;)‪exit(EXIT_FAILURE‬‬
‫‪11‬‬ ‫}‬
‫‪12‬‬ ‫;)‪SDL_WM_SetCaption(”My super SDL window !”, NULL‬‬
‫‪13‬‬ ‫;)(‪pause‬‬
‫‪14‬‬ ‫;)(‪SDL_Quit‬‬
‫} ‪15‬‬ ‫;‪return EXIT_SUCCESS‬‬

‫الرسالة التي تتركها لنا الدالة ‪ ، SDL_GetError‬مفيدة من أجل معرفة ما ال ّذي لم يعمل‪.‬‬

‫حكاية صغيرة ‪ :‬مرة أخطأت بينما أريد أن أفتح نافذة بأسلوب الشاشة الكاملة )‪ ،(Full screen‬في‬

‫عوض أن أطلب الدقة ‪ 1024×768‬كتبت بالخطأ ‪ ،10244×768‬لم أفهم لماذا لم يتم التحميل‪ ،‬لأن ّي لم أنتبه‬

‫إلى أنني كتبت ‪ 4‬م ّرتين )ربما كنت متعبا ً(‪ .‬و لحل المشكل ألقي ُت نظرة على الملف ‪، stderr.txt‬‬
‫توجهت إلى رسالة الخطأ و اكتشفت بأن الدقة التي طلبتها مرفوضة )شيء يثير الفضول أليس كذلك‬

‫؟(‪.‬‬

‫تلوين مساحة‬

‫لا توجد ‪ 36‬طر يقة لملء مساحة‪ ،‬الحقيقة أنه توجد طر يقتان ‪:‬‬
‫‪315‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬
‫• إما أن يتم تلوين المساحة بلون موحّد‪.‬‬
‫• إما أن يتم ملؤها عن طر يق تحميل صورة‪.‬‬

‫يمكنك في الحقيقة الرسم في المساحة بيكسلا ببيكسل‪ ،‬لـكن هذه الطر يقة مع ّقدة‪ ،‬لن نراها هنا‪.‬‬

‫سنرى أولا كيف نقوم بتلوين مساحة بلون موحّد‪ .‬في الفصل القادم سنتعلّم كيف نقوم بتحميل صورة‪.‬‬

‫الدالة التي تسمح بتلوين النافذة بلون موحّد هي ‪) SDL_FillRect‬العبارة ‪ FillRect‬تعني ملء‬
‫مستطيل بالإنجليز ي ّة(‪ .‬هذه الدالة تستقبل ‪ 3‬معاملات و هي ‪:‬‬

‫• مؤش ّر نحو المساحة التي نريد التلوين عليها )مثلا ‪.( screen‬‬

‫• الجزء من المساحة الذي نريد تلوينه‪ ،‬إذا أردت تلوين كل المساحة )و هذا ال ّذي نريده( فلتكن قيمة‬
‫المؤشر ‪. NULL‬‬

‫• اللون الذي نريد أن نلوّن به المساحة‪.‬‬

‫كمل ّخص ‪:‬‬

‫;)‪1 SDL_FillRect(surface, NULL, color‬‬

‫التحكم في الألوان بالـ‪SDL‬‬

‫في الـ ‪ SDL‬كل لون مخزن في عدد من نوع ‪. Uint32‬‬

‫إذا كان عددا ً‪ ،‬لماذا إذا لم نستعمل ببساطة النوع ‪ int‬أو النوع ‪ long‬؟‬

‫الـ ‪ SDL‬هي مكتبة متعددة المنصات‪ ،‬و كما تعلم فحجم الـ ‪ int‬يتغير من نظام تشغيل إلى آخر‪ .‬لهذا فإن‬
‫الـ ‪ SDL‬تقوم باستخدام أعداد من أنواع جديدة‪ ،‬هذه الأنواع الجديدة تحجز نفس المكان بالذاكرة في كل أنظمة‬

‫التشغيل‪.‬‬

‫هناك مثلا ً‪:‬‬
‫• ‪ : Uint32‬عدد صحيح بحجم ‪ 32 bits‬أي ‪) 4 octets‬للتذكير ‪.(1 octet = 8 bits :‬‬

‫• ‪ : Uint16‬عدد صحيح مشفر على ‪.(2 octets) 16 bits‬‬

‫‪316‬‬

‫التعامل مع المساحات‬

‫• ‪ : Uint8‬عدد طبيعي مشفر على ‪.(1 octet) 8 bits‬‬

‫لن تستعمل المكتبة سوى ‪ typedef‬لتقوم بتغيير قيمة العدد على حسب نظام التشغيل‪ .‬إذا كنت فضوليا ً‪،‬‬
‫فألق نظرة على الملف ‪. SDL_types.h‬‬

‫لن نتأخر في التعامل مع كل هذا‪ ،‬فالتفاصيل لا تهم حاليا ً‪ .‬كل ما عليك تذكره هو أن النوع ‪ Uint32‬لا‬
‫يخزن إلا عددا صحيحا ًليس إلا‪ ،‬مثل ‪. int‬‬

‫لـكن كيف أعرف أي عدد يوافق اللون ال ّذي أريد ؟‬

‫هناك بالفعل دالة من أجل ذلك ‪ ، SDL_MapRGB :‬هذه الأخيرة تستقبل ‪ 4‬معاملات ‪:‬‬

‫• صيغة الألوان ‪ :‬هذه الصيغة تعتمد على عدد ‪ bits/pixel‬التي قد طلبتها بالـ ‪. SDL_SetVideoMode‬‬
‫يمكنك استرجاع القيمة فهي موجودة في المتغير الداخلي ‪. screen->format‬‬

‫• كمية الأحمر في اللون‪.‬‬
‫• كمية الأخضر في اللون‪.‬‬
‫• كمية الأزرق في اللون‪.‬‬

‫قد لا يعرف البعض بأن كل الألوان يتم تشكيلها عن طر يق خلط الألوان ‪ :‬أزرق‪ ،‬أحمر و أخضر‪.‬‬
‫كل كمية ٺتدرج من العدد ‪) 0‬لا يوجد لون( إلى العدد ‪) 255‬كل اللون موجود(‪ .‬أي أننا لو كتبنا ‪:‬‬
‫)‪1 SDL_MapRGB(screen−>format, 255, 0, 0‬‬

‫فاللون المتشكل سيكون أحمرا‪ .‬لا وجود للأخضر و لا للأزرق‪ ،‬أما لو نكتب ‪:‬‬
‫)‪1 SDL_MapRGB(screen−>format, 0, 0, 255‬‬

‫اللون سيكون أزرقا‪ ،‬بينما لو نكتب ‪:‬‬

‫)‪1 SDL_MapRGB(screen−>format, 255, 255, 255‬‬

‫اللون سيكون أبيض لأننا دمجنا كل الألوان‪ ،‬لو أنك تريد تشكيل اللون الأسود‪ ،‬فلتجعل كل القيم على ‪.0‬‬

‫ألا يمكننا استعمال لون آخر غير هذه الألوان ؟‬

‫كل ّا‪ ،‬يمكنك ذلك لو أنك تقوم بمزج الألوان بشكل ذكي‪ .‬للمساعدة في ذلك‪ ،‬توجه إلى برنامج ‪ Paint‬ثم إلى‬
‫‪ ، Modify the colors / Colors‬انقر على ‪ Define the colors‬ثم ‪. Custom‬‬
‫هنا‪ ،‬اختر اللون ال ّذي يلائمك‪ .‬أنظر إلى الصورة التالية ‪:‬‬

‫‪317‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫مركّبات اللون متواجدة في أسفل يمين النافذة‪ .‬كما ترى فقد اخترت لونا أخضر مزرق ّا‪ ،‬و هو يتكوّن من ‪17‬‬
‫من الأحمر‪ 206 ،‬من الأخضر‪ ،‬و ‪ 112‬من الأزرق‪.‬‬
‫تلوين الشاشة‬

‫الدالة ‪ SDL_MapRGB‬تقوم بإرجاع عدد من نوع ‪ Uint32‬يوافق الل ّون المختار‪.‬‬
‫يمكننا إذا تعر يف متغير باسم ‪ blueGreen‬يحوي الشفرة الخاصة لاسترجاع هذا اللون ‪:‬‬
‫;)‪1 Uint32 blueGreen = SDL_MapRGB(screen−>format, 17, 206, 112‬‬
‫ليس من الضروري المرور دائما على متغير لتخزين اللون المراد استعماله )إلا إن كنت تحتاجه فعلا في‬

‫برنامجك(‪.‬‬
‫يمكنك مباشرة إعطاء القيمة التي تم ارجاعها من طرف الدالة ‪ SDL_MapRGB‬إلى الدالة ‪. SDL_FillRect‬‬

‫لو نريد أن نملئ الشاشة باللون الأخضر المزرق‪ ،‬يمكننا كتابة ‪:‬‬
‫))‪1 SDL_FillRect(screen , NULL, SDL_MapRGB(screen−>format, 17, 206, 112‬‬

‫;‬

‫لقد قمنا باستدعاء دالة خلال استدعاء دالة أخرى‪ ،‬أعتقد أنك تعرف بأن الأمر ممكن و لا يسبب أ ّي‬
‫مشاكل في لغة ‪.C‬‬

‫‪318‬‬

‫التعامل مع المساحات‬

‫تحديث الشاشة‬

‫لقد اقتربنا من تحقيق الهدف‪.‬‬
‫لقد نسينا أمرا ً بسيطا ً ‪ :‬و هو الأمر بتحديث الشاشة‪ .‬بالفعل‪ ،‬فالأمر ‪ SDL_FillRect‬يقوم بتلوين الشاشة‪،‬‬
‫لـكن هذا لا يحصل إلا في الذاكرة‪ ،‬إذ يجب أن نطلب من الحاسوب تحديث الشاشة لاستعمال البيانات الجديدة‪.‬‬

‫من أجل هذا سنستعمل الدالة ‪ ، SDL_Flip‬سنتكلم بشكل مفصل عن هذه الدالة لاحقا‪.‬‬
‫الدالة تستقبل معاملا واحدا و هو الشاشة ‪. screen‬‬

‫فلنل ّخص كل شيء !‬

‫هذه دالة ‪ main‬تقوم بفتح نافذة ملونة باللون الأخضر المزرق ‪:‬‬

‫‪1‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪2‬‬
‫{‬

‫;‪3 SDL_Surface *screen = NULL‬‬
‫;)‪4 SDL_Init(SDL_INIT_VIDEO‬‬

‫;)‪5 screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬

‫;)‪6 SDL_WM_SetCaption(”My super SDL window!”, NULL‬‬

‫‪7 // We colorize the screen with blue−green color‬‬

‫‪8 SDL_FillRect(screen, NULL, SDL_MapRGB(screen−>format, 17,‬‬

‫‪9‬‬ ‫;))‪206, 112‬‬
‫‪10‬‬ ‫;)‪SDL_Flip(screen‬‬
‫‪11‬‬ ‫;)(‪pause‬‬
‫‪12‬‬ ‫;)(‪SDL_Quit‬‬
‫} ‪13‬‬ ‫;‪return EXIT_SUCCESS‬‬

‫هاهي النتيجة ‪:‬‬
‫‪319‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫رسم مساحة أخرى في الشاشة‬

‫النتيجة السابقة جيدة‪ ،‬لـكننا لن نتوقف هنا‪ .‬لحد الآن ليست لدينا سوى مساحة واحدة و هي الشاشة‪ .‬نحن‬
‫نريد أن نقوم بالرسم عليها‪ ،‬أي ”نلصق” مساحات أخرى عليها بألوان مختلفة‪.‬‬

‫لهذا يجب علينا إنشاء متغير من نوع ‪ SDL_Surface‬للمساحة الجديدة ‪:‬‬
‫;‪1 SDL_Surface *rectangle = NULL‬‬

‫سنطلب إذا من الـ ‪ SDL‬أن تقوم بحجز مكان في الذاكرة من أجل المساحة الجديدة‪.‬‬
‫من أجل الشاشة كنا قد استعملنا ‪ . SDL_SetVideoMode‬لـكن هذه الأخيرة لا تعمل إلا على الشاشة‬

‫)المساحة الرئيسية(‪ ،‬لا نريد أن نقوم بإنشاء نافذة من أجل كل مستطيل نريد إنشاءه !‬
‫توجد إذا دالة أخرى من أجل إنشاء مساحة ‪ . SDL_CreateRGBSurface :‬هذه هي التي سنقوم‬

‫باستعمالها في كل مرة نريد أن ننشئ مساحة جديدة‪.‬‬
‫هذه الدالة تستقبل العديد من المعاملات )ثمانية !(‪ .‬لـكنني لن أتطر ّق إلا للمعاملات التي تهمّنا لح ّد الآن‪.‬‬

‫بما أن لغة ‪ C‬تلُزمنا بإدخال قيم لكل المعاملات‪ ،‬فإننا سنقوم بوضع القيمة ‪ 0‬في مكان كل معامل لا يهمّنا‪.‬‬
‫فلنتأمل قليلا في المعاملات الأربع الأولى )يجدر بها أن تذكّرنا بإنشاء الشاشة(‪.‬‬
‫• قائمة الأعلام )الخيارات(‪ .‬لديك الاختيار بين ‪:‬‬
‫‪320‬‬

‫التعامل مع المساحات‬

‫– ‪ : SDL_HWSURFACE‬المساحة يتم تحميلها في الذاكرة الرسومي ّة‪ .‬و هي تحتوي على مكان أقل‬
‫مقارنة بالذاكرة الخاصة بالنظام )حقيقة‪ ،‬مع بطاقات الـ‪ 3D‬في أيامنا هذه‪ ،‬قد لا يكون لهذا تأثير(‪،‬‬

‫لـكنها ذاكرات سر يعة و فعّالة‪.‬‬
‫– ‪ : SDL_SWSURFACE‬يتم تحميل المساحة في الذاكرة الخاصة بالنظام‪ ،‬أين يوجد الـكثير من المكان‪،‬‬
‫لـكن هذا الاختيار سيجبر المعالج على القيام بحسابات أكثر‪ .‬لو أنك حم ّلت المساحة على الذاكرة‬

‫الرسومي ّة‪ ،‬فإن البطاقة ‪ 3D‬هي المسؤولة عن القيام بأغلب الحسابات‪.‬‬
‫• عرض المساحة )‪.(pixels‬‬
‫• ارتفاع المساحة )‪.(pixels‬‬
‫• عدد الألوان )‪.(bits/pixel‬‬

‫هكذا إذا نقوم بحجز مكان للمساحة الجديدة في الذاكرة ‪:‬‬
‫‪1 rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 220, 180, 32, 0, 0,‬‬

‫;)‪0, 0‬‬

‫الأربع معاملات الأخيرة تساوي ‪ ،0‬كما قلت لك‪ ،‬لأننا لا نهتم بأمرها حاليا ً‪.‬‬

‫بما أننا قمنا بالحجز اليدوي للذاكرة‪ ،‬فيجب علينا تحريرها باستعمال الدالة ‪ SDL_FreeSurface‬و التي‬
‫نستعملها قبل ‪: SDL_Quit‬‬

‫;)‪1 SDL_FreeSurface(rectangle‬‬
‫;)(‪2 SDL_Quit‬‬

‫ليس هناك من داعي إلى تحرير المساحة ‪ screen‬باستعمال ‪ SDL_FreeSurface‬لأنه يتم تحريرها‬
‫تلقائيا ًعند استدعاء ‪. SDL_Quit‬‬

‫يمكننا الآن تلوين المساحة الجديدة باللون الأبيض مثلا ‪:‬‬
‫‪1 SDL_FillRect(rectangle, NULL, SDL_MapRGB(screen−>format, 255, 255,‬‬

‫;))‪255‬‬

‫لصق المساحة بالشاشة‬

‫اقتربنا من النهاية‪ ،‬هيا بعض الشجاعة ! المساحة جاهزة‪ ،‬لـكن لو تحاول تجريب البرنامج‪ ،‬ستلاحظ أنها لن تظهر‬
‫على الشاشة‪ ،‬بالفعل إذ أن المساحة ‪ screen‬هي وحدها التي تم إظهارها‪ .‬لـكي نستطيع رؤ ية مساحتنا الجديدة‬
‫يجب أن نقوم بـتسو ية المساحة‪ ،‬أي لصقها على الشاشة‪ ،‬سنستعمل لأجل هذا الدالة ‪. SDL_BlitSurface‬‬

‫هذه الدالة تنتظر ‪:‬‬

‫‪321‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬
‫• المساحة التي نريد لصقها )هنا ‪.( rectangle‬‬
‫• معلومة حول الجزء من تلك المساحة الذي نريد لصقه )اختياري(‪ .‬لن يهمنا الأمر الآن فنحن نريد لصق‬

‫كل المساحة و لهذا فستكون القيمة ‪. NULL‬‬
‫• المساحة التي نريد أن نلصق عليها المساحة الجديدة )في حالتنا هذه نتكلم عن الشاشة ‪.( screen‬‬
‫• مؤش ّر نحو متغير يحتوي الإحداثيّات‪ .‬هذه الإحداثيات تشير إلى المكان الذي نريد أن نلصق عليه المساحة‪،‬‬

‫أي موقعه‪.‬‬
‫للإشارة إلى الإحداثيّات‪ ،‬نحتاج إلى استعمال متغير من نوع ‪. SDL_Rect‬‬

‫إن ّه هيكل يحتوي العديد من المركّبات‪ ،‬إثنتان منها تهمّنا ‪:‬‬
‫– ‪ : x‬الفاصلة‪.‬‬
‫– ‪ : y‬الترتيبة‪.‬‬

‫يجب أن تعرف ان الإحداثيّة )‪ (0, 0‬توافق اقصى نقطة في يسار أعلى الشاشة‪.‬‬
‫أما الإحداثيّة )‪ (640, 480‬فهي توافق النقطة الموجودة في أقصى يمين أسفل الشاشة‪ ،‬و هذا إن كنت قد‬

‫فتحت نافذة بحجم ‪ 640 × 480‬مثلي‪.‬‬
‫هذا المخطط سيساعدك في الفهم ‪:‬‬

‫إذا كنت قد درست الر ياضيات من قبل‪ ،‬فعلى الأرجح لن تضيع بينما تحاول فهم كيفية العمل‪ .‬فلننشئ‬
‫إذا متغيرا ‪ . position‬سنعطي القيمة ‪ 0‬لكل من الفاصلة و الترتيبة و ذلك ليتم لصق مساحتنا )المستطيل(‬

‫في أعلى يسار النافذة ‪:‬‬
‫‪322‬‬

‫التعامل مع المساحات‬

1 SDL_Rect position;
2 position.x = 0;
3 position.y = 0;

: ‫ يمكننا تسو ية المساحة الجديدة على الشاشة‬،‫و الآن بما أننا حددنا موقعنا في النافذة‬
1 SDL_BlitSurface(rectangle, NULL, screen, &position);

. position ‫لاحظ أنني استعملت الرمز & و ذلك لأنه يجب علينا إرسال عنوان المتغير‬

‫تلخيص الشفرة المصدر ية‬

: ً ‫أعتقد أن وضع الشفرة المصدر ية ال ّتي تلخص ما شرحته لن يكون مضرا‬

1 int main(int argc, char *argv[])
2
{

3 SDL_Surface *screen = NULL, *rectangle = NULL;
4 SDL_Rect position;

5 SDL_Init(SDL_INIT_VIDEO);

6 screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);

7 // Surface allocation

8 rectangle = SDL_CreateRGBSurface(SDL_HWSURFACE, 220, 180, 32,

0,0, 0, 0);

9 SDL_WM_SetCaption(”My super SDL window !”, NULL);
10 SDL_FillRect(screen, NULL, SDL_MapRGB(screen−>format, 17,

206,112));

11 position.x = 0; // The coordinates of the surface will be (0,

0)

12 position.y = 0;
13 // Filling the surface with white color
14 SDL_FillRect(rectangle, NULL, SDL_MapRGB(screen−>format,

255,255, 255));

15 SDL_BlitSurface(rectangle, NULL, screen, &position); //

16 Sticking the surface on the screen
17 SDL_Flip(screen); // Updating the screen
18 pause();
19 SDL_FreeSurface(rectangle); // Freeing the surface
20 SDL_Quit();
21 } return EXIT_SUCCESS;

: ‫شاهد النتيجة‬

323

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫مركزةُ المساحة في الشاشة‬
‫نحن نجيد إظهار المساحة في أعلى اليسار‪ .‬يسهل أيضا موقعتها أسفل يمين الشاشة‪ .‬ستكون الإحداثيات‬

‫)‪ ،(640 − 220, 480 − 180‬لأنه يجب إنقاص حجم المستطيل ليتم إظهاره كاملا‪.‬‬
‫لـكن كيف تتم مركزةُ المستطيل الأبيض ؟ لو تفكّر قليلا ًستجد بأن الحساب ر ياضياتيّ‪ .‬فهنا نعرف الهدف‬

‫من الر ياضيات و الحساب الهندسي !‬
‫ك ّل هذا الأمر بمستوى سهل هنا ‪:‬‬

‫;)‪1 position.x = (640 / 2) − (220 / 2‬‬
‫;)‪2 position.y = (480 / 2) − (180 / 2‬‬

‫فاصلة المستطيل هي نصف عرض الشاشة )‪ .(640/2‬و لـكن‪ ،‬بالإضافة إلى هذا‪ ،‬يجب أن يتم إنقاص‬
‫نصف طول المستطيل أيضا ً )‪ ،(220/2‬لأنك إن لم تنقص هذا الحجم‪ ،‬سيكون تمركز المستطيل خاطئا ً )جرّب‬

‫عدم فعل ذلك و ستفهم ما ال ّذي أعنيه(‪.‬‬
‫كذلك بالنسبة للترتيبة مع ارتفاع الشاشة و المستطيل‪.‬‬
‫النتيجة ‪ :‬المستطيل الأبيض يتمركز بشكل جيد في الشاشة‪.‬‬
‫‪324‬‬

‫تمرين ‪ :‬إنشاء تدرّج لونيّ‬

‫ج‪ 4.2.‬تمرين ‪ :‬إنشاء تدرّج لونيّ‬

‫سننهي الفصل بتمرين صغير )مص ّحح( متبوع بسلسلة تمارين أخرى )غير مصححة من أجل حث ّك على‬
‫التدر يب(‪.‬‬

‫التمرين المصحح ليس صعبا ًح ّقا ‪ :‬ما نريد إنشاءه هو نافذة متدرّجة الألوان عموديا من الأسود إلى الأبيض‪.‬‬
‫سيكون عليك إنشاء ‪ 255‬مساحة بارتفاع ‪ 1‬بيكسل‪ .‬كل مساحة لها لون مختلف أكثر فأكثر سوادا‪.‬‬
‫هذا ما يجب عليك الحصول عليه في النهاية‪ ،‬صورة مشابهة لهذه ‪:‬‬

‫‪325‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬

‫إنه أمر جميل‪ ،‬أليس كذلك ؟ الشيء الأجمل هو أن بعض الحلقات التكرار ية كافية من أجل تحقيق‬
‫المطلوب‪.‬‬

‫لفعل ذلك يجب إنشاء ‪ 256‬مساحة )أي ‪ 256‬سطر( تحتوي مركبات الألوان )أحمر‪ ،‬أخضر‪ ،‬أزرق(‬
‫التالية ‪:‬‬

‫‪1 0, 0, 0) // Black‬‬
‫‪2 (1, 1, 1) // Gray that is so so close from black‬‬
‫‪3 (2, 2, 2) // Gray that is so close from black‬‬
‫‪4 ...‬‬
‫)‪5 (128, 128, 128) // Medium gray (to 50 %‬‬
‫‪6 ...‬‬
‫‪7 (253, 253, 253) // Gray that is so close from white‬‬
‫‪8 (254, 254, 254) // Gray that is so so close from white‬‬
‫‪9 (255, 255, 255) // White‬‬

‫يجب على الجميع أن يعرف أن ّه بحاجة إلى حلقة تكرار ي ّة للقيام بهذا )لن تسعد بتكرار ‪ 256‬سطرا !(‪ .‬و لهذا‬
‫سنقوم بإنشاء جدول من نوع *‪ SDL_Surface‬من ‪ 256‬خانة‪.‬‬

‫إلى العمل‪ .‬لديك ‪ 5‬دقائق !‬

‫تصحيح !‬

‫يجب أولا أن نقوم بتعر يف جدول من ‪ . SDL_Surface* 256‬سنهي ّؤه على ‪: NULL‬‬

‫;}‪1 SDL_Surface *lines[256] = {NULL‬‬

‫سنعرف متغيرا ً ‪ i‬من أجل الحلقات ‪. for‬‬

‫سنغيّر أيضا ًارتفاع النافذة لـكي تكون مناسبة للعمل‪ .‬إذ سنعطيها ‪ 256‬بيكسلز كارتفاع‪ ،‬و ذلك من أجل‬
‫عرض كل سطر من بين ‪ 256‬سطرا‪.‬‬

‫سنستعمل بعد ذلك حلقة تكرار ية ‪ for‬من أجل حجز مكان لـ‪ 256‬مساحة ال ّتي تم إنشاؤها‪ .‬الجدول‬
‫سيستقبل ‪ 256‬مؤشّرا إلى ك ّل واحد من المساحات المنشأة ‪:‬‬

‫)‪1 for (i = 0 ; i <= 255 ; i++‬‬
‫‪2 lines[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, 640, 1, 32,‬‬

‫;)‪0,0, 0, 0‬‬

‫بعد ذلك نقوم بملء و لصق كل مساحة في الشاشة واحدة بواحدة‪.‬‬

‫‪326‬‬

‫تمرين ‪ :‬إنشاء تدرّج لونيّ‬

‫)‪1 for (i = 0 ; i <= 255 ; i++‬‬
‫{‪2‬‬
‫)‪3 position.x = 0; // The lines are to the left (0 abscissa‬‬
‫’‪4 position.y = i; // The vertical position depends on the line‬‬

‫‪s number‬‬

‫‪5 SDL_FillRect(lines[i], NULL, SDL_MapRGB(screen−>format, i, i,‬‬

‫‪i)); // Drawing‬‬

‫‪6 SDL_BlitSurface(lines[i], NULL, screen, &position); //‬‬

‫‪Sticking‬‬

‫}‪7‬‬

‫لاحظ أنني استعمل كل الوقت المتغير ‪ . position‬إذ ليس لازما أن ننشئ ‪ 256‬واحدا‪ ،‬لأننا لن نقوم‬
‫إلا ببعث المتغير إلى الدالة ‪ . SDL_BlitSurface‬يمكننا إذن إعادة استخدامه دون مشاكل‪.‬‬

‫في ك ّل مرة أقوم بالتعديل على الترتيبة ) ‪ ،( y‬لتسو ية المساحة على الارتفاع الصحيح‪ .‬اللون يعتمد في ك ّل مرة‬
‫على قيمة المتغير ‪) i‬ستكون ‪ 0, 0, 0‬في أ ّول م ّرة و ‪ 255, 255, 255‬في آخر م ّرة(‪.‬‬

‫لـكن لماذا قيمة ‪ x‬هي دائما ً؟‬
‫كيف يمكن للمساحة أن ٺتلون كليا إذا كانت قيمة الـ ‪ x‬دائما ؟‬

‫المتغير ‪ position‬يشير إلى أي مكان ٺتواجد فيه المنطقة أعلى اليسار )هنا نتكلم عن السطر(‪ .‬هي لا‬
‫تحدد عرض المساحة و إنما فقط أين ٺتواجد المر ّكبة على الشاشة‪.‬‬

‫بما أن كل الأسطر تبدأ في أقصى يسار النافذة‪ ،‬فستكون الفاصلة مساو ية لـ‪ .0‬حاول وضع فاصلة تساوي ‪50‬‬
‫لترى ماذا سيعطيك ‪ :‬كل الأسطر ستتنحي إلى اليمين‪.‬‬

‫بما أن المساحة تأخذ ‪ 640‬بيكسل كطول ‪ ،‬فإن الـ‪ SDL‬تقوم بإنشاء ‪ 640‬بيكسلا في اتجاه اليمين )من نفس‬
‫اللون( إنطلاقا ًمن المركبات التي يشير إليها المتغير ‪. position‬‬

‫في المخطط التالي أر يك مركبات النقطة المتواجدة أعلى يسار الشاشة )وضعية أول سطر( ومركبات النقطة‬
‫المتواجدة أسفل يسار الشاشة )وضعية آخر سطر(‪.‬‬

‫‪327‬‬

‫ إنشاء نافذة و مساحات‬.2.‫الفصل ج‬

‫ وحده يتغير من أجل‬y ‫( بينما‬0‫ يبقى مساو يا لـ‬x ) ‫ المحور لا يتغير‬،‫ من الأعلى إلى الأسفل‬،‫كما ترى‬
. position.y = i; ‫ و بهذا‬،‫كل سطر جديد‬

‫ بمساعدة حلقة‬،‫ مساحة المنشأة‬256‫أخيرا ً لا تنس أنه يجب تحرير الذاكرة من أجل كل مساحة من الـ‬
.‫بالطبع‬

1 for (i = 0 ; i <= 255 ; i++) // Don’t forget to free the 256 surfaces
2 SDL_FreeSurface(lines[i]);

main ‫مل ّخص‬

: ‫ كاملة‬main ‫هذه هي الدالة‬

1 int main(int argc, char *argv[])
2{

3 SDL_Surface *screen = NULL, *lines[256] = {NULL};
4
SDL_Rect position;

5 int i = 0;

6 SDL_Init(SDL_INIT_VIDEO);

7 screen = SDL_SetVideoMode(640, 256, 32, SDL_HWSURFACE);

8 for (i = 0 ; i <= 255 ; i++)

9 lines[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, 640,

1, 32,0, 0, 0, 0);

10 SDL_WM_SetCaption(”My SDL gradient !”, NULL);
11 SDL_FillRect(screen , NULL, SDL_MapRGB(screen −>format, 0, 0,

0));

12 for (i = 0 ; i <= 255 ; i++)
13 {
14 position.x = 0; // The lines are to the left
15 position.y = i; // The vertical position depends on

the line’s number

16 SDL_FillRect(lines[i], NULL, SDL_MapRGB(screen−>

format, i, i, i));

17 SDL_BlitSurface(lines[i], NULL, screen, &position);
18 }
19 SDL_Flip(screen);
20 pause();
21 for (i = 0 ; i <= 255 ; i++) // Don’t forget to free the 256

22 surfaces
23 SDL_FreeSurface(lines[i]);
24
25 } SDL_Quit();
return EXIT_SUCCESS;

”! ‫”أريد تمارين للتدريب‬

! ‫ مول ّد التمارين مُشَغّل‬،‫لا مشكلة‬

328

‫مل ّخص‬
‫• قم بإنشاء تدرج عكسي للألوان‪ ،‬أي من الأبيض للأسود‪ .‬هذا الأمر لن يكون صعبا للبدأ !‬

‫• يمكنك أيضا ً وضع كلى التدرّجين‪ ،‬من الأبيض للأسود ثم من الأسود للأبيض )ستأخذ النافذة ضعف‬
‫الارتفاع الحالي(‪.‬‬

‫• أكثر صعوبة قليلا‪ ،‬يمكنك وضع تدرج أفقي بدل التدرج العمودي‪.‬‬
‫• حاول إنشاء تدرج ألوان مختلفة عن الأسود و الأبيض‪ .‬جرب مثلا من الأحمر إلى الأسود‪ ،‬من الأخضر‬

‫إلى الأسود‪ ،‬و من الأزرق إلى الأسود‪ ،‬ثم ّ من الأحمر إلى الأبيض‪ ،‬إلخ‪.‬‬

‫مل ّخص‬

‫• يتم تحميل الـ ‪ SDL‬بواسطة الـ ‪ SDL_Init‬في بداية البرنامج‪ ،‬و يتم إيقافها باستعمال ‪ SDL_Quit‬في‬
‫النهاية‪.‬‬

‫• الأعلام هي ثوابت يمكن جمعها فيما بينها باستعمال الرمز | ‪ ،‬و هي تلعب دور الخواص‪.‬‬
‫• تقوم الـ‪ SDL‬بالتعامل مع المساحات و التي هي عبارة عن مستطيلات من نوع ‪ . SDL_Surface‬الرسم‬

‫على النافذة يتم بالاستعانة بهذه المساحات‪.‬‬
‫• توجد دائما على الأقل مساحة واحدة و التي تحجز ك ّل النافذة‪ ،‬و نسميها في أغلب الأحيان الشاشة‬

‫) ‪.( screen‬‬
‫• ملء مساحة يتم باستعمال ‪ ، SDL_FillRect‬ولصقها في الشاشة يتم باستعمال ‪. SDL_BlitSurface‬‬

‫• الألوان معر ّفة بمزيج من الأحمر‪ ،‬الأزرق و الأخضر‪.‬‬

‫‪329‬‬

‫الفصل ج‪ .2.‬إنشاء نافذة و مساحات‬
‫‪330‬‬

‫الفصل ج‪3.‬‬

‫إظهار صور‬

‫لقد تعل ّمنا كيف نقوم بتحميل الـ‪ ،SDL‬فتح نافذة و التعامل مع المساحات‪ .‬إنها بالفعل من المبادئ التي‬
‫تجب معرفتها عن هذه المكتبة‪ .‬لـكن لح ّد الآن لا يمكننا سوى إنشاء مساحات موحّدة اللون‪ ،‬و هذا الأمر‬

‫بدائي قليلا ً‪.‬‬
‫في هذا الفصل‪ ،‬سنتعلّم كيف نقوم بتحميل صور على مساحات‪ ،‬مهما كانت صيغتها ‪ PNG ،BMP‬أو حتى‬
‫‪ GIF‬أو ‪ .JPG‬التحكم في الصور أمر مهم للغاية لأنه بتجميع الصور )نسميها أيضا ً”‪ (”sprites‬نضع اللبنات الأولى‬

‫في بناء لعبة فيديو‪.‬‬

‫ج‪ 1.3.‬تحميل صورة ‪BMP‬‬

‫الـ‪ SDL‬هي مكتبة بسيطة جدا ً‪ .‬فهي لا تستطيع أساسا تحميل سوى صور من نوع ”‪) ”bitmap‬ذات امتداد‬
‫‪ .( .bmp‬لا تقلق‪ ،‬فبفضل إضافة خا ّصة بالـ‪) SDL‬المكتبة ‪ ،(SDL_Image‬سنرى بأنه بإمكاننا أيضا ً تحميل‬

‫صور من صيغ أخرى‪.‬‬
‫للبدأ‪ ،‬سنكتفي الآن بما تسمح لنا به الـ‪ SDL‬بشكل قاعدي‪ .‬سنقوم بدراسة تحميل صور ‪.BMP‬‬

‫الصيغة ‪BMP‬‬

‫الصيغة ‪) BMP‬إختصار لـ‪ (bitmap‬هي صيغة صور‪.‬‬
‫الصور ال ّتي نجدها في الحاسوب مخز ّنة في ملفات‪ .‬يوجد العديد من صيغ الصور‪ ،‬أي العديد من الطرق لتخزين‬
‫صورة في ملف‪ .‬على حسب الصيغة‪ ،‬يمكن للصورة أخذ الـكثير أو القليل من مساحة القرص الصلب‪ ،‬و تملك‬

‫جودة أحسن أو أسوء‪.‬‬
‫الـ‪ Bitmap‬هي صيغة غير مضغوطة )على عكس الـ‪ ،GIF ،PNG ،JPG‬إلخ(‪ .‬فعلي ّا‪ ،‬هذا يعني الأمور التالية ‪:‬‬

‫‪331‬‬

‫الفصل ج‪ .3.‬إظهار صور‬

‫• يكون الملف سر يعا ً جدا ً من ناحية قراءته‪ ،‬على عكس الصيغ المضغوطة التي يجب أن يتم فك الضغط‬
‫عنها‪ ،‬مما يكل ّفنا بعض الوقت‪.‬‬

‫• جودة الصورة مثالية‪ .‬بعض الصيغ المضغوطة )أفكّر في الـ‪ JPG‬خصوصا‪ ،‬لأن الـ‪ PNG‬و الـ‪ GIF‬لا يغيّرون‬
‫في الصورة( تقوم بتخريب جودة الصورة‪ ،‬و هذا ليس هو الحال بالنسبة للـ‪.BMP‬‬

‫• لـك ّن الملف سيكون ضخما ًبما أنه ليس مضغوطا ً!‬

‫توجد هناك إذا مزايا و مساوئ‪.‬‬
‫بالنسبة للـ‪ ،SDL‬الشيء الجيد هو أن نوع الملف سيكون بسيطا و سهل القراءة‪ .‬إذا كان عليك تحميل الصور دائما‬
‫في نفس وقت تشغيل برنامجك‪ ،‬من المستحسن استعمال صور بصيغة ‪ .BMP‬سيكون حجم الملف ضخما حتما‪،‬‬
‫لـكنه يـ ُحمّل بشكل أسرع من الـ‪ GIF‬مثلا ً‪ .‬سيكون الأمر مه ّما إذا كان على برنامجك تحميل الـكثير من الصور‬

‫في وقت قليل‪.‬‬

‫تحميل صورة ‪Bitmap‬‬

‫تنز يل حزمة الصور‬

‫في هذا الفصل سنقوم بالعمل على كثير من الصور‪ .‬إذا أردت القيام بتجريب الشفرات بينما أنت تقرأ )و هذا‬
‫ما يجدر بك فعله !(‪ ،‬فأنصحك بتنز يل حزمة الصور التي تحتوي كل الصور التي نحتاج إليها‪.‬‬

‫‪https://openclassrooms.com/uploads/fr/ftp/mateo21/pack_images_sdz.zip‬‬
‫)‪(1 Mo‬‬

‫بالطبع‪ ،‬يمكنك استعمال صورك الخاصة‪ .‬يجب عليك فقط أن تع ّدل مقاييس النافذة على حسب مقاييس‬
‫الصورة‪.‬‬

‫قم بوضع كل الصور في مجل ّد المشروع‪ .‬سنبدأ أولا ّ بالعمل على الصورة ‪. lac_en_montagne.bmp‬‬
‫هي عبارة عن لقطة تم استخلاصها من مشهد ثلاثي الأبعاد مأخوذ من البرنامج الممتاز الخاص بنمذجة المناظر‬
‫الطبيعية ‪ ،Vue d’Espri 4‬و الذي تم إيقاف تسو يقه‪ .‬منذ ذلك‪ ،‬تم ّ تغيير اسم البرنامج إلى ‪ Vue‬و تم تطويره‬

‫كثيرا ً‪ .‬لمن يريد معرفة المزيد عنه‪ ،‬يمكنه ز يارة الموقع ‪.http://www.e-onsoftware.com/ :‬‬

‫تحميل صورة في مساحة‬

‫سنقوم باستعمال دالة تقوم بتحميل صورة ذات صيغة ‪ BMP‬و لصقها في مساحة‪.‬‬
‫هذه الدالة تدعى ‪ SDL_LoadBMP‬و سترى أن استعمالها سهل للغاية ‪:‬‬

‫;)”‪1 mySurface = SDL_LoadBMP(”image.bmp‬‬

‫‪332‬‬

BMP ‫تحميل صورة‬

: ‫ تقوم بتعو يض دالتين تعرفهما‬SDL_LoadBMP ‫الدالة‬

‫ تقوم بحجز مكان في الذاكرة من أجل تخزين مساحة ذات الحجم‬: SDL_CreateRGBSurface •
.( malloc ‫المطلوب )تكافئ دالة‬

.‫ تقوم بملئ الهيكل بلون موحّد‬: SDL_FillRect •

: ‫لماذا تقوم الدالة بتعو يض هذين الدالتين ؟ الأمر بسيط‬

‫ اذا كان حجم الصورة هو‬: ‫• الحجم الذي نقوم بحجزه في الذاكرة من أجل المساحة يعتمد على حجم الصورة‬
.‫ فستأخذ المساحة نفس الحجم‬250 × 300

.BMP ‫ يتم ملئ المساحة بيكسلا ببيكسل بمحتوى الصورة‬،‫• من جهة أخرى‬

: ‫فلنكتب الشفرة دون أي تأخير‬

1 int main(int argc, char *argv[])
2
{

3 SDL_Surface *screen = NULL, *backgroundImage = NULL;
4 SDL_Rect backgroundPosition;

5 backgroundPosition.x = 0;

6 backgroundPosition.y = 0;

7 SDL_Init(SDL_INIT_VIDEO);

8 screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);

9 SDL_WM_SetCaption(”Loading the images on SDL”, NULL);

10 /* Loading a Bitmap image in a surface */
11 backgroundImage = SDL_LoadBMP(”lac_en_montagne.bmp”);

12 /* We blit on the screen */
13
SDL_BlitSurface(backgroundImage, NULL, ecran, &

14 backgroundPosition);
15 SDL_Flip(screen);
16 pause();
17 SDL_FreeSurface(backgroundImage); // We free the surface
18 SDL_Quit();
19 } return EXIT_SUCCESS;

‫ ( و نحو كل المركّبات الموافقة لها‬backgroundImage ) ‫و بهذا أكون قد أنشأت مؤش ّرا ً نحو مساحة‬
.( backgroundPosition )

. SDL_LoadBMP ‫تم إنشاء المساحة في الذاكرة و ملؤها من طرف الدالة‬

: ‫ و هذا ك ّل شيء ! الصورة التالية تو ّضح النتيجة‬screen ‫نقوم بتسويتها على المساحة‬

333

‫الفصل ج‪ .3.‬إظهار صور‬

‫كما ترى‪ ،‬لم يكن الأمر صعبا ً!‬
‫إرفاق أيقونة بالتطبيق‬

‫بما أننا الآن نجيد تحميل الصور‪ ،‬يمكننا اكتشاف كيفية إرفاق أيقونة بالبرنامج‪ .‬سيتم إظهار الأيقونة في أعلى يسار‬
‫النافذة )و أيضا ًفي شر يط المهام(‪ .‬لح ّد الآن نحن لا نملك إلا ّ أيقونة افتراضي ّة‪.‬‬
‫لـكن ألا يجدر بأيقونات البرامج أن تكون ذات الامتداد ‪ .ico‬؟‬

‫كل ّا‪ ،‬ليس شرطا ً ! على ك ّل فالامتداد ‪ .ico‬لا يوجد إلا في نظام الويندوز‪ .‬الـ‪ SDL‬ٺتعامل مع ك ّل‬
‫أنظمة التشغيل باستعمالها نظاما خاصا بها ‪ :‬المساحة !‬
‫نعم‪ ،‬أيقونة برنامج ‪ SDL‬ماهي إلا مساحة بسيطة‪.‬‬

‫يجدر بالأيقونة أن تكون ذات حجم ‪ 16 × 16‬بيكسلز‪ .‬بينما في الويندوز يجب أن تكون بحجم ‪32 × 32‬‬
‫بيكسلز و إلا فستسوء جودتها‪ .‬لا تقلق إذ يمكن للـ‪” SDL‬تصغير” أبعاد الصورة لتتمكن من الدخول في‬

‫‪ 16 × 16‬بيكسلز‪.‬‬
‫لإضافة الأيقونة إلى النافذة‪ ،‬نستعمل الدالة ‪. SDL_WM_SetIcon‬‬
‫هذه الدالة تأخذ معاملين ‪ :‬المساحة التي تحتوي الصورة التي نريد إظهارها كما أنها تستقبل معلومات حول الشفافية‬

‫‪334‬‬

‫التحكم في الشفافية‬

‫ التحكّم في الشفافية الخاصة بأيقونة مع ّقد قليلا ً )يجب تحديد‬.(‫ تعني أننا لا نريد أية شفافية‬NULL ‫)القيمة‬
.‫ لن ندرس ذلك إذا‬،(‫البيكسلز الشفافة واحدة بواحدة‬
: ‫سنقوم باستدعاء دالة في استدعاء لأخرى‬

1 SDL_WM_SetIcon(SDL_LoadBMP(”sdl_icone.bmp”), NULL);

. SDL_WM_SetIcon ‫ و تم بعث عنوان المساحة مباشرة إلى‬SDL_LoadBMP ‫تم تحميل الصورة في الذاكرة بواسطة‬

‫ أي أنه يجدر بها التواجد‬،‫ قبل أن يتم فتح النافذة‬SDL_WM_SetIcon ‫يجب أن يتم استدعاء الدالة‬
.‫ في الشفرة المصدر ية‬SDL_SetVideoMode ‫قبل‬

.‫ مقارنة بالشفرة السابقة‬SDL_WM_SetIcon ‫ ستلاحظ أنني أضفت‬.‫هذه هي الشفرة المصدر ية الكاملة‬

1 int main(int argc, char *argv[])
2
{

3 SDL_Surface *screen = NULL, *backgroundImage = NULL;
4
SDL_Rect backgroundPosition;

5 backgroundPosition.x = 0;

6 backgroundPosition.y = 0;

7 SDL_Init(SDL_INIT_VIDEO);

8 /* Loading the icon before SDL_SetVideoMode*/
9
SDL_WM_SetIcon(SDL_LoadBMP(”sdl_icone.bmp”), NULL);

10 screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);

11 SDL_WM_SetCaption(”Loading images on SDL”, NULL);

12 backgroundImage = SDL_LoadBMP(”lac_en_montagne.bmp”);

13 SDL_BlitSurface(backgroundImage, NULL, screen, &

14 backgroundPosition);
15 SDL_Flip(screen);
16 pause();
17 SDL_FreeSurface(backgroundImage);
18 SDL_Quit();
19 } return EXIT_SUCCESS;

.‫ تم تحميل الصورة و عرضها أعلى يسار النافذة‬: ‫النتيجة‬

‫ التحكم في الشفافية‬2.3.‫ج‬

335

‫ إظهار صور‬.3.‫الفصل ج‬

‫مشكل الشفافية‬

.‫ في النافذة‬bitmap ‫لقد قمنا قبل قليل بتحميل صورة‬

‫ غالبا اللاعب الذي يتحر ّك في الخر يطة‬.‫ و هذا ما يحصل كثيرا ً في الألعاب‬.‫لنفرض أننا نريد لصق صورة فوقها‬
.‫ تتحرك فوق صورة خلفية‬bitmap ‫هو عبارة عن صورة‬

OpenClassrooms ‫ سلف الموقع‬Site du Zéro ‫ فهو شعار‬،‫ )لمن لا يعرفه‬Zozor ‫سنقوم بلصق صورة‬
: ‫حالي ّا( في المشهد‬

1 int main(int argc, char *argv[])
2{
3 SDL_Surface *screen = NULL, *backgroundImage = NULL, *zozor =

NULL;

4 SDL_Rect backgroundPosition, zozorPosition;
5 backgroundPosition.x = 0;
6 backgroundPosition.y = 0;
7 zozorPosition.x = 500;
8 zozorPosition.y = 260;
9 SDL_Init(SDL_INIT_VIDEO);
10 SDL_WM_SetIcon(SDL_LoadBMP(”sdl_icone.bmp”), NULL);
11 screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
12 SDL_WM_SetCaption(”Loading images on SDL”, NULL);
13 backgroundImage = SDL_LoadBMP(”lac_en_montagne.bmp”);
14 SDL_BlitSurface(backgroundImage, NULL, ecran, &

15 backgroundPosition);
16 //Loading and blitting Zozor on the screen
17 zozor = SDL_LoadBMP(”zozor.bmp”);
18 SDL_BlitSurface(zozor, NULL, screen, &zozorPosition);
19 SDL_Flip(screen);
20 pause();
21 SDL_FreeSurface(backgroundImage);
22 SDL_FreeSurface(zozor);
23 SDL_Quit();
24 } return EXIT_SUCCESS;

: ‫ و التي نقوم بلصقها في مكان معي ّن من المشهد‬،Zozor ‫لقد قمنا فقط بإضافة مساحة لنخز ّن فيها‬
336

‫التحكم في الشفافية‬

‫يبدو المشهد سي ّئا‪ ،‬أليس كذلك ؟‬
‫بالطبع يعود ذلك إلى الخلفية الزرقاء التي هي خلف ‪! Zozor‬‬
‫لأنك تعتقد أنه بوجود خلفية سوداء أو بن ّي ّة‪ ،‬ربما سيكون المظهر لائقا ً أكثر ؟ لا بالطبع‪ ،‬المشكل هنا هو‬
‫أنه من اللازم أن يكون شكل الصورة عبارة عن مستطيل‪ ،‬أي أنه إذا قمنا بلصقها على المشهد‪ ،‬سنرى خلفيتها‪،‬‬

‫مما يشوّه المظهر‪.‬‬
‫من حسن الح ّظ أن الـ‪ SDL‬تتحكم في الشفافية !‬

‫جعل صورة شفافة‬

‫الخطوة ‪ : 1‬تحضير الصورة‬
‫كبداية‪ ،‬يجب تحضير الصورة التي نريد تسويتها على المشهد‪.‬‬
‫الصيغة ‪ BMP‬لا تتحكم في الشفافية‪ ،‬على عكس الصيغتين ‪ GIF‬و ‪ .PNG‬لهذا يحب علينا أن نجد حلا ًآخر‪.‬‬
‫يجب استعمال نفس اللون للخلفية على الصورة‪ .‬هذه الأخيرة ستكون شفافة من طرف الـ‪ SDL‬في وقت‬
‫التسو ية‪ .‬لاحظ كيف تبدو الصورة ‪ zozor.bmp‬من ناحية أقرب ‪:‬‬
‫‪337‬‬

‫الفصل ج‪ .3.‬إظهار صور‬

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

‫يتناوله الحمار )أسفل يسار الصورة( شفافا ً‪.‬‬
‫استعمل إذا أي برنامج كان )‪… ،The Gimp ،Photoshop ،Paint‬لك ّل واحد من ّا ذوقه( لإعطاء خلفية‬

‫موحّدة للصورة‪.‬‬

‫الخطوة ‪ : 2‬تحديد اللون الشفاف‬

‫لـكي نقوم بتحديد اللون الذي يجب أن تجعله ‪ SDL‬شفافا ً‪ ،‬يجب أن نستعمل الدالة ‪. SDL_SetColorKey‬‬
‫يجب استدعاء هذه الدالة قبل تسو ية الصورة‪.‬‬

‫هكذا نقوم بتحو يل اللون الذي خلف ‪ Zozor‬إلى الشفاف ‪:‬‬
‫‪1 SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor−>format, 0,‬‬

‫;))‪0, 255‬‬

‫هناك ثلاثة معاملات ‪:‬‬

‫• المساحة التي يجب أن نقوم بتحو يلها إلى اللون الشفاف )هنا نتكلم عن ‪.( zozor‬‬
‫• قائمة الأعلام ‪ :‬استعمل ‪ SDL_SRCCOLORKEY‬لتفعيل الشفافية‪ 0 ،‬من أجل تعطيلها‪.‬‬
‫• حدد بعد ذلك اللون الذي يجب أن يتم تحو يله إلى الشفاف‪ .‬لقد استعملت ‪ SDL_MapRGB‬لإنشاء‬
‫اللون بصيغة عدد ) ‪ ( Uint32‬كما فعلنا بالسابق‪ .‬كما ترى إنه اللون الأزرق )‪ (0, 0, 255‬ال ّذي سيتم‬

‫تحو يله إلى الشفاف‪.‬‬

‫كملخص‪ ،‬نقوم أولا بتحميل الصورة باستعمال ‪ ، SDL_LoadBMP‬ثم ّ نحدد اللون الشفاف باستعمال‬
‫‪ SDL_SetColorKey‬ثم نقوم بتسو ية المساحة باستعمال ‪. SDL_BlitSurface‬‬

‫;)”‪1 zozor = SDL_LoadBMP(”zozor.bmp‬‬
‫‪2 SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor−>format, 0,‬‬

‫;))‪0, 255‬‬

‫;)‪3 SDL_BlitSurface(zozor, NULL, screen, &zozorPosition‬‬

‫‪338‬‬

‫التحكم في الشفافية‬

‫النتيجة ‪ :‬تم دمج صورة ‪ Zozor‬بشكل ممتاز في المشهد ‪:‬‬

‫هذه هي التقنية المبدئية التي ستعيد استعمالها كل الوقت في برامجك‪ .‬تعلّم كيف تتحكم جيدا ً بالشفافية لأنها‬
‫من أساسيات صنع لعبة تملك الح ّد الأدنى من الواقعية‪.‬‬

‫الشفافية ‪Alpha‬‬

‫هو نوع آخر من الشفافية‪.‬‬
‫لح ّد الآن قمنا بتعر يف لون واحد شفاف )الأزرق مثلا(‪ .‬هذا اللون لا يظهر في الصورة الملُصقة‪.‬‬
‫الشفافية ‪ Alpha‬توافق شيئا ًآخر‪ ،‬إنها تسمح بعمل ”مزج” بين صورة و خلفية‪ .‬هذا نوع من التلاشي‪.‬‬

‫يمكن تفعيل الشفافية ‪ Alpha‬لمساحة عن طر يق الدالة ‪: SDL_SetAlpha‬‬
‫;)‪1 SDL_SetAlpha(zozor, SDL_SRCALPHA, 128‬‬

‫يوجد هنا ثلاثة معاملات كذلك ‪:‬‬

‫• المساحة التي نتكلم عنها ) ‪.( zozor‬‬
‫• قائمة الأعلام ‪ :‬ضع ‪ SDL_SRCALPHA‬من أجل تفعيل الشفافية‪ 0 ،‬من أجل تعطيلها‪.‬‬

‫‪339‬‬

‫الفصل ج‪ .3.‬إظهار صور‬

‫• مهم جدا ‪ :‬قيمة الشفافية ‪ Alpha‬هي عدد يتراوح بين ‪) 0‬صورة شفافة تماما ً أي غير مرئية( و ‪255‬‬
‫)صورة ظاهرة كليا ً‪ ،‬و كأن الشفافية ‪ Alpha‬لم تكن موجودة(‪.‬‬

‫كلما كان العدد ‪ Alpha‬صغيرا ً كلما زادت شفافية الصورة و تلاشيها في الخلفية‪.‬‬
‫هذا مثال عن شفرة تقوم بتطبيق شفافية بقيمة ‪ 128‬على الصورة ‪: Zozor‬‬

‫;)”‪1 zozor = SDL_LoadBMP(”zozor.bmp‬‬
‫‪2 SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor−>format, 0,‬‬

‫;))‪0, 255‬‬

‫‪3 /* Average Alpha transparency (128) : */‬‬
‫;)‪4 SDL_SetAlpha(zozor, SDL_SRCALPHA, 128‬‬
‫;)‪5 SDL_BlitSurface(zozor, NULL, screen, &zozorPosition‬‬

‫تلاحظ أنني حافظت على شفافية ‪ . SDL_SetColorKey‬يمكن دمج النوعين الاثنين للشفافية معا ً‪.‬‬

‫الجدول التالي يو ّضح لك كيف يبدو ‪ Zozor‬باختلاف قيم ‪.Alpha‬‬

‫النتيجة‬ ‫‪Alpha‬‬

‫‪) 255‬مرئيّة بالكامل(‬

‫‪190‬‬
‫‪) 128‬شفافي ّة متو ّسطة(‬

‫‪75‬‬
‫‪340‬‬

‫تحميل صيغ صور أخرى باستعمال الـ‪SDL_Image‬‬

‫‪) 0‬غير مرئيّة بالكامل(‬

‫قيمة الشفافية ‪) 128 Alpha‬شفافية متوسطة( هي قيمة خا ّصة و كثيرة الإستعمال بالـ‪ .SDL‬هذا النمط‬
‫من الشفافية أسرع من ناحية حسابات المعالج مقارنة بالأنماط الأخرى‪ .‬قد يكون من المهم لك معرفة‬

‫هذه المعلومة خاصة إن كنت تستعمل الشفافية ‪ Alpha‬بشكل كبير في برامجك‪.‬‬

‫ج‪ 3.3.‬تحميل صيغ صور أخرى باستعمال الـ‪SDL_Image‬‬

‫الـ‪ SDL‬لا ٺتعامل إلا مع الـ‪) bitmap‬الصيغة ‪ (BMP‬كما رأينا‪.‬‬
‫و لـكن هذا ليس بمشكل لأن قراءة الصور ذات الصيغة ‪ BMP‬أسرع بالنسبة للـ‪ ،SDL‬و لـكن يجب معرفة أنه‬
‫في أيامنا هذه يتم استعمال صيغ أخرى للصور‪ .‬بالتحديد الصيغ ”المضغوطة” كالـ‪ ،PNG‬الـ‪ GIF‬و الـ‪ .JPEG‬لهذا‬

‫الغرض توجد مكتبة تسمى ‪ SDL_Image‬و تقوم بالتعامل مع كل صيغ الصور التالية ‪:‬‬
‫• ‪،TGA‬‬
‫• ‪،BMP‬‬
‫• ‪،PNM‬‬
‫• ‪،XPM‬‬
‫• ‪،XCF‬‬
‫• ‪،PCX‬‬
‫• ‪،GIF‬‬
‫• ‪،JPG‬‬
‫• ‪،TIF‬‬
‫• ‪،LBM‬‬
‫• ‪.PNG‬‬

‫بالمناسبة فإنه بالإمكان أن تتم إضافة صيغ أخرى للـ‪ .SDL‬و هي المكتبات التي تحتاج إلى الـ‪ SDL‬لـكي تعمل‪.‬‬
‫يمكننا تسمية هذا الأمر بالـ‪) add-ons‬بمعنى ”إضافات”(‪ SDL_Image .‬هي واحدة من بين هذه المكتبات ‪.‬‬

‫‪341‬‬

‫الفصل ج‪ .3.‬إظهار صور‬

‫ٺثبيت الـ‪ SDL_Image‬على ‪Windows‬‬

‫التنز يل‬

‫توجد صفحة خاصة من موقع الـ‪ SDL‬تشير إلى المكتبات التي تستعملها الـ‪ .SDL‬هذه الصفحة تحمل عنوان‬
‫”‪ .”Libraries‬ستجد رابطا ًفي القائمة اليسار ية‪.‬‬

‫ستلاحظ أن هناك الـكثير من المكتبات و أغلبها ليس من طرف المبرمجـين الأصليين للـ‪ .SDL‬بل هم مبرمجون‬
‫عاديون يستعملون الـ‪ SDL‬و يقومون باقتراح مكتباتهم الخاصة لتحسين هذه الأخيرة‪.‬‬

‫بعض هذه المكتبات مفيد جدا ً و يستحق إلقاء النظر عليه‪ ،‬و بعضها أق ّل جودة بل رب ّما فيه أخطاء‪ .‬لهذا‬
‫يجب ترتيب هذه المكتبات حسب أهميتها‪.‬‬

‫حاول إيجاد ‪ SDL_Image‬في القائمة‪ ،‬ستدخل إلى الصفحة المخصصة لهذه المكتبة ‪:‬‬

‫‪https://www.libsdl.org/projects/SDL_image‬‬

‫حم ّل النسخة التي تناسبك من القسم ”‪) ”Binary‬لا تحم ّل الملفات المصدر ية‪ ،‬لن نحتاجها !(‪.‬‬
‫إذا كنت تعمل على الويندوز‪ ،‬حم ّل الملف ‪ ، SDL_image-devel-1.2.10-VC.zip‬و هذا حتى و إن‬

‫لم تكن تستعمل البيئة التطوير ية ‪! Visual C++‬‬

‫التثبيت‬

‫في الملف ‪ .zip‬هذا‪ ،‬ستجد ‪:‬‬

‫• ‪ : SDL_image.h‬الملف الرأسي الوحيد الذي تحتاجه الـ‪ ،SDL_Image‬قم بلصقه في المسار‬

‫‪C:\Program Files\CodeBlocks\SDL-1.2.13\include‬‬

‫بمعنى آخر‪ ،‬إلى جانب الملفات الرأسية للـ‪.SDL‬‬
‫• ‪ : SDL_image.lib‬قم بلصقه في المسار‬

‫‪. C:\Program Files\CodeBlocks\SDL-1.2.13\lib‬‬
‫أعرف أنك ستخبرني بأن الملفات ذات الامتداد ‪ .lib‬هي محجوزة للبيئة التطوير ية ‪،Visual C++‬‬

‫لـكن هذه حالة استثنائية‪ ،‬فالملف ‪ .lib‬يعمل حتى مع المترجم ‪.mingw‬‬
‫• الـكثير من الملفات ‪ : DLL‬قم بوضعها كلها في المجل ّد الخاص بالمشروع )أي بجانب الملف ‪.( SDL.dll‬‬

‫بعد ذلك‪ ،‬يجدر بك تغيير خواص المشروع من أجل محر ّر الروابط )‪ (Linker‬للملف ‪. SDL_image.lib‬‬
‫إذا كنت تعمل بالـ‪ Code::Blocks‬مثلا ً‪ ،‬توجّه إلى القائمة ‪ ، Build options / Projects‬في الفرع‬
‫‪ Linker‬أنقر على الزر ‪ Add‬و اختر المسار الذي يتواجد به الملف ‪ ، SDL_image.lib‬لاحظ الصورة ‪:‬‬

‫‪342‬‬

‫تحميل صيغ صور أخرى باستعمال الـ‪SDL_Image‬‬

‫إذا ظهرت لك رسالة تحمل سؤال ‪ ،”Keep as a relative path ?” :‬فلتجب بما أردت لأنه لن يغير شيئا ً‬
‫في الوقت الحالي‪ .‬أنصحك بالإجابة بالسلب‪ ،‬شخصي ّا‪.‬‬

‫بعد ذلك‪ ،‬ما عليك سوى تضمين الملف الرأسي ‪ SDL_image.h‬في الشفرة المصدر ية‪ .‬على حسب المكان‬
‫الذي وضعت فيه الملف ‪ SDL_image.h‬سيكون عليك استعمال هذه الشفرة ‪:‬‬

‫>‪1 #include <SDL/SDL_image.h‬‬

‫أو هذه‬

‫>‪1 #include <SDL_image.h‬‬

‫جرّبهما كليهما‪ ،‬يجدر بأحداهما أن تعمل‪.‬‬

‫إذا كنت تعمل بالـ‪ Visual Studio‬فستكون العملي ّة نفسها‪ .‬لأنه إن تمكنت من ٺثبيت الـ‪ SDL‬لن يصعب‬
‫عليك ٺثبيت الـ‪.SDL_Image‬‬

‫ٺثبيت الـ‪ SDL_Image‬على ‪Mac OS X‬‬

‫إن كنت تستعمل ‪ ،Mac OS X‬نزّل الملف ذو الامتداد ‪ .dmg‬من موقع الـ‪ SDL‬و ضعه في المجلد‬
‫‪. Library/Frameworks‬‬

‫‪343‬‬

‫الفصل ج‪ .3.‬إظهار صور‬

‫اكتب بعد ذلك ”‪ ”search paths‬في حقل البحث الخاص بـ‪ .Xcode‬اعثر على السطر‬
‫‪ ، Header search paths‬انقر مرتين على السطر من اليمين و أضف‬

‫‪. /Library/Frameworks/SDL_image.framework/Headers‬‬
‫لم يبق لك سوى اضافة إطار العمل إلى المشروع‪ .‬الصورة التالية توضح لك كيف يظهر‬

‫الـ ‪ Header search paths‬بعد ٺثبيت الـ‪.SDL_image‬‬

‫و بهذا يجب عليك تضمين الملف الرأسي في بداية الـكود كالتالي ‪:‬‬

‫”‪1 #include ”SDL_image.h‬‬

‫في عوض استعمال الإشارتين > < قم باستعمال الكتابة السابقة فيما سأعطيك لاحقا‪.‬‬

‫تحميل الصور‬

‫الحقيقة أن ٺثبيت الـ‪ SDL_image‬أصعب بمئة مرة من استعمالها ! إنه عليك أنت تحديد صعوبة العمل بالمكتبة !‬
‫توجد دالة وحيدة عليك معرفتها ‪. IMG_Load :‬‬

‫و هي تستقبل معاملا واحدا ‪ :‬اسم الملف الذي نريد فتحه‪.‬‬

‫و هذا أمر عملي لأن هذه الدالة تتمكن من تحميل أي نوع من الملفات التي ٺتعامل معهاالـ‪SDL_image‬‬
‫)‪ GIF ،PNG ،JPG‬و حتى الـ‪ ،TIF‬إلخ(‪ .‬إذ تقوم وحدها بتحديد نوع الملف من خلال امتداده‪.‬‬

‫بما أن الـ‪ SDL_Image‬تستطيع أيضا ً فتح الصور ‪ ،BMP‬فيمكنك الآن نسيان أمر استعمال الدالة‬
‫‪ SDL_LoadBMP‬و استعمال الدالة ‪ IMG_Load‬لتحميل كل أنواع الصور‪.‬‬

‫شيء جيد آخر ‪ :‬إذا كانت الصورة التي تحم ّلها تملك الشفافية )كما هو حال الصور ‪ PNG‬و ‪ (GIF‬فإ ّن‬
‫‪ SDL_Image‬تفعّل تلقائيّا الشفافية من أجل هذه الصورة ! مما يعني عدم وجود دا ٍع لاستدعاء الدالة‬

‫‪. SDL_SetColorKey‬‬

‫‪344‬‬

SDL_Image‫تحميل صيغ صور أخرى باستعمال الـ‬

.‫ و إظهارها‬sapin.png ‫سأ ٌق ّدم لك الشفرة المصدر ية التي تقوم بتحميل الصورة‬

SDL_SetColorKey ‫ كما أنني لا استدعي الدالة‬SDL/SDL_image.h ‫لاحظ جيدا أنني قمت بتضمين‬

.‫ التي استعملها شفافة طبيعي ّا‬PNG ‫لأن الصورة‬

. SDL_LoadBMP ‫ في ك ّل مكان بالشفرة و ذلك بتعو يض الدالة‬IMG_Load ‫سترى أنني أستعمل الدالة‬

1 #include <stdlib.h>

2 #include <stdio.h>

3 #include <SDL/SDL.h>

4 /* including the header of SDL_image (adapt your directory) */
5 #include <SDL/SDL_image.h>

6 void pause();

7 int main(int argc, char *argv[])
8
{

9 SDL_Surface *screen = NULL, *backgoundImage = NULL, *sapin =

NULL;

10 SDL_Rect backgoundPosition, sapinPosition;

11 backgoundPosition.x = 0;

12 backgoundPosition.y = 0;

13 sapinPosition.x = 500;

14 sapinPosition.y = 260;

15 SDL_Init(SDL_INIT_VIDEO);

16 SDL_WM_SetIcon(IMG_Load(”sdl_icone.bmp”), NULL);

17 screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);

18 SDL_WM_SetCaption(”Loading images on SDL”, NULL);

19 backgoundImage = IMG_Load(”lac_en_montagne.bmp”);

20 SDL_BlitSurface(backgoundImage, NULL, screen, &

backgoundPosition);

21 /* Loading a PNG image with IMG_Load
22 We won’t have any problem because the PNG image contains the

transparency information inside */
23 sapin = IMG_Load(”sapin.png”);
24 SDL_BlitSurface(sapin, NULL, screen, &sapinPosition);
25 SDL_Flip(screen);
26 pause();
27 SDL_FreeSurface(backgroundImage);
28 SDL_FreeSurface(sapin);
29 SDL_Quit();
30 return EXIT_SUCCESS;
31 }
32 void pause()
33 {
34 int cont = 1;
35 SDL_Event event;
36 while (cont)
37 {
38 SDL_WaitEvent(&event);
39 switch(event.type)
40 {
41 case SDL_QUIT:
42 cont = 0;

345

‫} ‪43‬‬ ‫الفصل ج‪ .3.‬إظهار صور‬
‫} ‪44‬‬ ‫كما يمكننا الملاحظة‪ ،‬فقد تم دمج الصورة مع الخلفية بشكل ممتاز ‪:‬‬
‫} ‪45‬‬

‫مل ّخص‬

‫• تسمح الـ‪ SDL‬بتحميل صور على مساحات‪ .‬افتراضي ّا‪ ،‬هي تسمح بالتعامل مع الصور ذات الصيغة ‪BMP‬‬
‫باستعمال الدالة ‪. SDL_LoadBMP‬‬

‫• يمكننا تعر يف لون شفاف باستعمال الدالة ‪. SDL_SetColorKey‬‬
‫• يمكننا جعل الصورة أكثر أو أقل شفافية و ذلك باستعمال الدالة ‪. SDL_SetAlpha‬‬
‫• المكتبة ‪ SDL_image‬تسمح بإدخال صور من أي ّة صيغة كانت )‪ (… ،PNG ،JPG‬باستعمال الدالة‬

‫‪ . IMG_Load‬لـكن علينا تسطيب هذه المكتبة بالإضافة إلى الـ‪.SDL‬‬

‫‪346‬‬

‫الفصل ج‪4.‬‬

‫معالجة الأحداث‬

‫معالجة الأحداث هو من أهم الأساسيات في الـ‪.SDL‬‬
‫و رب ّما قد يكون الشطر الأكثر شغفا ًلاكتشافه‪ .‬لأنه انطلاقا من هنا ستبدأ فعلا ًفي التحكّم في تطبيقك‪.‬‬
‫ك ّل من مرفقات الحاسوب )فأرة‪ ،‬لوحة مفاتيح‪ (… ،‬قادرة على إنتاج حدث‪ .‬سنتعلّم كيف نستقبل كل‬

‫حدث و نتعامل معه‪ .‬تطبيقك سيصبح أخيرا ً تفاعلي ّا !‬
‫فعليا ً‪ ،‬ما هو الحدث ؟ الحدث هو عبارة عن إشارة )‪ (signal‬يتم إرسالها عن طر يق إحدى مرفقات‬
‫الحاسوب )‪) (peripherals‬أو عن طر يق نظام التشغيل بذاته( إلى التطبيق‪ .‬هذه أمثلة عن بعض الأحداث‬

‫المألوفة ‪:‬‬
‫• حينما يضغط الم ُستعمل على زر من لوحة المفاتيح‪.‬‬

‫• و أيضا ًحينما ينقر بالفأرة‪.‬‬
‫• حينما يحر ّك الفأرة‪.‬‬

‫• حينما يقوم بتصغير النافذة‪.‬‬
‫• حينما يطلب إغلاق النافذة‪.‬‬

‫• إلى آخره‪.‬‬

‫الهدف من هذا الدرس هو تعلّم كيفية معالجة الأحداث‪ .‬يمكنك أخيرا ًالقول للحاسوب ‪” :‬إذا نقر المستعمل‬
‫في هذا المكان‪ ،‬قم بفعل كذا‪ ،‬و إن لم يفعل‪ ،‬قم بكذا‪ .‬إذا حرّك الفأرة‪ ،‬قم بكذا‪ .‬إذا ضغط على الزر ‪، Q‬‬

‫أوقف البرنامج‪ .‬إلخ”‪.‬‬

‫‪347‬‬

‫الفصل ج‪ .4.‬معالجة الأحداث‬

‫ج‪ 1.4.‬مبدأ عمل الأحداث‬

‫لنتعوّد على الأحداث‪ ،‬سنتعلّم كيف نتعامل مع أسهل حدث ‪ :‬طلب غلق البرنامج‪ .‬هذا حدث يـ ُنت ُج حينما‬
‫يقوم المستعمل بالنقر على الزر ‪: X‬‬

‫إنه فعلا ً الحدث الأكثر سهولة‪ .‬إضافة على ذلك‪ ،‬هو حدث قد استعملته سابقا ً دون أن تعلم بذلك لأنه‬
‫متواجد في الدالة ‪! pause‬‬

‫بالفعل‪ ،‬دور هذه الدالة هو انتظار المستعمل حت ّى يقررّ غلق البرنامج‪ ،‬لأننا لو لم نستعملها كانت النافذة لتظهر و‬
‫تختفي بسرعة البرق !‬

‫يمكنك من الآن نسيان الدالة ‪ . pause‬قم بحذفها من الشفرة المصدر ية لأننا سنتعلّم كيف نكتب‬
‫محتواها بأنفسنا‪.‬‬

‫متغيّر الحدث‬

‫لمعالجة الأحداث‪ ،‬ستحتاج إلى التصريح عن متغيّر )واحد فقط‪ ،‬كن متأكدا( من نوع ‪. SDL_Event‬‬
‫فلتقم بتسميته بالاسم الذي يحلو لك‪ ،‬أنا سأسم ّيه ‪ ، event‬و هي تعني ”حدث” بالإنجليز ي ّة‪.‬‬

‫;‪1 SDL_Event event‬‬

‫من أجل اختبارات الشفرة‪ ،‬سنستعمل دالة ‪ main‬بسيطة للغاية تقوم بإظهار نافذة فقط‪ ،‬مثلما رأينا في‬

‫الفصول الأولى‪ .‬هذا ما يجب أن تبدو عليه الدالة ‪: main‬‬

‫‪1‬‬ ‫)][‪int main(int argc, char *argv‬‬
‫‪2‬‬
‫{‬

‫‪3‬‬ ‫;‪SDL_Surface *screen = NULL‬‬
‫‪4‬‬
‫‪SDL_Event event; // This variable will help us to manage the‬‬

‫‪5‬‬ ‫‪events‬‬
‫‪6‬‬ ‫;)‪SDL_Init(SDL_INIT_VIDEO‬‬
‫‪7‬‬ ‫;)‪screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE‬‬
‫‪8‬‬ ‫;)‪SDL_WM_SetCaption(”Managing the events in SDL”, NULL‬‬
‫‪9‬‬ ‫;)(‪SDL_Quit‬‬
‫} ‪10‬‬ ‫;‪return EXIT_SUCCESS‬‬

‫إذا‪ ،‬هي شفرة بدائية جدا ً‪ ،‬و هي لا تحوي سوى شيء جديد ‪ :‬تعر يف المتغير ‪ event‬الذي سنستعين به‬
‫قريبا ً‪.‬‬

‫جرّب الشفرة ‪ :‬مثلما توق ّعنا‪ ،‬يجدر بالنافذة أن تظهر و تختفي في لحظة‪.‬‬

‫‪348‬‬

‫مبدأ عمل الأحداث‬

‫حلقة الأحداث‬

‫حينما نريد انتظار حدث‪ ،‬نستعمل غالبا ًحلقة‪ .‬هذه الحلقة التكرار ية تستمر في الاشتغال مادُمنا لم نستقبل الحدث‬
‫المـ ُراد‪.‬‬

‫يجب علينا أن نستعمل متغيرا ً منطقيا ًلـكي يحدد لنا ما إن كان علينا البقاء في الحلقة أو الخروج منها‪.‬‬
‫أنشئ هذا المتغير و سم ّه مثلا ‪: 1 cont‬‬

‫;‪1 int cont = 1‬‬

‫هذا المتغير المنطقي يأخذ القيمة ‪ 1‬في البداية لأننا نريد للحلقة أن ٺتكرر مادام المتغير ‪ cont‬يحمل هذه القيمة‬
‫)صحيح(‪ .‬ما إن يأخذ المتغير المنطقي القيمة ‪) 0‬خطأ(‪ ،‬نخرج من الحلقة و يتوقف البرنامج‪.‬‬

‫هذا ما تبدو عليه الحلقة ‪:‬‬

‫)‪1 while (cont‬‬
‫{‪2‬‬
‫‪3 // Dealing with the event‬‬
‫}‪4‬‬

‫هكذا إذا ً ‪ :‬لدينا لح ّد الآن حلقة غير منتهية لا تنتهي إلا إذا أخذ المتغير ‪ cont‬القيمة ‪ .0‬الأكثر أهمية هو‬
‫ما نكتبه في داخل تلك الحلقة‪.‬‬

‫استرجاع الحدث‬

‫الآن سنقوم باستدعاء دالة من الـ‪ SDL‬لـكي نتحقق ما إن تم إنتاج حدث‪.‬‬
‫لدينا دالتان للقيام بهذا العمل‪ ،‬لـكن كلا منه ُما تعمل بطر يقة مختلفة عن الأخرى ‪:‬‬

‫• ‪ : SDL_WaitEvent‬تقوم بانتظار إنتاج حدث‪ .‬هذه الدالة نقول عنها تعطيلية لأنها توقف عمل البرنامج‬
‫مادام لم يتم إنتاج أي حدث‪.‬‬

‫• ‪ : SDL_PollEvent‬هذه الدالة تقوم بنفس العمل لـكنها ليست تعطيلية‪ .‬لأنها ُتخـبرنا ما إن تم انتاج‬
‫حدث أم لا‪ ،‬فإن لم يكن هناك أي حدث فإنها تعيد التحكّم إلى البرنامج مباشرة‪.‬‬

‫هاتان الدال ّتان مهمّتان‪ ،‬لـكن في حالتين مختلفتين‪.‬‬
‫لتبسيط الأمور‪ ،‬إذا استعملت ‪ SDL_WaitEvent‬فإن برنامجك لن يـ ُتعب كثيرا ًالمـ ُعالج لأنه سيتوقف مـ ُنتظرا ً‬

‫إنتاج حدث‪.‬‬

‫‪ 1‬إذا كنت تفكّر في تسميته ‪ continue‬فلا تفعل‪ ،‬لأ ّنها كلمة مفتاحي ّة )محجوزة(‪ ،‬و بالتالي لا يمكن استخدامها كاسم لمتغيّر‪.‬‬

‫‪349‬‬

‫الفصل ج‪ .4.‬معالجة الأحداث‬

‫بالمـ ُقابل‪ ،‬إذا استعملت ‪ ، SDL_PollEvent‬سيقوم البرنامج بالعمل على الحلقة ‪ while‬و استدعاء الدالة‬
‫‪ SDL_PollEvent‬بشكل غير معر ّف إلى حين انتاج حدث مُعين‪ .‬و بهذا تستعمل الم ُعالج بنسبة ‪.% 100‬‬

‫لـكن ألا يجب أن نستعمل دائما ًالدالة ‪ SDL_WaitEvent‬بما أنها لا تستعمل المـ ُعالج كثيرا ً ؟‬

‫كل ّا‪ ،‬لأنه توجد حالات لا يمكن الاستغناء فيها عن الدالة ‪ . SDL_PollEvent‬و هي حالة الألعاب‬
‫التي يتم فيها تحديث الشاشة حتى و إن لم يكن هناك أي حدث‪.‬‬

‫فلنأخذ مثلا ًاللعبة ‪ : Tetris‬تقوم الكتل بالنزول لوحدها‪ ،‬لا يحتاج الم ُستعمل إلى إنتاج حدث من أجل حصول‬
‫هذا الأمر ! لو استعملنا ‪ ، SDL_WaitEvent‬سيبقى البرنامج مـ ُع ّطلا و لن تتم ّكن من تحديث الشاشة لإنزال‬

‫الكتل !‬

‫ماذا تفعل ‪ SDL_WaitEvent‬لـكي لا تستهلك من الـمُعالج كثيرا ً ؟‬
‫فبعد كل شيء‪ ،‬الدالة ُمجـبرة على البقاء في حلقة غير منتهية لـكي تختبر ك ّل الوقت ما إن كان هناك حدث‬

‫أم لا‪ ،‬أليس كذلك ؟‬

‫الحقيقة أنني كنت أطرح هذا السؤال قبل وقت قليل‪ .‬الإجابة مع ّقدة قليلا ًلأنها تخ ّص الطر يقة التي يتحكّم‬
‫فيها النظام بالعملي ّات )‪) (Processes‬البرامج التي هي في طور الاشتغال(‪.‬‬

‫إذا كنت تريد ‪-‬لـكن ّي سأتح ّدث بسرعة‪ ،-‬بالنسبة للدالة ‪ ، SDL_WaitEvent‬عملي ّة البرنامج ت ُوضع في طور‬
‫الانتظار‪.‬‬

‫إذا فإن البرنامج لا يعمل عليه المعالج بعد تلك اللحظة‪.‬‬
‫سيتم ”إيقاظه” من طرف نظام التشغيل حينما يتم إنتاج حدث‪ .‬يعني أن المعالج سيعود إلى العمل على البرنامج‬

‫في هذه اللحظة‪ .‬هذا ما يشرح ل ِم َ لا يستهلك البرنامج من المعالج شيئا بينما يكون في طور انتظار الحدث‪.‬‬

‫أدري أن هذه المفاهيم تبدو مجر ّدة لك الآن‪ .‬لـكنك لست ُمجـبرا ً على فهم كل هذا الآن لأنك ستبدأ في‬
‫التأقلم مع هذه المعلومات شيئا ًفي شيئا ًمع التطبيق‪.‬‬

‫الآن سنستعمل ‪ SDL_WaitEvent‬لأن البرنامج سيبقى بسيطا باستخدامها‪ .‬على أي حال فالتعامل مع هاتين‬
‫الدالتين لن يتغير من واحدة إلى أخرى‪.‬‬

‫يجب أن تبعث للدالة عنوان المتغير ‪ event‬الذي يقوم بتخزين الحدث‪.‬‬
‫بما أن هذا المتغير ليس عبارة عن مؤش ّر )أعد رؤ ية طر يقة التصريح به أعلاه(‪ ،‬سنستعمل الاشارة & قبل اسم‬

‫المتغير و ذلك لن ُعطي عنوانه ‪:‬‬
‫;)‪1 SDL_WaitEvent(&event‬‬

‫بعد استدعاء هذه الدالة‪ ،‬المتغير ‪ event‬يحتوي إجبار يا ًحدثا ًما‪.‬‬

‫‪350‬‬


Click to View FlipBook Version