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

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

  1. وائل بوزاهر

    وائل بوزاهر

    الأعضاء


    • نقاط

      1

    • المساهمات

      16


  2. paithfinder

    paithfinder

    الأعضاء


    • نقاط

      1

    • المساهمات

      1


  3. Soheib

    Soheib

    الأعضاء


    • نقاط

      1

    • المساهمات

      142


  4. hamiddunc

    hamiddunc

    الأعضاء


    • نقاط

      1

    • المساهمات

      1


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

المحتوى الأعلى تقييمًا في 05/20/16 في كل الموقع

  1. لدي فكرة مشروع ناشيء وأود الالتحاق بتعليم جامعي مناسب لمشروعي، بماذا تنصحوني ؟
    1 نقطة
  2. التسويق هو عنصر أساسي في نشاطك التجاري مهما كان نوعه، ومفهوم التسويق تغير ويتغير باستمرار، ونحن بحاجة إلى تغيير طريقة تفكيرنا تجاهه لمواكبة هذا التطور. هل لديك نشاط تجاري متخصص في تصميم الويب، أو أنك مسؤول عن الجوانب الرقمية في الشركة التي تعمل بها؟ إذا كان الأمر كذلك فإن التسويق يعتبر عنصرًا مهمًا في عملك. العامل المستقل Freelancer بحاجة لبناء علامته التجارية الخاصة، وأصحاب الأنشطة التجارية بحاجة إلى التعريف بأنشطتهم لكسب المزيد من العملاء، وحتى الشركات الرقمية التي تعمل على شبكة الإنترنت تحتاج إلى زيادة متابعيها والحصول على مزيد من الزوار لمواقعها الإلكترونية، وكل هذا يتطلب معرفة بسيطة بمفهوم التسويق. ربما تكون غير محب للتسويق، ولكنه في النهاية أمر واقع يجب عليك أن تتعامل معه وتنجزه بالشكل الصحيح. مفهوم التسويق تغير، ماذا عنك؟أدى التطور الرقمي إلى تغير التسويق، ولكن ومع الأسف فإن تفكيرنا في أغلب الأحيان لم يتطور ليواكب هذا التغيير. لا زلت أرى شركات تصميم الويب تستخدم أدلة الصفحات الصفراء أو نظيرها الرقمي إعلانات Google Adsense، وكذلك أرى شركات كبيرة تصرف مبالغ مالية ضخمة لتضع بانرات إعلانية على شبكة الإنترنت. هذا كله عبارة عن الشكل الإلكتروني للإعلانات اللوحية التقليدية، هذه الأساليب التقليدية بجميع أشكالها تقودنا إلى نتيجة واحدة، من يصرف مالا أكثر يصل إلى شريحة أكبر من الجمهور ويحصل على أكبر قدر من الاهتمام. الأسلوب السالف الذكر لم يعد فعالا في وقتنا هذا، فالمستخدمون أصبحوا أكثر نباهة وقد تعرفوا على طرق لحجب كل تلك الأمور. ابتكر المسوقون طريقة جديدة للتغلب على هذه المشكلة، وأطلق على هذه الطريقة مسمى التسويق بالمحتوى ( content marketing). إذا كنت ترغب بالوصول إلى جمهورك المستهدف فإنه ينبغي عليك الاهتمام بهذه الطريقة، ولكن انتبه لأنه من السهل أن تنجزها بشكل خاطئ. ما هو التسويق بالمحتوى؟يتميز مصطلح التسويق بالمحتوى بنوع من الغموض كغيره من المصطلحات الطنانة، ويشير هذا المصطلح هنا إلى التسويق الذي يسعى إلى منح الفائدة للمستخدم. هذه المقالة التي تقرأها هي مثال للتسويق بالمحتوى، فهي تهدف إلى إفادتك كقارئ بمعلومات جديدة، وفي نفس الوقت تثبت مدى مهارتي ومصداقيتي ككاتب على أمل أن يؤدي ذلك إلى توظيفي من قبلك لإعطاء الاستشارات والنصائح. هذا النوع من التسويق يسعى إلى تجاوز الطرق الإعلانية الصريحة والمباشرة، من خلال التحول إلى بناء علاقات مع العملاء المحتملين. يتجلى هذا الأمر بشكل واضح في التدوينات ومنشورات شبكات التواصل الاجتماعي وكذلك في مقاطع الفيديو المنشورة على موقع يوتيوب وما شابه ذلك. هل لا زال الأمر غامضا؟كثير من الأشخاص ومع الأسف يبدؤون باستخدام الأدوات المخصصة للتسويق بالمحتوى دون تبني الفلسفة الكاملة لهذا النوع من التسويق، فنجد أنهم يشرعون في التدوين وينشطون على شبكات التواصل الاجتماعي ويقومون بإنتاج مقاطع الفيديو، ولكنهم يحاولون من كل ذلك الترويج لخدماتهم بدلا من تقديم الفائدة لمتابعيهم. ينشطون في التدوين للحديث حول خصائص منتجاتهم، ويحاولون إخفاء الصبغة الإعلانية في مقاطع الفيديو التي ينشرونها، بل حتى منشوراتهم في شبكات التواصل الاجتماعي يسعون من خلالها إلى زيادة زوار مواقعهم بدلا من مساعدة متابعيهم. الفكرة الصحيحة للتسويق بالمحتوى هي أبعد ما تكون عن الطرق التقليدية المستخدمة في النشر، فهي تتيح لك بناء علاقات حقيقية مع المستخدمين وتكوين سمعة جيدة حولك وزيادة مصداقيتك لديهم، ولكن تحقيق ذلك كله يتطلب تخصيص الكثير من الوقت، حيث أن هذا النوع وخلافا للتسويق التقليدي لا يمكن بناؤه باستخدام المال، وهذا هو التحدي الحقيقي. هل أنت مستعد لدفع الثمن؟الشركات لا تمانع صرف الأموال على الحملات الإعلانية، واتخاذ القرار لذلك يتم بأسرع وقت، ولكنها تتثاقل في توظيف أفراد جدد في فريق العمل هربا من دفع المزيد من الأجور. في الحقيقة فإنه وللبدء باستخدام التسويق بالمحتوى بشكل صحيح فإنك تحتاج لتخصيص الكثير من الوقت لهذا الأمر، إذا كنت مستقلا Freelancer فهذا يعني أن عليك تخصيص مزيد من ساعات العمل أسبوعيا، أما إذا ما كنت مالكا لنشاط تجاري أو عضوا في فريق مسؤول عن الجانب الرقمي في منظمة تجارية، فإنك قد تحتاج إلى توظيف شخص جديد في فريق العمل بشكل دائم. كمثال على ما أقول فإني وخلال عملي السابق في شركة Headscape كنت أخصص ما لا يقل عن 70% من وقتي للتسويق بالمحتوى، مستخدما هذه المدونة* والمقاطع الصوتية وشبكات التواصل الاجتماعي وكذلك بعض الكتابات والمنشورات الأخرى، هذا كله بالإضافة إلى إلقاء المحاضرات وكتابة الكتب، وكنت أعمل كل هذا بالرغم من أن فريق العمل لم يكن يتكون إلا من 13 فردا. الاستثمار في التسويق بالمحتوى ثمنه مرتفع، ولكن العائد أكبر دون شك، استثماري في التسويق بالمحتوى مكّن Headscape من الحصول على تدفق مالي مستمر مدة 12 سنة، وهذا ساعدنا في تكوين سمعة جيدة على مستوى عالمي والحصول على الكثير من العملاء المرموقين، وبالطبع فإننا لم نكن لنصل إلى كل هذا بنشر بعض الإعلانات على Google Adsense. سر النجاحما هو سر النجاح في التسويق بالمحتوى؟ كما ذكرت سابقا فإن مفتاح النجاح هو التركيز على تقديم الفائدة لمتابعيك، ولا ينبغي أن تفكر في الترويج لمنتجاتك أو خدماتك بشكل كبير ومباشر إلا فيما ندر. بالإضافة إلى ذلك فإن أحد أهم العوامل للنجاح هي الانتظام في النشر. إذا كان منتجك أو خدمتك يعتمد على البيع الموسمي فقط، فإنه من المهم أن تكون في ذاكرة عملائك المحتملين عندما يرغبون بالشراء، فلا بد أن تتواصل معهم باستمرار، ولا بد أن تكون قد تواصلت معهم منذ فترة بسيطة عندما يقررون اتخاذ قرارهم الشرائي. إذا كانت لديك مدونة ولكنك لا تقوم بالنشر فيها إلا مرة كل عدة أشهر فإن هذا لن يساعدك على النجاح، بل على العكس من ذلك قد يؤدي هذا التصرف إلى الإضرار بنشاطك التجاري، وسيكون الوقت الذي استثمرته في الكتابة مجرد وقت ضائع لا قيمة له ولن يعود عليك بأي فائدة. إذا لم تكن قادرا على توظيف شخص للقيام بهذا العمل، قم بتخصيص جزء من وقتك لنشر شيء قيّم لمتابعيك، سواء كان ذلك تدوينة أو إضافة برمجية لمنصة التدوين وورد بريس أو مقطع فيديو تعليمي، أنت بحاجة إلى نشر شيء ما بشكل أسبوعي. عندما يتعلق الأمر بشبكات التواصل الاجتماعي فإن نشر التحديثات ينبغي أن يكون يوميا. شارك بعض المعلومات والروابط المفيدة وكذلك المقولات الملهمة. انشر روح المرح بين متابعيك وعلّمهم ما يفيدهم وساعد في إلهامهم بالأفكار المفيدة. كن متواجدا أمامهم باستمرار بحيث تخطر على بالهم مباشرة عندما يقررون الشراء. وأخيرا اجعل المحتوى الذي تنشره تفاعليا، ومصطلح المحتوى التفاعلي قد يساء فهمه، فلا يقصد به أن تجعل المحتوى مثيرا للانتباه بطريقة أو بأخرى، التفاعلية تعني التواصل الجيد مع الآخرين، أن تبين لهم بأنك تهتم بوقتهم الذي سيقضونه في قراءة ما تنشر، يعني أن تهتم بهم وبمشاكلهم وآرائهم في منشوراتك. في النهاية الناس يشترون من الأشخاص الذين يعجبون بهم. إذا اعجبوا بك ستكون محلا لثقتهم، وإذا وثقوا بك فإنهم سيقومون بتوظيفك، ولن تحصل على ثقتهم إلا إذا بينت اهتمامك بمصالحهم وقدمت المساعدة لهم. الكثيرون يبحثون عن حلول سريعة للتسويق، ولا أعلم إن كانت هذه الحلول موجودة فعلا أو أنها قد وجدت في يوم ما. التسويق اليوم يعني جهد ساعات، يعني الثبات على المبدأ وإظهار الاهتمام الحقيقي بالآخرين، وهو شيء لا بد أن تكون مستعدا لفعله. *: المقصود به المدونة التي نُشر فيها المقال الأصلي ترجمة وبتصرف للمقال: An introduction to content marketing and why it matters to you لصاحبه Paul Boag.
    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. قمت ببعث موضوع ولم يتم الرد علي هل تم قبولى ام تم رفضى
    1 نقطة
  5. العمل الحر (أو الجلوس الطويل، الوجه الآخر لنفس العملة) قد يجرُّك للهلاك! لا أعني هنا الضّغط الناتج عنه أو عن الإفراط في شرب القهوة الذي غالبًا ما يكون من طقوس المُستقلّين. العمل الحر يجرُّك للهلاك بسبب جلوسك الطّويل متقوّس الظهر أمام شاشة الكمبيوتر طوال اليوم، حيث أجريت العديد من الدراسات العلمية حول هذا الموضوع والتي توصلت إلى أخطارٍ صحية كبيرة نتيجة الجلوس الطويل وقلة الحركة. الجلوس الطويل يمحو أثر كل الجهد الجهيد الذي قد تبذله في ممارسة التمارين الرياضية حتى إن كنت تذهب بانتظام للنادي الرياضي، وهذا ليس بالخبر الجديد على مسامعنا. عبّر الدكتور ديفيد آجوس عن هذا الأمر بكلماتٍ قاسية: أظهر التقرير الذي أعده المركز الوطني لمعلومات التكنولوجيا الحيويّة عام 2012 حول هذا الموضوع نتائج غير مبشّرة. حيث بيّن أن إطالة الجلوس مرتبط مع أمراضٍ خطيرة مثل: أمراض القلب، السرطان، ارتفاع ضغط الدم والبدانة (فالجلوس الطويل لا يمنع الجوع كما يمكن أن يعتقد البعض). لا أعرف ما هي ردود أفعالكم على هذه المعلومات، لكنّني لم أقتنع بها للوهلة الأولى. أتحرّك ولا أطيل الجلوس وأنا لديّ إطارٌ زمنيٌّ محدد لإنجاز مهامّي؟ حركتي تقتصر على المرّات القليلة التي أنهض فيها لأذهب للحمام أو لأعدّ المزيد من القهوة. لكن كيف يمكنني أن أتحرّك أكثر ولا أطيل الجلوس وأنا أكسب دخلي من جلوسي أمام لوحة المفاتيح للتدوين؟ المشكلة ليست فقط في دوام العمل الذي يستمر من الساعة التاسعة للخامسة، فبعد الجلوس في العمل، معظمنا يعود للمنزل (وفي حالة المدوّنين المستقلين مثلي فإننا ننهض من أمام حواسيبنا المحمولة) لنلقي بأنفسنا على الأريكة أمام شاشةٍ أخرى غير شاشة الحاسوب. وهذا ليس مفيدًا على كل حال. لكوني مدوّنةً، قرّرتُ أن أبحث عن خيارات الوقاية المتوفّرة قبل أن يبحثوا لي عن نعشٍ مناسب. ثمن الوقوف في العملهناك دائمًا شخصٌ يسعى لأن يربح على حساب خسارتك، وبدائل الجلوس لا تختلف عن هذا بالنسبة لي. ربّما تختلف معي، لكنني أجد المكاتب الواقفة والمدمجة بأجهزة المشي غير مريحة على الإطلاق. وأيضًا، لديّ ميزانيةٌ وفواتيرٌ لدفعها وأفضّل ألا تكون إحداها لأحد المكاتب المترفة المدمجة بجهاز مشي كهربائي. وبالإضافة إلى أنني لا أحبّ طريقة الاجتماعات والمقابلات التي تتمّ وأفرادها واقفون لتفادي مخاطر الجلوس، والتي يحثّ عليها العديد من الشخصيات البارزة مثل ستيف جوبز ومارك زوكربرغ – فإنّها لا تزال حلًّا غير فعّال لواقع الحاجة للجلوس أمام مكتبٍ طوال اليوم لإنجاز الأعمال. العملاء قد يعتقدون أنّك مجنونٌ إذا قمت لتقف في أحد الأركان خلال اجتماعٍ ما لتتفادى أخطار إطالة الجلوس، نسعى جاهدين لنتودّد للعملاء ونكسب ثقتهم لذلك لا داعي لجعلهم يشكّون في سلامتنا العقلية. الحل الأمثل مجاني!العجيب في الأمر أنّ علاج ما فيه هلاكك بسيطٌ بشكلٍ مدهش، ورخيص الثمن، وفي كثيرٍ من الحالات مجّاني: كلّ 20 دقيقة: انهض واقفًا، تحرّك قليلًا، صفّ ذهنك، وكرّر هذا. هذه النصيحة من غريتشن رينولدز، كاتبة صحفيّة أسبوعيّة في النيويورك تايمز حاولت إيجاد حلٍّ بسيط لتقليل المشاكل الناجمة عن نمط حياتنا المفتقر للحركة. وهذه أحد نصائحها التي ذكرتها في مقابلةٍ معها نشرت في صحيفة النيويورك تايمز: توصّلت رينولدز لشيءٍ رائع من خلال بحثها أثناء كتابة كتابها حول هذا الموضوع: معظم فوائد التمرين تكون في العشرين دقيقة الأولى من الحركة والباقي -كما تقول رينولدز- مجرّد "بهارات". ممارسة الأنشطة الرياضية البسيطة بشكلٍ منتظم ومنفصل لها فائدة عظيمة. لا حاجة لمدرّب. لا حاجة لعضويةٍ في نادي. لا حاجة لأداةٍ على معصمك تحسب خطواتك. كلّ ما تحتاجه هو مؤقّت، وهو موجودٌ في كلّ مكان: في الهاتف النقال وفي جهازك المحمول. المؤقّت يساعدني ألا أستغرق في اللهو وأنسى مهامّي. جمعت أسعارًا لخياراتٍ متنوّعة لمكاتب وأجهزة لياقة في الجدول التالي. (ارتفاع نبضات قلبك نتيجةً لرؤية هذه الأسعار لا يمكن إدراجه ضمن ممارسة الرياضة). ضمّنته مؤقّتي المفضل وكتاب رينولدز: أوّل عشرين دقيقة: نتائج علميّة مفاجئة تظهر لنا كيف يمكننا: أن نتمرن أفضل، نتدرّب بذكاء، ونعيش أطول (أعتقد أنّها احتاجت محرّرًا لكتابة عنوان الكتاب هذا!) سعره مناسب وقد تعتقد أنه يستحقّ أن تدفع فيه، وستجده أرخص في المكتبات على كل حال. تستطيع أيضًا أن تنشئ بنفسك مكتبًا واقفًا باستخدام هذه الحيل من إيكيا. ليس لأفجعك، لكنّ أرخص ثمن ستدفعه بالنسبة لهذه الأفكار 139 دولار، بالإضافة إلى جهدك الذي ستبذله. تريد رأيي؟ الطرق المجّانية أفضل. كيف تحافظ على حياتكألهمتني ريلنولدز ببعض الأفكار، وقمت بإعداد خطّة عمل خاصة بي لتجنّب مخاطر إطالة الجلوس أمام الحاسوب: 1- عين مؤقتا للعشرين دقيقة السحريةأنهضُ واقفةً، ثمّ أسيرُ في دوائر أو أقوم بمهامٍ متعدّدة. قد أخرج الملابس من المجفف (دون أن أطويها بالتأكيد) وفي بعض الأحيان، لجعل الأمر ممتعًا أكثر، أقفز على سبيل الرياضة. في بعض الأحيان أعطي نفسي راحةً أستحقها بجدارة للرقص، ثم أعود للعمل مجدّدًا. هل تعلم ما المفاجئ فعلًا بالنسبة لي؟ أن هذه الطريقة وسيلةٌ فعّالة لإدارة الوقت. أصبح أكثر تركيزًا وتزيد إنتاجيّتي عندما أعرف أنّ لديّ وقتٌ محدّد قبل أن يدق وقت الراحة وعندما أتحرّك أكثر. مكسبٌ مضاعَف! قد أبدو مفرطة في التفاؤل والإيجابيّة، لكن لا يهم. أحاول تحويل شبح الحركة إلى شيءٍ إيجابيّ. يتحسّن شعوري نتيجة قيامي بهذا وأشعر بالمزيد من النشاط. قدماي لا تتخدّران، وعقلي تتحسّن لياقته أيضًا: لا يكون مشوّشًا أو مشتّتًا. ولا أعلق في هذه الدوّامة الرهيبة التي تحدث عندما أتصفّح الإنترنت في وقت الراحة، والتي تتركني أشعر بالخمول كما لو أنّني تناولت للتوّ صندوقًا كاملًا من الكعك. 2- قم واقفا عندما ترد على الهاتف أو تحصل على رسالةهذه إحدى نصائح الذكيّة. أنت تعمل في المنزل لوحدك. لا أحد يراك إذا هببت واقفًا كلّما أردت الردّ على مكالمةٍ هاتفيّة. أصبحت أتصفّح بريدي الإلكتروني على جهازي النقال بدلًا من الحاسوب لأحصل على فرصةٍ للنهوض. وبالنظر إلى كميّة المكالمات التي تتلقاها في وقت العمل، إنّها لمعجزةٌ حقًّا أن تستطيع الجلوس لأكثر من عشر دقائق متواصلة دون أن تنهض واقفًا لبعض الوقت للرد على مكالمة. 3- مارس الرياضة بطريقة غير مباشرةعندما تركن سيّارتك اختَر لها المكان الأبعد. استخدم السلالم وليس المصعد. يجب أن تكون متيقّظًا للفرص التي تُمنح لك للحركة، ابتسِم عندما ترى طابورًا طويلًا في المحلّات. هناك أدلةٌ مثيرةٌ أيضًا تشير إلى أنّ التمارين القصيرة خلال اليوم يمكن أن تكون الحل الأمثل لأولئك الذين لا يستطيعون الذهاب للنادي الرياضي. مهمّتكُ أن تعدّ خطّتك الخاصّة للحركة. من حسن الحظ أنّه لا يوجد حلٌّ وحيدٌ أوحد لتفادي مخاطر إطالة الجلوس، وتستطيع أن تُعد طريقةً مناسبةً لك. لا تجعل هذه النصائح تقف عندك. أنا متأكّدٌ أنّك تعرف على الأقلّ مدوّنًا آخر يواجه مخاطر الجلوس الطويل الآن. احمِ حياته وشاركه هذا المقال! سيسعدني معرفة الأفكار التي تنوي تطبيقها. لديّ صديقٌ يشاهد التلفاز واقفًا. هذا يبدو مؤلمًا لي، لذلك أستبدل الجلوس على الأريكة ببعض القفزات الرياضية (وأجد متعةً في هذا). والآن، شاركنا نصائحك للانتقال إلى حياةٍ صحيّةٍ طويلة الأمد مليئة بالعمل الحر. ترجمة –وبتصرّف– للمقال : Blogger Warning: Don’t Let Your Job Be the Death of You لصاحبته: Marianne Griebler. حقوق الصورة البارزة: Hardworking Businessman Working Late Night | Free vector by Vector Open Stock.
    1 نقطة
  6. 1-Antivirus Security انتي فايروس سيكوريتي او ما يعرف ب AVG واحد من افضل تطبيقات مكافحة الفايروسات المجانية للاندرويد حيث يساعدك في القضاء على اخطر البرمجيات الخبيثة بسهولة .مجاني تسستطيع تحميله من متجر جوجل بالضغط على العنوان. 2-Avast Mobile Security واحد من بين اقوى المضادات و اكثرها شعبية حول العالم ربما يكون اسمه مفروضا بقوة في مجال الكمبيوتر لكنه اكتسب شعبية كبيرة وسط مستخدمي نظام الاندرويد , قوي جدا تستطيع الاعتماد عليه و العمل براحة دون الخوف على خصوصياتك.فيه الكثير من الخصائص الجميلة و هو مجاني تستطيع تحميله بالضغط على العنوان. 3-Antivirus Free مضاد فايروسات بسيط و مجاني ذو واجهة استخدام سهلة لكنه قوي جدا في عمله حيث يترصد اقوى الفايروسات و اعتاها و يقضي عليها مباشرة.مجاني يمكنك تحميله بالضغط على العنوان.
    1 نقطة
  7. كيف يمكنني ان اتحصل على الكثير من المتابعة لمنشوراتي!!
    1 نقطة
  8. أولا يجب أن يكون المنشور ذو فائدة ومهم للقارئ. ثانيا من المحبب ان تستعمل بعض العبارات التسويقية من اجل اثارة انتباه المستخدم. ثالثا : الصبر، لا يمكن أن تتلقى اهتمام كبير منذ البداية، هذا شئ طبيعي، لا يوجد نجاح منذ البداية يجب أن تتعب قليلا. رابعا: الاستمرارية، سر من الاسرار فالاستمرارية تجبر متابعيك على التفاعل معك، في حال نشر منشوراتك مرتين أو ثلاثة أسبوعيًا لا يمكن ابدا ان تتحصل على وفاء من المتابعين. خامسا: نوع في طبيعة منشوراتك بين القصير والطويل، المكتوب المرئي والصوري.
    1 نقطة
×
×
  • أضف...