اذهب إلى المحتوى

لوحة المتصدرين

  1. أمير شراب

    أمير شراب

    الأعضاء


    • نقاط

      1

    • المساهمات

      1


  2. Sarah Hani Mahboub

    Sarah Hani Mahboub

    الأعضاء


    • نقاط

      1

    • المساهمات

      16


  3. سارة طه

    سارة طه

    الأعضاء


    • نقاط

      1

    • المساهمات

      18


  4. Mohamad Ibrahim3

    Mohamad Ibrahim3

    الأعضاء


    • نقاط

      1

    • المساهمات

      1311


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 08/18/15 في كل الموقع

  1. الإصدار 1.0.0

    76184 تنزيل

    هذا الكتاب ليس وصفةً سريعةً للثّراء! وهو لا يَعِدُكَ بجنيِ آلافِ الدولاراتِ منْ خلالِ بقائكَ نائمًا في البيت. لا يُقدّم الكتاب وَصفاتٍ سحريّةً للحُصولِ على 500$ خلالَ ساعتين من خلال مواقعَ خطيرة. ولا يعرض نماذجَ لأناسٍ حصلوا على مليون دولار في عامهم الأوّل بعد قراءة الكتابْ! هذا الكتاب، كتابٌ واقعيٌّ. يلامسُ الحقيقةَ الصعبة بأنّهُ مِن الصّعبِ الحُصولُ على وظيفة في الكثير من الدُّولِ العربيّة. ويخبرك بأن هناكَ أملًا وبديلًا. بل بديلًا قويًّا قَد يكون أفضل من الوظيفة بمراحل. ويبرهن على ذلك بعرض قصص نجاحٍ لأشخاصٍ مثلك، عاشوا ظروفك نفسها، ومن بلدك، ويعانون من جميع المصاعب التي تعاني منه، وبدأوا بمؤهِّلاتٍ قريبةٍ جدًا من مؤهلاتك، وامتلكوا بعضَ المهاراتِ التي تَمتلكها، ولربما كنتَ تُحسِنُها أكثر مِنْ بَعضِهم. ولكنَّ الفرقَ الوحيد (ليس طبعا أنّهم قرأوا الكتاب)، الفرقُ الوَحيدُ أنّهُم وَجَدوا طَريقَهُم للعملِ عَبْر الأنترنت وتحقيقِ مصدرِ دخلٍ كافٍ ومستمرٍّ لأنفسهم، بعضهم – بل الكثير منهم – يحقِّقُ ضِعف الرّاتِبِ الّذي تَحلُمُ بِه شَهريا. يَستعرضُ الكِتابُ قِصصَ النَّجاح بغرضِ إلهامكَ ومَنحِكَ الدَّافِع لتنجح كما نَجحُوا. ويؤكد أنّهم نجحوا ليس لأنّهم تعلّموا المُعادلة السِّحرية للنَّجاح، وليس لأنّهم وجدوا الوصفة السّرية لعصيرِ النّجاح فأعدّوه وشربوه، وليس لأنّ هناك (واسطةً) أخدتْ بأيديهم وعبرت بهم إلى طريقِ النّجاح. إنّما نجَحوا لأنّهم عَمِلوا وتَعبوا وصَابروا وواصَلوا حتّى وَصَلوا. يعرض عليك الكتابُ فرصةَ أنْ تنجح كَما نجحوا، بَل ويَضَعك في ظروفٍ أَفضَل مِن ظُروفهم. وذلك بشرحِ الخُطواتِ اللّازمِ اتّخاذها لبدءِ عملكَ عبر الأنترنت. فالكثير مِنهم لم تُتَح لَه فرصة الحصول على تلك المعلومات، وإنما جرّبوا فأخطأوا فتعلّموا فجرّبوا ثانيةً فنجحوا. وهنا – في هذا الكتاب – نختصر عليك الطّريق، فنعرضُ لكَ تجارِبَهم وأخْطاءَهُم وأَفْضلَ ما حقَّقُوه. يبدأ الكتاب بتعريفِ العمل الحرّ، ومجالاتِه، ومُميّزاتهِ وعُيوبِه. ثمّ يُرشِدُكَ إِلى الكيفيّةِ التي تَبدأُ بِها عملكَ الحُرّ بخطواتٍ بسيطةٍ وسهلةِ التّطبيق. ويُتابِع معك هذِه الخُطوات خُطوة بخطوة. فيقدّم لكَ النَّصائِحَ حولَ إِنشاءِ ملفِّكَ الشّخصيّ، ويُحدثك عَن الطّريقة التي تُقدّمُ بها عروضَ العمل، ويُعلّمكَ كيفيّة تحديدِ السِّعرِ المُناسِب للمشروع، وكيفيّة تَقدير الزّمن اللّازِم لتنفيذه. ويُواسيكَ في حال عدمِ حُصولِكُ عُلى مَشاريع. يَعرضُ الكتابُ عَددًا مِنَ المَهاراتِ اللّازِمة للعَملِ الحُرّ عبرَ الأنترنت، فيستعرضُ مهاراتِ التّواصلِ معَ الزّبائن، ومهاراتِ التّفاوُضِ والإِقْناعْ، ومهاراتِ إدارةِ وتنظيمِ الوقتْ. الكتابُ لا يَدّعي أنّهُ المرجعُ الشاملُ لكلِّ ما لهُ علاقةٌ بالعملِ الحُرّ، إنَّما يرجو مُؤلّفُ الكتابِ أنْ تَكونَ كلماتُهُ قُد لامستْ مَواطنَ الإرادةِ فِي قَلبك. وفُصولَه قدْ شَقّتْ لكَ طريقًا واضحًا للعملِ الحرِّ عبر الأنترنت. وأن يَكونَ ركيزةَ البدايةِ والخُطوة الأولَى في عملكَ عبْر الأنْترنَت. أُمنِيَتُنا في هَذا الكِتاب، أَنْ تَكونَ قِصّةَ نجاحٍ ملهمةً يُحتَفَى بِها، وتُذكَرُ في إصْداراتٍ لاحقةٍ مِنَ الكِتاب. ضَعْ ذَلكَ نُصبَ عَيْنيكْ خِلالَ قِراءتِكَ للكِتابْ.
    1 نقطة
  2. FreeBSD هو نظام تشغيل شبيه بيونكس Unix-like حرّ ومفتوح المصدر يشيع استخدامه على الخوادم. يتشارك FreeBSD والأنظمة الأخرى المبنية على BSD قواسم عدّة مع أنظمة مثل لينكس Linux؛ وفي المقابل تبقى هناك نقاط اختلاف مهمة تُميّز بين هاتين العائلتين. سنناقش في هذا الدرس بإيجاز بعض القواسم المشتركة بين FreeBSD و لينكس، ثم سنتحدث بشكلٍ أكثر استفاضة عن الفروقات المهمّة بينهما. تنطبق معظم النقاط الواردة في هذا الدرس على باقي أنظمة BSD أيضًا رغم تركيزنا على FreeBSD فقط. السمات المشتركة بين FreeBSD و لينكسقبل أن نبدأ بدراسة نقاط الاختلاف بين FreeBSD و لينكس دعونا نتحدث بصورة عامة عن القواسم المشتركة بينهما. ينتمي كلا النظامين إلى دائرة البرمجيات الحرّة ومفتوحة المصدر؛ حيث يمكن للمستخدمين الإطلاع على الشيفرة المصدرية، التعديل عليها والمساهمة في تطويرها، وذلك رغم استخدام كل منهما لأنواع رخص مختلفة (المزيد عن هذا لاحقًا). ويُعتبر كلًا من FreeBSD و التوزيعات المبنية على غنو لينكس من عائلة الأنظمة الشبيهة بيونكس Unix-like أساسًا، حيث يمتلك FreeBSD جذورًا شديدة الصلة بنظام يونكس في الماضي، في المقابل أُنشئ غنو لينكس من الصفر كبديلٍ حرّ للأنظمة الشبيهة بيونكس. هذا الترابط يُعطينا لمحة عن أسلوب تصميم النظامين، كيفيّة تفاعل المكوّنات بين بعضها البعض، والتوقعات العامة حول كيف يجب أن يبدو النظام وكيف تُنجز المهام عليه. لهذه الاعتبارات فإن FreeBSD وتوزيعات لينكس المختلفة تتقاسم الكثير من الأدوات والتطبيقات. ورغم أنّ بعض الحالات تُحتّم وجود اختلافات في إصدارات هذه البرامج بين النظامين، إلا أنه يمكن وبسهولة أكثر تمرير البرامج بينهما مما لو كنّا نتعامل مع أنظمة غير شبيهة بيونكس non-Unix. بعد أخذ هذه النقاط بعين الاعتبار ننتقل الآن إلى مناقشة المجالات التي تختلف فيها هاتين العائلتين من أنظمة التشغيل، وكلي أمل أن يساعدك الإطلاع على القواسم المشتركة السابقة بفهم أكثر دقّة لنقاط الاختلاف التالية. الاختلاف في الرخصأحد الفروق الأساسية بين نظامي FreeBSD و لينكس هي مسألة التراخيص المُستخدمة. إذ تُرخّص نواة لينكس، تطبيقات غنو الأساسيّة GNU-based، والعديد من البرامج المكتوبة لبيئة لينكس أساسًا تحت رخصة GPL أو رخصة غنو العموميّة، والتي غالبًا ما توصف بأنها رخصة “حقوق متروكة copyleft”، حيث تسمح بحرية عرض، توزيع، وتعديل الشيفرة المصدريّة للبرنامج مع مطالبة الأعمال المشتقة منها الالتزام بذات الرخصة. وفي المقابل يُرخّص نظام FreeBSD بما في ذاك النواة وأية أدوات تمّ إنشاؤها من قبل مُساهمي FreeBSD تحت "رخصة BSD"، والتي توصف بأنها أكثر تساهلًا من GPL حيث لا تطلب من الأعمال المشتقّة استخدام الرخصة عينها. وهذا يعني بأنّ أي شخص أو منظمة يمكنها استخدام أو توزيع أو تعديل برامج BSD دون الحاجة لإعادة المساهمات إلى المنبع أو إتاحة الشيفرة المصدرية لتغييراتها تلك. الشروط الوحيدة المفروضة هي إرفاق نسخة من رخصة BSD مع الشيفرة المصدرية أو مع وثائق العمل المشتق (بناءً على أسلوب الإصدار) إضافةً إلى تنويه حدود المسؤولية. على العموم تُعتبر رخصة BSD قصيرة للغاية ويمكنك الإطلاع على محتواها من هنا. يميل المستخدم في اختياره لأحد هذين الترخيصين بناء على الفلسفة التي يتبعها واحتياجاته في العمل، فرخصة GPL تهتم بتعزيز المشاركة والإبقاء على نظام برمجي مفتوح مُلزمةً الأعمال المشتقة بنفس الترخيص وذلك فوق أية اعتبارات أخرى؛ لذا تحرص البرمجيات الاحتكارية بشدّة ألا تضم أجزاء مُرخّصة وفق GPL. من ناحية أخرى تسمح رخصة BSD بتضمين برامجها في إصدارات احتكارية مغلقة المصدر؛ وهذا ما يجعلها أكثر جاذبية للعديد من الشركات والأفراد التي تأمل بتحقيق دخل من بيع البرامج الخاصة والتكتم على المصدر. إن فهم هاتين الفلسفتين يساعدنا على ادارك ما يقف وراء خيارات المطوّرين والتفضيلات التي يميلون إليها، ويبقى بالتأكيد لكل فلسفةٍ ما يميزها عن الأخرى. نشأة FreeBSDمن الفروق المهمّة بين نظامي FreeBSD و لينكس هو تاريخ نشأة كل واحدٍ منهما، فإلى جانب الاختلافات في التراخيص التي ناقشناها للتوّ، لعل هذا هو أكبر مؤثّر على اختيار المطورين لهذه الفلسفة أو تلك. كتب لينوس تورفالدز النواة لينكس بدءًا من عام 1991 أثناء دراسته في جامعة Helsinki في فنلندا كهواية مستخدمًا حاسوبه الشخصي العامل بنظام MINIX، لكن وبسبب القيود المفروضة على استخدام وتطوير MINIX كتب لينوس بديلًا له. بإضافة نواة لينوس مع الكثير من مكونات النظام المكتوبة من طرف GNU حصلنا على نظام التشغيل غنو/لينكس الذي يملك عددًا من خصائص الأنظمة الشبيهة بيونكس على الرغم من أنه لم يُكتب اعتمادًا على نسخة سابقة من يونكس؛ إذ انطلق لينوس مع نواته بدءًا من الصفر ممّا أورث المشروع اختلافاتٍ أيضًا من الناحية التصميمية عن تلك النظم التي تربطها مع يونكس علاقة أوثق. في المقابل يرتبط FreeBSD مع يونكس بصلات مباشرة. حيث أُنشئ BSD أو توزيعة برمجيات بيركلي كإحدى توزيعات نظام التشغيل يونكس في جامعة كاليفورنيا في بيركلي، والذي أضاف عددًا من الميزات على نظام التشغيل يونكس المملوك آنذاك لشركة AT&T مع رخصة تسمح بالتعديل والتحسين. في وقتٍ لاحق اتُّخِذ قرار لمحاولة استبدال أكبر جزء ممكن من نظام التشغيل الخاص بـ AT&T مع بدائل حرّة ومفتوحة المصدر بحيث لا تُجبر المستخدمين الحصول على رخصة من AT&T لاستعمال BSD. في نهاية المطاف تمّ إعادة كتابة جميع المكونات المعتمدة على رخصة AT&T وإتاحتها برخصة BSD وتطويعها لتعمل على معالجات i386 والتي صدرت باسم “386BSD”. لاحقًا اشتقت FreeBSD من هذه الإصدارة في محاولة للحفاظ على عملية التطوير، دعمها وتحسينها، فيما بعد أعيد إصدار FreeBSD بناء على النسخة المسماة BSD-Lite والتي لا تحتوي على أية شيفرة من يونكس المملوك لـ AT&T نتيجة إحدى الدعاوي القضائية وللتخلص من كافة مشاكل الترخيص. خلال هذه العملية الطويلة ومتعدّدة المراحل من الاشتقاق غدا FreeBSD غير مرتبط بشروط الترخيص المُقلقة. حيث ركّز المطوّرون على كتابة نظام يستفيد ويستثمر في أسلوب يونكس لإنجاز المهام؛ يعود ذلك ربّما إلى الافتراض الشائع بأنّ FreeBSD هو النسخة المجانية من يونكس، وقد أثّرت هذه الجذور على عمليات التطوير اللاحقة وهي التي تقف اليوم وراء بعض النقاط التي سنتطرّق إليها. فصل جوهر نظام FreeBSD عن التطبيقات الإضافيةالفارق الرئيسي من الناحية التصميمية بين FreeBSD و توزيعات غنو/لينكس يكمن في مجال scope النظام. حيث طوّر فريق FreeBSD نظام التشغيل والنواة كوحدة واحدة متجانسة، بينما يشير “لينكس” من الناحية الفنيّة إلى النواة فقط، والتي تُضاف إلى باقي المكونات الأخرى متنوعة المصادر لتشكيل ما يعرف بنظام غنو/لينكس. ورغم أنّ هذا يبدو كفارقٍ صغير للوهلة الأولى، إلا أنّه يؤثّر في الواقع على أسلوب تفاعلك مع النظام وإدارته، ففي لينكس تضم التوزيعة مجموعة مختارة من الحزم بعد التأكد من توافقها معًا بشكل جيد، وبكل الأحوال فإن معظم المكوّنات الأخرى تأتي من قبل مجموعة واسعة من المصادر والمطوّرين وموزّعي البرامج والمشرفين والتي تتضافر جهودهم معًا لضمان عمل النظام بشكل صحيح. بهذا المعنى، لا تختلف كثيرًا المكونات الأساسية للنظام عن الحزم الاختيارية المتاحة من خلال المستودعات الإضافية، حيث تُستخدم أدوات إدارة الحزم نفسها مع مجموعتي المكونات هذه بنفس الطريقة تمامًا. قد تُخصّص التوزيعة مستودعات مختلفة للحزم تبعًا للفِرق المسؤولة عن صيانتها (المستودعات الأساسية، الإضافية، وتلك الخاصة بالمجتمع)، حيث يتسنى لفريق التطوير الأساسي التركيز على مجموعة الحزم المتاحة تحت المستودعات الأساسيّة فقط، إلا أن هذا الفصل بغرض تنظيمي ولا يؤدّي إلى أية اختلافات في إدارة الحزم من وجهة نظر المستخدم النهائي. في المقابل يُطوّر فريق FreeBSD لبّ نظام التشغيل بأكمله بما في ذلك النواة ومجموعة البرامج الأساسيّة التي كُتبت من قبلهم مما يجعل النظام يبدو كوحدة واحدة متجانسة. لذا فليس من البساطة استبدال أحد المكونات ببديل آخر خارجي بسبب التجانس والتكامل بين جميع المكونات؛ وهذا ما يسمح لفريق FreeBSD إدارة نظام التشغيل بأكمله عن قرب وضمان التوافق المناسب بين أجزائه والتنبؤ بسلوكه ومشاكله. كما تُعتبر البرامج الأساسيّة المُضمّنة مع لبّ نظام التشغيل معزولة تمامًا عن المكونات الاختياريّة الأخرى، حيث يقدّم فريق FreeBSD مجموعة كبيرة من البرامج الإضافية، تمامًا كما مع توزيعات لينكس، إلا أنّ إدارتها تبقى منفصلة، فبينما يُحدّث النظام الأساسي كوحدة واحدة، يتم تحديث البرامج الاختيارية بشكل مستقل. كيف تتشكّل الإصدارات؟تتشكّل إصدارات لينكس نتيجة دمج مجموعة كبيرة ومتنوعة من البرامج من مختلف المصادر مع إدخال بعض التعديلات عند الحاجة، ويُقرّر مشرفو التوزيعة المكونات التي يريدون تضمينها في وسائط التثبيت وتلك التي يرغبون بإتاحتها عبر المستودعات الأخرى، بعد اختبار توافق المكونات مع بعضها يتم إصدار التوزيعة مُضمّنةً بالبرمجيات المُختبرة. ذكرنا في الفقرة السابقة: يُطوّر فريق FreeBSD الجزء الأكبر من نظام التشغيل FreeBSD. بشكل رئيسي يُنتج الفريق لبّ نظام التشغيل الأساسي. تُعتبر البرمجيات الأساسية وحدة متجانسة. تقودنا هذه النقاط إلى النهج المُتبع في إصدار البرامج هنا والمختلف عن ما تتبعه معظم توزيعات لينكس، حيث يُنظّم FreeBSD المهام على مستوى نظام التشغيل محتفظًا بكل المكونات الأساسية في مستودعٍ واحد للشيفرة المصدرية، الأمر الذي يُفرز عددًا من النتائج المهمة. في البداية، وبسبب تطوير جميع الأدوات جنبًا إلى جنب في مستودعٍ واحد، يتشكّل الإصدار ببساطة عن طريق اختيار إحدى تنقيحات فروع المستودع، وهذا يشبه الطريقة التي تصدر بها معظم البرامج المستقرة حيث يتم اختيارها من شيفرة أساسية منظمة. وبما أنّ نظام التشغيل الأساسي بأكمله تحت التطوير النشط، هذا يعني بأنّه يمكن للمستخدمين “تتبّع track” فروع أو درجات مختلفة من الاستقرار اعتمادًا على درجة الاختبار التي يفضّلون عندها استخدام النظام، وهكذا فالمستخدمون ليسوا بحاجة لانتظار المطورين ريثما يصادقوا على التغييرات الجديدة كي تصبح جاهزة للاستخدام على أنظمة تشغيلهم. يشبه هذا إلى حدٍ ما تتبّع مستخدمي لينكس لمستودعات مختلفة من ناحية الاستقرار ورقم الإصدار، ففي لينكس يمكنك تتبّع مستودع حزمة ما، بينما في FreeBSD أنت تتبع فرع من مستودع مركزي. الفروق البرمجيّة وتصميم النظامسنناقش فيما تبقى من نقاط الفروق المتعلقة بالبرمجيات نفسها والصفات العامة لكل نظام. الحزم المدعومة والتثبيت من المصدرأحد الفروق الرئيسية بين نظام FreeBSD و معظم توزيعات غنو/لينكس من وجهة نظر المستخدم هي كم البرامج المتاحة والمدعومة بصيغة مُحزّمة أو كبناء من المصدر. ففي حين توفّر معظم توزيعات لينكس حزم البرامج مُترجمة فقط وجاهزة للتثبيت الفوري من المستودعات الرسميّة، فإن FreeBSD توفّر إضافة إلى ذلك نظام لبناء وتثبيت الحزم من المصدر، وهذا ما يتيح لك حريّة الاختيار بين تركيب الحزم مسبقة الترجمة بقيم افتراضية معقولة أو بناءها من المصدر وتخصيصها بما يلائم مع احتياجاتك من خلال نظام يُدعى المنافذ “ports”. يضم نظام المنافذ هذا مجموعة من البرامج التي يملك FreeBSD دليلًا عن كيفيّة بنائها من المصدر، تُتاح هذه البرامج في الدليل “/usr/ports” بشكلٍ هرمي مُنظّم حيث يمكن للمستخدمين من خلالها الوصول للبرامج. تضم هذه الأدلة عددًا قليلًا من الملفات والتي تُحدّد مواقع الملفات المصدريّة للبرامج، إضافةً لتعليمات الترجمة والتي تتيح بناء البرنامج بشكل متوافق مع FreeBSD. تُنتَج الإصدارات المُحزمّة سلفًا من البرامج من قبل نظام المنافذ أيضًا، ممّا يجعل FreeBSD توزيعة مصدرية بالدرجة الأولى مع توفير حزم مُترجمة للتسهيل، ويبقى بإمكانك تركيب البرامج من كلا النوعين أو أحدهما على نظام التشغيل الخاص بك ومن خلال نظام إدارة البرمجيات نفسه. الاختلاف في نهج تعديل البرامجإحدى الأشياء التي قد تبدو غريبة بعض الشيء على مستخدمي توزيعات لينكس الشائعة هو أن FreeBSD لا تُدخل تعديلات على البرامج بعد المنبع إلا للضرورة. حيث تجري العديد من توزيعات لينكس تعديلات متنوعة على البرامج بهدف جعلها أسهل في التواصل والتشبيك مع مكونات النظام الأخرى أو لتسهيل إدارتها، إحدى الأمثلة على ذلك هي إعادة هيكلة هرمية إعدادات خوادم الوِب الشائعة لجعل عملية ضبط الخوادم قياسيّة أكثر. وعلى الرغم من أن المستخدمين يرون هذه التعديلات مفيدة غالبًا، فهناك نقاط ضعف تُعيب هذا النهج، فهو على سبيل المثال يفترض معرفة ما هي الإعدادات الأفضل للمستخدمين، كما أنه يُصعّب التعامل مع البرنامج على المستخدمين القادمين من منصات أخرى بمقدار انحرافه عن مواصفات المنبع. يُعدّل مشرفو نظام FreeBSD البرامج بواسطة “رقع patches”، إلا أنّ هذه التعديلات غالبًا ما تكون أكثر تحفظًا مما تقوم به توزيعات لينكس, وهي تهدف بالعموم إلى إدخال تغييرات ضرورية لبناء الحزم من المصدر مع بعض الافتراضات المناسبة لضمان عملها بشكل سليم في بيئة FreeBSD. لا يتم تعديل ملفات ضبط البرامج والتي توضع مع ملفات النظام بشكل كبير عادةً، لذا فقد تحتاج إلى بعض العمل الإضافي لتأمين تواصل وتشبيك مناسب بينها وبين باقي مكونات النظام. نكهات FreeBSD للأدوات الشائعةإحدى الجوانب التي قد تسبب ارتباك لمستخدمي لينكس في نظام FreeBSD هو الاختلاف البسيط في أسلوب عمل الأدوات المعروفة مقارنة مع أنظمة لينكس. يحتفظ فريق FreeBSD بنسخهم الخاصة لعددٍ كبير من الأدوات الشائعة، فبينما تستورد توزيعات لينكس العديد من أدواتها من فريق GNU، فإن فريق FreeBSD يعتمد تنويعاته الخاصة من هذه الأدوات. في الحقيقة هناك عدّة أسباب لإتباع هذا النهج، أولها أنّ فريق FreeBSD مسؤول عن تطوير وصيانة لبّ نظام التشغيل الأساسي، إضافةً للتحكم في عملية تطوير هذه التطبيقات وإدراجها تحت رخصة FreeBSD إذا كانت ضرورية أو مفيدة. بعض هذه الأدوات ترتبط أيضًا بشكل وثيق وظيفيًا مع أدوات BSD و يونكس التي تم اشتقاقها عنها، وهذا خلافًا لأدوات GNU والتي تميل لعدم التوافق عكسيًا بين بعضها في العادة. غالبًا ما تُعبّر هذه الاختلافات عن نفسها في خيارات الأوامر أو صياغتها عمومًا. فإذا كنتَ ترغب بتنفيذ الأوامر بأسلوب ما موافق لما هو عليه الحال في أجهزة لينكس فإنّ هذا قد لا يعمل على خوادم FreeBSD، لذا فمن المهم دومًا أن تطلع على أدلة استخدام الأوامر man للتحقق من الخيارات المتاحة على أنظمة FreeBSD. صدفة شل Shell القياسيّةمن النقاط الأخرى التي يُفترض أن تسبب بعض الارتباك لمستخدمي لينكس في FreeBSD هو أنّ صدفة شل الافتراضية ليست bash وإنما tcsh، وهي النسخة المُحسنّة من csh المكتوبة بلغة C بواسطة BSD. عدم اختيار bash يعود إلى كونها إحدى مكونات نظام GNU وليس BSD. وبينما تعمل كلا الصدفتين بأسلوب متشابه في سطر الأوامر، فإن نصوص سكربت البرمجية لن تعمل في tcsh. إلا أنّه يمكن استخدام صدفة Bourne الأساسية والمعروفة بصدفة sh بهدف الحصول على قدر أعلى من الموثوقية لتجنب المشاكل المرتبطة بكل من tcsh و csh، علاوةً على سهولة تغيير الصدفة الافتراضية للنظام إلى صدفة bash إن كنتَ تفضّل ذلك. طبقات أكثر لنظام الملفاتذكرنا آنفًا أن FreeBSD يُميّز بين نظام التشغيل الأساسي والمكونات الاختيارية (المنافذ)، والتي يمكن تثبيتها أعلى تلك الطبقة، وهذا ما ينعكس على الأسلوب المُتبع في FreeBSD لتنظيم المكونات ضمن هياكل الملفات. توضع الملفات التنفيذية في لينكس عادةً ضمن الأدلة bin ،/sbin ،/usr/sbin/، و usr/bin/ بناءً على الغرض منها ومدى أهميتها لعمل الوظائف الأساسيّة، وبينما يُراعي FreeBSD هذا المعيار التنظيمي فإنه يُضيف مستوىً آخر من الفصل بين المكونات المثبتة كجزء من النظام الأساسي أو تلك الاختيارية (المنافذ)، حيث توضع أدوات النظام الأساسية في أحد الأدلة السابقة، وتُعتمد الأدلة usr/local/bin/ و usr/local/sbin/ لبرمجيات المنافذ. يضم الدليل usr/local/ بنية تعكس صيغة الأدلة / و usr/، وهو الدليل الجذر الرئيسي للبرامج المُثبتة من نظام المنافذ، وغالبًا ما يتم حفظ إعدادات المنافذ عبر ملفات تُخزن في usr/local/etc/، بينما تُخزّن ملفات الضبط الخاصة بالنظام الأساسي في etc/ كالمعتاد. وهذا يُسهّل معرفة إذا كان برنامج ما جزء من نظام المنافذ الأساسي ويُبقي نظام الملفات نظيف. كلمة أخيرةيتقاسم FreeBSD و لينكس العديد من الخصائص المشتركة، وإذا كنت قادمًا من إحدى توزيعات لينكس فمن المهم إدراك وفهم نقاط الاختلاف بينهما، وما يُميّز كل نظام عن الآخر، لمعرفة الأسباب التي دفعت بأنصار كل طرف إلى اختياره. التعامل مع FreeBSD كنظام تشغيل مستقل بدلًا من النظر إليه من خلال عدسة لينكس سوف يجنبك مشاكل عدّة في الفهم والتعامل ويساعدك على بناء تجربة أفضل عمومًا مع FreeBSD. آمل أن أكون قد تمكنت من شرح الاختلافات بين النظامين بشكل جيّد. ترجمة وبتصرف للمقال: A Comparative Introduction to FreeBSD for Linux Users لصاحبه Justin Ellingwood.
    1 نقطة
  3. بعد أن انتهينا من الكائنات والقوالب اللازمة للعبة، سنقوم بإضافة مشهد جديد للمشروع من أجل صنع القائمة الرئيسية، ومن ثم سنقوم بإضافة بعض النوافذ والأزرار التي تسمح للاعب بالتنقل بين اللعبة والقائمة الرئيسية. ملاحظة: يمكن تحميل الملفات المصدرية لكامل هذه السلسلة عبر حساب أكاديمية حسوب على Github، يمكن أيضا تحميل ملف APK لتجريب اللعبة على أجهزة Android. بناء الشاشة الرئيسية والواجهةلإضافة مشهد جديد اضغط Control+N ومن ثم قم بحفظ هذا المشهد باسم MenuScene. آلية التنقل بين المشاهد في محرك Unity تعتمد على رقم كل مشهد في ترتيب بناء اللعبة. هذا الترتيب يمكن الوصول إليه عن طريق القائمة: File > Build Settings النافذة التي ستظهر هي المسؤولة عن ترتيب المراحل في اللعبة وتصديرها. ما يهمنا الآن هو الترتيب. قم بسحب المشهدين MenuScene و GameScene من مستعرض المشروع إلى القائمة Scenes in Build كما ترى في الصورة التالية. من المهم هنا مراعاة الترتيب حيث يأخذ المشهد MenuScene الرقم 0 والمشهد GameScene الرقم 1. بعد إضافة المشاهد قم بإغلاق النافذة حيث سيتم الحفظ تلقائيا. بعد ذلك سنقوم ببناء القائمة الرئيسية للعبة، والتي ستحتوي على زرين هما "ابدأ اللعب" و "خروج". الأول سيعرض للاعب مجموعة من المراحل ليختار أحدها ليلعبها، والثاني سيخرج من البرنامج نهائيا. إضافة لذلك سنضيف نصا على الشاشة وهو اسم اللعبة وليكن "الحيوانات الغاضبة" مثلا. سنكرر هذا النص مرتين بحيث نضع نسخة أمام الأخرى ونصغرها ومن ثم نغير ألوانهما لدرجات مختلفة. هذا سيؤدي لأن يظهر النص الخلفي كأنه ظل. لنر الآن كيف تتم إضافة كائنات واجهة المستخدم في Unity. عناصر واجهة المستخدم في محرك Unity تندرج تحت القائمة: Game Object > UI لنبدأ أولا بصورة خلفية للشاشة الرئيسية. هذه الخلفية تتم إضافتها عن طريق لوح: Game Object > UI > Panel بعد أن تضيف هذا اللوح للمشهد، ستلاحظ أن Unity قد قام بإضافته كإبن لكائن جديد اسمه Canvas، وقام أيضا بإضافة كائن آخر اسمه EventSystem. هذان الكائنان جزء من الآلية المتبعة لبناء واجهة المستخدم، حيث يعتبر Canvas الكائن الجذري لجميع كائنات الواجهة، ويقوم EventSystem بتسهيل عملية استقبال مدخلات اللاعب على عناصر الواجهة بغض النظر عن نوع أداة التحكم التي يستخدمها. ما يهمنا الآن هو الكائن الذي أضفناه نحن وهو Panel والذي ستلاحظ أنه تلقائيا قد ملأ إطار الواجهة كاملا. وأنه يحتوي على مكوّن من نوع Image وهو عبارة عن صورة يتم عرضها على الواجهة. قبل الخوض في خطوات بناء الواجهة لنتعرف معا على الآلية المستخدمة للإبقاء على عناصرها في أماكنها وأحجامها الصحيحة بغض النظر عن قياس الشاشة التي تعرض اللعبة عليها. المكوّن المسؤول عن هذه الآلية هو RectTransform والذي ستراه في كائنات واجهة المستخدم بدلا من المكوّن Transform الموجود في كائنات المشهد الأخرى. هذا المكوّن موضح في الصورة التالية: أكثر ما يعنينا في هذا المكوّن هو متغيرا الحجم Scale على المحورين x و y، إضافة إلى نوع وموقع نقطة الارتكاز لكل عنصر من عناصر واجهة المستخدم. لنتحدث بقليل من التفصيل عن طريقة الارتكاز التي عن طريقها يتم تحديد موقع العنصر على الشاشة ولنطّلع أولا على الصورة التالية التي تمثل الخيارات المتوفرة للارتكاز: أول ما يمكن ملاحظته هو إمكانية تحديد نوع الارتكاز بشكل مختلف أفقيا وعموديا، حيث يمكننا استخدام التمدد stretch والذي يجعل العنصر مربوطا من زواياه الأربع وبالتالي يجب أن تبقى هذه الزوايا دائما في مواقعها بغض النظر عن حجم الشاشة. أما الخيارات الأخرى مثل left ،center ،right أفقيا أو top ،middle ،bottom عموديا، فهي تحدد نقطة ارتكاز العنصر بالنسبة للكائن الأب، فإذا حددت مثلا نقطة الارتكاز بأنها middle center، فإن العنصر سيحافظ على مسافة ثابتة من وسط الكائن الأب بغض النظر عن حجم هذا الأخير وحجم الشاشة. سنستخدم هذا الخيار عند إضافة أزرار القائمة الرئيسية كأبناء لكائن اللوح، وبذلك نضمن وجودها دائما في وسط الشاشة. بالعودة لخلفية القائمة، قم بسحب إحدى صور الخلفية المتوفرة إلى الخانة Source Image لتظهر هذه الصورة في خلفية الشاشة الرئيسية. افتراضيا سيقوم Unity بجعل كائن اللوح شفافا نسبيا مما يظهره بشكل معتم وهذا ما لا نريده. لنقم بإزالة هذه الشفافية عن طريق فتح لوح الألوان بالضغط على المستطيل الأبيض في الخانة Color، ومن ثم تحريك منزلق الشفافية A إلى أقصى اليمين كما ترى هنا: بعد ذلك قم بتغيير اسم الكائن من Panel إلى MainMenu. سنضيف لهذا اللوح ثلاثة أبناء: الأول هو ظل العنوان GameTitleShadow.الثاني والثالث هما الزران "ابدأ اللعب" NewGame و "خروج" Exit.لنبدأ أولا مع ظل العنوان: لماذا أضفت ظل العنوان قبل العنوان نفسه؟ السبب هو أن ترتيب تصيير عناصر واجهة المستخدم يقدّم تصيير الآباء على الأبناء. لذا سنضيف العنوان نفسه GameTitle كابن لظل العنوان GameTitleShadow. بعد ذلك قم بكتابة عنوان اللعبة "الحيوانات الغاضبة" داخل الخانة Text لكل من الظل والابن، ومن ثم غير ألوانهما للأخضر بحيث يبدو الظل أفتح من العنوان نفسه. وأخيرا قم بتصغير العنوان قليلا حتى يظهر الظل من خلاله. (استخدمت خطا يسمى HACEN PROMOTER LT ويمكن تحميله مجانا من الموقع hacen.net). الشكل التالي يوضح الإعدادات الكاملة لنص العنوان وظله: بالنسبة للنص العربي الذي يظهر مقطعا ومن اليسار لليمين: لا تقلق حيال هذا الأمر فالحل موجود وسهل وسنطبقه بعد قليل. أخيرا سيظهر شكل العنوان في الشاشة كما يلي: علينا بعد ذلك أن نقوم بإضافة كائنين من نوع Button أي أزرار، وسنضيفهما بشكل عمودي أحدهما فوق الآخر في منتصف الشاشة. لكن قبل ذلك لنضف بعض المصادر الجديدة ونقوم بإعدادها، وهذه المصادر هي عبارة عن صور ورموز لواجهة المستخدم تم استخراجها من المجموعتين التاليتين: http://www.kenney.nl/assets/ui-packhttp://www.kenney.nl/assets/game-iconsطبعا لن نحتاج لجميع محتويات المجموعتين، لكن سنكتفي بالعناصر الموضحة في الصورة التالية: لنبدأ أولا بإعداد صور الأزرار الستة: الثلاث الزرقاء والثلاث الحمراء. قم باختيار أحد الأزرار من مستعرض المشروع ومن ثم اضغط على الزر Sprite Editor في نافذة الخصائص. ستظهر لك نافذة تحرير الصورة Sprite Editor والتي تمكنك من تقطيع الصورة مستخدما نظام الأجزاء التسعة. هذا النظام يقوم على تقسيم أي صورة نريد استخدامها في واجهة المستخدم إلى 9 مناطق كما هو موضح في الصورة التالية: الهدف من هذا التقسيم هو جعل الصورة قابلة للتمدد أفقيا وعموديا، بحيث تبقى الزوايا دائما بحجمها الأصلي ويتم شد الأجزاء أفقيا وعموديا دون أن يؤثر ذلك سلبا على المظهر. يمكنك من خلال النافذة المذكورة تحريك خطوط التقسيم الخضراء من أجل عزل الزوايا عن بقية الأجزاء التي ستتم عملية شدها أثناء تغيير حجم عنصر الواجهة. ل احظ أن لدينا 3 أزرار من كل لون: الأول مرتفع والثاني عادي والثالث مضغوط للأسفل. الأزرار التي سنضيفها ستعمل كالآتي. في الحالة الافتراضية سنعرض صورة الزر العادي، وحين تمرير الفأرة على الزر سنعرض صورة الزر المرتفع، وحين الضغط عليه سنعرض صورة الزر المنخفض. يمكنك تحقيق هذا السلوك عن طريق ضبط إعدادات المكوّنين Image و Button في كائن الزر وفق القيم التي تراها في الصورة التالية. تذكر أن نقطة الارتكاز للأزرار وللعنوان هي المنتصف أفقيا وعموديا middle center. لاحظ أننا حددنا الصورة الافتراضية للزر عبر المكوّن Image، حيث تلاحظ أن نوع الصورة هو Sliced أي صورة مقسمة إلى 9 أجزاء كما سبق ورأينا. بعدها قمنا بتغيير نوع الانتقال في الزر Transition إلى Sprite Swap بحيث نقوم بتبديل الصورة حين الانتقال بين الحالات. حددنا هنا صورتين أخريين إحداهما لحالة التحديد أو المرور بالفأرة Highlighted Sprite والثانية لحالة الضغط Pressed Sprite. أخيرا ستلاحظ وجود كان ابن لكل زر وهو عبارة عن نص يعرض الكتابة التي نرغب بظهورها على الزر. بالتالي يمكننا استخدام هذه الكائنات للكتابة والحصول في النهاية على النتيجة التالية: حل مشكلة اللغة العربيةمشكلة اللغة العربية في محرك Unity قديمة وقد عانيت معها منذ أول إصدار استخدمته وهو 3.5، وحتى الإصدار الخامس لم تحل هذه المشكلة من قبل الشركة. إلا أن الحل موجود، حيث قمت قبل عدة سنوات بكتابة بريمج يسمى ArabicText، ومبدأ عمله يقوم على عكس ترتيب الأحرف بحيث تصبح من اليمين لليسار كما يفترض، إضافة إلى استبدال رموز الحروف المتقطعة بالمتصلة حسب موقع الحرف في الكلمة. هذا البريمج موجود في المشروع داخل المجلد Assets\Scripts\UI وكل ما عليك هو إضافته لكل كائن من نوع Text (أي العنوان وظل العنوان وكائنات الأبناء النصيّة للأزرار). عند تشغيل اللعبة سيقوم البريمج بعمله في تصحيح النص كما ترى في الصورة التالية. هذا البريمج مجرد أداة مساعدة لا علاقة لها بموضوع الدرس لذا لن أقوم بشرحه هنا، لكن يمكنك الاطلاع عليه في المجلد المذكور إن كنت ترغب بذلك. التفاعل مع عناصر واجهة المستخدمأصبحت القائمة الرئيسية جاهزة الآن، إلا أن ضغطك على الأزرار لن يكون ذا تأثير حيث لا توجد أية أوامر ترتبط بها بعد. ربط الأوامر بالأزرار يتم عن طريق استدعاء داّلة أو أكثر من بريمج محدد عند الضغط على الزر. من أجل ذلك سنقوم بكتابة بريمج لكل أمر من هذه الأوامر. البريمج الأول وهو الأسهل هو برنامج الخروج من اللعبة ExitGameCommand. أمر الخروج يمكن تنفيذه في القائمة الرئيسية وفي مشهد اللعبة على حد سواء، حيث يقوم في الحالة الأولى بإغلاق تطبيق اللعبة نهائيا وفي الثانية بالعودة للقائمة الرئيسية. هذا البريمج موضح في السرد التالي: using UnityEngine; using System.Collections; public class ExitGameCommand : MonoBehaviour { //يتم استدعاؤها مرة واحدة عند بداية التشغيل void Start () { } //يتم استدعاؤها مرة عند تصيير كل إطار void Update () { } //تخرج من اللعبة public void ExitGame() { if (Application.loadedLevel == 0) { //نحن الآن في القائمة الرئيسية، بالتالي أغلق التطبيق نهائيا Application.Quit(); } else if (Application.loadedLevel == 1) { //نحن في مشهد اللعبة، بالتالي عد للقائمة الرئيسية Application.LoadLevel(0); } } }لاحظ أن البريمج يستخدم أوامر مباشرة يتيحها محرك Unity من أجل تحميل المشاهد حسب أرقامها. حيث نعرف المشهد الحالي عن طريق المتغير Application.loadedLevel ونقوم بتحميل المشهد الذي نريد عن طريق الدّالة ()Application.LoadLevel. تذكر أن مشهد القائمة الرئيسية يحمل الرقم 0 ومشهد اللعبة يحمل الرقم 1. أخيرا يمكنك ملاحظة أن الدّالة ()Application.Quit تستخدم لإغلاق التطبيق. الخطوة التالية هي ربط الضغط على الزر "خروج" باستدعاء الدّالة ()ExitGame. الخطوة الأولى هي أن نضيف هذا البريمج إلى المشهد على أي كائن، وليكن كائن الزر نفسه. بعدها نعود للمكوّن Button حيث سنجد في أسفله قائمة بالأوامر التي نريد استدعاءها حين الضغط على هذا الزر وهي مرتبة في القائمة ()OnClick كما في ترى في الصورة التالية. يمكنك إضافة أمر جديد بالضغط على الزر + في أسفل القائمة: عند إضافة أمر جديد للقائمة، عليك تحديد الكائن الذي سينفذ الأمر، ومن ثم تحدد البريمج، وأخيرا تحدد الدّالة داخل هذا البريمج. بما أننا أضفنا البريمج ExitGameCommand على كائن الزر نفسه، علينا أن نسحب الزر "خروج" Exit من الهرمية إلى داخل الخانة الخاصّة بالكائن، ومن ثم نفتح قائمة الأوامر والتي تكون قيمتها الافتراضية No Function حيث نختار البريمج ExitGameCommand ومن ثم الدّالة ()ExitGame كما في الصورة التالية: بالتالي عند الضغط على الزر "خروج" فإن التطبيق سيتم إيقاف تشغيله (ملاحظة: لا يعمل الأمر ()Application.Quit من داخل محرر المحرك، عليك بناء التطبيق وتشغيله منفردا لتجربته). لننتقل الآن للزر الثاني وهو زر بداية اللعب. عند الضغط عليه سيعرض نافذة جديدة تحتوي على المراحل الموجودة بحيث يتسنى للاعب اختيار مرحلة منها. من أجل ذلك علينا أولا بناء نافذة مستقلة تحتوي على أزرار المراحل. مبدئيا سنكتفي بزرين يحملان الأرقام 1 و 2 حيث سيكون لدينا مرحلتان فقط في هذا المثال. إضافة لذلك سيكون هناك زر ثالث يحمل الرمز X يقوم بإغلاق النافذة والعودة للقائمة الرئيسية مرة أخرى. لعمل النافذة المذكورة قم بإضافة لوح جديد Panel واحرص على أن يكون ترتيبه بين أبناء الكائن Canvas تحت اللوح الأول الخاص بالقائمة الرئيسية MainMenu. هذا الترتيب مهم حيث أن الكائنات في أسفل الهرمية تظهر على الشاشة أمام الكائنات التي في الأعلى، وهذا ما نريده: أن تظهر هذه النافذة حين عرضها أمام القائمة الرئيسية. قم بتغيير لون اللوح للأسود مع الإبقاء على الشفافية، ومن ثم غير اسمه إلى LevelSelector وحجمه على المحورين الأفقي والعمودي إلى 0.9. هذا سيجعل شكله يبدو كالآتي (لاحظ أيضا ترتيب العناصر في الهرمية على اليسار). ما يلزمنا الآن هو ترتيب الأزرار داخل هذه النافذة على شكل جدول مكون من صفوف وأعمدة، بحيث تكون هذه الأزرار متساوية في الحجم وبينها مسافات ثابتة. لحسن الحظ فإن Unity يسهل علينا هذه المهمة عن طريق توفير المكوّن GridLayoutGroup. هذا المكوّن يقوم بترتيب العناصر داخل اللوح بالطريقة التي ذكرتها للتو، وهو يحتوي على عدة متغيرات كما ترى في هذه الصورة. انتبه لأن إضافة مكوّن كهذا يلغي تأثير طريقة الارتكاز التي تحدثنا عنها سابقا، حيث يصبح المكوّن هو المسؤول عن المواقع والأحجام الخاصة بالعناصر التي يحتويها. المتغيرات الأربع تحت البند Padding تحدد حجم الهوامش من الجهات الأربعة بالبكسل، وهنا اخترت القيمة 32. بعدها نقوم بتحديد حجم كل عنصر أفقيا وعموديا عن طريق المتغير Cell Size وأخيرا نحدد المسافات بين العناصر وهي هنا 16. باقي المتغيرات يمكن تركها على قيمها الافتراضية. بعد هذا علينا أن نصنع قالبا لزر المرحلة بحيث يمكننا إضافته عدة مرات مع تغيير المرحلة التي سيتم تحميلها بتغير الزر. الزر المذكور شبيه بالأزرار التي أضفناها حتى الآن من حيث آلية العرض بتغيير الصور، لكن الذي سيتغير هو النص حيث سيحمل كل زر رقم المرحلة (1، 2، 3، …) إضافة لتغيير البريمج الذي سيستقبل الأمر. بعد صنع قالب الزر حسب الوصف السابق، سنضيف عليه البريمج LevelButton، وهو موضح في السرد التالي: using UnityEngine; using System.Collections; public class LevelButton : MonoBehaviour { //تستدعى مرة واحدة عند بداية التشغيل void Start () { } //تستدعى مرة عند تصيير كل إطار void Update () { } //تقوم ببدء اللعبة مستخدمة رقم المرحلة المزود public void StartLevel(int levelIndex) { //SelectedLevelخزن رقم المرحلة في الإعدادات في الخانة PlayerPrefs.SetInt("SelectedLevel", levelIndex); //قم بتحميل المشهد رقم 1 وهو مشهد اللعبة Application.LoadLevel(1); } } يعمل هذا البريمج عند استدعاء الدّالة ()StartLevel على تحميل مشهد اللعبة (المشهد رقم 1)، لكن قبل ذلك يقوم بتخزين رقم المرحلة التي يجب تحميلها في إعدادات اللاعب. هذه الإعدادات يتم تخزينها على القرص الصلب أي أنها دائمة وليست في الذاكرة. بالتالي فإن القيمة التي تخزن فيها ستبقى محفوظة حين الانتقال بين مشهدي القائمة واللعبة. يمكن الوصول لإعدادات اللاعب عبر PlayerPrefs والتي تحتوي على دوالّ لتخزين وقراءة بيانات بأنواع مختلفة. هنا مثلا استخدمنا الدّالة ()SetInt والتي تقوم بتخزين عدد صحيح، واخترنا اسما للقيمة التي قمنا بتخزينها وهي SelectedLevel. سنرى لاحقا كيف يمكننا قراءة هذه القيمة وتحميل المرحلة بناء عليها. ما علينا فعله الآن هو إضافة عنصر جديد للقائمة ()OnClick ومن ثم سحب الزر نفسه لخانة الكائن تماما كما فعلنا مع زر الخروج من اللعبة. بعدها سنختار البريمج LevelButton من القائمة ومن ثم نختار الدّالة ()StartLevel. الشيء الجديد الذي ستلاحظه هذه المرة هو وجود خانة لإدخال قيمة المتغير levelIndex، حيث أن هذه الدّالة تأخذ متغيرا بخلاف ()ExitGame التي تعاملنا معها في زر الخروج من اللعبة. لاحظ الصورة التالية: سنقوم بعمل زرين من هذا القالب. أحدهما سيحمل النص 1 والقيمة 0 للدّالة ()StartLevel، والآخر سيحمل النص 2 والقيمة 1 للدّالة ()StartLevel. هذان الزران سنقوم بإضافتهما كأبناء للكائن LevelSelector. بعد إضافة الأزرار بالترتيب الصحيح سيتكفل المكوّن Grid Layout Group بوضع كل منهما في الموقع الصحيح وبالحجم الصحيح. قبل الانتقال للحديث عن الزر الثالث وهو زر إغلاق النافذة، لنقم بكتابة البريمج الذي سيحول هذا اللوح إلى نافذة يمكن فتحها وإغلاقها. هذا البريمج هو UIDialog وهو موضح في السرد التالي: using UnityEngine; using System.Collections; public class UIDialog : MonoBehaviour { //قياس النافذة حين تكون مفتوحة public Vector2 maxSize = Vector2.one; //هل تتمدد النافذة حاليا؟ private bool expanding = false; //هل تتقلص النافذة حاليا؟ private bool shrinking = false; //تستدعى مرة واحدة عند بداية التشغيل void Start () { //أخف النافذة مبدئيا transform.localScale = Vector2.zero; } //تستدعى مرة عند تصيير كل إطار void Update () { //اجلب القياس الحالي للنافذة Vector2 scale = transform.localScale; //احسب القياس الجديد بناء على حالة النافذة if (expanding) { scale = Vector2.Lerp(scale, maxSize, Time.deltaTime * 10); //تحقق من الوصول للمنطقة الميتة if (Vector2.Distance(scale, maxSize) < 0.01f) { scale = maxSize; expanding = false; } } else if (shrinking) { scale = Vector2.Lerp(scale, Vector2.zero, Time.deltaTime * 10); //تحقق من الوصول للمنطقة الميتة if (Vector2.Distance(scale, Vector2.zero) < 0.01f) { scale = Vector2.zero; shrinking = false; } } //قم بتغيير القياس للقيمة الجديدة transform.localScale = scale; } //تقوم بفتح النافذة public void Show() { expanding = true; shrinking = false; } //تقوم بإغلاق النافذة public void Hide() { shrinking = true; expanding = false; } } يعتمد مبدأ عمل هذا البريمج على قيمة المتغيرين expanding و shrinking، حيث يحددان ما إذا كانت النافذة تتقلص إلى أن تصل لمرحلة الإغلاق أو إن كانت تتمدد حتى تصل لمرحلة الفتح. حين فتح النافذة يتم إيصال قياسها لقيمة الحد الأعلى المحددة في maxSize، أما حين الإغلاق يجب أن تصل قيمة القياس لصفر حتى تختفي النافذة تماما. لاحظ أن تمدد وتقلص النافذة يتم بشكل سلس عبر ()Vector2.Lerp والتي تستخدم الاستيفاء الذي شرحناه سابقا. افتراضيا يتم ضبط قياس النافذة على Vector2.zero مما يؤدي لأن تبدأ مختفية (مغلقة)، وسيتم إظهارها (فتحها) حين استدعاء الدّالة ()Show، كما يمكن استدعاء ()Hide لإخفائها (أو إغلاقها) ثانية. بعد إضافة هذا البريمج للكائن LevelSelector ستلاحظ أنه يختفي تلقائيا عند تشغيل اللعبة. بقي علينا أن نظهره حين يضغط اللاعب على "ابدأ اللعب" ونخفيه حين يضغط اللاعب على الزر X الذي سنضيفه لهذه النافذة. لنبدأ بعمل زر إغلاق النافذة مستخدمين الصور الثلاث للزر الأحمر. بعد إضافة هذا الزر سنقوم بحذف مكوّن النص من الكائن الإبن Text ونضيف بدلا منه كائن صورة Image كما هو موضح في الصورة التالية: بعدها سنقوم بسحب الصورة cross والموجودة في مجموعة رسوم واجهة المستخدم في المجلد Assets\Kenney.nl\UI Pack إلى الخانة Source Image مما يجعل الشكل النهائي لنافذة اختيار المرحلة يبدو كالتالي: بالنسبة لزر الإغلاق الأحمر سيكون الكائن الهدف لتنفيذ الأمر هو النافذة LevelSelector بالتالي سنسحبها لعنصر جديد نضيفه للقائمة ()OnClick، ومن ثم سنقوم بتحديد البريمج UIDialog والدّالة ()Hide كأمر يتم تنفيذه حين الضغط على هذا الزر. بعدها سنعود للزر الأول في القائمة الرئيسية وهو "ابدأ اللعب" ونضيف له النافذة LevelSelector كهدف للأمر والبريمج UIDialog أيضا، إلا أن الدّالة هذه المرة ستكون ()Show حيث أن الضغط على هذا الزر سيظهر النافذة. الشكل النهائي للقائمة ()OnClick في هذين الزرين سيبدو كالآتي: لو قمت بتشغيل اللعبة الآن ستلاحظ أن الضغط على "ابدأ اللعب" سيظهر لك نافذة اختيار المراحل، ومن هناك يمكنك الضغط على الزر 1 أو 2 لتحميل المرحلة التي تريدها. بطبيعة الحال لا توجد أي مراحل حاليا، لذا سيأخذك الضغط على هذه الأزرار إلى مشهد اللعبة الفارغ. ما نريد عمله الآن هو إضافة زر في مشهد اللعبة يمكّن اللاعب من العودة للقائمة الرئيسية. كل ما علينا فعله هو إضافة زر صغير في أعلى يمين الشاشة يحمل إشارة X ، وعند الضغط عليه سيظهر للاعب نافذة صغيرة يسأله من خلالها إن كان يريد أن يعود للقائمة الرئيسية. بالنظر لموقع الزر المفترض، علينا مراعاة أن تكون نقطة ارتكازه في أعلى اليمين، وذلك حتى يبقى على مسافة ثابتة من أعلى يمين الشاشة بغض النظر عن حجمها. هذا الزر لا يختلف عن التي أنشأناها سابقا سوى أنه أصغر حجما. سنعود لاحقا لإضافة الأمر الخاص بهذا الزر. الصورة التالية توضح موقعه في الشاشة، ويمكنك ملاحظة نقطة ارتكازه في أعلى اليمين: بعد إضافة هذا الزر سنضيف نافذة حوار جديدة كالتي أضفناها في القائمة الرئيسية لاختيار المراحل، إلا أنها ستكون أصغر حجما وتحتوي على سؤال لتأكيد العودة للقائمة الرئيسية، إضافة لزرين للاختيار بين نعم و لا. الصورة أدناه تمثل الشكل والحجم المفترضين لنافذة كهذه. (لاحظ الهرمية في يسار الصورة لترى مم تتكون هذه النافذة): الزر الذي يحمل علامة ✓ سيعود باللاعب للقائمة الرئيسية، بينما الآخر سيقوم بإغلاق نافذة الحوار هذه مع البقاء في مشهد اللعبة• من أجل العودة للقائمة الرئيسية سنحتاج مرة أخرى للبريمج ExitGameCommand ولكننا سنضيفه هذه المرة على الكائن الجذري للواجهة Canvas حيث سنحتاج لاستدعائه من أكثر من نافذة كما سنرى. بعد إضافة البريمج ستكون الدّالة ()ExitGame المعرفة فيه هي الأمر الذي سينفذ حين الضغط على الزر ✓، بينما سيكون Canvas هو الكائن الهدف حيث أنه من يحمل هذا البريمج. بالتالي سيكون شكل القائمة ()OnClick كما يلي: تذكر أن الدّالة ()ExitGame تعود للقائمة الرئيسية في حال تم استدعاؤها من مشهد اللعبة. بعد ذلك علينا أن نضيف لهذه النافذة الصغيرة البريمج UIDialog بحيث تبدأ مختفية وتظهر حين استدعاء ()Show. بطبيعة الحال سيكون زر الخروج الموجود أعلى يمين الشاشة هو من يستدعي الدّالة ()Show عند الضغط عليه، بينما سيكون زر الإغلاق X الموجود على النافذة نفسها هو من يستدعي لها الدّالة ()Hide. أعتقد أنه إلى هنا أصبحت فكرة ربط الضغط على الزر بكائن معين واستدعاء دالّة من بريمج عليه واضحة، لذا لن أعاود شرحها بالصور وسأكتفي بذكر الارتباطات اللازمة. بهذا تكون القائمة الرئيسية للعبة جاهزة، ويمكننا الانتقال بينها وبين مشهد اللعبة. بقي علينا أن نجهز المراحل وما يتعلق بحالة اللعبة حتى تصبح لعبتنا مكتملة ويمكننا لعبها. إضافة المراحل والتنقل بينهابعد أن أصبحت عناصر بناء المرحلة مكتملة لدينا إضافة للشاشة الرئيسية وبعض عناصر واجهة المستخدم، سنقوم الآن بصنع مرحلتين لتجربة تتابع المراحل إضافة للتنقل بينها وبين الشاشة الرئيسية. يمكنك أن تستخدم أي مقذوفات ترغب بها وأي وحدات بنائية وخصوم. المهم هو أن تتبع بناء هرميا محددا حتى تكون جميع المراحل متوافقة في الشكل. الشكل التالي يوضح مثالا على مرحلة صغيرة ومما تتكون هرمية المرحلة. لاحظ أن المرحلة تتكون من 3 عناصر: القاذف، والعناصر البنائية والوحوش والتي تندرج تحت الكائن الفارغ Elements، وأخيرا المقذوفات والتي تندرج تحت الكائن الفارغ Projectiles. لاحظ أيضا أن جميع العناصر على مستوى أفقي واحد وهو المستوى الذي ستظهر فيه الأرضية. عند بناء المرحلة، راعي أن يكون الكائن الفارغ الأب للمرحلة (Level1 في الصورة السابقة) في منتصف المشهد، وأن يكون أسفل المرحلة على مستوى الأرضية التي ستظهر. بعد بناء المرحلة يجب أن نحولها كاملة إلى قالب واحد كبير، لكن قبل ذلك علينا إضافة بريمج بسيط لكائن المرحلة الجذري. هذا البريمج مهمته تحديد رقم الخلفية التي ستظهر حين تحميل المرحلة ويسمى GameLevel وهو موضح في السرد التالي: using UnityEngine; using System.Collections; public class GameLevel : MonoBehaviour { //صورة الخلفية التي ستظهر عند تحميل المرحلة public int backgroundIndex; //تستدعى مرة واحدة عند بداية التشغيل void Start () { } //يتم استدعاؤها مرة عند تصيير كل إطار void Update () { } }المهم في هذا البريمج هو أن نعرف أي صورة خلفية يجب أن نختار عند تحميل المرحلة، عدا عن ذلك فمحتويات المرحلة كفيلة بالتحكم بحالة اللعبة كما سنرى بعد قليل. بعد تجهيز المراحل على شكل قوالب، سنقوم بعمل بريمج جديد لتخزين هذه القوالب ومن ثم إنشائها حسب الحاجة، أي حسب المرحلة التي يتم تحميلها. هذا البريمج يسمى GameLevelLoader وسنقوم بإضافته للكائن الجذري في المشهد. السرد التالي يوضح هذا البريمج: using UnityEngine; using System.Collections; public class GameLevelLoader : MonoBehaviour { //تقوم بتخزين القوالب الخاصة بجميع المراحل public GameLevel[] allLevels; //العنصر الخاص بالمرحلة المحملة حاليا private int currentLevel = -1; //مرجع لبريمج التحكم بالخلفية private BackgroundManager bgManager; //مرجع لبريمج أمر الخروج من اللعبة ExitGameCommand egc; //يتم استدعاؤها مرة عند بداية التشغيل void Start () { bgManager = GetComponent<BackgroundManager>(); egc = FindObjectOfType<ExitGameCommand>(); } //يتم استدعاءها مرة عند تصيير كل إطار لكن في وقت متأخر void LateUpdate () { if (currentLevel == -1) { //قم بتحميل المرحلة التي تم اختيارها من القائمة الرئيسية //إذا لم تكن هناك أي مرحلة، قم تلقائيا بتحميل المرحلة الأولى int selectedLevel = PlayerPrefs.GetInt("SelectedLevel", 0); LoadLevel(selectedLevel); } } //تقوم بتحميل المرحلة المحددة public void LoadLevel(int index) { //قم بالتأكد من وجود المرحلة المطلوبة في المصفوفة //إن لم تكن موجودة فعد للقائمة الرئيسية if (index < 0 || index >= allLevels.Length) { egc.ExitGame(); return; } //قم بالبحث عن المرحلة المحملة حاليا وتدميرها إن وجدت GameLevel current = FindObjectOfType<GameLevel>(); if (current != null) { Destroy(current.gameObject); } //قم بإنشاء المرحلة الجديدة مستخدما قالبها GameObject newLevelObject = (GameObject)Instantiate(allLevels[index].gameObject); GameLevel newLevelScript = newLevelObject.GetComponent<GameLevel>(); //قم بتحديد الكائن الأب والموقع للقائمة الجديدة newLevelObject.transform.parent = transform; newLevelObject.transform.position = Vector2.zero; //قم بتغيير رقم العنصر الخاص بالمرحلة الحالية currentLevel = index; //قم بتغيير الخلفية للصورة المحددة في المرحلة الجديدة bgManager.ChangeBackground(newLevelScript.backgroundIndex); //قم بإبلاغ البريمجات الأخرى بان هناك مرحلة جديدة تم تحميلها للتو SendMessage("NewLevelLoaded"); } //تقوم بإعادة لعب المرحلة الحالية public void RestartCurrentLevel() { if (currentLevel != -1) { LoadLevel(currentLevel); } } //تقوم بتحميل المرحلة التالية في المصفوفة public void LoadNextLevel() { LoadLevel(currentLevel + 1); } }هذا البريمج يحتوي على متغير عام واحد فقط وهو المصفوفة allLevels التي تحتوي على قوالب جميع مراحل اللعبة. لاحظ أن تحميل المرحلة يتم تأخيره باستخدام الدّالة ()LateUpdate وذلك حتى نضمن أن جميع البريمجات الأخرى قد بدأت العمل ويمكننا الاعتماد عليها مثل البريمج BackgroundManager والذي سنستخدمه لتغيير صورة الخلفية للصورة المحددة في البريمج GameLevel الخاص بالمرحلة الحالية. يبحث البريمج مبدئيا عن متغير مخزن في إعدادات اللاعب ويحمل الاسم SelectedLevel. كما تذكر فإن هذا المتغير يفترض أن يتم تخزينه من قبل البريمج LevelButton والخاص بأزرار المراحل في القائمة الرئيسية. إذا لم يوجد هذا المتغير يتم إرجاع القيمة الافتراضية وهي 0 بالتالي يتم تحميل المرحلة الأولى في المصفوفة. الدّالة ()LoadLevel هي الأساسية في هذا البريمج حيث نعطيها رقم المرحلة التي نرغب بتحميلها من المصفوفة، فإذا لم يكن رقم المرحلة المحددة صالحا ستعود للقائمة الرئيسية للعبة. أما إذا كان الرقم صحيحا فإنها تتأكد من عدم وجود مرحلة محملة حاليا عن طريق البحث عن بريمج من نوع GameLevel، إذا وجدت هذا البريمج فإنها تقوم بتدمير الكائن الذي يحمله، وبما أن الكائن هو جذر عناصر المرحلة جميعها، سيتم تدمير جميع هذه العناصر أيضا، مما يجعل المشهد فارغا وجاهزا لاستقبال المرحلة الجديدة. هذه المرحلة يتم إنشاؤها عن طريق استخراج القالب الموجود في الموقع المحدد index ومن ثم بناء كائن منه. هذا الكائن تتم إضافته كابن للكائن الجذري لمشهد اللعبة كما يتم وضعه في منتصف المشهد. بعدها يتم تحديث قيمة currentLevel إلى المرحلة الجديدة وتغيير الخلفية باستخدام المتغير backgroundIndex الخاص ببريمج المرحلة الجديدة. أخيرا تقوم الدّالة بإرسال الرسالة NewLevelLoaded حتى تخبر البريمجات الأخرى بأن المرحلة الجديدة تم تحميلها. إضافة لذلك لدينا الدّالتان ()RestartCurrentLevel والتي تقوم بإعادة تحميل المرحلة الحالية، و ()LoadNextLevel والتي تقوم بتحميل المرحلة التالية في الترتيب في المصفوفة. حالة اللعبة وشروط الفوز والخسارةبعد أن أصبحت جميع محتويات اللعبة مكتملة بما فيها المراحل، بقي علينا أن نضيف شروط الفوز والخسارة وما يترتب عليها من تغيير على حالة اللعبة. في ألعاب من هذا النوع يفوز اللاعب إذا قام بتدمير جميع الخصوم وهي الوحوش في لعبتنا هذه، ويخسر إذا استنفد جميع ما لديه من مقذوفات دون تدمير الخصوم. تذكر أننا سابقا أضفنا البريمج Enemy لكائنات الوحوش والذي يرسل للكائن الجذري الرسالة EnemyDestroyed حين يتم تدمير الكائن، كما أن بريمج المقلاع Launcher يقوم بإرسال الرسالة ProjectilesConsumed عندما يتم إطلاق كافة المقذوفات التي كانت بحوزة اللاعب. ما يتوجب علينا هو كتابة بريمج يستقبل هاتين الرسالتين وبناء عليهما يقوم بفحص حالة اللعبة والتأكد من فوز أو خسارة اللاعب. هذا البريمج هو GameStateManager وهو موضح في السرد التالي: using UnityEngine; using System.Collections; public class GameStateManager : MonoBehaviour { //متغير لمعرفة ما إذا فاز اللاعب بالمرحلة private bool playerWon; //تستدعى مرة واحدة عند بداية التشغيل void Start () { playerWon = false; } //تستدعى مرة عند تصيير كل إطار void Update () { } //والتي ترسلها EnemyDestroyed تستقبل الرسالة //كائنات الوحوش عند تدميرها void EnemyDestroyed() { //قم بعد الوحوش المتبقية في المشهد Enemy[] enemies = FindObjectsOfType<Enemy>(); if (enemies.Length <= 1) { //تم تدمير جميع الوحوش، أي فاز اللاعب بالمرحلة SendMessage("PlayerWon"); playerWon = true; } } //تقوم باستقبال رسالة استنفاد اللاعب //لجميع المقذوفات التي كانت بحوزته void ProjectilesConsumed() { if (!playerWon) { SendMessage("PlayerLost"); } } //التي تعني NewLevelLoaded تستقبل الرسالة //false إلى playerWon أنه تم تحميل مرحلة جديدة، وبناء عليها تعيد void NewLevelLoaded() { playerWon = false; } }في كل مرة يتم فيها تدمير أحد الوحوش يستقبل هذا البريمج الرسالة EnemyDestroyed ومن ثم يقوم بعد الوحوش المتبقية في المشهد عن طريق البحث عن البريمج Enemy. لاحظ أن وجود بريمج واحد في المشهد يعني أن اللاعب قد فاز فكيف هذا؟ الجواب هو أن تدمير الكائن لا يتم مباشرة عند استدعاء ()Destroy، وإنما يتم تأخيره حتى نهاية الإطار الحالي. لذا فمن المحتمل أن تصل الرسالة ويتم بعدها البحث عن بريمج من نوع Enemy وإيجاده. فإن كان العدد واحدا فهذا يعني أنه الأخير المتبقي في المشهد واستقبال الرسالة يعني أنه تم تدميره. لذا نعرف هنا بأن اللاعب قد فاز في المرحلة ويتم إرسال الرسالة PlayerWon وتغيير قيمة playerWon إلى true. أما استقبال الرسالة ProjectilesConsumed فيعني أن آخر مقذوف أطلقه اللاعب قد انقضت مدة بقائه وتم حذفه من المشهد، وأن القاذف لم يجد أي مقذوفات أخرى. حينها تقوم الدّالة ()ProjectilesConsumed باستقبال الرسالة ومن ثم التأكد من أن اللاعب لم يفز باللعبة حتى الآن – أي لم يدمر جميع الوحوش – وفي هذه الحالة تحكم بخسارة اللاعب عن طريق إرسال الرسالة PlayerLost. السؤال الآن هو ماذا سيحدث عندما يتم إرسال PlayerWon أو PlayerLost؟ الجواب هو أن كل رسالة ستقوم بإظهار نافذة حوار مختلفة. ففي حال فوز اللاعب ستظهر له نافذة تخيره بين إعادة اللعب وبين التقدم للمرحلة التالية واسمها WinDialog، وفي حالة الخسارة تظهر نافذة أخرى تخيره بين إعادة المرحلة والخروج للقائمة الرئيسية واسمها LoseDialog. هاتان النافذتان ستكونان كالنوافذ السابقة عبارة عن كائنات Panel مضاف عليها البريمج UIDialog وتحتوي كل منهما على نص وزرين تماما كنافذة تأكيد العودة للقائمة الرئيسية. بداية لنقم ببناء هاتين النافذتين وتحديد الوظائف الخاصة بأزرارها. لنبدأ مع نافذة الفوز والتي ستبدو بالشكل التالي: المشترك في الزرين الموجودين على النافذة هو أن الهدف لأوامرهما هو الكائن الجذري لمشهد اللعبة SceneRoot وتحديدا بريمج تحميل المراحل GameLevelLoader. أما الفرق فهو أن الزر الأيمن سيقوم باستدعاء الدّالة ()LoadNextLevel عند الضغط عليه مما ينقل اللاعب للمرحلة التالية، بينما الزر الأيسر يستدعي عند الضغط عليه الدّالة ()RestartCurrentLevel مما يؤدي لإعادة تحميل المرحلة الحالية. علاوة على ذلك، يجب أن يقوم كلا هذين الزرين أيضا بإخفاء النافذة حتى يتمكن اللاعب من متابعة اللعب سواء في المرحلة التالية أو الحالية. من أجل ذلك يجب أن نضيف لكل منهما هدفا آخر وهو النافذة نفسها، حيث سيقوم كلاهما باستدعاء الدّالة ()Hide من البريمج UIDialog. لاحظ أن ()OnClick هي عبارة عن قائمة كما ذكرنا سابقا، بالتالي يمكنها أن تستدعي أكثر من أمر من أكثر من كائن وبريمج كما هو مبين في الصورة التالية: النافذة الأخرى وهي التي تظهر في حال الخسارة تبدو بهذا الشكل: الزر الأيمن وهو زر العودة للقائمة الرئيسية سيكون الكائن الهدف بالنسبة له هو الكائن الجذري للواجهة Canvas وتحديدا البريمج ExitGameCommand والدّالة ()ExitGame. أما الزر الأيسر فتماما كما في نافذة الفوز يستدعي الدّالة ()RestartCurrentLevel ويقوم أيضا باستدعاء ()Hide من البريمج UIDialog الموجود على كائن نافذة الخسارة LoseDialog. بقي علينا الآن أن نربط بين الرسائل التي يرسلها GameStateManager وبين ظهور هذه النوافذ. المشكلة التي تواجهنا هنا هي أن النوافذ تقع تحت كائن جذري مختلف عن الكائن الجذري للمشهد، وكل منهما ذو وظيفة محددة ولا يجب أن تتداخل هذه الوظائف كثيرا. من أجل ذلك سنقوم بكتابة بريمج يعمل على استقبال الرسائل من GameStateManager ومن ثم استدعاء دوال من بريمج آخر سنضيفه على Canvas بحيث يشكل هذان البريمجان معا جسر التواصل بين واجهة المستخدم ومنطق اللعبة. لنبدأ مع البريمج الأول الذي سنضيفه على جذر واجهة المستخدم Canvas وهو GameStateDialogs الموضح في السرد التالي: using UnityEngine; using System.Collections; public class GameStateDialogs : MonoBehaviour { //متغير لتخزين نافذة فوز اللاعب public UIDialog winDialog; //متغير لتخزين نافذة خسارة اللاعب public UIDialog loseDialog; //تستدعى مرة واحدة عن بداية التشغيل void Start () { } //تستدعى مرة عند تصيير كل إطار void Update () { } //تعرض نافذة فوز اللاعب public void ShowWinDialog() { winDialog.Show(); } //تعرض نافذة خسارة اللاعب public void ShowLoseDialog() { loseDialog.Show(); } } كل ما يفعله هذا البريمج البسيط هو تخزين نافذتي الفوز والخسارة في مراجع ومن ثم عرضها عند استدعاء الدّالة ()ShowWindDialog أو الدّالة ()ShowLoseDialog. بعد إضافة هذا البريمج للجذر Canvas عليك أن تسحب كلا من نافذة الفوز ونافذة الخسارة لخانة المتغير المناسب لها كما ترى في الصورة التالية: لننتقل الآن للطرف الآخر وهو جذر المشهد SceneRoot والذي سنضيف عليه البريمج GameStateReporter الموضح في السرد التالي: using UnityEngine; using System.Collections; public class GameStateReporter : MonoBehaviour { //مرجع لبريمج عرض نافذتي الفوز والخسارة GameStateDialogs gsDialogs; //تستدعى مرة عند بداية التشغيل void Start () { gsDialogs = FindObjectOfType<GameStateDialogs>(); } //تستدعى مرة عند تصيير كل إطار void Update () { } //تستقبل رسالة فوز اللاعب void PlayerWon() { gsDialogs.ShowWinDialog(); } //تستقبل رسالة عرض اللاعب void PlayerLost() { gsDialogs.ShowLoseDialog(); } }كل ما يفعله هذا البريمج هو استقبال رسائل الفوز والخسارة ومن ثم استدعاء الدّالة التي تعرض النافذة المناسبة من البريمج GameStateDialog. بهذا تكون لعبتنا قد اكتملت على جهاز الحاسب ويمكن تشغيلها ولعب المراحل والفوز والخسارة بها. بقي علينا أن ننقلها للهواتف الذكية وشاشات اللمس، وهي خطوة بسيطة نظرا للطريقة المنظمة التي اتبعناها في استقبال المدخلات.
    1 نقطة
  4. سواء كنت كاتباً أو مصمماً أو مبرمجاً فلابد أن يكون للإبداع مكان بحياتك، الإبداع هو بصمتك في منتجاتك الرقمية وهو شفرتك بسوق الأعمال التي يجب أن تجتهد لاكتشافها، كثير ممن يعمل بالمجال الرقمي يعرف أنه يجب أن يكون مبدعاً بعمله حتى ينجح، ولكنه لا يدري كيف.. هل تريد أن تحصل على الإبداع بحياتك؟ لا تستعجل ولا تخجل من ارتكاب الأخطاء ولكن تعلم منها، الأمر الذي ستكتشفه أن الإبداع مُكتشف ونتيجة طبيعية لجهدك وتعبك وسعيك نحو ما تريد، إضافة قيمة حقيقية بمنتجاتك الرقمية إحدى هذه الأهداف، بعض المبدعين يكتشفون أنفسهم بعمل تلك المنتجات والبعض الآخر يندمجون معها حتى يصبح المنتج والمبدِع شيئاً واحداً كلا منهما يمتلك خصائص من الآخر. الإبداع ليس سهلاً لكنك ستحتاج عدة أمور لتعرفها أثناء اكتسابك وتطويره بمرور الوقت، هل تريد معرفتها؟ هذه 15 أمرا يجب أن تعرفهم إذا أردت أن تصبح مبدعاً بعملك ومنتجاتك الرقمية..ولا تنس أن تخبرنا بالتعليقات ما الذي تعلمته أثناء العمل على منتجاتك الإبداعية. 1. لست الأولسهل أن تنخدع بجمال فكرتك وعبقريتها دون أن تدرك أنه تم تنفيذها من قبل، البحث والتأكد من وجود مثيلات أفكارك المبدعة أمر مهم، لأنه ما لم تقدم جديد أو تتفوق على الأفكار الشبيهة فلا قيمة لمنتجك أو جهدك، ويمكنك بكل بساطة أن تأخذ بعض الوقت بالبحث لتقييم فكرتك، ومعرفة هل يمكنك تقديم شيء جديد أم لا حتى تقوم بعد ذلك بإظهار المختلف والقيّم بمنتجك خلافاً عن الآخرين.2. يوجد دائما من هو أفضل منكتقبل هذه الحقيقة ولا تجعلها تؤثر على عملك، تعلم منهم جيداً وتعرف ما الذي ينقصك حتى تتفوق عليهم، الأفضل دائماً لم يصل إلا ببذل الجهود والمثابرة، مهما بذلت من العمل على مشروع أو منتج فيمكنك دائماً إنتاج ما هو أفضل، لما؟..لتصبح أنت الأفضل، اسع لتكن الأفضل وكن فخوراً بما تبذل لكن لا ترضى أبداً. 3. نجاح غيرك لا يعني فشلكالنجاح شيء لا حدود له يمكن للجميع أن يأخذ منه وسيفيض، نجاح منافسيك لايعني بالضرورة فشلك ولكن ربما يعني اشتداد المنافسة، فلولا المنافسة لما ظهرت الأشياء العظيمة، تعرف على أنماط نجاح هؤلاء وستستطيع النجاح في جوانب أخرى من عملك، لا تبتئس واصنع فرص جديدة من نجاحات الآخرين. 4. لن تحقق شيء بدون هدفكل منتج تقوم بعمله يجب أن يكون ذا هدف أو عدة أهداف، هذه الأهداف هي ما ستمد منتجك بالقيمة والفائدة، لكي تربح من منتجاتك يجب أن تقدم قيمة عالية للزبائن والعملاء، هم يشترون القيمة، لذا ضع تركيزك على القيمة وليست الأرباح، حدد هدفك لكل منتج هل هو للإلهام، التوعية، التثقيف، التعليم، حل مشكلة، سد حاجة..الخ. 5. البداية صعبة دائمابداية العمل وجلب زبائن لمنتجاتك والتسويق لنفسك وأعمالك كل هذا سيحتاج منك طاقة كبيرة بالبداية، معرفتك لهذا الأمر يجب أن يهون عليك قليلاً ولا يجعلك تستسلم من البداية، كلما استصعبت أمراً بعملك أو منتج فتذكر أنه ليس بعد، فلم تصل لحدودك ولم تصل لأقصى إبداعاتك بعد، مع كل شروع بالعمل على منتج تعامل على هذا الأساس. 6. الحصول على زبائن أيسر مما تعتقدإذا كنت تشتكي قلة المبيعات والحصول على زبائن فإن الأمر بسيط، كل ما ستحتاجه منتج عظيم، مجهود،شخصية حسنة التعامل، الكثير يركز على أول اثنتين وينسى الأخيرة، تعاملك مع زبائنك سيصنع فارقا كبيرا ستكتشفه على مدار عملك معهم، “إعجاب العميل بشيء” قوة تسويقية كبيرة ستكتشف أهميتها عندما تحسن التعامل معهم. 7. الشك يقتل الإبداعلا تقلل من شأن نفسك، فمن يقلل من شأن نفسه كمن يمتلك منجم ذهب ولكن يدفنه في التراب، كيف يمكن أن تصل لحدود إبداعك وأنت لا تؤمن بوجودها، عبر عن نفسك بعملك ولا تخشى شيئا، ضع لمساتك الشخصية وستجد من يقدرها، اترك الشك جانباً وأثبت لنفسك أنها جديرة بالاحترام. 8. موقعك .. عنوانك أُعجب شخص بعملك ويريد أن يطلع على أعمالك الأخرى فأين سيجدها؟ العمل بدون موقع خاص أو مدونة سيصعب من العثور عليك ومسألة التسويق كثيراً، موقعك هو عنوانك الذي يجب أن يتجه إليه كل من يريد التعامل معك، إذا أردت الترويج لنفسك وأعمالك جيداً فابدأ بعمل موقعك الآن. 9. ركز على الجودة لا الكميةتطبيق واحد ناجح خير من عشرات التطبيقات المليئة بالأخطاء والعلل البرمجية، جودة عملك ستضمن نجاحك، العمل العظيم يحتاج وقتاً أكثر، خذ وقتك ولا تتعجل النتائج والبحث عن الأرباح، تصميماتك ستصبح متشابهة ما لم تأخذ وقتاً لتجد الإلهام وتصنع الاختلاف بينها، ليكن كل منتج يضيف الجديد. 10. استمع لحدسكليس كل الإبداع مفهوما، أحياناً أجمل الإبداع هو ما لا تستطيع فهمه ولكن تشعر بجماله وتناسقه، إذا خطرت ببالك بعض الأشياء التي تريد فعلها ولا تدري لماذا..فافعلها، ثق بحدسك فغالباً هذا الشيء نابع من مصدر ما أو تجربة مررت أنت بها ولكنك لم تفهمها بعد، خذها قاعدة بسيطة “إذا لم تتحمس لعملك فلن يتحمس له أحد“، أقرب تطبيق لهذا الأمر سيكون التصميم والتصوير الفوتوغرافي. 11. لا تنس عمل أكثر من صيغةإذا كنت تعرف احتياجات عملائك فعمل أكثر من صيغة لمنتجاتك الرقمية أمر ضروري، فالتصميمات يمكن عرضها pdf أو jpg وعلى حسب حاجة كذلك التطبيقات، فكل صيغة منها تعني أنك ستستهدف هذه الشريحة فقط من الزبائن، مثلاً تطبيقات سطح المكتب يجب أن تضع باعتبارك أي الأنظمة ستعمل عليها سواء وندوز أو ماك. 12. قدر عملكإذا كنت ستعمل فلا تعمل دون مقابل، ومقابل هنا تعني مادياً أو معنوياً، فمنتجاتك المجانية يجب أن تكون ذات مردود معنوي كإضافة للقائمة البريدية، أو التسويق لأعمالك الأخرى، طالما بذلت جهد ووقت فيجب أن تحسن تقديرهما، تسعير منتجاتك كذلك بالطرق الصحيحة دون بخس حقك والغلو على الزبائن. 13. اعمل..اعمل.. ثم اعملالإبداع سيأتي من ممارسة عملك جيداً، الاستمرار بالعمل هو ما سيزيد من رصيد خبراتك والتي يمكنك استخدامها بأحد المنتجات أو المشاريع، إذا كان الإبداع عبارة عن انفجارات بركانية فإن العمل والاستمرار باكتساب الخبرات هو الحمم البركانية التي تغلي منتظرة أن تخرج في منتج أو مشروع خلاّق. 14. اكتسب الأصدقاء لا الأعداءفي المجال الرقمي ستجد منافسين كُثر، التواصل معهم والاستفادة من خبراتهم سيعمل على خلق مناخ تنافسي شريف، يعمل كل شخص فيه ليقدم أفضل ما عنده، الأصدقاء والعلاقات الاجتماعية ضرورية حتى تصبح حياتك متزنة وتتجنب العداءات المعرقلة للتقدم. 15. اصبرالإبداع قد يظهر فجأة، لا تستعجل، تغلب على الطبيعة البشرية للاستعجال بالصبر، طالما أنك بذلت كل ما بوسعك سيأتي الإبداع لا شك، لكن كل شيء يأخذ وقته، تحتاج أفكارك ومشاريعك أن تتخمر حتى تخرج بالشكل الصحيح. الأعمال الإبداعية ملهمة للأفكار والأفكار ملهمة للتغيير، سعيك لتصبح مبدعاً هو سعيك نحو التغيير، ويوجد دائماً قطعة من الأحجية لن يستطيع أن يكتشفها أحد إلا أنت، إذا كنت تعرفت عليها من تجاربك وأعمالك فشاركنا بها . حقوق الصورة البارزة: Designed by Freepik.
    1 نقطة
  5. هل بدأت رحلتك في التصميم مؤخرَا؟ تشعر بالتخبط وبتدني المستوى، وتتمتع بمستوى من التصاميم أقل ما يوصف بالبشاعة؟! لا تقلق هذا طبيعي للغاية فأنت في مرحلة الاكتشاف وبداية تعلم مهارة جديدة، ولكن لأساعدك على تخطي تلك المرحلة في أسرع وقت وبأقل قدر ممكن من الأخطاء، تعرف على بعض الأخطاء التي يقع بها الكثير من المبتدئين في مجال التصميم والتي تؤخر بشدة من عملية التطوير السريع والفعال لمستواهم. البدأ في استعمال البرامج على الفورمعظمنا اكتشف حبه للتصميم عندما رأى بعض التصاميم الجميلة على مواقع الويب، وتمنى لو استطاع صناعة مثلها وبأسرع وقت ممكن، ولذلك ابتدأ فورَا بالتصميم على إحدى البرامج مثل الفوتوشوب مثلَا. استخدامك للبرنامج سيساعدك على إخراج التصميم الذي تريد ولكن بدون فهم أو دراسة لما تفعله وسيجعلك متمكن من أدوات لا تفهم آلية عملها فتكون أقرب للتقني المطبق منك إلى المصمم أو المبتكر. لا ألومك إن وقعت في هذا الخطأ فمعظم ورش ودورات التصميم المدفوعة أو المتاحة على الإنترنت لا تقوم بتوفير أساسات قوية بل تقوم بتعليمك الأدوات بشكل مباشر لتمكنك من صنع ما تريد من التصاميم المتنوعة، كما أن كثرة الدروس المرفوعة في كل مكان تجعلك مشتت الذهن بما عليك البدأ بتعلمه في الوقت الصحيح والأهم من ذلك بالترتيب الصحيح! وتكون النتيجة كارثية بالطبع! عوضَا عن البدأ بالبرامج مباشرة هل سألت نفسك يومَا بعضَا من هذه الأسئلة؟ هل لديك فكرة عن عناصر التصميم؟ هل تدرك ما هي أساسيات التصميم أصلَا؟هل روادتك الأفكار مرة عن كيفية استعمال مهارات التصميم المختلفة لتوصيل الأفكار؟هل تعرف الأدوات اللازمة لتكون مصمم بغض النظر عن البرامج؟بالطبع لم تفكر في تلك الأسئلة لإنك مشغول وبشدة في كيفية صنع التصاميم بأسرع وقت ممكن تفكر طوال الوقت في السؤال الأبدي "كم من الوقت يلزمني لأصل للاحتراف؟". من الصعب والنادر توفر كليات دراسة أكاديمية للتصميم الجرافيكي فإن لم تجدها حاول تعويض ذلك بفهمك العميق للتصميم ومحاولة الإجابة عن الأسئلة السابقة. قد تفضل الكتب المطولة أو المدونات الإلكترونية أو ربما تشترك في إحدى مواقع الدروس المدفوعة إن سمحت لك مادياتك، ولكن أيَا كان الأسلوب الذي ستلجأ إليه للتعلم رجاءَ لا تصمم بدون فهم تلك الأساسيات. عدم ترتيب الأفكار قبل البدأ في التصميملا تبدأ تصاميمك على ورقة بيضاء تحدق فيها متساءلَا ماذا أصمم! سيكون من الجيد لو نظمت أفكارك ابتداء من مشاهدة بعض التصاميم للاستلهام ورسم بعض الخرائط الذهنية والمخططات لاختيار أفضل الأفكار ومن ثم الانتقال للبرامج للتطبيق ابتداءَ من اختيار البرنامج المناسب والتفكير في آليات التطبيق مرورَا بالتعديلات النهائية وكيفية عرض الأعمال على العميل. هذا سيختصر عليك الكثير من الوقت والجهد إضافة إلى جعل تصاميمك أكثر دقة واحترافية. لا تكن مصممَا من الإبرة للصاروخ!لأكن صادقة معك معظم المشكلات التي أكتبها هنا هي نتاج تجربة ذاتية عانيت منها. بعضها قد تخلصت منه والبعض الآخر أعمل على علاجه إلى الآن، ومن أهم المشكلات التي واجهتني هي عدم التخصص! كنت أرى أن المصمم المثالي لا بد أن يكون على خبرة بجميع برامج التصميم ابتداء من البرامج الرسومية إلى برامج الحركة والتصاميم ثلاثية الأبعاد إضافة لتعديل الصور وتصميم الخطوط! كثير من الوقت قضيته أحاول بلا جدوى التوفيق بين هذا الكم الرهيب من البرامج لأكتشف أن البرنامج الواحد منهم قد يحتاج إلى سنوات للتخصص العميق فيه والوصول لمستوى مميز. لم أدرك ذلك في بداية الأمر فكنت دومَا أشعر بالتقصير إضافة إلى مقارنة مستواي المتوسط في البرنامج الواحد والتشتت وحساب كم الوقت اللازم لاحترافهم جميعَا! أعلم هذا لأن الكثيرين إلى الآن يؤمنون أن تخصصات أكثر تعني فرص عمل أعلى ومرونة أعلى بالضرورة وهي مدرسة في التفكير أفخر بتخلصي منها إلى الأبد! دراسة تخصص بعينه والوصول لمستوى الاحتراف فيه قد يستلزم منك قضاء حوالي 10,000 ساعة فماذا عن أربع إلى خمس تخصصات معَا! من الضروري للغاية أن تتعرف على التخصصات المختلفة للتصميم وتسأل نفسك إذا ما كنت تميل لأحدهم وترغب في قضاء عمرك كاملَا في هذا المجال! هل تريد أن تصبح مصمم جرافيكي أم تعشق الرسم وتود التخصص في مجال الـ Illustration، ربما تهتم بأن تكون مصمم لتجربة المستخدم أو مصمم حركة أو حتى مصمم هوية وشعارات! أيَا كان التخصص الذي اخترته لا تشتت نفسك في محاولة جمع بين أكثر من تخصص هذا سيضيع وقتك وسيقلل من جودتك في كلا التخصصين. تلميح: التخصص كلمة مطاطة بعض الشيء البعض يبالغ فيقول أن المصمم لا يجب أن يفكر وتخصصيته تكمن في تطبيق أفكار الآخرين وحسب! والآخر يصمم كل شيء وأي شيء. تذكر أن هناك من صنع لنفسه تخصص في تصميم الأغلفة للكتب فقط أو أغلفة الأكواب الورقية ولكن هناك أيضَا مصممون عالميون يستمتعون بتصاميم الهويات إضافة إلى تصاميم الـIllustration. الأمر مفتوح في النهاية لأسلوبك في التفكير لكن تذكر أنه كلما زاد توسعك في دائرة التخصص كلما أصبحت في وضع حرج وفقدت احترافيتك في العمل. عدم معرفة أساسيات البرامجصدق أو لا تصدق هناك من يفخر بكونه تعلم برنامج معين بدون دروس عن طريق فتح الواجهة وبدأ التجربة! لا أمانع أبدَا من أن تجرب بنفسك و أن تحاول اكتشاف البرامج عن طريق استخدام الأدوات ولكن على الأقل تعرف على الأساسيات! المشكلة أن الكثيرين ينخدعون بقدرتهم على بدأ التصميم فورَا بسبب استعمالهم لبرنامج ذو واجهة استخدام سهلة فيتجاهلون الأساسيات و يستمرون هكذا لفترة طويلة دون ملاحظة المشكلات نظرَا لقدرتهم على صنع تصاميم بالفعل مثل التصاميم المستخدمة في مواقع التواصل الاجتماعي أو المنتديات الإلكترونية. لأعطيك مثال حقيقي أنا واحدة من هؤلاء الأشخاص الذين ظلوا لفترة لا بأس بها يتعلمون الدروس ويطبقونها دون معرفة أساسيات وأدوات البرنامج في الفوتوشوب، والنتيجة أنني كنت إذا أخطأت خطأً واحدَ صغيرَا في التصميم أمسحه وأقوم بالتصميم من البداية لإنني لم أكن أعرف أداة الـ History، أو أستغرب بشدة عندما يعرض أحد المصممين تصميمَا له ويرحب بالانتقادات ويعدل التصميم المرة بعد المرة، بالنسبة إليّ آخر خطوة لا أستطيع التراجع بعدها هي الخطوة التي أقوم فيها بحفظ التصميم بصيغة JPEG لإنني لم أكن أعرف صيغة الـPSD وبالتالي طلب أي تعديل في التصميم كان يتطلب مني بدأ التصميم منذ البداية في كل مرة! هناك عشرات التفاصيل الأخرى التي ندمت عليها في طريقة تعلمي للبرنامج وهذا ما تجنبته تمامَا في أي برنامج جديد تعلمته في مشواري لاحتراف التصميم. الثبات على المستوىغالبَا تحدث هذه المشكلة عندما تتوقف عن تعلم الجديد وتقوم بتكرير أسلوبك في جميع التصاميم الجديدة. لا تبتكر أي شيء جديد ولا تقوم بمحاولة تغيير الطريقة التي تصمم بها لإنك لا تعرف غيرها! الثبات على المستوى هو واحد من أهم المشكلات التي يواجهها المصممون بشكل عام طوال رحلتهم ولكن أن تصاب بثبات المستوى في بداية الرحلة وأنت ما زال لديك الكثير لتتعلمه هو أمر كارثي لا محالة! ضع لنفسك تحديات مختلفة وحاول ألا تقولب نفسك في تصاميم سهلة أو بسيطة لا تستوجب منك الكثير من العناء. حاول أن تتعلم كل يوم أو كل فترة زمنية قصيرة -تبعَا لجدولك- درسَا جديدَا أو تقنية مختلفة أو حتى قراءة كتاب عن التصميم جديد بالنسبة إليك. ماذا عن ورش العمل أو محاولة نقل خبراتك للآخرين؟ لا تستبعد فكرة الاشتراك في ورش عمل بعيدة عن التصميم لتجديد أفكارك مثل ورش الخط العربي أو الرسم على الحائط أو غيرها. أي نوع من أنواع الفنون المختلفة قد يساعدك في استلهام أفكار مميزة وغير تقليدية في تصاميمك. والأهم ألاّ تنسى متابعة مواقع الإلهام العالمية بشكل دوري من وقت للآخر أو قبل البدأ في تصاميمك الجديدة دومَا لا لتنقلها كما هي بل لتنشظ ذاكرتك وتعينك على التفكير بطرق إبداعية أكثر. المشاهدة بدون تطبيقواحدة من تجاربي الأليمة هي احتراف مشاهدة الدورات التعليمية وفهم التقنيات المستعملة في التصميم فهم جيد ولكن بدون التطبيق! حجتي في هذا كانت كثرة الدروس والدروات التي يتوجب عليَ الانتهاء منها قبل فترات الدراسة مثلَا فأعمل بجد لكي أنهي الدورات ولو جاء هذا على حساب التطبيق! من جديد اكتشفت التبعات الرهيبة لهذا الأسلوب! فبعد مشاهدة أكثر من ثلاثين إلى أربعين ساعة في برنامج معين اكتشفت بعد شهرين أو أكثر أنني قد نسيت معظم ما تعلمته لأنني لم أطبقه واكتفيت بالمشاهدة فقط! صدقني لا شيء قد يؤثر فيك ويرتبط في ذاكرتك بشكل قوي مالم تكن قد طبقته بشكل جيد أيَا كانت وسيلة التطبيق. كلما طبقت أكثر صار من الصعب جدَا عليك أن تنسى تلك المهارة حتى يصبح استعمالها أسهل من شرب الماء وتكتشف أنك أصبحت تمارسها بدون وعي تقريبَا! عدم تقبل النقد والابتهاج الشديد بالمدحمن العيوب القاتلة التي قد تدمر مستقبل أي مصمم مبتدئ هو عدم تقبل النقد! أوافقك تمامَا في أنّ تقبل فكرة أن ينتقدك أحدهم مُظهرَا أسوأ ما في تصاميمك حتى لا يكاد يترك شيئَا واحدَا لم ينتقده هي عملية ليست سعيدة إلى تلك الدرجة! ولكن لك أن تتخيل مغبة أن تكون مصمم مبتدئ يمتلئ تصميمك -على الأرجح- بعيوب كثيرة ومتنوعة ثم يأتي أحدهم ليقول لك: " يا لك من مصمم عظيم لقد أصبحت محترف!" هكذا تسترخي في مقعدك بكل أريحية وتتوقف عن التصميم لأسبوع ربما شاعرَا أنك قد بذلك الكثير من الجهد وحان وقت إعطاء نفسك القليل من الراحة! لا تستسلم لفكرة تقبل المديح من الآخرين وحاول أن تكون أنت العين الناقدة لتصميماتك وخذ دومَا آراء الآخرين بعين الاعتبار وحاول ألا تجعل الموضوع شخصيَا بينك وبين من ينتقدك. على الجانب الآخر أعلم أن الكثيرين لا يجيدون فن تزويق الكلام أو الانتقاد بالأسلوب السليم الذي يظهر المحاسن قبل المساوئ ويشجع المصمم على أن يكمل التعلم ليصل لمستوى أفضل! ولكن بربك ليس هذا الذي سيوقفك عن إكمال هدفك لتصبح مصمم مميز أليس كذلك؟! استعمال "الجاهز" هو خيارك الأول!لماذا أصمم تدرجات لونية أو تأثير معين طالما أنه يوجد الكثير منهم مصممين بالفعل؟ هل عليَ رسم التصميم من البداية للنهاية بدون استعمال بعض الفكتورز الجاهزة والمصممة بالفعل؟ نعم! كلنا كمصممين نُصاب بالإرهاق أحيانَا من كثرة التفاصيل التي يجب أن تنتبه إليها وتعدلها وتأخذها بحسبانك فنركن للحل الأسهل وهو استعمال الأدوات الجاهزة قدر الإمكان. مشكلات هذا الأسلوب عديدة للأسف فأولَا أنت على الأغلب لم تقم بعمل تصميم أصيل أو مختلف بل جمعت بعض العناصر في تصميمك و قمت بعملية تجميع ليس أكثر! وثانيَا لم تقم بابتكار فكرة جديدة. وثالثَا وهو الأهم لم تقم بتنمية أو تطوير مهاراتك في عملية التصميم وعلى الأرجح لم تكتسب أي خبرة جديدة أو مشكلة واجهتك وبحثت عن حل لها لإنك تجنبت كل هذا الألم النسبي والمؤقت لتلجأ للحل الأمثل وهو استعمال تصميم جاهز! لن أقل لك توقف عن فعل هذا فهو أمر قد يستوجب بعض الوقت و كثيرَا ما يحتاج لرفع درجة مهاراتك للتخلي عن بعضهم ولكن حاول تقنين استخدامهم قدر الإمكان ولا تعتمد عليهم بشكل كلي. الاهتمام المبالغ فيه بنسخ البرامج المستخدمة والأجهزة المستخدمة للتصميمأدرك تمامَا أن هناك فروقات شاسعة بين نسخ الفوتوشوب القديمة والحديثة. بل إن إضافة واحدة قيمة في نسخة جديدة قد توفر عليك ساعات وساعات من العمل الشاق! لكن ما أعترض بشأنه هو المبالغة في تصور قدرة البرنامج على إخراج تصميم مميز إلى النور! قد تمتلك أحدث نسخة من الفوتوشوب ولكن مع مهارات فقيرة للغاية وأسلوب تصميم رديء تخرج أبشع التصاميم الممكنة! أعرف مصممون مازالوا يستخدمون إلى اليوم الإصدار السابع للبرنامج وتتمتع تصاميمهم بدرجة من الإبداع مذهلة وعجيبة! لا تجعل النسخة هي أهم شواغلك فيما يخص إخراج تصميم جيد إلى الوجود وركز أكثر على تعلم التقنيات الصحيحة وتطوير مهاراتك بشكل أساسي. الأمر نفسه في ولع البعض الشديد في امتلاك أجهزة مميزة مثل ماك أو استعمال تابلت للرسم في بداية مشوارهم في التصميم! سرقة التصاميم!نعم لم تخطئ القراءة! بعد كل تلك المشكلات التي وضعتها لكي تتجنبها كمصمم مبتدئ يبدو الأمر معقدًا للغاية وصعب! كل ما تريده هو كسب المال بأقل قدر ممكن من الجهد والوقت! تفكر في سرقة الأفكار فأنت لست ملاكًا كما أنه ليس أمرًا مستبعدًا فأكبر الشركات العربية والعالمية تقوم بسرقة الأفكار والمخططات فلماذا تختلف أنت عنهم؟! لن أجيبك على هذا السؤال من منطلق الضمير أو الدين ولكن بشكل عملي أكثر كن متأكدَا أن عالم الويب صغير للغاية! أكثر مما تتخيل. وتدمير سمعتك فيه كفيل بإنهاء حياتك المهنية من قبل أن تبدأ أصلَا. هناك مواقع متخصصة لفضح لصوص التصاميم،و إرفاق بعض سوابق الأعمال التي سرقتها من غيرك في سيرتك الذاتية للتقدم للعمل كفيلة بتقليل فرصك في الحصول على وظيفة جيدة إلى الحد الأدنى! إن لم تكن محوها نهائيَا. أنت تصم نفسك أيضَا عوضَا عن السرقة بقلة الإبداع وبعدم القدرة على الابتكار وبالتالي أنت تلجأ لسرقة الأفكار ونقلها حرفيَا في معرض أعمالك. لا تفكر حتى في هذا الموضوع وأسقطه من اعتباراتك وبشكل قاطع! أسئلة مفتوحة للنقاشمنذ متى تصمم وما هي أهم الأخطاء التي وقعت بها كمصمم مبتدئ؟كيف تعلمت التصميم بالدراسة الذاتية أم بالالتحاق بالدورات والورش وأيهما أفضل برأيك؟كيف اخترت تخصصك في التصميم؟
    1 نقطة
  6. إن إنشاء عروض وتصاميم باستخدام أوراق الأنماط المُتتالية CSS ليس بالأمر الجلل بحدّ ذاته، ولكنّها وسيلة جيّدة لاستعراض قدرات وإمكانيات CSS، وتجربة أدوات ومفاهيم جديدة، أو للتدريب على العمل ضمن شروط وقيود مُحدّدة، حيثُ سيُلقي هذا المقال نظرةً على كيفيّة إنشاء تأثير قطرات مطر (raindrops) على نافذة وذلك باستخدام تقنيات HAML و SASS. يُمكن استعراض مثال كامل لفكرة الدرس على موقع CodePen مع الشيفرة الخاصّة به. المعالج التمهيدي (Preprocessor)سيتمّ أوّلًا وقبل كل شيء توضيح لماذا سيتمّ استخدام تقنيتي HAML/SASS بدلًا من الزوج الشائع HTML/CSS، ومع العلم أنّهما يتمتعان بالعديد من المزايا والتسهيلات ولكن السبب في الحاجة إلى معالجات تمهيديّة هنا هو أنها تسمح للمطوّر باستخدام المُتغيّرات، إنشاء حلقات تكراريّة (loops)، وتوليد قيم عشوائيّة، وبذلك لن يتمّ التعامل مع المئات من قطرات المطر بشكل منفصل بل سيتمّ إنشاؤها برمجيًّا. يُمكن الاستزادة حول الإعداد الأوّلي والصياغة (syntax) من خلال زيارة موقع كل تقنيّة سواءً SCSS أو HAML، أو من المُمكن مبدئيًّا تطبيق الدرس على موقع CodePen، من خلال إنشاء pen جديد واختيار SCSS كمُعالج تمهيدي لـِ CSS و HAML من أجل HTML. إنشاء النافذةستكون الخطوة الأولى هي عرض النافذة نفسها. .container .window // صورة الخلفية $image: 'http://i.imgur.com/xQdYC7x.jpg'; // عرض وطول الحاوية $width:100vw; $height:100vh; .container{ position:relative; width:$width; height:$height; overflow:hidden; } .window{ position:absolute; width:$width; height:$height; background:url($image); background-size:cover; background-position:50%; filter:blur(10px); }تمّ في الشيفرة السابقة وبكل بساطة رسم div مع صورة خلفيّة (background image)، وتطبيق مُرشح غشاوة (blur) عليها لكي تُصبح القطرات جليّة أكثر للناظر. يُلاحظ كيف أنّه تمّ تخزين مسار (URL) صورة الخلفيّة في مُتغيّر image$، وذلك لأنه سيتمّ استخدام ذات الصورة للقطرات نفسها كما سيتّضح ذلك فيما بعد. قطرات المطر في الطبيعةسيتمّ إلقاء نظرة على القطرة وكيف تبدو في الحياة الطبيعيّة قبل الشروع في تطبيق التأثير. يعود مصدر الصورة إلى موسوعة ويكيبيديا. ستَقلب القطرة الصورة الّتي خلفها بمقتضى انكسار الضوء، كما سيكون للقطرة حدودًا (border) سوداء عندما يكون شكلها نصف كرويّ كامل أو غير كامل. إنشاء قطرات المطر (Raindrops)سيتمّ في الخطوة التّالية إنشاء قطرة مطر واحدة بعد أن تمّ معرفة الأساسيات. .container .window .raindrop $drop-width:15px; // قطرات المطر لن تكون دائرية تماما لذلك سنقوم بتمديدها قليلا // حتى لا تتمدد الخلفية أيضا transform:scale لن نستخدم $drop-stretch:1.1; $drop-height:$drop-width*$drop-stretch; .raindrop{ position:absolute; top:$height/2; left:$width/2; width:$drop-width; height:$drop-height; // border-radius:100% بدلا من border-radius:100px, حتى يكون شكل قطرات المطر بيضاوي وليس كبسولي border-radius:100%; background-image:url($image); background-size:$width*0.05 $height*0.05; transform:rotate(180deg); }ما تمّ عمله في الشيفرة السابقة هو رسم div على شكل إهليلجي (بيضاوي)، وتطبيق صورة خلفيّة (background image) داخله، وهي نفس الصورة المُستخدمة سابقًا، وبعد ذلك تم تقليص حجم الخلفيّة ومن ثم قلب القطرة رأسًا على عقب. سيتمّ الآن إضافة حدودًا حول القطرة، لتبدو القطرة وكأن لها حجمًا. ... .border .raindrop ... .border{ position:absolute; top:$height/2; left:$width/2; margin-left:2px; margin-top:1px; width:$drop-width - 4; height:$drop-height; border-radius:100%; box-shadow:0 0 0 2px rgba(0,0,0,0.6); }يُلاحظ كيف أنّه لم يتمّ إضافة حدودًا كاملة حول القطرة، بل التعديل على مكانها والضغط على جانبيها قليلًا لتبدو أقرب إلى القطرة الطبيعيّة. سيتمّ في الخطوة التّالية إضافة المئات من هذه القطرات وذلك بعد الانتهاء من استكمال رسم القطرة الأولى على أكمل وجه. ... .raindrops .borders - (1..100).each do .border .drops - (1..100).each do .raindropإن الشيفرة السابقة ما هي إلا شيفرة HAML في صياغة حلقة تكرار (loop)، فكل ما تمّ عمله هو إضافة مئة كائن من raindrop.و مثلها للكائن border. سيتمّ إلقاء نظرة مُفصّلة على شيفرة SASS بما أنّها مُحيّرة بعض الشيء. سيتمّ بدايةً إنشاء الحلقة التكراريّة (loop) ومن ثُمّ اختيار كل عنصر (element) بشكل منفصل: @for $i from 1 through 100{ .raindrop:nth-child(#{$i}){ } .border:nth-child(#{$i}){ } }سيتمّ الآن توليد وتطبيق تَمَوْضُعات (positions) وأحجام عشوائية لقطرات المطر: @for $i from 1 through 200{ //توليد رقم عشوائي من 0 إلى 1 لإختيار التموضع $x:random(); $y:random(); // إختيار حجم وتمديد قطرة المطر عشوائيا // بما أن لكل قطرة مطر حجم مختلف، سنقوم بحساباتنا هنا .raindrop selector $drop-width:5px+random(11); $drop-stretch:0.7+(random()*0.5); $drop-height:$drop-width*$drop-stretch; .raindrop:nth-child(#{$i}){ // ضرب قيمة الموضع العشوائي في حجم الحاوية left:$x * $width; top:$x * $height; width:$drop-width; height:$drop-height; } .border:nth-child(#{$i}){ // سنقوم بنفس الشيء لحدود القطرة left:$x * $width; top:$x * $height; width:$drop-width - 4; height:$drop-height; } } سيتمّ أخيرًا تغيير تموضع خلفيّة كل قطرة بحسب تموضع القطرة، ليكون تأثير الانعكاس أكثر جمالًا. ... .raindrop:nth-child(#{$i}){ ... background-position:percentage($x) percentage($y); } ... سيكون بذلك قد تمّ الانتهاء من إنشاء التأثير الرئيسي، ولكن بالإمكان التعديل والتحسين عليه، وذلك من خلال الاهتمام ببعض التفاصيل الصغيرة، مثل زيادة السطوع (brightness) للقطرات قليلًا لتبدو صافية وذات لمعة، أو تغيير التركيز البصري ليكون على الخلفيّة بدلًا من القطرات، أو رُبّما تغيير صورة الخلفيّة. يُمكن الوصول إلى النسخة النهائيّة للمثال بجانب الشيفرة بشكلها النهائي من خلال موقع CodePen. ترجمة وبتصرّف للمقال CSS-Only Raindrops on Window Effect لصاحبه Lucas Bebber.
    1 نقطة
  7. مِمَّا لا شكَّ فيه أنَّ هُناك قوالب ووردبريس رائعة المظهر ولكن هُناك العديد من الأمثلة على أشياءٍ بسيطة قد نُريد تغييرها في القالب. كلونٍ هُنا، حجم خطٍ هُناك ورُبَّما استدعاء للإجراء على الأزرار. تتمحور المُشكلة في أنَّ تعديل القالب حتَّى ولو كانَ تعديلًا بسيطًا يمنعُكَ من تحديثه إلى نُسخة جديدة في المُستقبل، هذا ببساطة راجع إلى أنَّه إذا قُمتَ بتحديثه فسيؤدِّي هذا إلى فُقدان كُلّ التغييرات التي أُحدِثَت عليه. تُقدِّم القوالب الفرعيَّة حلًّا لهذه المُشكلة عن طريق السَّماح لكَ باستخدام وظائف القالب المُختار إلى جانب إمكانيَّة التَّحديث دون الخوف من فُقدان تلكَ التَّعديلات. سنُقدِّم من خلال هذا الدرس توضيحًا للفائدة من استخدام قالب ووردبريس فرعي وكيفيَّة إنشائه. كيفيَّة عمل قوالب ووردبريس الفرعيَّة والفائدة من استخدامهاالقوالب الفرعيَّة هي قوالب مُنفصلة تعتمد على قالب أساسي في تأدية مُعظم وظائفها. إذا كُنتَ تستخدم قالب فرعي، فإنَّ ووردبريس سيقوم أوَّلًا بالتحقُّق من قالبك الفرعي ليتأكَّد من ما إذا كانت هُناك تأدية وظيفيَّة مُحدَّدة به. إذا لم يجد ووردبريس أيَّة تأدية وظيفية مُحدَّدة فسوف يستخدم القالب الأساسي مُباشرةً. تُعتبر هذه ميزة رائعة حيثُ أنَّها تُتيح لكَ التَّعديل على ما تُريد تعديله فقط. يجب استخدام القوالب الفرعيَّة إن كُنتَ تنوي تعديل ولو مُجرَّد حرف واحد في قالبك. هُناك سببين أساسيَّين للاستخدام، هما: التَّحديثات والتَّنظيم. 1. التَّحديثاتإذا قُمتَ بتعديل قالب بدون استخدام قالب فرعي فسيكون لديكَ خيارين بعد عمليَّة التَّعديل: قد تختار عدم تحديث قالبك في المُستقبل، أو تحديثه وخسارة كُلّ التغييرات المُضافة إلى القالب. رُبَّما يعملُ الخيار الثَّاني فنيًّا ولكنَّه أمرٌ غير مُقترح. حتَّى لو كان من السَّهل نسخ ولصق تعديلاتك، ما هي الفائدة من تضييع دقيقتين من وقتك على مُهمَّة قد تُعرِّضك للخطأ في كُلِّ تحديث؟ مُجرَّد التَّفكير في عدم تحديث القالب ليست فكرة جيِّدة. تُعتبر القوالب الغير مُحدَّثة من أكثر القوالب تعرُّضًا للاختراق. يجب عليكَ دائمًا الإبقاء -بدون استثناء- على كلٍّ من: ووردبريس، قالبك والإضافات مُحدَّثين بما يتناسب مع الوقت الحالي. 2. التَّنظيمعندما تُضيف شفرات لقالب موجود فإنَّك بهذا تُضيف إلى قاعدة شفرات قد تحتوي على الآلاف والآلاف من الأسطر. سيواجه المُطوِّرون ممن يعملون على موقعك (بالاضافة إليكَ بالتَّأكيد) أوقاتًا صعبة في تعقُّب التَّغييرات. نتيجة واحدة على الأقل لهذا الأمر هي تكاليف تطوير زائدة. حيثُ أنَّ القوالب الفرعيَّة تعود من جديد إلى القالب الأساسي -إلَّا إذا تمَّ تحديد ما هو غير ذلك- فإنَّ قالبك الفرعي هو عبارة عن مجموعة من التَّغييرات في قالبك الأساسي. يُمكن أن ينتج عن هذا تغييرات شاملة في حين أنَّ القالب الفرعي قد يحتوي على مُجرَّد مائة سطر من الشَّفرات. إنشاء قالب فرعييُعتبر إنشاء قالب فرعي أمرٌ بسيطٌ للغاية لدرجة أنَّه بامكانك تنفيذ هذا بمُجرَّد نسخ ولصق المثال الموجود بالأدنى. لإنشاء قالب فرعي لقالب عليكَ اتَّباع الخطوات التالية: أنشئ مُجلَّد قالب في تثبيت ووردبريس.أنشئ ملفّ نمط يحتوي على معلومات عن قالبك الفرعي.قُم بإيقاف تفعيل أنماط القالب الأساسي.يُمكنكَ تفعيل القالب الفرعي بمُجرَّد الانتهاء من تنفيذ هذه الخطوات وسيبدو موقعك تمامًا مثلما كان من قبل، الفرق الوحيد هو أنّ الموقع سيستخدم القالب الفرعي في عمله. دعونا الآن ندرس الخطوات أعلاه بالتَّفصيل. سأنشئ على سبيل المثال قالب فرعي للقالب الافتراضي Twenty Fourteen. أوَّلًا، توجَّه إلى مُجلَّد القالب وقُم بانشاء ملفًّا لقالبك الجديد. يُمكنكَ تسميته بالاسم الذي تُريد. من أجل التَّوضيح سنُسمِّي القالب twentyfourteen-child. الخطوة الثَّانية هي إنشاء ملفّ نمط. يجب تسمية هذا الملفّ style.css قُم بنسخ ولصق الشفرات التالية إلى الملف الذي أنشأته لتوِّك: /* Theme Name: Twenty Fourteen Child Theme URI: http://yourwebsite.com/twentyfourteen-child/ Description: My first child theme, based on Twenty Fourteen Author: Daniel Pataki Author URI: http://danielpataki.com Template: twentyfourteen Version: 1.0.0 Tags: black, green, white, light, dark, two-columns, three-columns, left-sidebar, right-sidebar, fixed-layout, responsive-layout, custom-background, custom-header, custom-menu, editor-style, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready, accessibility-ready, responsive-layout, infinite-scroll, post-slider, design, food, journal, magazine, news, photography, portfolio, clean, contemporary, dark, elegant, modern, professional, sophisticated Text Domain: twenty-fourteen-child */العُنصرين الأساسيَّين في هذه الشَّفرة هي السُّطور البادئة بـ "Theme Name" و"Template". يُخبر اسم القالب Theme Name ووردبريس عن اسم قالبك ويُعرَضُ هذا في مُنتقي القالب. أمَّا Template فيُحدِّد لووردبريس أيُّ القوالب يجب اعتباره القالب الأساسي. ما تبقى يصف نفسه بنفسه باستثناء نطاق النَّصّ text domain والوسوم tags. يُستخدم نطاق النَّصَّ لترجمة المقاطع. يجب أن يكون نطاق النَّصّ مُميّزٌ لقالبك ويجب استخدامه متى قُمتَ باستخدام دوال التَّرجمة. لمعلوماتٍ أكثر راجع I18n لمُطوِّري ووردبريس. قسم الوسوم هو قائمة من الوسوم التي تُستَخدم بواسطة مُستودع قالب ووردبريس. على سبيل المثال قد قُمتُ بالنَّظر في ملف style.css الخاصّ بالقالب الأساسي وببساطة قُمتُ بنسخ ولصق الوسوم من هُناك. إلى هذه النُّقطة فإنَّ قالبك الفرعي يعمل بشكلٍ جيِّد. إذا قُمتَ بتفعيله ثُمَّ إعادة تحديث الصَّفحة ستجد كُلّ مُحتواك بها ولكن لن تحتوي على أيّ تنسيق. ذكرتُ سابقًا أنَّ ووردبريس يبحثُ عن التأديَّات الوظيفيَّة في القالب الفرعي وإذا لم يجدها فإنَّه يعود مُجدَّدًا إلى القالب الأساسي. في حالتنا هذه فإن لدينا بالفعل ملف نمط ولذلك فإنَّ ووردبريس قد فهم أنَّه غير مسموح بتحميل ملفّ القالب الأساسي. وبُناءً عليه فإنَّنا سنحتاج إلى إدراج ملفّ نمط القالب الأساسي لكي نتأكَّد من أنَّنا قد قُمنا بتحميله. يُمكن عمل هذا في ملفّ القالب function.php دعونا نُنشيء الآن هذا الملفّ وننسخ الشفرات التالية به: add_action( 'wp_enqueue_scripts', 'enqueue_parent_styles' ); function enqueue_parent_styles() { wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css' ); }إذا لم تكُن لديك أيَّة فكرة عن PHP وكُلّ ما تُريده هو تغيير بعض الأنماط فقط فلا تهتمّ كثيرًا لمعرفة سبب عمل هذا. يُمكنكَ الآن التوجُّه ببساطة إلى ملف النَّمط والبدء بعمل التَّغييرات التي تُريد. إذا كان لديكَ فضول لمعرفة المزيد عن الإدراج يُمكنكَ الاطِّلاع على صفّ وتسجيل ملفات Javascript و CSS في قوالب ووردبريس. تقنية القوالب الفرعيَّةإذًا كيف يعمل القالب الفرعي؟ تعملُ القوالب الفرعية في مستوى الملف. عند استخدام ملف خلال عملية تحميل قالب فيتمّ التحقُّق من ما إذا كان هذا الملفّ موجود في القالب الفرعي. إذا كان الملف موجودًا، يتمّ استخدام محتوى هذا الملف. أمَّا إذا لم يكن موجودًا، فيتمّ استخدام نفس الملف في القالب الأساسي. هُناكَ استثناءٌ واحد لهذه القاعدة ألا وهو ملفّ دوال القالب. يتمّ تحميل ملف functions.php الموجود في كلٍّ من القالب الأساسي والقالب الفرعي. إذا قامت دوال القالب الفرعي باستبدال دوال القالب الأساسي فقد تواجه موقعًا به خلل أو قد تحتاج إلى نسخ ولصق محتويات ملف دوال القالب الأساسي كلُّها إلى ملف القالب الفرعي والتي تُفشِلُ نوعًا ما الهدف من تمديد قالب. خطوات سير العمل عند تعديل التأدية الوظيفيَّة هي كالتَّالي: إذا أردتَ عمل تعديلات على التَّرويسة header فعليكَ نسخ ولصق ملفّ القالب الأساسي header.php إلى قالبك الفرعي. قُم بتعديل الملفّ كما يحلو لك، قُم بحفظ الملف بعد الانتهاء من التَّعديل وشاهد نتائج عملك. بعض المُلاحظات إلى صانعي قوالب ووردبريسإذا كُنتَ تُنشيء قالبكَ الخاصّ فهُناكَ بعض الإرشادات التي رُبَّما عليكَ اتِّباعها من أجل بناءٍ أسهل للقالب الفرعي. الإرشادين الأهمّ هما: معرفة الفرق بين دالَّتي ()get_stylesheet_directory و()get_template_directory، وإنشاء دوال قابلة للإضافة. 1. المُجلَّد الصحيحعليك -عند الرَّبط مع مُمتلكات باستخدام الدَّوال المذكورة- أن تكون على دراية بأنَّ عائلة دوال get_template_ ستُشيرُ دائمًا إلى مُجلَّد القالب الأساسي في حين أنَّ عائلة دوال get_stylesheet_ ستُشيرُ دائمًا إلى مُجلَّد القالب الفرعي. <a href="http://twitter.com/danielpataki"><img src="<?php echo get_template_directory_uri() ?>/images/twitter.png" alt='Twitter Logo'>Follow Me</a> <a href="http://github.com/danielpataki"><img src="<?php echo get_stylesheet_directory_uri() ?>/images/github.png" alt='Github Logo'>On Github</a>في المثال أعلاه، يأخذ الرابط الأول صورته من القالب الأساسي في حين أنَّ الرابط الثاني يأخذ صورته من القالب الفرعي. ليس هُناك أفضيلة لطريقة على الأخرى، اختيار احداهما هو أمرٌ يرجع إليك. ميزة استخدام ()get_stylesheet_directory_uri هي أنَّه يُمكن لمُطوِّري القالب الفرعي استخدام صورهم الخاصَّة ويتمّ هذا ببساطة عن طريق إنشائها في الموقع المُناسب. على الجانب الآخر، إذا لم تكن الصور موجودة في القالب الفرعي فلن يتم عرضها على الإطلاق. سبب هذا هو أنَّه إذا كان القالب الفرعي مُفَعَّل فإنَّ دالَّة ()get_stylesheet_directory_uri لا تتحقَّق من (ولا تعرف) ما هو الملفّ الذي تقوم أنتَ بتحميله ولذلك فلن تقوم الدَّالَّة بالتحقُّق من وجوده أصلًا. ستقوم الدَّالَّة دائمًا بإعادة مُعرِّف الموارد المُوحَّد URI للقالب الفرعي. 2. دوال قابلة للتَّعديلالطريقة الأخرى التي عليكَ استخدامها هي ما يُسمِّيها ووردبريس دوال قابلة للإضافة. يسمح هذا لمالكي القالب الفرعي الكتابة على الدوال التي قُمتَ بتعريفها في القالب الأساسي. يشتمل هذا على إحاطة دوالّك بتأكيدات ()function_exists. لنفترض أنَّكَ قد قُمتَ بإنشاء دالَّة تُسمَّى ()my_meta لعرض بادئة تدوينة مُخصَّص. لا يوجد مجال للقالب الفرعي لتعديل هذه الدَّالَّة حيثُ أنَّه لا يُمكن تعريفها مرَّتين. حلّ المُشكلة هو إنشاء هذه الدَّالَّة إذا لم يتمّ تعريفها (تذكَّر، يتمّ تحميل ملف دالَّة القالب الفرعي أوَّلًا). if ( !is_defined( 'my_meta' ) ) { function my_meta() { // code for postmeta here } }ختامًايُمكنكَ باستخدام بعض خطوات النَّسخ واللَّصق البسيطة إنشاء بيئة مُستقبليَّة لقالبك والتي ستُبعد عنكَ الكثير من المتاعب. رغم أنَّه من المُغري استخدام مُحرِّر القالب المُدمج في ووردبريس، إلَّا أنَّه غالبًا ما يُسبِّب أخطاءً أكثر مِمَّا يحلّ في حالة عدم استخدام قالب فرعي. قُم باستغلال بعض الوقت لاتِّباع الخطوات الموجودة بهذا الدَّرس وسيكون موقعك ومُطوِّره شاكرين لفعلكَ هذا. أخيرًا، إن كان لديكَ بعض النَّصائح حول القوالب الفرعيَّة، لا تتردَّد في اعلامنا بها.
    1 نقطة
×
×
  • أضف...