<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x635;&#x646;&#x627;&#x639;&#x629; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628;</title><link>https://academy.hsoub.com/programming/game-development/page/5/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x635;&#x646;&#x627;&#x639;&#x629; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628;</description><language>ar</language><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x62D;&#x635;&#x644; &#x639;&#x644;&#x649; &#x623;&#x641;&#x643;&#x627;&#x631; &#x623;&#x644;&#x639;&#x627;&#x628; &#x641;&#x64A;&#x62F;&#x64A;&#x648; &#x646;&#x627;&#x62C;&#x62D;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%A3%D9%81%D9%83%D8%A7%D8%B1-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%81%D9%8A%D8%AF%D9%8A%D9%88/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_01/--.png.840920c9d0da5d6b98cd2a7e857ba60d.png" /></p>
<p>
	نعرفك في مقال اليوم على طريقة الحصول على أفكار ألعاب فيديو ناجحة ومميزة لمشروعك القادم؟ فسواءً أكنت مبتدئًا أو محترفًا متمرسًا في مجال تطوير الألعاب الإلكترونية، فإن الاستراتيجيات والأفكار في هذه المقالة ستزودك بأهم النصائح والأدوات التي تساعدك على صياغة أفكار ألعاب فيديو ناجحة. لا شك أن عملية إنشاء لعبة إلكترونية ناجحة تتطلب الكثير من الوقت والجهد لتصل بها إلى المستوى المرغوب، ولعل أول ما يتبادر إلى ذهننا عند التفكير بصعوبتها هي البرمجة اللازمة لتطبيقها، وآلية تنفيذ التصميم المقترح لهذه اللعبة وما إلى ذلك.
</p>

<p>
	ولكن في الواقع إن سألت أي مصمم ألعاب فيديو أو مطورًا متمرسًا عن ذلك، سيجيبك بأن أصعب خطوة في <a href="https://academy.hsoub.com/programming/game-development/" rel="">صناعة الألعاب</a> هي تحديد فكرة اللعبة الأساسية، فقبل البدء بأي مرحلة من مراحل البرمجة أو تصميم <a href="https://academy.hsoub.com/programming/game-development/%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D9%86%D8%A7%D8%AC%D8%AD%D8%A9-r2212/" rel="">شخصيات الألعاب الإلكترونية</a> يلزم ابتكار فكرتها الأساسية، لكن هذه العملية ليست بالسهولة التي تتخيلها نظرًا لوجود عدد هائل من الألعاب المطورة فعلًا الأمر الذي يستلزم منك اختيار أفكار مبتكرة تشهد إقبالًا ورواجًا بين جمهور اللاعبين.
</p>

<h2 id="">
	أهم النصائح التي تساعدك في ابتكار أفكار ألعاب فيديو
</h2>

<p>
	قد يكون لديك شغف بصناعة الألعاب الإلكترونية ومعرفة تقنية <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">بلغات برمجة الألعاب الإلكترونية </a> وباستخدام أحد <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محركات الألعاب</a> المساعدة، لكنك تجد صعوبة في توليد فكرة لعبة جيدة تلقى رواجًا بين اللاعبين. لذلك سنعرض لك أهم الخطوات التي ستساعدك بالحصول على فكرة مبتكرة، ونعرفك على أفضل الاستراتيجيات من أجل الوصول لهذا الهدف.
</p>

<p>
	ليس بالضرورة أن تكون فكرة اللعبة الناجحة معقدة، فقد تكون الفكرة الناجحة هي فكرة بغاية البساطة والوضوح. فمثلًا من لا يعرف اللعبة الشهيرة Subway Surfers؟ تدور فكرة هذه اللعبة حول شاب يركض هُروبًا من الشرطي وكلبه، حيث يركض فوق القطارات التي تواجهه ليجمع خلال ركضه أكبر عدد من القطع المعدنية. وبالرغم من بساطة هذه الفكرة إلا أنها مصممة ومبرمجة بشكل جيد، وهذا يجعلها محبوبة من قبل الجميع.<br>
	وفيما يلي أهم الخطوات التي عليك اتباعها للحصول على أفكار ألعاب فيديو ناجحة:
</p>

<ul>
	<li>
		أولًا:حدد جمهورك المُستهدف.
	</li>
	<li>
		ثانيًا: اختر تصنيفًا محددًا.
	</li>
	<li>
		ثالثًا: اعرف نطاق مشروعك.
	</li>
	<li>
		رابعًا: حدد أفكار الألعاب من المواضيع الرائجة حاليًا.
	</li>
	<li>
		خامسًا: تأمل العالم من حولك للبحث عن فكرة لعبة مميزة.
	</li>
	<li>
		سادسًا: اشترك في مسابقة Game Jam.
	</li>
	<li>
		سابعًا: استعن بمولدات الأفكار العشوائية وأدوات الذكاء الاصطناعي.
	</li>
	<li>
		ثامنًا: تعلم واستلهم الأفكار من محبّي الألعاب والمطورين.
	</li>
	<li>
		تاسعًا: اعرف ما هي مواصفات اللعبة - التي لن تلعبها!
	</li>
	<li>
		عاشرًا: جرب مفهوم اللعبة الأساسي قبل الاعتماد على الفكرة.
	</li>
</ul>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلة صناعة الألعاب ثنائية وثلاثية الأبعاد وابتكر ألعاب ممتعة تفاعلية ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<p>
	لنناقش كل خطوة من هذه الخطوات بمزيد من التفصيل ونتعرف على دورها وأهميتها في الحصول على أفكار ألعاب ناجحة.
</p>

<h3 id="-1">
	أولًا: حدد جمهورك المُستهدف
</h3>

<p>
	برأيك هل ستنجح لعبة تتضمن قوانين عديدة ومعقدة والكثير من التحركات المتقدمة إن كانت موجهة للأطفال؟ بالتأكيد الجواب هو لا! فمن الضروري قبل البدء بالتفكير باللعبة وقواعدها وغيره من التفاصيل أن تحدد من هي الفئة التي تستهدفها بلعبتك القادمة؟ وعلى هذا الأساس تبدأ في التوسع بتفاصيل هذه اللعبة.
</p>

<p>
	هذه العملية مهمة لعدة أسباب:
</p>

<ol>
	<li>
		تصميم اللعبة حسب تفضيلات الفئة المستهدفة: يتيح لك فهم الاهتمامات والسلوكيات لجمهورك المستهدف إنشاء لعبة تناسبهم. وذلك يشمل موضوع اللعبة وطريقة اللعب ومستوى الصعوبة. فمثلًا تختلف مستويات اللعبة وقوانينها بحسب الفئة العمرية الموجهة إليها.
	</li>
	<li>
		التسويق: إن معرفة جمهورك المستهدف يمكنك من تسويق لعبتك والترويج لها بشكل فعال للأشخاص المناسبين، فإن كانت اللعبة موجهة للأطفال فعليك أن تستخدم أسلوبًا بسيطًا ومرحًا في شرح فكرتها بالإضافة لألوان زاهية، أما إن كانت موجهة للأعمار الأكبر فمن الجيد تضمين أساليب تشويقية للعبتك.
	</li>
	<li>
		رضا اللاعب: يمكنك إنشاء لعبة توفر تجربة أكثر إرضاءً ومتعة للاعبين من خلال تلبية تفضيلات واحتياجات جمهورك المستهدف.
	</li>
</ol>

<h3 id="-2">
	ثانيًا: اختر تصنيفًا محددًا
</h3>

<p>
	تتبع كل لعبة تصنيف معين تجري فيه أحداثها، وهذه نصيحة أساسية للتركيز على نوع معين من <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">تصنيفات الألعاب</a> وبناء قصتك وأحداثك على أساسها. ومن أشهر الأنواع:
</p>

<ol>
	<li>
		ألعاب العالم المفتوح Sandbox: نوع يتمتع فيه اللاعبون بطريقة لعب حرَة ويمكنهم استكشاف عالم اللعبة وإنشائه والتغيير به. مثال: ماين كرافت.
	</li>
	<li>
		استراتيجية الوقت الفعلي (RTS): نوع يتحكم فيه اللاعبون في الموارد ويديرونها، ويبنون القواعد، ويقودون الوحدات في معارك بأسلوب تفاعلي لحظي. مثال: ستار كرافت.
	</li>
	<li>
		ألعاب إطلاق النار (FPS و TPS): نوع يستخدم فيه اللاعبون الأسلحة النارية للمشاركة في القتال. مثال: Counter StrikeGears of War.
	</li>
	<li>
		ساحة معركة متعددة اللاعبين عبر الإنترنت (MOBA): نوع يتحكم فيه اللاعبون في شخصية واحدة في لعبة تنافسية قائمة على الفريق، بهدف تدمير قاعدة الفريق المنافس. مثال: League of Legends
	</li>
	<li>
		ألعاب المحاكاة والرياضة: نوع يحاكي فيه اللاعبون أنشطة العالم الحقيقي أو يشاركون في اللعب المتعلق بالرياضة. مثال: The Sims و FIFA .
	</li>
	<li>
		ألعاب الألغاز: نوع حيث يحلّ اللاعبون الألغاز أو يشاركون في مجموعة ألعاب مصغرة متعددة اللاعبين. مثال: Portal 2.
	</li>
</ol>

<h3 id="-3">
	ثالثًا: اعرف نطاق مشروعك
</h3>

<p>
	لتضمن بدء المشروع بوعي كامل بالتفاصيل ونقاط القوة والضعف والعوائق التي ستواجهك، احرص قبل الشروع بإنشاء لعبتك وحتى قبل البحث عن أفكار ألعاب فيديو على طرح هذه الأسئلة على نفسك لمعرفة هذه الحدود:
</p>

<ul>
	<li>
		هل تعمل ضمن فريق؟ ما حجمه؟ أم أنه مشروع خاص بك فقط؟
	</li>
	<li>
		ما هي المهارات التي تمتلكها أنت وفريقك؟ وهل هي كافية لتطوير فكرة اللعبة؟
	</li>
	<li>
		ما هي المهارات التي تفتقدها، ما الذي يمكنك تعلمه أو الاستعانة بمصادر خارجية؟
	</li>
	<li>
		هل هناك حزمة تطوير جاهزة ستستخدمها أم ستبني اللعبة بالكامل من الصفر؟
	</li>
	<li>
		هل ستكون اللعبة ثنائية الأبعاد 2D أم ثلاثية الأبعاد 3D؟
	</li>
	<li>
		كم من الوقت يمكنك استثماره في تطوير اللعبة أنت وفريقك وسطيًا؟
	</li>
</ul>

<h3 id="-4">
	رابعًا: حدد أفكار الألعاب من المواضيع الرائجة حاليًا
</h3>

<p>
	إذا كنت تبحث عن أفكار ألعاب فيديو جيدة ومحببة، خذ نظرة من حولك وتعرف على أبرز الأفكار والاتجاهات الرائجة التي تتجه إليه صناعة الألعاب؟ بالإضافة إلى ذلك، فكّر بأساليب تستطيع من خلالها جذب الجمهور إلى لعبتك، كأن تستغل مثلًا شهرة مسلسل تلفزيوني وتقتبس من أحداثه وشخصياته. وبذلك تضمن وجود إقبال أكبر على لعبتك.
</p>

<p>
	مثال على ذلك فكرة لعبة أنتون بلاست ANTONBLAST والمستوحاة بشكل كبير من سلسلة Wario Land المنسية منذ فترة طويلة والتي لم تشهد إصدارًا جديدًا منذ عام 2008، إلا أنها لاقت بعد نشرها إقبالًا كبيرًا من الأشخاص بسبب شهرة هذه السلسلة واستغراب الجمهور من إحيائها بهذه الطريقة.
</p>

<h3 id="-5">
	خامسًا: تأمل العالم من حولك للبحث عن فكرة لعبة مميزة.
</h3>

<p>
	لا يمكنك الخروج بأفكار إبداعية وأنت مستلقي على سريرك في غرفتك وحيدًا، انهض وتأمل الدنيا من حولك! قد يبدو لك الأمر يسيرًا وليس ذا أهمية كبيرة، ولكن هل تعلم أن أعظم الأفكار الإبداعية لألعاب الفيديو تشكلت عبر محاكاة الواقع؟ عليك بمراقبة البيئة المحيطة بك لتنشيط خيالك والبدء في الخروج بأفكار ألعاب إبداعية. انتبه إلى الأشياء الصغيرة، وكيف تبدو وتعمل الأشياء من حولك، شاهد الأفلام المتنوعة، اقرأ الروايات، فقد تجد فيها عدد كبير جدًا من الأفكار الرائعة التي ما كانت لتخطر على بالك.
</p>

<p>
	في الواقع، يميل الناس لمحبة الألعاب التي صممت وطورت باستخدام قصص واقعية بشكل أكبر. فالنصيحة الذهبية لك هنا أن تحصل على الإلهام من البيئة المحيطة بك وأن تحاول استخدامها في ألعابك لإبقاء اللاعبين مهتمين ومتحمسين.
</p>

<p>
	من الأمثلة على الألعاب التي بنيت على محاكاة الواقع هي سلسلة GTA الشهيرة، حيث تحدث الأحداث في هذه السلسلة ضمن أماكن مستوحاة من مدن الحياة الواقعية، وذلك رغبةً من المطورين في أن يركز اللاعب على إكمال المهام اللازمة للتقدم في القصة مع شعوره بأنه الشخصية بحد ذاتها. مثالٌ آخر، هو لعبة بوكيمون Pokemon، حيث استلهم مطوّرها فكرة لعبته من اهتمامه وهو طفل بجمع الحشرات.
</p>

<h3 id="gamejam">
	سادسًا: اشترك في مسابقة Game Jam
</h3>

<p>
	مسابقات Game Jam هي عبارة ماراثونات مخصصة لتطوير الألعاب تهدف لجمع مطوري الألعاب بإنشاء ألعاب إلكترونية من الصفر وتعاونهم معًا للخروج بأفكار ألعاب فيديو حول موضوع معين أو بشروط معينة والبدء بإنشائها واختبارها وتلقي الآراء حولها.والمشاركة في هذه المسابقة تساعدك على تطوير إمكانياتك وبناء مجتمع في مجالك والحصول على العديد من أفكار ألعاب الفيديو المميزة خارج الصندوق. من أشهر هذه المسابقات مسابقة GMTK game jam، وهو حدث سنوي يهدف لإنشاء لعبة واحدة أو أكثر خلال فترة زمنية قصيرة تتراوح عادة بين 24 إلى 72 ساعة والمشاركة فيها من شأنه تعزيز الإبداع والابتكار في تصميم الألعاب.
</p>

<h3 id="-6">
	سابعًا: استعن بمولدات الأفكار العشوائية وأدوات الذكاء الاصطناعي
</h3>

<p>
	هناك العديد من أدوات الذكاء الاصطناعي التي يمكنها مساعدتك في توليد أفكار ألعاب فيديو ترغب في إنشائها. فيما يلي أربع أدوات مفيدة بالإضافة إلى معلومات حول كيفية عملها وكيف يمكنك استخدامها:
</p>

<h4 id="chatgpt">
	تشات جي بي تي ChatGPT
</h4>

<p>
	يمكنك الاستفادة من <a href="https://academy.hsoub.com/apps/web/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-chatgpt-api-%D9%84%D8%AA%D8%AD%D8%B3%D9%8A%D9%86-%D8%AE%D8%AF%D9%85%D8%A7%D8%AA%D9%83-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r909/" rel="">خدمات ChatGPT</a> في جميع مراحل إنشاء اللعبة متضمنًا عملية البحث عن الفكرة الأساسية وتفاصيلها. وذلك من خلال تزويده بوصف لما تبحث عنه في فكرة لعبة الفيديو سواءً كان <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">نوع لعبة</a> محدد اخترته أم فئة معينة توجه لها هذه اللعبة وسيقدم لك أفكار إبداعية بناءً على مدخلاتك.
</p>

<h4>
	أداة <span ipsnoautolink="true">Let's Make a Game</span>
</h4>

<p>
	هي أداة مصممة خصيصًا لمساعدة مصممي الألعاب على توليد أفكار لألعاب الفيديو إذ يمكنك إدخال كلمات رئيسية أو معايير محددة تتعلق بنوع اللعبة التي ترغب في إنشائها، وسيزودك المولد بمفاهيم مختلفة للعبة تتوافق مع تلك المواصفات. توفر لك هذه الأداة الوقت من خلال اقتراح أفكار الألعاب تلقائيًا بناءً على تفضيلاتك، مما يسمح لك باستكشاف الاحتمالات المختلفة بسرعة.
</p>

<h4 id="plotgeneratorhttpswwwplotgeneratororguk">
	أداة <span ipsnoautolink="true">Plot Generator</span>
</h4>

<p>
	هي أداة متعددة الاستخدامات يمكن استخدامها لتطوير القصص والروايات الخاصة بالألعاب. حيث يُنشئ المولد قصص وشخصيات ومهام فريدة للعبتك من خلال اختيار نوع اللعبة وعناصر القصة الأساسية ما يساعدك على العثور على أفكار ألعاب فيديو مبتكرة قد لا تخطر ببالك.
</p>

<h4 id="conceptandartideageneratorhttpswwwartideasgeneratorcom">
	أداة <span ipsnoautolink="true">Concept and Art Idea Generator</span>
</h4>

<p>
	توفر لك هذه الأداة المدعومة <a href="https://academy.hsoub.com/programming/artificial-intelligence/%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A/" rel="">بالذكاء الاصطناعي</a> طريقة لتوليد العديد الأفكار الملهمة لألعاب الفيديو التي تريد تطويرها وتعطيك اقتراحات حول بيئة اللعبة ومظهر <a href="https://academy.hsoub.com/programming/game-development/%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D9%86%D8%A7%D8%AC%D8%AD%D8%A9-r2212/" rel="">شخصيات الألعاب</a> التي تشترك في اللعب وغيرها من الأفكار المميزة. وذلك عبر إدخال كلمات رئيسية أو سمات محددة تتعلق بلعبتك.
</p>

<h3 id="-7">
	ثامنًا: تعلم واستلهم الأفكار من محبّي الألعاب
</h3>

<p>
	توجد العديد من المجتمعات والمنتديات على الإنترنت تهتم بتطوير الألعاب وتضم أشخاصًا يشاركونك الاهتمام ذاته، وتستطيع الاشتراك بها ومتابعتها للحصول على العديد من أفكار الألعاب أو طرح فكرتك والحصول على آراء المستخدمين حولها. حيث يمكنك إنشاء على سبيل المثال إنشاء منشور على <a href="https://io.hsoub.com/" rel="external">مجتمع حسوب</a> وطرح فكرة لعبة تدور ببالك للحصول على آراء متعددة ومتنوعة من المهتمين لا سيما إذا كان استهداف لعبتك هو السوق العربيّ فهذا المكان هو الأمثل.
</p>

<h3 id="-8">
	تاسعًا: اعرف ما هي مواصفات اللعبة التي لن تلعبها!
</h3>

<p>
	هل تعلم أن لعب لعبة سيئة وغير محببة قد يساعدك بشكل كبير عندما يتعلق الأمر بالبحث عن أفكار ألعاب! فهذا الأمر من شأنه أن يساعدك بشكل كبيرعلى اكتشاف العيوب والأخطاء التي تواجهك في اللعبة السيئة كي تتجنبها ولا تقع بمثلها عند اختيار فكرة لعبتك، كما يمكنك بذلك استلهام أفكار جديدة من أفكار قديمة لم يتم تطويرها بشكل جيد والعمل على تحسينها وصياغتها بلعبة ناجحة.
</p>

<h3 id="-9">
	عاشرًا: جرب مفهوم اللعبة الأساسي قبل الاعتماد على الفكرة
</h3>

<p>
	تعد تجربة فكرة اللعبة الخاصة بك قبل العمل عليها أمرًا بالغ الأهمية لعدة أسباب:
</p>

<ol>
	<li>
		تحديد العيوب: يساعدك اختبار فكرة لعبتك على تحديد أي عيوب أو مشكلات محتملة قبل استثمار وقت وموارد كبيرة في تطويرها. فهو يسمح لك باكتشاف المشكلات في المفهوم أو آليات اللعب ومعالجتها.
	</li>
	<li>
		تقييم الجمهور المستهدف: يتيح لك اختبار فكرة لعبة الفيديو التي تريدها قياس اهتمام وتفاعل جمهورك المستهدف. يمكن أن تساعدك تعليقاتهم المبكرة على فهم ما إذا كانت لعبتك تنال إعجاب الفئة المستهدفة أم لا، مما يساعدك على تحسين المفهوم ليناسب تفضيلاتهم وتوقعاتهم.
	</li>
	<li>
		التحسين: يمكنك تحصيل بيانات حول نقاط نجاح لعبتك وفشلها من من خلال مراقبة أداء اللاعب ودرجة انغماسه في اللعب. تضمن لك هذه العملية أن تطور من لعبتك بما يحقق نجاحها.
	</li>
	<li>
		توقع التكلفة: يمكنك توفير الوقت والموارد في التطوير من خلال اختبار فكرة لعبتك في وقت مبكر، وذلك بتحديد العيوب ونقاط الضعف في مرحلة مبكرة مما يسمح لك بإجراء التعديلات اللازمة قبل استثمار أموالك في البرمجة والتصميم والتفاصيل الأخرى.
	</li>
</ol>

<h2 id="-10">
	أمثلة على أفكار ألعاب فيديو لاقت نجاحًا كبيرًا
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="141439" href="https://academy.hsoub.com/uploads/monthly_2024_01/---.png.4a24de279417a4f6e34380e67cac9a24.png" rel=""><img alt="أفكار ألعاب فيديو ناجحة" class="ipsImage ipsImage_thumbnailed" data-fileid="141439" data-unique="7wui8a3w4" style="width: 450px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2024_01/---.png.4a24de279417a4f6e34380e67cac9a24.png"> </a>
</p>

<p>
	إذا كنت مهتمًا بصناعة ألعاب إلكترونية ومعرفة السر وراء نجاح العديد من الألعاب الرائجة فإليك أمثلة على أبرز الألعاب الإلكترونية التي لاقت رواجًا وأهم الأسباب في نجاحها وشهرتها:
</p>

<ul>
	<li>
		لعبة ماين كرافت Minecraft.
	</li>
	<li>
		لعبة كاندي كراش Candy Crash.
	</li>
	<li>
		لعبة سوبر ماريو برو Super Mario Bros.
	</li>
	<li>
		لعبة وي سوبرتس Wii Sports.
	</li>
	<li>
		لعبة أمونغ آس Among Us.
	</li>
</ul>

<p>
	لنحاول اكتشاف أبرز الأسباب التي جعلت من أفكار هذه الألعاب محبوبة ومنتشرة بين جمهور كبير من اللاعبين حول العالم.
</p>

<h3 id="minecraft">
	لعبة ماين كرافت Minecraft
</h3>

<p>
	تقوم فكرة لعبة ماين كرافت على أسلوب اللعب المفتوح من خلال السماح للاعبين ببناء واستكشاف عوالم افتراضية بناءً على تفضيلاتهم الشخصية، مما يوفر فرصة للإبداع والخيال ففي هذه اللعبة لايوجد طريقة أو أسلوب معين للعب وهذه الإمكانيات الإبداعية غير المحدودة وقدرة اللاعبين على مشاركة إبداعاتهم مع الآخرين هي ما أكسب اللعبة شعبية هائلة، كما ساهمت طبيعتها التي يتحكم فيها مجتمع اللاعبين والتحديثات المتكررة لها في زيادة نجاحها.
</p>

<h3 id="candycrash">
	لعبة كاندي كراش Candy Crash
</h3>

<p>
	هي لعبة ألغاز يقوم اللاعبون فيها بمطابقة ثلاث قطع حلوى أو أكثر من نفس اللون لإزالتها من اللوحة. وقد لاقت اللعبة شهرة واسعة منذ نشرها إلى الآن واستقطبت اللاعبين من مختلف الأعمار بفضل أسلوبها الجذاب وقوانينها البسيطة في اللعب وتصميم رسوماتها الملونة ذات الألوان الزاهية وتضمنها لمئات المستويات التي تزداد صعوبة مع تقدم اللاعب في اللعب وتقدم له مكافآت تحفزه على مواصلة اللعب، كما ساعد توفرها على منصات متعددة كالهواتف الجوالة والأجهزة اللوحية وأجهزة الحاسوب في زيادة شعبيتها وانتشارها على نطاق واسع.
</p>

<h3 id="supermariobros">
	لعبة سوبر ماريو Super Mario Bros
</h3>

<p>
	يعود نجاح فكرة لعبة سوبر ماريو التي طورتها شركة نينتندو Nintendo إلى عدة عوامل من أبرزها أسلوب اللعب الممتع والوضح إلى جانب تصميم شخصية لعبة ماريو المحبب والتي أصبحت واحدة من أشهر شخصيات ألعاب الفيديو، كما ساهم إصدار اللعبة على العديد من المنصات في زيادة شعبيتها وانتشارها وهي واحدة من أكثر ألعاب الفيديو مبيعًا على الإطلاق.
</p>

<h3 id="wiisports">
	لعبة وي سبورتس Wii Sports
</h3>

<p>
	تعتمد فكرة لعبة Wii Sports التي طورتها شركة Nintendo EAD عام 2006 على تضمين من ألعاب المحاكاة الرياضية وقد حققت هذه اللعبة نجاحًا واسعًا بسبب سهولة لعبها وقواعدها البسيطة التي تسمح للاعبين من مختلف الأعمار والمستويات المهارية اللعب والاستمتاع بها كما تتميز هذه اللعبة باستخدام تقنية الحركة وتتضمن وحدة تحكم Wii التي تستخدم تقنية الاستشعار عن الحركة للتحكم بالألعاب عن طريق حركة الجسم مما وفر تجربة لعب واقعية وممتعة.
</p>

<h3 id="amongus">
	لعبة أمونغ آس Among Us
</h3>

<p>
	هي لعبة جماعية تتضمن فريق من اللاعبين الذين يجتمعون معًا لإصلاح سفينة فضائية أثناء التعامل مع وجود المحتالين الذين يحاولون القضاء على الطاقم. تشجع اللعبة على التواصل والشك والعمل الجماعي حيث يحاول اللاعبون التعرف على المحتالين والتصويت ضدهم.
</p>

<p>
	لاقت اللعبة نجاحًا عظيمًا بسبب طريقة لعبها البسيطة والجذابة التي تشجع العمل الجماعي والتفكير للوصول إلى استنتاجات. كما ارتفعت شعبيتها مع بدء العديد من اللاعبين وصنّاع المحتوى المشهورين بلعبها على البث المباشر، مما ساهم بخلق ضجة كبيرة حولها على مستوى العالم.
</p>

<h2 id="-11">
	الخلاصة
</h2>

<p>
	لا ريب أن عملية تطوير الألعاب تتطلّب عددًا من المهارات للحصول على منتج نهائي ناجح يستمتع به اللاعبون بدءًا من التطوير والتصميم وصولًا إلى التسويق وإطلاق اللعبة على المتاجر، إلا أن التوصل إلى فكرة ممتعة فريدة من نوعها هو أساس هذه العملية وستضمن أن المنتج النهائي سيبدأ على أسس قوية تضمن نجاحه.
</p>

<p>
	هل هناك فكرة في بالك للعبة إلكترونية مميزة وناجحة تعتقد أنها ستحقق النجاح لكنك متردد في آلية تنفيذها؟ اطرحها للمناقشة أسفل المقال، ودع القراء الآخرين يبرزون لك مواضع ضعفها وقوتها!
</p>

<h2 id="-12">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">مطور الألعاب: من هو وما هي مهامه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">تعرف على أشهر لغات برمجة الألعاب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%AC%D9%88%D8%AF%D9%88-godot/" rel="">مدخل إلى محرك الألعاب جودو Godot</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">نبذة عن صناعة الألعاب ومحرك Unity3D</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2218</guid><pubDate>Sat, 13 Jan 2024 12:05:00 +0000</pubDate></item><item><title>&#x634;&#x62E;&#x635;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628; &#x627;&#x644;&#x625;&#x644;&#x643;&#x62A;&#x631;&#x648;&#x646;&#x64A;&#x629; &#x627;&#x644;&#x646;&#x627;&#x62C;&#x62D;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D9%86%D8%A7%D8%AC%D8%AD%D8%A9-r2212/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_01/--.png.9d88744a43fb2aa66a44650c6a866d4d.png" /></p>
<p>
	تعد عملية اختيار وتصميم شخصيات الألعاب جزءًا لا يتجزأ من صناعة الألعاب الإلكترونية، وهي لا تقتصر على التركيز على الجانب الجمالي للتصميم وجعله جذابًا، بل تلعب دورًا حاسمًا في تشكيل تجربة اللاعبين وتضمن تناسق قصة اللعبة وانسجام اللاعب معها. حيث تتمتع الشخصية المنتقاة جيدًا بالقدرة على التأثير على المشاعر، وتحفيز اللاعب على اللعب باستمرار، وتضمن الارتقاء باللعبة في النهاية إلى آفاق جديدة من النجاح. سننظر سويًا في هذا المقال إلى أهم الاعتبارات التي عليك الأخذ بها لاختيار شخصية ناجحة في لعبتك القادمة وأهم برامج وأدوات تصميم شخصية لعبة، ونختم المقال بأمثلة لأبرز شخصيات الألعاب المصممة جيدًا فإذا كنت مهتمًا بتطوير ألعاب الفيديو فتابع قراءة المقال للنهاية.
</p>

<h2 id="">
	معايير تصميم شخصية لعبة ناجحة
</h2>

<p>
	لا شك أن تصميم شخصيات الألعاب يلعب دورًا مهمًا جداً في <a href="https://academy.hsoub.com/programming/game-development/" rel="">صناعة الألعاب الإلكترونية</a>، فالشخصيات هي وسيلة اللاعبين للتفاعل مع العالم الافتراضي للعبة، فإذا كنت مبرمج ألعاب فيجب أن تكون الشخصيات التي تختارها في لعبتك محببة وجيدة التصميم ومنسجمة مع <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">نوع اللعبة</a> وقصتها، وتعكس الأهداف التي تهدف اللعبة إلى تحقيقها، وإليك مجموعة من المعايير أو النقاط التي عليك الانتباه لها عند اختيار أو تصميم شخصية لعبة إلكترونية:
</p>

<ul>
	<li>
		تحديد المفهوم العام لشخصية اللعبة ويشمل:
	</li>
	<li>
		السمات الجسدية والنفسية لشخصية اللعبة.
	</li>
	<li>
		سلوك الشخصية وتفاعلها مع محيطها.
	</li>
	<li>
		نبرة صوت الشخصية أو التأثيرات الصوتية الخاصة بها.
	</li>
	<li>
		نقاط قوة الشخصية ونقاط ضعفها والموازنة فيما بينهما.
	</li>
	<li>
		قصة الشخصية.
	</li>
	<li>
		مظهر شخصية اللعبة.
	</li>
</ul>

<p>
	لنناقش كل نقطة من هذه النقاط ونتعرف على دورها عند التفكير في تصميم شخصيات الألعاب الإلكترونية.
</p>

<h3 id="-1">
	أولًا: تحديد المفهوم العام للشخصية
</h3>

<p>
	من المهم تحديد الدور العام لشخصيات الألعاب أولًا قبل البدء بتصميمها، والانتباه لأن تكون لكل شخصية لعبة مميزات وخصائص فريدة مختلفة عن بقية الشخصيات الأخرى لضمان تميزها وتفردها وتحديد خصائصها العامة مثل السمات النفسية والجسدية ونبرة الصوت وغيرها من التفاصيل التي تساهم بتشكيل مفهوم شخصية اللعبة، وإليك أهم العوامل التي تساعدك على تصور المفهوم العام للشخصية:
</p>

<h4 id="1">
	1. السمات الجسدية والنفسية لشخصية اللعبة
</h4>

<p>
	أول ما عليك التفكير به عند اختيار شخصية لعبة فريدة هو تحديد السمات الجسدية والنفسية لشخصية اللعبة لأنها تساعدك على تصور شكل جسدها وملامحها بما يتوافق مع هدف الشخصية في اللعبة. فمثلًا من المهم أن تكون الشخصية ذات جسد رياضي في حال كانت اللعبة تتضمن الركض والهروب.
</p>

<h4 id="2">
	2. سلوك الشخصية وتفاعلها مع محيطها
</h4>

<p>
	يعد سلوك الشخصية جانبًا حيويًا مهمًا في تصورها وتحديد طريقة تفاعلها مع بيئة اللعبة ومع الشخصيات الأخرى لذا عليك أن تحدد هل الشخصية التي تريدها في لعبتك هي شخصية بطولية أو مغامرة أو مرحة أو مؤذية أن ويتماشى تصميم الشخصية مع أفعالها وسلوكها، فإذا كانت الشخصية عدوانية وشريرة فيجب أن تعكس ملامح وجه الشخصية عدوانيتها حتى تكون مقنعة.
</p>

<h4 id="3">
	3. نبرة صوت الشخصية أو التأثيرات الصوتية الخاصة بها
</h4>

<p>
	تشير نبرة الشخصية إلى سلوكها وموقفها العام في اللعبة. فهي تحدد الحالة المزاجية للعبة وتؤثر على كيفية إدراك اللاعبين للشخصيات والتفاعل معها فينبغي أن تكون النغمة متسقة طوال اللعبة، ومتناسبة من الحديث أو الموقف الحاصل مما يعزز هوية الشخصية ويعزز الاتصال العاطفي للاعب معها. كما أن النبرة المميزة والمتغيرة بحسب الموقف مثلًا نبرة حماسيّة، حزينة، مبتهجة …إلخ. تجعل منها شخصية متفردة وتبقى عالقة في ذهن اللاعب.
</p>

<h4 id="4">
	4. نقاط قوة الشخصية ونقاط ضعفها والموازنة فيما بينهما
</h4>

<p>
	يعد تحديد نقاط القوة والضعف لدى شخصية لعبة الفيديو أمرًا مهمًا لعدة أسباب فهو يضيف عمقًا وتعقيدًا للشخصية، ويجعلها أكثر واقعية وإقناعًا كما أنه يؤثر على آليات اللعب ويجعله أكثر حماسًا، على سبيل المثال تتميز شخصية ماريو في لعبة Super Mario Bros بعدة نقاط قوة مثل القدرة على الركض السريع والقفز عاليًا مما يسمح له بالهروب من الأعداء والوصول إلى الأماكن المرتفعة وتجاوز العقبات، لكنه يملك نقاط ضعف فهو صغير الحجم ولا يستطيع السباحة فهو يغرق إذا سقط في الماء.
</p>

<h3 id="-2">
	ثانيًا: قصّة الشخصية
</h3>

<p>
	تساهم قصة شخصية اللعبة الجذابة في إضافة عمق وتشويق على اللعبة وتجعل اللاعب يتفاعل معها بشكل أفضل، ويشعر بالإنجاز عندما ينتقل عبر مستويات اللعبة ويفوز في النهاية ويحقق الهدف المطلوب، فلا يمكن التغاضي عن أهمية قصة شخصية لعبة الفيديو أثناء اللعب ودورها في ارتباط اللاعب في اللعبة وتحفيزه واهتمامه بأدق تفاصيلها. وليس بالضرورة أن تكون قصة الشخصية معقدة ومطولة فقد تكون بسيطة بحسب حجم اللعبة. خذ لعبة الطيور الغاضبة Angry Birds على سبيل المثال، إذ أنّ هذه الطيور غاضبة بسبب أن الخنازير الأشرار في اللعبة قد اختطفوا بيوض صغارهم وهذا ما يمنح للعبة دافعًا وسببًا لوجود الشخصيات في عالم اللعبة الإلكترونية.
</p>

<h3 id="-3">
	ثالثًا: مظهر الشخصية
</h3>

<p>
	يلعب مظهر الشخصية وتصميمها المرئي دورًا مهمًا في إنشاء الشخصية وتصميمها إذ يجب أن يكون مظهر الشخصية جذابًا وفريدًا ويعكس شخصيتها ودورها في اللعبة وعند تصميم مظهر الشخصية يجب أن تهتم بعدة عوامل إلى جانب ملامحها الجسدية والنفسية مثل زي الشخصية حيث تلعب أزياء شخصيات ألعاب الفيديو دورًا مهمًا في المساهمة في نجاح اللعبة وتساعد في تحديد الهوية المرئية للشخصية وتجعلها أكثر قابلية للتمييز والتذكر بالنسبة للاعب.
</p>

<p>
	كما تعكس أزياء الشخصيات أيضًا إعدادات اللعبة أو الفترة الزمنية لها على سبيل المثال، قد يشتمل زي إحدى الشخصيات في لعبة خيالية من العصور الوسطى على دروع وتروس، بينما قد تتمتع الشخصية في لعبة خيال علمي مستقبلية بملابس عالية التقنية. علاوة على ذلك، يمكن أن تؤثر أزياء الشخصيات أيضًا على آليات اللعب من خلال توفير مكافآت أو قدرات متنوعة. على سبيل المثال، قد يوفر الزي دفاعًا معززًا أو خفة الحركة، أو يمنح قدرات خاصة يمكن استخدامها بشكل استراتيجي أثناء اللعب.
</p>

<h3 id="-4">
	رابعًا: حركات الشخصية
</h3>

<p>
	والمقصود بحركات الشخصية الأفعال التي تقوم بها شخصية اللعبة مثل المشي او الجري أو القفز أو التسلق أو إطلاق النار …إلخ. وتؤثر انسيابية واستجابة حركات الشخصية بشكل مباشر على تجربة اللاعب وقدرته على التنقل في عالم اللعبة بفعالية. حيث يمكن للحركات السلسة والطبيعية أن تجعل تجربة اللعب أكثر متعة وواقعية وتعزز تفاعل اللاعب مع اللعبة وتطيل مدة اللعب، بالمقابل ستتسبب حركات الشخصية المصممة بشكل سيء في إحباط اللاعبين وتقلل من استمتاعهم باللعبة.
</p>

<h2 id="-5">
	خطوات تصميم شخصيات الألعاب
</h2>

<p>
	بعد تعرّفنا على معايير تصميم الشخصية الناجحة، كيف تبدأ فعلًا ببدء التصميم؟ نستطيع تجزئة خطوات تصميم الشخصية إلى ما يلي:
</p>

<ol>
	<li>
		تحديد تصنيف الشخصية الأولية.
	</li>
	<li>
		بناء قصة الشخصية.
	</li>
	<li>
		البحث عن موارد لشخصيات الألعاب.
	</li>
	<li>
		استخدام أدوات وبرامج مخصصة لتصميم الشخصية.
	</li>
</ol>

<h3 id="1-1">
	1. تحديد الشخصية الأولية
</h3>

<p>
	قد تكون الشخصية بعد الانتهاء من تصميمها فريدةً من نوعها بمزاياها المختلفة من صفات جسدية وحركة وشكل وقصة، إلا أن تصميم الشخصية يبدأ دائمًا بتحديد شخصيتها الأولية أو الابتدائية، حيث أن تصنيف شخصيات الألعاب يحدد توجه الشخصية العام وكيفية تطبيق تصميمك عليها لتلائمها، وإليك بعض الأمثلة على أشهر شخصيات الألعاب الأولية التي يمكنك اختيارها للعبتك الإلكترونية:
</p>

<ul>
	<li>
		<strong>شخصية البطل</strong>: وهي الشخصية التقليدية في معظم ألعاب الفيديو التي تواجه التحديات بقوة وتنتصر عليها، وتتميز هذه الشخصية بشجاعتها وأخلاقياتها العالية، مثال على هذه الشخصية شخصية سوبرمان أو شخصية لينك من سلسلة أسطورة زيلدا The Legend Of Zelda.
	</li>
	<li>
		<strong>شخصية الطيب</strong>: تتميز هذه الشخصية بإنسانيتها وشغفها إلا أنها قد تكون غير منطقية في بعض الأحيان مما يتسبب في وقوعها في بعض المشكلات. مثال على هذه الشخصية هي شخصية الكوماندر شيبرد في لعبة ماس إيفيكت Mass Effect.
	</li>
	<li>
		<strong>شخصية الساحر</strong>: هي شخصية لعبة غامضة تملك حيلًا وأسرار خاصة لتحقيق غاياتها، مثال على هذه الشخصية شخصية هاري بوتر Harry Potter وشخصية جاندالف Gandalf في لعبة أمير الخواتم The Lord Of The Rings: Shadow of Mordor.
	</li>
</ul>

<p>
	كما يوجد عدة أنواع أخرى من الشخصيات، كشخصية المتمرد وشخصية المغامر والمحب للاستكشاف والقدوة والساذج والمنبوذ والشرير، وقد تتشارك بعض الشخصيات فيما بينها بعدد من الصفات ومن المهم أن تحدد الشخصية الأولية لكل شخصية تستخدمها في ألعابك لأنها تساعدك في اختيار التصميم الملائم بشكل أفضل.
</p>

<h3 id="2-1">
	2. بناء قصة الشخصية
</h3>

<p>
	بعد تحديد تصنيف شخصيات الألعاب الأولية تحتاج للبدء بتخيل قصة الشخصية وتحديد سبب وجودها في عالم اللعبة ودورها فهذا أمر مهم وذلك لتجعل لاعبي اللعبة يرتبطون عاطفيًا مع الشخصية ويحزنون لحزنها ويفرحون لفرحها. لذا تأكّد من تحديد قصة حياة الشخصية وماضيها وهدفها في قصة اللعبة كما يساعد ذلك أيضًا مصممي الغرافيك ومبرمحي الألعاب على الاعتماد على هذه المعلومات في تصميم الشخصية بصريًا بشكل يلائم قصتها وبرمجة تحركاتها بالشكل الصحيح المناسب لتحقيق أهدافها.
</p>

<h3 id="3-1">
	3.البحث عن مراجع لشخصيات الألعاب
</h3>

<p>
	عندما تفكر في اختيار شخصيات ألعابك ستجد أمامك خيارين الأول هو تصميم الشخصية من الصفر باستخدام أدوات وبرامج مخصصة أو استخدام شخصيات جاهزة، فمن المرجّح أنك عندما تفكر بتصميم لشخصية لعبة خاصة بك ستجد رسومات لشخصيات افتراضية تخيلية تطابق الشخصية التي تريد أن تكون موجودة في لعبتك ويمكنك في هذه الحالة الاعتماد عليها بدلًا من تصميمها من الصفر.
</p>

<p>
	هناك عشرات المصادر على الإنترنت التي تستطيع من خلالها تحميل عدد من الشخصيات تشابه الشخصية التي تريدها ومن ثم التعديل عليها أو ربما حتى استخدامها مباشرةً في لعبتك الإلكترونية دون أي تعديلات إن وجدت أنها مطابقة للمواصفات التي تريدها. نذكر من هذه المصادر:
</p>

<ul>
	<li>
		<a href="https://assetstore.unity.com/" rel="external nofollow">متجر محرك يونيتي Unity</a>
	</li>
	<li>
		<a href="https://www.unrealengine.com/marketplace/en-US/store" rel="external nofollow">متجر محرك أنريل Unreal</a>
	</li>
	<li>
		<a href="https://kenney.nl/assets" rel="external nofollow">متجر كيني</a> الذي يحتوي على شخصيات مجانية
	</li>
	<li>
		<a href="https://itch.io/game-assets" rel="external nofollow">متجر itch.io</a> الشهير
	</li>
	<li>
		موقع <a href="https://stock.adobe.com/" rel="external nofollow">Adobe Stock</a>
	</li>
	<li>
		موقع <a href="https://www.pinterest.com/" rel="external nofollow">Pinterest</a>
	</li>
</ul>

<p>
	وغيرها من المواقع التي توفر مجموعات منوعة من الصور والتصاميم لشخصيات ألعاب مجانية أو مدفوعة يمكنك استخدامها في لعبتك الإلكترونية، لكن انتبه لصيغة الشخصية وتوافقها مع <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محرك الألعاب</a> الذي تود استخدامه في برمجة اللعبة أو تحريك الشخصية وهذا الأمر مفيد ويوفر عليك الكثير من الوقت خصوصًا لو كنت تعمل ضمن فريق حيث أن مصمم الشخصية مختلف عن محركها وعن مبرمجها.
</p>

<h3 id="4-1">
	4. استخدام أدوات وبرامج مخصصة لتصميم الشخصية
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="141272" href="https://academy.hsoub.com/uploads/monthly_2024_01/---.png.d5f9881c3bbcee5d4bf0e30707ba96ca.png" rel=""><img alt="برامج تصميم شخصيات الألعاب" class="ipsImage ipsImage_thumbnailed" data-fileid="141272" data-ratio="62.67" data-unique="mzvh3pd12" style="width: 400px; height: auto;" width="500" src="https://academy.hsoub.com/uploads/monthly_2024_01/---.thumb.png.146b2e60413e16b1de06e6a3b6c1d90f.png"> </a>
</p>

<p>
	إذا كنت مهتمًا بتصميم شخصيات الألعاب من الصفر أو لم تعثر على تصميم شخصية يناسب ما رسمته في مخيلتك في المواقع التي توفر مصادر لشخصيات للألعاب، فستجد عدة أدوات وبرامج مخصصة تساعدك على تصميم شخصيات الألعاب وتحويلها من أفكار إلى رسومات ثنائية أو ثلاثية الأبعاد جاهزة لبرمجتها ومن أشهر هذه البرامج نذكر:
</p>

<ul>
	<li>
		Piskel: هو تطبيق ويب مجاني ومفتوح المصدر يعمل في المتصفح ويمكنك كذلك تثبيته على أنظمة تشغيل لينكس وويندوز ويوفر العديد من الأدوات السهلة لإنشاء شخصيات ألعاب بسيطة ثنائية الأبعاد المعروفة باسم sprite وحفظها بتنسيق PNG أو GIF.
	</li>
	<li>
		GIMP: هو برنامج مفتوح المصدر لمعالجة الصور وهو يوفر إمكانية تصميم شخصيات ألعاب ثنائية الأبعاد وتصديرها إلى العديد من التنسيقات المختلفة.
	</li>
	<li>
		Sketchbook: برنامج مميز يوفر إصدار مجاني لرسم شخصيات الألعاب ثنائية الأبعاد ويوفر عدة خيارات لتصدير الرسومات.
	</li>
	<li>
		بليندر <a href="https://academy.hsoub.com/design/3d/blender/" rel="">Blender</a>: هو برنامج مجاني ومفتوح المصدر ومجاني لتصميم ورسم الشخصيات ثلاثية الأبعاد ويمكنه تصدير الرسومات إلى العديد من تنسيقات الملفات الجاهز لاستخدامها في برامج تطوير الألعاب.
	</li>
	<li>
		Magic Voxel: هو برنامج مجاني لتصميم شخصيات ألعاب ثلاثية ويمكنك من تصدير الرسومات إلى التنسيق OBJ. والبدء ببرمجتها في محركات الألعاب.
	</li>
	<li>
		MakeHuman: برنامج مفتوح المصدر لتصميم شخصيات ألعاب ثلاثية قريبة من الواقع.
	</li>
	<li>
		SculptGL: برنامج فعال يعمل في المتصفح ويمكنك من تصميم الأشكال والشخصيات ثلاثية الأبعاد بسهولة.
	</li>
	<li>
		مايا Maya: هو برنامج احترافي مدفوع من شركة Autodesk مخصص للهندسة المعمارية والتصاميم الداخلية كما يستخدم في صناعة الأفلام ورسم ونمذجة شخصيات الألعاب ثلاثية الأبعاد ويوفر ميزات متقدمة للتحكم بإضاءتها وحركتها وغيرها من المميزات الاحترافية.
	</li>
	<li>
		<a href="https://academy.hsoub.com/design/3d/3ds-max/" rel="">3Ds Max</a>: برنامج مدفوع من شركة Autodesk يشابه برنامج مايا ويوفر مجموعة قوية من الأدوات لنمذجة لتصميم ونمذجة شخصيات الألعاب والرسوم المتحركة ثلاثية الأبعاد ويوفر أيضًا تراخيص مجانية للطلاب.
	</li>
</ul>

<p>
	كانت هذه قائمة بأبرز أدوات تصميم شخصيات الألعاب وهناك الكثير غيرها، لذا عليك اختيار الأداة التي تناسبك يعتمد على طبيعة الرسومات التي تود الحصول عليها ثنائية الأبعاد 2D أم ثلاثية الأبعاد 3D، وعلى ميزانيك وخبرتك في استخدام الأداة، وفي محرك اللعبة الذي ستجلب هذه الشخصية إليه وتبرمجها فيه فبعض محركات الألعاب تدعم تنسيقات ملفات محددة فقط.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلة صناعة الألعاب ثنائية وثلاثية الأبعاد وابتكر ألعاب ممتعة تفاعلية ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<h2 id="-6">
	أمثلة لأبرز شخصيات الألعاب المصممة جيدًا
</h2>

<p>
	تضفي الشخصية المصممة بدقة الحياة على اللعبة، مما يجعلها أكثر جاذبية وبقاء في الذهن. ومن أهم شخصيات الألعاب وسنختم المقال بأكثر شخصيات الألعاب شهرة بين جمهور اللاعبين ونكتشف سبب شهرتها والتعلق بها بالرغم من بساطة بعضها.
</p>

<h3 id="-7">
	شخصية لعبة ماريو
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="jpg" data-fileid="141271" href="https://academy.hsoub.com/uploads/monthly_2024_01/super-mario-.jpg.8f4d719a4ed747cacc522df0143c1636.jpg" rel=""><img alt="super mario شخصية" class="ipsImage ipsImage_thumbnailed" data-fileid="141271" data-ratio="57.72" data-unique="oecfqh2m0" style="width: 400px; height: auto;" width="447" src="https://academy.hsoub.com/uploads/monthly_2024_01/super-mario-.jpg.8f4d719a4ed747cacc522df0143c1636.jpg"> </a>
</p>

<p>
	أصبح ماريو، الشخصية الشهيرة من سلسلة سوبر ماريو رمزًا لها بالرغم من بساطة تصميمه، ولعل السر في شخصية لعبة ماريو هو مظهره المميز وكلامه وأفعاله. فيمكن التعرف على مظهر ماريو المحبوب على الفور بفضل قبعته الحمراء المميزة، وبدلته الزرقاء، وشاربه الكثيف إلى جانب صوته عالي النبرة وعباراته الشهيرة "هذا أنا ماريو!" التي جعلت منه شخصية محبوبة لأجيال من اللاعبين، كما أن خفة الحركة التي يتمتع بها ماريو في القفز والجري والمناورة عبر المستويات المختلفة جعلت منه شخصيةً ممتعة للتحكم واللعب بها، أضف إلى ذلك دافعه طوال اللعبة لإنقاذ الأميرة المخطوفة من قبل السلحفاة الشريرة باوزر.
</p>

<h3 id="-8">
	شخصية باك مان
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="141270" href="https://academy.hsoub.com/uploads/monthly_2024_01/pac-mancharacter.png.2e30d20e895617395fdfc4541b8fae44.png" rel=""><img alt="pac man character" class="ipsImage ipsImage_thumbnailed" data-fileid="141270" data-ratio="62.58" data-unique="r2qh2wn9x" style="width: 400px; height: auto;" width="449" src="https://academy.hsoub.com/uploads/monthly_2024_01/pac-mancharacter.thumb.png.9dbeb7df3074f29ffdd723a47120d6d9.png"> </a>
</p>

<p>
	حققت باك مان، الشخصية الدائرية الصفراء من <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">لعبة الآركيد Arcade</a> شهرة واسعة من خلال تصميمها وأسلوب لعبها البسيط. إذ أصبحت شخصيتها الأيقونية رمزًا لألعاب الفيديو من نوع الآركيد التقليدية التي كانت مشهورة في فترة سابقة، وعلى الرغم من القيود الموجودة على أجهزة ألعاب الفيديو آنذاك إلا أن مصممي اللعبة استطاعوا ببراعة خلق شخصية لعبة بقيت عالقةً في أذهان الجميع لحد اليوم على الرغم من بساطتها. فمن منا لا يتذكر باك مان بلونه الأصفر الفاقع وفمه المفتوح والأشباح الملونة التي تلاحقه!
</p>

<p>
	ولعل هذه الأمثلة تجعلنا نلاحظ أنه ليس من الضروري للشخصية أن تمتلك الكثير من الأشياء والمميزات لتصبح شخصية لعبة ناجحة، فشخصية باك مان ما هي سوى نقطة صفراء في غاية البساطة، ومع ذلك فقد حصدت الكثير من المعجبين.
</p>

<h3 id="godofwar">
	شخصية لعبة كريتوس من سلسلة God of War
</h3>

<p>
	استطاعت شخصية كريتوس الوصول إلى الشهرة وجذب أعداد هائلة الجماهير من خلال التركيز على قصة الشخصية وتصميم شكلها بناءً على ذلك، متضمنًا تصميم جسد الشخصية ببنية قوية وملابس ملائمة لدوره في اللعبة بشكل مثالي، فهذه التفاصيل بالإضافة للتأثيرات الصوتية جعلت منه شخصية مهيبة، كما أن قدراته القتالية المتعددة أضافت إلى كريتوس إحساس القوة والتصميم، وهو الشيء ذاته الذي انجذب له الجمهور وجعلت منه شخصية هائلة لا تُنسى. بالإضافة إلى ذلك، فإن أسلوب كريتوس القتالي الوحشي، جنبًا إلى جنب مع خلفيته المعقدة وعمقه العاطفي، جعل منه شخصية مقنعة ومبدعة في عالم ألعاب الفيديو.
</p>

<p>
	إلى هنا نكون قد وصلنا لنهاية مقالنا الذي فصلنا فيه مرحلة اختيار شخصيات الألعاب التي تعد من أهم مراحل <a href="https://academy.hsoub.com/programming/game-development/" rel="">صناعة ألعاب الفيديو</a>، حيث يقوم مصمم اللعبة بإنشاء المفهوم والأسلوب والعمل الفني الكامل للشخصية من الصفر بعملية معقدة ودقيقة يضمن بها تحليل السمات الشخصية لشخصيات الألعاب من أجل إضافة الحياة إليها وجعلها أكثر واقعيّة.
</p>

<p>
	ويجب على من يقوم بهذه الوظيفة أن يتمتع بالموهبة والمهارات المتطورة فتصميم شخصية اللعبة يعد جانبًا حيويًا في تصميم ألعاب الفيديو ومن شأنه أن يترك صدى لدى اللاعبين على مستوى واسع من خلال التركيز على الخصائص الجسدية والنفسية والسلوك والنبرة والمظهر وغيرها من التفاصيل.
</p>

<h2 id="-9">
	الخلاصة
</h2>

<p>
	إن التركيز على شخصيات ألعاب الفيديو الخاصة بك يضمن لك ارتباط اللاعبين بلعبتك ارتباطًا عميقًا ويزيد من شعبية اللعبة، ومن شأنه أيضًا أن يكوّن مجتمعًا من الأشخاص الذين ينتظرون جديد الشخصية من قصص وتطوّرات متعلقة بها فيما إذا أردت تطوير جزء آخر أو لعبة مشتقة من لعبتك السابقة. لذا، تأكد من أنك تمنح هذا الجانب من تصميم لعبتك وقتًا وجهدًا مناسبين.<br>
	هل هناك لعبةٌ حاضرة في ذهنك من أيام الطفولة بفضل شخصياتها المنفّذة والمصممة بشكل جيد؟ شاركها معنا!
</p>

<h2 id="-10">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">مطور الألعاب: من هو وما هي مهامه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">نبذة عن صناعة الألعاب ومحرك Unity3D</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%B5%D9%88%D9%85-%D9%81%D9%8A-unity3d-r134/" rel="">إنشاء الوحدات البنائية وشخصيات الخصوم في Unity3D</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8%D8%9F-r2068/" rel="">ما هي برمجة الألعاب؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2212</guid><pubDate>Thu, 04 Jan 2024 12:09:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x645;&#x62D;&#x631;&#x631; &#x645;&#x62D;&#x631;&#x643; &#x627;&#xFEF7;&#x644;&#x639;&#x627;&#x628; &#x62C;&#x648;&#x62F;&#x648; Godot</title><link>https://academy.hsoub.com/programming/game-development/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%85%D8%AD%D8%B1%D8%B1-%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%EF%BB%B7%D9%84%D8%B9%D8%A7%D8%A8-%D8%AC%D9%88%D8%AF%D9%88-godot-r2183/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_11/godot_2.png.03ce0decfca949a1b93ecd184649b9f6.png" /></p>
<p>
	نعرض في هذا المقال لمحة موجزة عن واجهة <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%AC%D9%88%D8%AF%D9%88-godot/" rel="">محرك الألعاب جودو Godot</a>، ونلقي نظرة على شاشاتها المختلفة وقوائمها كي تعرف كيف ترتب الواجهة بما يلائمك.
</p>

<h2 id="">
	مدير المشروع
</h2>

<p>
	وهي أول نافذة تظهر عندما تُشغّل جودو Godot، وتضم نافذتين فرعيتين أولهما "المشاريع الخاصة Local projects" التي تتيح لك إدارة المشاريع الموجودة على حاسوبك وإدراج أو إنشاء مشاريع جديدة وغيرها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138988" href="https://academy.hsoub.com/uploads/monthly_2023_11/01_editor_intro_project_manager.png.e5592e105725d24b0878ca0eb884813c.png" rel=""><img alt="01 editor intro project manager" class="ipsImage ipsImage_thumbnailed" data-fileid="138988" data-unique="rhy4amswl" src="https://academy.hsoub.com/uploads/monthly_2023_11/01_editor_intro_project_manager.thumb.png.5986c6e675cb240d41323b7d23bba7be.png"> </a>
</p>

<p>
	أما النافذة الأخرى فهي "مشاريع مكتبة الملحقات Asset Library Projects" التي تساعدك على البحث عن مشاريع تجريبية في مكتبة الموجودات <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D8%A7%D9%84%D9%85%D9%82%D8%B5%D9%88%D8%AF-%D8%A8%D9%85%D8%B5%D8%B7%D9%84%D8%AD-%D9%85%D9%81%D8%AA%D9%88%D8%AD-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-open-source%D8%9F-r885/" rel="">مفتوحة المصدر</a> وتضم الكثير من المشاريع التي يطوّرها مجتمع جودو.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138987" href="https://academy.hsoub.com/uploads/monthly_2023_11/02_editor_intro_project_templates.png.cd7d8b00ab46d59f127ea321c433dc36.png" rel=""><img alt="02_editor_intro_project_templates.png" class="ipsImage ipsImage_thumbnailed" data-fileid="138987" data-ratio="58.56" data-unique="yqdc146cn" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_11/02_editor_intro_project_templates.thumb.png.61b93d5a39eba4c5a121596e48383c1a.png"></a>
</p>

<p>
	تستطيع أيضًا تغيير لغة المحرر الافتراضية (اﻹنكليزية) من خلال النقر على زر القائمة المنسدلة أعلى ويمين نافذة المحرك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138986" href="https://academy.hsoub.com/uploads/monthly_2023_11/03_editor_intro_language.png.14ff04457549978ae65e5e1d006bcca2.png" rel=""><img alt="03 editor intro language" class="ipsImage ipsImage_thumbnailed" data-fileid="138986" data-unique="8f7fyuz0v" src="https://academy.hsoub.com/uploads/monthly_2023_11/03_editor_intro_language.thumb.png.fe1026880de749c68ca322100084968b.png"> </a>
</p>

<h2 id="-1">
	نظرة أولى إلى محرر جودو
</h2>

<p>
	عندما تفتح مشروعًا موجودًا أو تنشئ مشروعًا جديدًا، سيعرض لك المحرّك نافذة المحرر كما في لقطة الشاشة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138985" href="https://academy.hsoub.com/uploads/monthly_2023_11/04_editor_intro_editor_empty.png.5ca13a1608a41a980896bcd05a1bbadd.png" rel=""><img alt="04 editor intro editor empty" class="ipsImage ipsImage_thumbnailed" data-fileid="138985" data-unique="shrntjcbz" src="https://academy.hsoub.com/uploads/monthly_2023_11/04_editor_intro_editor_empty.thumb.png.3cba0865a0c0b8eb273e7e5c761301b7.png"> </a>
</p>

<p>
	تتكون النافذة من قوائم وشاشات رئيسية وأزرار للتحكم أعلى النافذة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="webp" data-fileid="138984" href="https://academy.hsoub.com/uploads/monthly_2023_11/05_editor_intro_top_menus.webp.8cae2b7c97e343532795e658fb49b84f.webp" rel=""><img alt="05_editor_intro_top_menus.webp" class="ipsImage ipsImage_thumbnailed" data-fileid="138984" data-ratio="3.56" data-unique="3of7iinev" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_11/05_editor_intro_top_menus.thumb.webp.a135c6cdc6048113e011f9fbfc9ac5f9.webp"></a>
</p>

<p>
	ستجد في منتصف الشاشة نافذة العرض مع شريط أدواتها في الأعلى، وستجد ضمن الشريط أدوات لتحريك أو تحجيم أو قفل عقد المشهد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138983" href="https://academy.hsoub.com/uploads/monthly_2023_11/06_editor_intro_3d_viewport.png.94489ff67bf76dee734e31a152cbbe31.png" rel=""><img alt="06 editor intro 3d viewport" class="ipsImage ipsImage_thumbnailed" data-fileid="138983" data-unique="c8qpdxrt3" src="https://academy.hsoub.com/uploads/monthly_2023_11/06_editor_intro_3d_viewport.png.94489ff67bf76dee734e31a152cbbe31.png"> </a>
</p>

<p>
	وستجد على طرفي نافذة العرض حاويات docks وفي أسفلها لوحة أدوات سفلية. يتغيّر شريط اﻷدوات وفقًا لسياق العمل والعقدة المختارة. إليك لقطة شاشة شريط أدوات مشهد ثنائي البعد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138982" href="https://academy.hsoub.com/uploads/monthly_2023_11/07_editor_intro_toolbar_2d.png.01b7826e573148a15880aab5bd9af3c7.png" rel=""><img alt="07 editor intro toolbar 2d" class="ipsImage ipsImage_thumbnailed" data-fileid="138982" data-unique="n61ltcsw3" src="https://academy.hsoub.com/uploads/monthly_2023_11/07_editor_intro_toolbar_2d.png.01b7826e573148a15880aab5bd9af3c7.png"> </a>
</p>

<p>
	وشريط أدوات مشهد ثلاثي اﻷبعاد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138981" href="https://academy.hsoub.com/uploads/monthly_2023_11/08_editor_intro_toolbar_3d.png.933c8176047472eaec7a0e4132f6e13d.png" rel=""><img alt="08 editor intro toolbar 3d" class="ipsImage ipsImage_thumbnailed" data-fileid="138981" data-unique="0ebr8x6oh" src="https://academy.hsoub.com/uploads/monthly_2023_11/08_editor_intro_toolbar_3d.png.933c8176047472eaec7a0e4132f6e13d.png"> </a>
</p>

<p>
	لنلق نظرة اﻵن إلى الحاويات وأولها الحاوية "نظام الملفات FileSystem" التي تعرض قائمة بملفات المشروع بما في ذلك السكربتات والصورة ومقاطع الصوت وغيرها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138980" href="https://academy.hsoub.com/uploads/monthly_2023_11/09_editor_intro_filesystem_dock.png.f528667da6a5aee667e6a8a6222f2618.png" rel=""><img alt="09 editor intro filesystem dock" class="ipsImage ipsImage_thumbnailed" data-fileid="138980" data-unique="q4637fd5b" src="https://academy.hsoub.com/uploads/monthly_2023_11/09_editor_intro_filesystem_dock.png.f528667da6a5aee667e6a8a6222f2618.png"> </a>
</p>

<p>
	أما الحاوية الثانية فهي "المشهد Scene" التي تعرض قائمة بالعقد الفعّالة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138979" href="https://academy.hsoub.com/uploads/monthly_2023_11/10_editor_intro_scene_dock.png.e85a560295d8e3a3a4df23276f42f974.png" rel=""><img alt="10 editor intro scene dock" class="ipsImage ipsImage_thumbnailed" data-fileid="138979" data-unique="utj3d0dyo" src="https://academy.hsoub.com/uploads/monthly_2023_11/10_editor_intro_scene_dock.png.e85a560295d8e3a3a4df23276f42f974.png"> </a>
</p>

<p>
	وتتيح لك حاوبة "الفاحص Inspector" تعديل خصائص العقدة المختارة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138978" href="https://academy.hsoub.com/uploads/monthly_2023_11/11_editor_intro_inspector_dock.png.96d6fa954016f1bfaef9ab02dcede7ca.png" rel=""><img alt="11 editor intro inspector dock" class="ipsImage ipsImage_thumbnailed" data-fileid="138978" data-unique="exddjsju1" src="https://academy.hsoub.com/uploads/monthly_2023_11/11_editor_intro_inspector_dock.png.96d6fa954016f1bfaef9ab02dcede7ca.png"> </a>
</p>

<p>
	تظهر لوحة اﻷدوات السفلية تحت نافذة العرض وتضم طرفية التنقيح debug console ومحرر الرسوم المتحركة والمازج الصوتي وغيرهم من اﻷدوات. تشغل اللوحة مساحة لا بأس بها لهذا تكون مخفية افتراضيًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138977" href="https://academy.hsoub.com/uploads/monthly_2023_11/12_editor_intro_bottom_panels.png.ad158da0376482bf5d775d3dd0642265.png" rel=""><img alt="12 editor intro bottom panels" class="ipsImage ipsImage_thumbnailed" data-fileid="138977" data-unique="sztsy1cnp" src="https://academy.hsoub.com/uploads/monthly_2023_11/12_editor_intro_bottom_panels.png.ad158da0376482bf5d775d3dd0642265.png"> </a>
</p>

<p>
	عندما تنقر على أي عنصر من اللوحة تتمدد شاقوليًا. إليك لقطة شاشة للوحة وهي تعرض المحرر الرسومي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138976" href="https://academy.hsoub.com/uploads/monthly_2023_11/13_editor_intro_bottom_panel_animation.png.8ede5125366b99cea7f7dfdc35225f3f.png" rel=""><img alt="13 editor intro bottom panel animation" class="ipsImage ipsImage_thumbnailed" data-fileid="138976" data-unique="pel3n2ace" src="https://academy.hsoub.com/uploads/monthly_2023_11/13_editor_intro_bottom_panel_animation.png.8ede5125366b99cea7f7dfdc35225f3f.png"> </a>
</p>

<h2 id="-2">
	الشاشات الرئيسية اﻷربعة
</h2>

<p>
	هناك أربعة أزرار للشاشات الرئيسية أعلى المحرر وهي "الثنائي 2D" و "الثلاثي 3D" و "Script" و "AssetLib".
</p>

<h3 id="2d">
	الشاشة 2D
</h3>

<p>
	ستستخدم الشاشة ثنائية البعد 2D لمختلف أنواع الألعاب، فإضافة إلى اﻷلعاب ثنائية اﻷبعاد ستستخدم هذه الشاشة لبناء الواجهات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138975" href="https://academy.hsoub.com/uploads/monthly_2023_11/14_editor_intro_workspace_2d.png.272f67e0fc54c3600e574ca73e5ed04e.png" rel=""><img alt="14 editor intro workspace 2d" class="ipsImage ipsImage_thumbnailed" data-fileid="138975" data-unique="f62kb7uqd" src="https://academy.hsoub.com/uploads/monthly_2023_11/14_editor_intro_workspace_2d.thumb.png.7b66c69188349d56a26040c238bda75b.png"> </a>
</p>

<h3 id="3d">
	الشاشة 3D
</h3>

<p>
	تتعامل في النافذة ثلاثية اﻷبعاد مع الشبكات واﻷضواء ومراحل تصميم اﻷلعاب ثلاثية الأبعاد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138974" href="https://academy.hsoub.com/uploads/monthly_2023_11/15_editor_intro_workspace_3d.png.1290d5797be75c3c23944f1daa54f029.png" rel=""><img alt="15 editor intro workspace 3d" class="ipsImage ipsImage_thumbnailed" data-fileid="138974" data-unique="ouc3ok6xu" src="https://academy.hsoub.com/uploads/monthly_2023_11/15_editor_intro_workspace_3d.thumb.png.3f72d9e8b5d9986ef620abb400dbb512.png"> </a>
</p>

<p>
	<strong>ملاحظة</strong>: بالنقر على الزر "perspective" تحت شريط اﻷدوات سيفتح لك قائمة بخيارات تتعلق بالمشهد ثلاثي اﻷبعاد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138973" href="https://academy.hsoub.com/uploads/monthly_2023_11/16_editor_intro_3d_viewport_perspective.png.81ed7ee8a78bc3b9a79dbd9d7fb44052.png" rel=""><img alt="16 editor intro 3d viewport perspective" class="ipsImage ipsImage_thumbnailed" data-fileid="138973" data-unique="dx4r53gkn" src="https://academy.hsoub.com/uploads/monthly_2023_11/16_editor_intro_3d_viewport_perspective.png.81ed7ee8a78bc3b9a79dbd9d7fb44052.png"> </a>
</p>

<h3 id="script">
	الشاشة Script
</h3>

<p>
	تعرض هذه الشاشة محرر الشيفرة المتكامل والمزود بمنقح وآلية ﻹكمال الشيفرة ومراجع مدمجة إلى الشيفرة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138972" href="https://academy.hsoub.com/uploads/monthly_2023_11/17_editor_intro_workspace_script.png.4fc7764b3f85f556c67bc2a15e2fc40f.png" rel=""><img alt="17 editor intro workspace script" class="ipsImage ipsImage_thumbnailed" data-fileid="138972" data-unique="zr0fw6v5g" src="https://academy.hsoub.com/uploads/monthly_2023_11/17_editor_intro_workspace_script.png.4fc7764b3f85f556c67bc2a15e2fc40f.png"> </a>
</p>

<h3 id="assetlib">
	الشاشة AssetLib
</h3>

<p>
	تضم الشاشة مكتبة من الإضافات مفتوحة المصدر والسكربتات وغيرها من الموجودات التي تساعد في مشروعك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138971" href="https://academy.hsoub.com/uploads/monthly_2023_11/18_editor_intro_workspace_assetlib.png.88715242469c360fbf592ed74b209157.png" rel=""><img alt="18 editor intro workspace assetlib" class="ipsImage ipsImage_thumbnailed" data-fileid="138971" data-unique="xlfvt176p" src="https://academy.hsoub.com/uploads/monthly_2023_11/18_editor_intro_workspace_assetlib.thumb.png.c18c06cb8d6cae2912fd59b72dcf6dae.png"> </a>
</p>

<h2 id="-3">
	مراجع مدمجة إلى اﻷصناف
</h2>

<p>
	يزوّدك جودو بمراجع مدمجة إلى اﻷصناف وتوابعها وخاصياتها وثوابتها وإشاراتها ويساعدك في البحث عنها بسهولة بإحدى الطرق التالية:
</p>

<ul>
	<li>
		الضغط على زر <code>F1</code> (أو Alt+Space في ماك أو fn+F1 في الحواسب المحمولة التي تحتوي الزر fn).
	</li>
	<li>
		النقر على الزر "البحث في المساعدة Search help" في أعلى ويمين شاشة السكربت الرئيسية.
	</li>
	<li>
		النقر على قائمة "مساعدة Help" ثم "البحث في المساعدة Search Help".
	</li>
	<li>
		النقر على اسم الصنف أو الدالة او المتغير المدمج مع الضغط على الزر Ctrl.
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138970" href="https://academy.hsoub.com/uploads/monthly_2023_11/19_editor_intro_search_help_button.png.5cb3f69d2cee7470bd14e2b87928211c.png" rel=""><img alt="19 editor intro search help button" class="ipsImage ipsImage_thumbnailed" data-fileid="138970" data-unique="2dv6j7mzc" src="https://academy.hsoub.com/uploads/monthly_2023_11/19_editor_intro_search_help_button.thumb.png.d0c0b6ee05e404ff8b736bd262a3f4cd.png"> </a>
</p>

<p>
	عند استخدام أية طريقة من الطرق السابقة تنبثق نافذة اكتب فيها ما تريد البحث عنه، كما يمكنك استخدامها لتصفح الكائنات والتوابع المتاحة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138969" href="https://academy.hsoub.com/uploads/monthly_2023_11/20_editor_intro_search_help.png.fd72d2aee143d61a22e00d495e5a6f8a.png" rel=""><img alt="20 editor intro search help" class="ipsImage ipsImage_thumbnailed" data-fileid="138969" data-unique="zj6bmmls2" src="https://academy.hsoub.com/uploads/monthly_2023_11/20_editor_intro_search_help.png.fd72d2aee143d61a22e00d495e5a6f8a.png"> </a>
</p>

<p>
	انقر نقرة مضاعفة على العنصر لفتح الصفحة المتعلقة به ضمن نافذة السكربت.
</p>

<p>
	ترجمة -وبتصرف-للمقال <a href="https://docs.godotengine.org/en/stable/getting_started/introduction/first_look_at_the_editor.html" rel="external nofollow">First look at Godot's editor</a> من توثيق جودو الرسمي.
</p>

<h2 id="-4">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%AC%D9%88%D8%AF%D9%88-godot/" rel="">مدخل إلى محرك الألعاب جودو Godot</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/" rel="">مدخل إلى صناعة ألعاب المتصفح</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D8%AA%D8%A7%D9%87%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AD%D8%B1%D9%83-%D9%8A%D9%88%D9%86%D9%8A%D8%AA%D9%8A-unity-r1700/" rel="">برمجة لعبة متاهة باستخدام محرك يونيتي Unity</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2183</guid><pubDate>Sun, 26 Nov 2023 13:09:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628; &#x62C;&#x648;&#x62F;&#x648; Godot</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%AC%D9%88%D8%AF%D9%88-godot/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_11/godot1.png.941c049ae7a09f3b3cafddf943c01202.png" /></p>
<p>
	يساعدك هذا المقال على تقدير إذا ما كان محرّك الألعاب جودو Godot ملائمًا لاحتياجاتك، إذ سنقدم لك بعض الميزات العامة للمحرك كي نعرض ما يمكنك إنجازه، واﻹجابة عن أسئلة مثل " مالذي عليّ معرفته كي أبدأ العمل؟". لن تكون هذه المقدمة شاملة، لكننا سنقدّم الكثير من المفاهيم العامة في سلسلة المقالات المتتالية.
</p>

<h2 id="godot">
	ما هو محرك الألعاب جودو Godot
</h2>

<p>
	جودو Godot هو <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محرك ألعاب</a> ثنائية وثلاثية أبعاد عام اﻷغراض يدعم مختلف أنواع المشاريع، يساعدك في بناء اﻷلعاب والتطبيقات التي يمكن نشرها على الحواسب أو أجهزة الهاتف المحمول وعلى الويب أيضًا.
</p>

<p>
	يمكنك أيضًا بناء ألعاب مخصصة لمنصات الألعاب console games لكن ذلك يتطلب مهارات برمجية عالية أو الاستعانة بمطوّر ليساعدك على ذلك.
</p>

<p>
	<strong>ملاحظة:</strong> لا يمكن أن يقدّم لك مطورو جودو وسيلة مفتوحة المصدر لنقل اللعبة إلى منصات اﻷلعاب نظرًا لشروط الترخيص التي يضعها صانعو تلك المنصات. وبصرف النظر عن المحرّك الذي تستخدمه، سيكون إصدار نسخة من اللعبة على منصة أمرًا مجهدًا.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" id="ips_uid_5439_6" src="https://academy.hsoub.com/applications/core/interface/index.html" title="YouTube video player" width="560" data-embed-src="https://www.youtube.com/embed/O5suGXMNMdU?si=fsF514PDa2OGA6Ik"></iframe>
</p>

<h2 id="">
	ما الذي يمكن لمحرك جودو فعله؟
</h2>

<p>
	طوّر محرّك جودو أصلًا في المنزل من قبل استدوديو ألعاب أرجنتيني، وقد بدأ العمل عليه عام 2001 ثم حُسِّن كثيرًا منذ ذلك الحين وحتى إطلاق النسخة مفتوحة المصدر منه عام 2014.
</p>

<p>
	من اﻷلعاب التي طوّرت باستخدام جودو نذكر "Ex-Zodiac" و "Helms of Fury":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138968" href="https://academy.hsoub.com/uploads/monthly_2023_11/01_examples_of_games.png.b68390cbff49101ffba421c808409169.png" rel=""><img alt="01 examples of games" class="ipsImage ipsImage_thumbnailed" data-fileid="138968" data-unique="pfhrze9vb" src="https://academy.hsoub.com/uploads/monthly_2023_11/01_examples_of_games.png.b68390cbff49101ffba421c808409169.png"> </a>
</p>

<p>
	ومن التطبيقات التي تعتمد عليه نجد برنامج الرسم النقطي مفتوح المصدر "Pixelorama" وكذلك "voxel RPG creator":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138967" href="https://academy.hsoub.com/uploads/monthly_2023_11/02_example_of_app.png.3abc59571fc6653c59d09a797dc6a803.png" rel=""><img alt="02 example of app" class="ipsImage ipsImage_thumbnailed" data-fileid="138967" data-unique="f1t6y4g1b" src="https://academy.hsoub.com/uploads/monthly_2023_11/02_example_of_app.png.3abc59571fc6653c59d09a797dc6a803.png"> </a>
</p>

<h2 id="-1">
	كيف يعمل محرك جودو وكيف يبدو؟
</h2>

<p>
	يأتي المحرّك مع محرر ألعاب كامل الميزات وأدوات أصلية مدمجة معه لتقدم حلولًا لمعظم المهام الشائعة.من هذه اﻷدوات محرر شيفرة ومحرر رسوم متحركة ومحرر خرائط tilemap editor ومحرر المعالج اللوني shader ومنقح debugger ومحلل أداء Profiler وغيرها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138966" href="https://academy.hsoub.com/uploads/monthly_2023_11/03_godot_editor.png.1f17ab71b1df43774249096c493b3a61.png" rel=""><img alt="03 godot editor" class="ipsImage ipsImage_thumbnailed" data-fileid="138966" data-unique="66mfpvj4m" src="https://academy.hsoub.com/uploads/monthly_2023_11/03_godot_editor.png.1f17ab71b1df43774249096c493b3a61.png"> </a>
</p>

<p>
	يجاهد الفريق لتقديم محرر ألعاب غني بالميزات مع تجربة مستخدم تتطور باستمرار، وطالما أن هناك دائمًا ما يمكن تحسينه، سيستمر تطوير واجهة المحرّك. بإمكانك أيضًا العمل على برمجيات خارجية أخرى إن أردت، إذ يقدّم المحرك دعمًا رسميًا للمشاهد ثلاثية اﻷبعاد المصممة على <a href="https://academy.hsoub.com/design/3d/blender/" rel="">بلندر Blender</a> والإضافات الخاصة ببرنامج فيجوال ستديو كود و إيماكس Emacs لدعم البرمجة باستخدام GDScript و #C. كما يدعم المحرّك أيضًا فيجيوال ستوديو و<a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-c-r597/" rel="">لغة #C</a> على ويندوز.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138965" href="https://academy.hsoub.com/uploads/monthly_2023_11/04_godot_vscode.png.7bb9484359ad3616f0f92cc89ce0c818.png" rel=""><img alt="04 godot vscode" class="ipsImage ipsImage_thumbnailed" data-fileid="138965" data-unique="aw2q0ozib" src="https://academy.hsoub.com/uploads/monthly_2023_11/04_godot_vscode.thumb.png.ecdd7ccc42573087ef0e8ebd82c34eff.png"> </a>
</p>

<h2 id="-2">
	لغات البرمجة في جودو
</h2>

<p>
	بإمكانك استخدام لغة GDScript وهي <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغة برمجة</a> عالية التكامل خاصة بمحرك جودو وتتمتع بصياغة سهلة، أو يمكن استخدام لغة #C الشائعة الاستخدام في عالم الألعاب. هاتان اللغتان هما اللغتان الرئيسيتان المدعومتان من قبل محرك جودو. لكن باستخدام اﻹضافات عبر تقنية GDExtension، ستتمكن من كتابة ألعاب أو <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">خوارزميات</a> باستخدام <a href="https://academy.hsoub.com/programming/c/" rel="">لغة C</a> أو <a href="https://academy.hsoub.com/programming/cpp/" rel="">لغة ++C</a> دون إعادة تصريف المحرّك. وتستطيع استخدام هذه التقنية أيضًا في دمج مكتبات يؤمنها طرف آخر وغيرها من أدوات تطوير البرمجيات SDK مع المحرّك. كما يمكنك إضافة وحدات برمجية جاهزة وميزات إلى المحرّك وهي مجانية ومفتوحة المصدر.
</p>

<h2 id="-3">
	ما الذي علي معرفته لاستخدام محرك جودو؟
</h2>

<p>
	يُعد محرّك جودو محركًا مبنيًا على الكثير من الميزات، ومع وجود اﻵلاف منها ستجد أن هنالك الكثير لتتعلمه. وللاستفادة من كامل إمكانياته، لا بد أن تمتلك خلفية جيدة في البرمجة. ومع أننا نحاول جعل المحرّك سهل الاستخدام، سيفيدك تعلّم التفكير مثل المبرمجين.
</p>

<p>
	ويعتمد المحرّك على <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a>، لهذا ستساعدك معرفة بعض المفاهيم مثل الأصناف والكائنات في كتابة شيفرة أكثر فعالية. إما إذا كنت جديدًا في عالم البرمجة، ننصحك بالاطلاع على <a href="https://academy.hsoub.com/store/c1-%d8%af%d9%88%d8%b1%d8%a7%d8%aa-%d8%aa%d8%b9%d9%84%d9%8a%d9%85%d9%8a%d8%a9/" rel="">دورات تعلم البرمجة</a> التي تقدمها <a href="https://academy.hsoub.com" rel="external">أكاديمية حسوب</a> والتي تأخذك خطوة بخطوة إلى طريق احتراف البرمجة.
</p>

<h2 id="-4">
	المفاهيم الرئيسية لمحرك اﻷلعاب جودو
</h2>

<p>
	يتمحور عمل أي محرك ألعاب حول مجموعة من المفاهيم اﻷساسية التي تٌستخدم لبناء التطبيقات. وفي جودو، تُمثّل اللعبة على شكل <strong>شجرة tree</strong> مكوّنة من <strong>عقد nodes</strong> تتجمع مع بعضها لتشكل <strong>مشهدًا scene</strong>، وترتبط هذه العقد ببعضها كي تكون قادر على التخاطب فيما بينها باستخدام <strong>إشارات signals</strong>.
</p>

<p>
	سنلقي نظرة سريعة في هذا المقال على المفاهيم اﻷربعة السابقة ونتعلم طبيعة عمل المحرك.
</p>

<h3 id="scenes">
	المَشاهد scenes
</h3>

<p>
	تُجزّأ اللعبة في جودو إلى مشاهد يمكن استخدامها بشكل متكرر، وقد يكون المشهد شخصية أو سلاحًا أو قائمة ضمن واجهة المستخدم أو بيت أو مستوى كامل للعبة وعمومًا أي شيء قد تفكّر به. تتمتع مشاهد جودو بالمرونة، إذ تؤدي دور الكائنات الجاهزة prefab والمشاهد في محركات ألعاب أخرى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138964" href="https://academy.hsoub.com/uploads/monthly_2023_11/05_key_concepts_main_menu.png.6b24909cf3a8ca0e0bc74deb06d7d363.png" rel=""><img alt="05 key concepts main menu" class="ipsImage ipsImage_thumbnailed" data-fileid="138964" data-unique="jy4t5i5rt" src="https://academy.hsoub.com/uploads/monthly_2023_11/05_key_concepts_main_menu.thumb.png.eb8853c06104a807e346fb6a75a3197c.png"> </a>
</p>

<p>
	بإمكانك أيضًا إنشاء مشاهد متداخلة، كأن تضع شخصية ضمن مرحلة عن طريق سحب وافلات مشهد ضمن آخر ليكون ابنًا له.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138963" href="https://academy.hsoub.com/uploads/monthly_2023_11/06_key_concepts_example_scene.png.6694c5b1d1b543cdc1e0890791a574ae.png" rel=""><img alt="06 key concepts example scene" class="ipsImage ipsImage_thumbnailed" data-fileid="138963" data-unique="ja49dq34p" src="https://academy.hsoub.com/uploads/monthly_2023_11/06_key_concepts_example_scene.png.6694c5b1d1b543cdc1e0890791a574ae.png"> </a>
</p>

<h3 id="nodes">
	العقد nodes
</h3>

<p>
	يتكون المشهد من عقدة أو أكثر وتمثّل هذه العقد أصغر الكتل البنائية التي ترتبها في الشجرة. إليك مثالًا عن عقدة لشخصية في لعبة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138962" href="https://academy.hsoub.com/uploads/monthly_2023_11/07_key_concepts_character_nodes.png.74f6612926789bf2cf0a200fcccf9370.png" rel=""><img alt="07 key concepts character nodes" class="ipsImage ipsImage_thumbnailed" data-fileid="138962" data-unique="ebne2iphx" src="https://academy.hsoub.com/uploads/monthly_2023_11/07_key_concepts_character_nodes.png.74f6612926789bf2cf0a200fcccf9370.png"> </a>
</p>

<p>
	تتكون الشخصية من عقدة نوعها <code>CharacterBody2D</code> وتُدعى "Player" وضمنها ثلاث عقد أبناء هي <code>Camera2D</code> و <code>Sprite2D</code> و <code>CollisionShape2D</code>.
</p>

<p>
	<strong>ملاحظة</strong>: تنتهي أسماء العقد السابقة باللاحقة "2D" لأن المشهد ثنائي البعد. وتنتهي أسماء العقد في المشاهد ثلاثة اﻷلعاب باللاحقة "3D". وانتبه إلى أن العقد من النوع "الفراغي Spatial" لم تُعد تُسمّى "Node3D" ابتداءًا من الإصدار 4 لجودو.
</p>

<p>
	لاحظ كيف تبدو العقد والمشاهد متطابقة في المحرر، فعندما تُخزّن شجرة عقد على أنها مشهد، سيعرض المحرر عقدة واحدة ويخفي بنيتها الداخلية ضمنه.
</p>

<p>
	يقدّم جودو مكتبة قابلة للتوسّعة تضم أنواعًا مختلفة من العقد التي يمكن دمجها أو توسعتها لبناء عقد أقوى. فكل ما ستبنيه وتتعامل معه سواء في التصاميم ثنائية أو ثلاثية اﻷبعاد هي العقد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138961" href="https://academy.hsoub.com/uploads/monthly_2023_11/08_key_concepts_node_menu.png.0446b655cd94cca2ed79b97980041962.png" rel=""><img alt="08 key concepts node menu" class="ipsImage ipsImage_thumbnailed" data-fileid="138961" data-unique="9kqxhw3b7" src="https://academy.hsoub.com/uploads/monthly_2023_11/08_key_concepts_node_menu.png.0446b655cd94cca2ed79b97980041962.png"> </a>
</p>

<h3 id="scenetree">
	شجرة المشهد scene tree
</h3>

<p>
	تتجمع كل مشاهد اللعبة في شجرة من المشاهد أو (شجرة مشهد scene tree)، وشجرة المشاهد هي شجرة من العقد لكن من اﻷسهل تخيّل اللعبة كمشاهد لأنها تمثّل الشخصيات واﻷسلحة واﻷبواب والواجهات بطريقة أوضح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138960" href="https://academy.hsoub.com/uploads/monthly_2023_11/09_key_concepts_scene_tree.png.7b5d0584e679bcdb9b9ac0ff6695f648.png" rel=""><img alt="09 key concepts scene tree" class="ipsImage ipsImage_thumbnailed" data-fileid="138960" data-unique="ghjzectog" src="https://academy.hsoub.com/uploads/monthly_2023_11/09_key_concepts_scene_tree.png.7b5d0584e679bcdb9b9ac0ff6695f648.png"> </a>
</p>

<h3 id="signals">
	اﻹشارات signals
</h3>

<p>
	ترسل العقد إشارات عندما تقع بعض الأحداث، وتساعدك هذه الميزة في تأسيس اتصالات بين العقد دون أن تفعل ذلك يدويًا ضمن الشيفرة، مما يمنحك مرونة في هيكلة المشاهد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="138959" href="https://academy.hsoub.com/uploads/monthly_2023_11/10_key_concepts_signals.png.e5ca01ad000cfec6e232a6e3211d19a0.png" rel=""><img alt="10 key concepts signals" class="ipsImage ipsImage_thumbnailed" data-fileid="138959" data-unique="5n923w4h1" src="https://academy.hsoub.com/uploads/monthly_2023_11/10_key_concepts_signals.png.e5ca01ad000cfec6e232a6e3211d19a0.png"> </a>
</p>

<p>
	<strong>ملاحظة</strong>: تُعد اﻹشارات نسخة جودو من من نمط "المراقب observer" في محركات أخرى.
</p>

<p>
	تُرسل اﻷزرار إشارات عند النقر عليها مثلًا، وبالتالي يمكنك الاتصال بهذه اﻹشارة لتشغيل شيفرة محددة كاستجابة لحدث معين، كبدء اللعبة أو عرض قائمة.
</p>

<p>
	وقد تخبرك إشارات أخرى مدمجة عن تصادم كائنين أو عند دخول شخصية منطقة محددة وغيرها الكثير. وبإمكانك تعريف إشارات جديدة مخصصة للعبتك.
</p>

<h2 id="-5">
	خلاصة
</h2>

<p>
	تعرفنا في هذا المقال على المفاهيم البنيوية اﻷريعة لمحرك اﻷلعاب جودو والعقد والمشاهد وشجرة المشاهد واﻹشارات وهي ما ستتعامل معه دائمًا. فالعقد هي الكتل البنائية اﻷصغر في اللعبة والتي تجمع بينها لتشكل مشهدًا ثم تجمع المشاهد لتشكل شجرة مشاهد. ثم تستخدم بعد ذلك اﻹشارات كي تتفاعل العقد مع اﻷحداث التي تقع في عقد أخرى أو فروع أخرى من شجرة المشاهد.
</p>

<p>
	قد تخطر في بالك اﻵن الكثير من اﻷسئلة، لهذا نطلب منك التروي ومتابعة ما ستعرضه في مقالات أخرى لتحصل على الكثير من اﻷجوبة.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://docs.godotengine.org/en/stable/getting_started/introduction/introduction_to_godot.html" rel="external nofollow">Introduction to Godot</a> والمقال <a href="https://docs.godotengine.org/en/stable/getting_started/introduction/key_concepts_overview.html" rel="external nofollow">Overview of Godot's key concepts</a> من توثيق جودو الرسمي.
</p>

<h2 id="-6">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">أشهر أنواع الألعاب الإلكترونية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">مطور الألعاب: من هو وما هي مهامه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">أشهر لغات برمجة الألعاب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2182</guid><pubDate>Thu, 09 Nov 2023 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x637;&#x648;&#x631; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628;: &#x645;&#x646; &#x647;&#x648; &#x648;&#x645;&#x627; &#x647;&#x64A; &#x645;&#x647;&#x627;&#x645;&#x647;</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_10/games-programmer.png.92849f845969c016ba597ce947657e6b.png" /></p>
<p>
	إذا كنت مهتمًا ببرمجة الألعاب وتتساءل من هو مطور الألعاب وما هي مهامه ومسؤولياته، وما أبرز المراحل والخطوات التي عليه اتباعها لبرمجة لعبة خاصة به، وهل مجال تطوير الألعاب الإلكترونية مناسب لك ويوفر فرصًا وظيفية جيدة أم لا فهذا المقال لك.
</p>

<p>
	سنعرّفك في مقال اليوم على خطوات تطوير الألعاب ونركّز بشكل خاص على توضيح مهام مبرمج الألعاب أو مطور الألعاب المسؤول عن كتابة الكود البرمجي الذي ينفذ تصميم اللعبة ويحولها من فكرة مجردة إلى لعبة ممتعة نابضة بالحياة.
</p>

<h2>
	أهمية مجال تطوير الألعاب
</h2>

<p>
	لنوضح بداية أهمية مجال تطوير الألعاب الذي يعد واحدًا من أكثر المجالات البرمجية سرعةً في النمو وطلبًا في سوق العمل ولا غرابة في ذلك فبحسب <a href="https://explodingtopics.com/blog/number-of-gamers" rel="external nofollow">موقع Exploding Topics</a> هناك حوالي 3.09 مليار مستخدم لألعاب الفيديو في العالم ومن المتوقع أن يصل هذا الرقم إلى 3.32 مليار بحلول عام 2024 فالألعاب الإلكترونية وألعاب الفيديو أصبحت وسيلة أساسية للترفيه وقضاء الوقت.
</p>

<p>
	وقد أصبحت صناعة الألعاب تشكل جزءًا مهمًا من الإيرادات وقد تجاوزت صناعة السينما والموسيقى في بعض الدول فبحسب إحصائية نشرها موقع <a href="https://www.statista.com/statistics/292751/mobile-gaming-revenue-worldwide-device/" rel="external nofollow">Statista</a> تشكل الألعاب الإلكترونية أكبر قطاع في سوق الترفيه والإعلام وقد بلغت إيراداتها 91.8 مليار دولار في عام 2022، وشكلت 50% من حجم السوق العالمي. وكانت ألعاب الهواتف الجوالة هي أكثر أنواع الألعاب ربحية.
</p>

<p>
	هذه الأرقام تشير إلى شعبية كبيرة للألعاب الإلكترونية في جميع أنحاء العالم وتوضح الطلب الكبير على مطوري ومصممي الألعاب وغيرهم من المتخصصين في صناعة الألعاب والرواتب العالية التي يتقاضونها وتعد رواتب مطوري الألعاب مرتفعة مقارنةً بباقي التخصصات وبالرغم من أن راتب مطور الألعاب قد يختلف حسب الدولة والخبرة والمهارات والمجال إلا أن مهنة تطوير الألعاب الإلكترونية رائجة ومجزية جدًا وبحسب <a href="https://survey.stackoverflow.co/2023/#section-salary-salary-by-developer-type" rel="external nofollow">استبيان موقع stackoverflow لعام 2023</a> يبلغ متوسط رواتب مطوري الألعاب 71 ألف دولار سنويًا.
</p>

<p>
	فإذا كنت تحب تطوير الألعاب الإلكترونية وتود بأن تصبح مبرمج ألعاب فهذا سيضمن لك فرصة عمل براتب جيد ويوفر لك حرية اختيار العمل كموظف في إحدى شركات الألعاب أو العمل كمستقل وإطلاق ألعابك الخاصة، لكن تذكر أن هذا المجال تنافسي ويحتاج منك لامتلاك العديد من المهارات والتقنيات ومتابعة التطورات المستمرة في مجال صناعة الألعاب لتتمكن من إصدار ألعاب مميزة تنال شعبية واسعة.
</p>

<h2>
	خطوات تطوير الألعاب
</h2>

<p>
	يتضمن تطوير الألعاب الإلكترونية العديد من المراحل وقد تختلف هذه المراحل من لعبة لأخرى، لكن هناك مجموعة أساسية من الخطوات المطلوبة التي يحتاج أي مبرمج ألعاب لمعرفتها من أجل تصميم لعبة إلكترونية متكاملة وهي:
</p>

<ol>
	<li>
		وضع تصور أولي للعبة
	</li>
	<li>
		وضع خطّة لتنفيذ اللعبة
	</li>
	<li>
		تطوير وبرمجة اللعبة
	</li>
	<li>
		اختبار اللعبة
	</li>
	<li>
		إطلاق اللعبة
	</li>
	<li>
		الصيانة والتطوير المستمر
	</li>
</ol>

<p>
	لنشرح كل خطوة من هذه الخطوات بمزيد من التفصيل ونوضح كيف يمكنك كمطور ألعاب القيام بها.
</p>

<h3>
	1. وضع تصور أولي للعبة
</h3>

<p>
	تحدد هذه المرحلة ما هي الفكرة العامة للعبة وما قصتها وما نوعها، وما الأهداف التي يحتاج اللاعب لأن يحققها في اللعبة، ومن هو الجمهور المستهدف لها وما المنصة التي ستعمل عليها اللعبة، ومن المفيد هنا الاطلاع على الألعاب المنافسة للعبة المقترحة للتفكير في مميزات تنافسية تجعل اللعبة الإلكترونية تتميز عن الألعاب المشابهة لها.
</p>

<h3>
	2. وضع خطة لتنفيذ اللعبة
</h3>

<p>
	يحتاج مطور الألعاب في هذه المرحلة إلى التعاون مع مصمم الألعاب لتحديد تفاصيل أكثر عن اللعبة مثل تخيل قصة اللعبة وشخصياتها ويضع كافة قواعدها وآليات لعبها وطريقة تقدم اللاعبين فيها وكيفية تحقيق الأهداف كما يرسم نماذج أولية وقصص مصورة تساعد على فهم اللعبة وتصورها بشكل أفضل ووضع مستند تصميم اللعبة Game Design Document وهو مستند يلخص كل خطة اللعبة ويسهل فهمها كما يضع جدول زمني يوضح مراحل تنفيذ اللعبة الإلكترونية والوقت المطلوب لكل مرحلة.
</p>

<h3>
	3. تطوير وبرمجة اللعبة
</h3>

<p>
	في هذه الخطوة يبدأ مبرمج الألعاب مرحلة التنفيذ الأساسي لخطة اللعبة الموضوعة في الخطوة السابقة بدءًا من الحصول على كافة الأصول assets المطلوبة للعبة كالشخصيات المتحركة أو ما يعرف بالسبرايتس game sprites والرسومات والأصوات وبيئات اللعب أو يتعاون مع مصمم الألعاب ومصمم الصوتيات للحصول على مصادر مخصصة للعبة ثم يبدأ مطور الألعاب بكتابة الشيفرة البرمجية لإضافة المنطق البرمجي لهذه الأصول.
</p>

<h3>
	4. اختبار اللعبة
</h3>

<p>
	بعد الانتهاء من برمجة اللعبة تخضع اللعبة للاختبار ويطلب مطور الألعاب تجربتها من قبل مجموعة من المستخدمين للتأكد من أنها تعمل كما هو متوقع والتحقق من عدم وجود أي أخطاء أو مشكلات وإصلاحها في حال وجودها والتأكد من أنها توفر تجربة لعب جيدة وممتعة لهم.
</p>

<h3>
	5. إطلاق اللعبة
</h3>

<p>
	بعد التأكد من أن اللعبة تعمل بالشكل المطلوب يجب على مبرمج الألعاب نشر اللعبة التي طورها على منصة اللعب المستهدفة أو رفعها على متجر الألعاب المتخصص كي يتمكن المستخدمون الفعليون من تجربتها واللعب بها.
</p>

<h3>
	6. الصيانة والتطوير المستمر
</h3>

<p>
	لا ينتهي دور مبرمج الألعاب بعد إصدار ونشر اللعبة بل تحتاج كمطور العاب إلى متابعة آراء تعليقات اللاعبين حول اللعبة باستمرار والحصول على رأيهم حول اللعبة وأخذ اقتراحاتهم بشأنها بعين الاعتبار وإضافة الميزات والتحسينات التي يقترحونها لجعلها أكثر جاذبية ومتعة.
</p>

<p>
	هل تطمح لتصبح مطور ألعاب فيديو محترف وتحويل شغفك إلى مهارة عملية بطريقة احترافية وسهلة. ستحقق لك <a href="https://academy.hsoub.com/learn/game-development/" rel="">دورة تطوير الألعاب</a> من أكاديمية حسوب هذا الهدف، حيث ستتعلم في هذه الدورة كل ما تحتاجه لتطوير ألعابك الخاصة من الصفر بإشراف خبراء محترفين.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلة صناعة الألعاب ثنائية وثلاثية الأبعاد وابتكر ألعاب ممتعة تفاعلية ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<h2>
	من هو مطور الألعاب
</h2>

<p>
	مطور الألعاب أو مبرمج الألعاب game developer هو الشخص المسؤول عن إنشاء الألعاب الإلكترونية وتحويل اللعبة من فكرة إلى واقع قابل للعب عبر منصات مختلفة وتطوير بيئات الألعاب ودمج تقنيات الذكاء الاصطناعي في بيئة اللعب باستخدام لغات البرمجة أو بالاستفادة من أحد محركات تطوير الألعاب.
</p>

<p>
	يعمل مبرمج الألعاب عادة إما ضمن فريق متكامل في شركة تطوير ألعاب أو استوديو ألعاب متخصص في برمجة وتطوير الألعاب الإلكترونية ويضم مبرمجين ومصممين ومهندسي صوت ورسامين وكتّاب إنشاء كافة موارد تطوير لعبة، وقد يعمل بشكل مستقل في حال برمجة لعبة بسيطة ومحدودة وتعتمد على موارد جاهزة.
</p>

<p>
	يتخصص أي مبرمج ألعاب عادةً ببرمجة نوع أو أسلوب محدد من <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">أنواع الألعاب الإلكترونية</a> كالألعاب الاستراتيجية أو الألعاب المنطقية وقد يتخصص كذلك في برمجة لعبة مخصصة لمنصة محددة مثل ألعاب الجوال أو ألعاب الحاسوب أو ألعاب بلاي ستيشن …إلخ.
</p>

<h2>
	مهام مطور الألعاب
</h2>

<p style="text-align: center;">
	<img alt="مهام مطور الألعاب" class="ipsImage ipsImage_thumbnailed" data-fileid="136911" data-ratio="62.56" data-unique="9895iuovw" style="width: 700px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_10/---.thumb.png.bb1d92c3acca669dd0ebd5ba39dae6e0.png">
</p>

<p>
	تختلف مهام مطوّر الألعاب بحسب طبيعة اللعبة وتعقيدها والمنصة التي تستهدفها، كما تعتمد طبيعة مهامه على كونه سيبرمج لعبته بشكل فردي أم سيعمل ضمن فريق عمل متخصص وهل سيطور الألعاب بشكل مستقل أم لصالح شركة أو استوديو ألعاب معين فكل هذه العوامل تؤثر على طبيعة المهام التي سيقوم بها في دورة حياة اللعبة.
</p>

<p>
	بالرغم من أن تطوير الألعاب الإلكترونية أمر معقد ويحتاج للكثير من العمل إلا أن تطوير لعبة بمفردك أمر ممكن وغير مستحيل، فإذا افترضنا أن مطور ألعاب سيطور لعبته بنفسه بالكامل، في هذه الحالة ستكون أبرز المهام التي يقوم بها هي كالتالي:
</p>

<ul>
	<li>
		التخطيط للعبة
	</li>
	<li>
		اختيار محرك تطوير اللعبة
	</li>
	<li>
		الحصول على موارد اللعبة
	</li>
	<li>
		برمجة اللعبة
	</li>
	<li>
		اختبار اللعبة
	</li>
	<li>
		صيانة اللعبة وتحسينها
	</li>
</ul>

<p>
	لنناقش كل مهمة من هذه المهام بمزيد من التفصيل.
</p>

<h3>
	التخطيط للعبة
</h3>

<p>
	يحتاج مطور الألعاب في هذه المرحلة إلى التعاون من مصمم الألعاب للتخطيط للعبة بدءًا من تصميم فكرتها الأولية وتحديد <a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/" rel="">نوع اللعبة</a> والمنصة التي تستهدفها ومتطلباتها وإنتاج نماذج أولية لأفكاروطرق اللعب فيها وقواعد الربح والخسارة.
</p>

<h3>
	اختيار محرك تطوير اللعبة
</h3>

<p>
	يلجأ مطور الألعاب في هذه المرحلة إلى الاعتماد على أحد محركات الألعاب الجاهزة التي تسهّل وتسرّع تطوير الألعاب مثل محرك ألعاب يونتي Unity أو أن ريل Unreal أو جودو Godot وكما يمكن للمطور المحترف إنشاء المحرك الذي سيتم تشغيل اللعبة عليه.
</p>

<h3>
	الحصول على موارد اللعبة
</h3>

<p>
	يتواصل المطور في هذه المرحلة مع المصممين والفنانين ومهندسي الصوت لإنشاء كافة موارد اللعبة game assets  من رسومات وأصوات أو يلجأ للحصول عليها من مصادر جاهزة حيث تتوفر العديد من المواقع والمنصات التي توفر مصادر مجانية متنوعة خالية الحقوق يمكن لمطوري الألعاب الإلكترونية الاعتماد عليها.
</p>

<h3>
	برمجة اللعبة
</h3>

<p>
	بعد تأمين كافة موارد اللعبة يبدأ مطور الألعاب بإضافة المنطق البرمجي للعبة وكتابة كافة الأكواد البرمجية اللازمة لتحريك الشخصيات وتشغيل الأصوات وضمان تفاعل كافة المكونات ضمن بيئة اللعبة بالشكل الصحيح وجعلها قابلة للعب وفق الهدف المطلوب من اللعبة.
</p>

<h3>
	اختبار اللعبة
</h3>

<p>
	بعد الانتهاء من برمجة اللعبة يجب ان يختبر مطور الألعاب لعبته على المنصة المستهدفة ويقيم أداءها ويتأكد من أنها تعمل على المنصة المطلوبة بالشكل الصحيح وأنها لا تحتوي أي أخطاء في الشيفرات البرمجية أو في آلية اللعب.
</p>

<h3>
	صيانة اللعبة وتحسينها
</h3>

<p>
	أخيرًا يحتاج أي مبرمج ألعاب إلى إصلاح أي أخطاء برمجية أو مشكلات فنية تظهر في اللعبة كما قد يحتاج لإجراء مجموعة من التعديلات البرمجية لنقل اللعبة من منصة إلى أخرى في حال برمجة لعبة أو تطوير لعبة متعددة المنصات.
</p>

<h2>
	مهارات مطور الألعاب
</h2>

<p>
	تختلف برمجة الألعاب الإلكترونية عن <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA/" rel="">برمجة أنواع التطبيقات الأخرى</a> بكونها تحتاج لعدة مواهب ومهارات فنية وإبداعية وتحليلية لتطوير لعبة ناجحة تجذب المستخدمين. وإليك قائمة بأهم المهارات التي يحتاج إليها مطورالألعاب الناجح:
</p>

<ul>
	<li>
		يحتاج مبرمج الألعاب لوجود معرفة برمجية بإحدى <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a> وبرامج تطوير وتشغيل الألعاب.
	</li>
	<li>
		يحتاج مبرمج الألعاب لتعزيز التفكير المنطقي لديه وامتلاك مهارة عالية في حل المشكلات فهذه مهارة أساسية لأي مطور أو مبرمج وهي تفيد مبرمج الألعاب بشكل خاص لبرمجة الألعاب بسرعة وكفاءة وتصحيح أي أخطاء مكتشفة في برمجة اللعبة بسهولة أكبر.
	</li>
	<li>
		الحس الإبداعي لإنشاء الألعاب بأفكار مثيرة وتصميم مستوياتها وأسلوب لعبها والتنقل في بيئة اللعب بطريقة تجذب المستخدم وتحفزه على اللعب.
	</li>
	<li>
		التنظيم والقدرة على إدارة الوقت وإكمال المهام بكفاءة وإطلاق اللعبة في الموعد المحدد لها.
	</li>
	<li>
		امتلاك شغف بالألعاب الإلكترونية ومواكبة أحدث التقنيات فمجال تطوير الألعاب متجدد ويتحدث بشكل مستمر.
	</li>
	<li>
		القدرة على العمل الجماعي والتعاون والتواصل الفعال وشرح أفكارك بوضوح وإيجاز لباقي أعضاء الفريق المساهمين في تطوير وتصميم الألعاب أو العملاء وأصحاب المصلحة.
	</li>
	<li>
		إذا كنت تنوي كمبرمج ألعاب أن تصمم موارد ألعابك بنفسك ستحتاج عندها لتطور مهارات إضافية مثل مهارات الرسم ومبادئ تصميم الألعاب وهندسة الصوت لكن هذا الأمر سيزيد العبء والعمل لذا يمكنك الاعتماد على استخدام تصاميم وأصوات جاهزة أو توظف متخصصين لإنشائها لك، ستجد في مواقع العمل الحر مثل مستقل وخمسات أشخاصًا أكفاء يقدمون هذه الخدمات.
	</li>
	<li>
		خيال واسع ومهارة في سرد القصص لإنشاء قصة محفزة تشجع المستخدمين على فهم الهدف من اللعبة بشكل جيد وإبراز شخصياتها وأحداثها.
	</li>
</ul>

<h2>
	كيف أصبح مطور ألعاب؟
</h2>

<p>
	أمامك عدة خيارات مختلفة يمكنك من خلالها تعلم تطوير وبرمجة الألعاب إما من خلال التعليم الجامعي في إحدى كليات البرمجة وعلوم الحاسوب والتخصص بعدها في مجال برمجة وتصميم الألعاب لكن هذا الطريق طويل ويستغرق وقتًا ويضطرك لتعلم الكثير من المواد التي لا صلة لها بمجال تطوير الألعاب.
</p>

<p>
	كما يمكنك تعلم تطوير الألعاب بشكل ذاتي وتعلم كافة المهارات اللازمة التي تمكنك من بناء ألعاب احترافية وناجحة، وإليك أهم عشر خطوات لتصبح مطور ألعاب ناجح:
</p>

<ul>
	<li>
		تعلّم أنواع الألعاب الإلكترونية المختلفة وطريقة اللعب بها ومكوناتها المختلفة حتى تتمكن من وضع خطة تعلّم واضحة بحسب طبيعة الألعاب التي ستطورها والتقنيات التي تحتاج لتعلّمها وتحدد أفكار ألعابك وميزات اللعبة وطريقة لعبها بشكل صحيح.
	</li>
	<li>
		اعتمد على مصادر التعلم الموثوقة والحديثة المتاحة عبر الإنترنت حول تصميم الألعاب وبرمجتها وتطويرها من مقالات ودروس وكتب ومقاطع فيديو ومنتديات ومجتمعات ودورات تدريبية حول تطوير وتصميم الألعاب.
	</li>
	<li>
		تعلم المهارات التقنية اللازمة لك كمطور ألعاب وابدأ من <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">أساسيات البرمجة</a> ثم تعلم إحدى <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a> مثل لغة جافا أو ++C أو Lua واكتسب خبرة في استخدام أحد <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محركات تطوير الألعاب Game Engines</a> لبناء وتشغيل الألعاب الخاصة بك.
	</li>
	<li>
		تعلم أساسيات الرياضيات والفيزياء فهما مهارتان ضروريتان لأي مطور ألعاب لتحريك عناصر اللعبة بشكل صحيح وواقعي.
	</li>
	<li>
		تعلم طريقة التعامل مع قواعد البيانات في حال رغبت بتطوير ألعاب متقدمة تحتاج لتخزين البيانات مثل الألعاب متعددة اللاعبين عبر الإنترنت وتخزين معلومات حول اللاعبين والمستويات وتتبع التقدم في اللعبة وحفظ الإنجازات والجوائز والإحصائيات …إلخ.
	</li>
	<li>
		اعمل على تطوير ألعاب خاصة بك، إذا كنت مبرمج ألعاب مبتدئ يمكنك البدء بألعاب بسيطة وبدائية والانتقال بعدها لألعاب أكثر تقدمًا واطلب من أصدقائك تجربة لعبتك وإعطائك رأيهم حولها وقم بتحسينها فهذا يمكنك من تطبيق المهارات النظرية واكتساب خبرة عملية وبناء معرض أعمال خاص بك.
	</li>
	<li>
		تعلم طريقة سرد قصص الألعاب وكتابة حبكتها بشكل مشوّق ومقنع يجذب اهتمام المستخدمين وتحفّزهم على استكشاف اللعبة والتفاعل معها، والفرق بين الروايات الخطية linear narratives التي تكتب أحداث اللعبة بتسلسل زمني وغير الخطية non-linear narratives التي تكتب الأحداث بشكل متفرق ودون مراعاة الترتيب الزمني.
	</li>
	<li>
		احرص على حضور أي فعاليات تخصّ صناعة الألعاب والتعرف على الأشخاص العاملين في مجال تطوير الألعاب والاستفادة من أفكارهم وتجاربهم وفهم المزيد حول صناعة الألعاب وتطوير مهاراتك وخبراتك.
	</li>
	<li>
		طوّر مهاراتك الناعمة مثل التنظيم والتواصل والتعاون والتفكير الإبداعي وحل المشكلات فهذه مهارات ضرورية لأي مبرمج ألعاب وتساعدك على التميّز في سوق العمل.
	</li>
	<li>
		ابحث عن فرصة عمل مناسبة من خلال التعاقد مع استوديوهات ألعاب أو شركات متخصصة في تطوير ألعاب احترافية أو العمل بشكل مستقل وتطوير ألعاب خاصة به ونشرها على متاجر الألعاب والربح منها.
	</li>
</ul>

<h2>
	الأسئلة الشائعة بمجال تطوير الألعاب
</h2>

<p>
	نختم المقال ببعض الأسئلة الشائعة حول تصميم تطوير الألعاب:
</p>

<h3>
	ما هو تطوير الألعاب؟
</h3>

<p>
	تطوير الألعاب هو أحد التخصصات البرمجية الذي يتضمن إنشاء ألعاب إلكترونية من خلال المرور بعدة مراحل أهمها تصميم اللعبة وبرمجتها واختبارها ونشرها في متاجر الألعاب أو المنصات المتخصصة ويتطلب تطوير الألعاب الاحترافية عادة تضافر جهود فريق عمل متخصص يضم مبرمجي ألعاب ومصممين ورسامين وبالرغم من ذلك هناك ألعاب ناجحة وذات شعبية كبيرة أنشأها مطور ألعاب واحد فقط.
</p>

<h3>
	كيف أبدأ في برمجة الألعاب؟
</h3>

<p>
	يمكنك البدء بتعلم أساسيات تطوير اللعبة، مثل مبادئ تصميم اللعبة وآليات اللعبة وأنواع الألعاب. يمكنك أيضًا استخدام البرامج التعليمية أو الكتب أو الدورات التدريبية عبر الإنترنت لتتعلم كيفية استخدام محركات الألعاب وأدواتها. يمكنك أيضًا الانضمام إلى المجتمعات والمنتديات عبر الإنترنت للحصول على تعليقات ونصائح من مطوري الألعاب الآخرين
</p>

<h3>
	ما الفرق بين مطور الألعاب ومصمم الألعاب؟
</h3>

<p>
	مصمم الألعاب هو المسؤول عن الجانب الإبداعي والجمالي للعبة ويجب أن يتملك مهارات في الرسم والتصميم الرسومي وإنشاء الوسائط المتعددة أما مطور الألعاب فهو المسؤول عن الجانب التقني والبرمجي للعبة وتحويل تصميمها إلى تطبيق فعلي ويجب أن يمتلك مهارات بلغات البرمجة ومحركات الألعاب والرياضيات والفيزياء.
</p>

<p>
	كي تصبح مطور لعبة ناجح تحتاج كمطور ألعاب إلى التعاون والتواصل مع مصمم الألعاب ومعرفة الفرق بين مهامك ومهامه، كما يمكن أن يتولى مطور الألعاب في بعض الحالات مسؤولية التطوير والتصميم بنفس الوقت في حال تطوير ألعاب بسيطة واختيار برمجة لعبة بالاعتماد على تصاميم جاهزة.
</p>

<h2>
	ما هو محرك الألعاب؟
</h2>

<p>
	محرك الألعاب هو بيئة برمجية لتطوير وبرمجة لعبة بسهولة وسرعة حيث يوفر محرك الألعاب أدوات تسهل عمل المطورين وتمكّنهم من التركيز على تطوير لعبة متكاملة في مكان واحد بدلاً من الحاجة إلى كتابة الكود البرمجي الكامل لها من الصفر ويبّسط مهام التطوير المعقدة مثل الفيزياء والإضاءة والصوت وعرض الرسومات <a href="https://academy.hsoub.com/programming/artificial-intelligence/%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A/" rel="">والذكاء الاصطناعي</a>.
</p>

<h3>
	كيف تربح المال من تطوير الألعاب؟
</h3>

<p>
	يكسب مطور الألعاب المال بعدة طرق أهمها العمل في أحد شركات تطوير الألعاب أو بيع الألعاب الخاصة به على المنصات والمتاجر المتخصصة مثل جوجل بلاي Google Play أو متجر أبل App Store أو منصة ألعاب الفيديو Steam كما يمكنه نشر ألعاب بميزات مجانية وميزات احترافية مدفوعة تحتاج لدفع مبلغ إضافي للحصول عليها، أو ترك ألعابه مجانية بالكامل والربح من وضع إعلانات بداخلها، ومن طرق الربح الممكنة أيضًا استخدام منصات مثل Patreon لتلقي تبرعات من اللاعبين الذين يرغبون في دعم المطور.
</p>

<h3>
	ما هو استوديو الألعاب؟
</h3>

<p>
	استوديو الألعاب هو شركة كبيرة متخصصة في تطوير الألعاب الإلكترونية ويضم استوديو الألعاب عادة فريق متكامل من الأشخاص المتخصصين في إنتاج الألعاب من مصممين ومبرمجين يبرمجون الألعاب وكتَّاب يكتبون قصة اللعبة ومختبرين يفحصون اللعبة ويتأكدون من جودتها وخلوها من الأخطاء وجاهزيتها للإطلاق في السوق، ويمكن أن يكون الاستوديو شركة مستقلة أو جزء من شركة ألعاب كبيرة، ومن أشهر استوديوهات الألعاب نذكر Ubisoft و Blizzard Entertainment و Nintendo و Electronic Art.
</p>

<h3>
	ما هي منصات نشر الألعاب؟
</h3>

<p>
	منصات الألعاب هي الأنظمة أو المعدات التي تمكن المستخدمين من تحميل الألعاب ولعبها بعد الانتهاء من تطويرها ومن أشهر منصات اللعب الحواسيب الشخصية والجوالات التي تعمل بنظام أندرويد Android أو آي أو إس iOS والطرفيات أو وحدات الألعاب game consoles مثل بلاي ستيشن PlayStation وإكس بوكس Xbox وهناك منصات مخصصة لبث الألعاب مباشرة عبر الإنترنت مثل منصة تويتش Twitch.
</p>

<h3>
	ما هي صعوبات تطوير لعبة؟
</h3>

<p>
	يتضمن تطوير الألعاب بعض التحديات والصعوبات فهو مجال يتطلب توفّر العديد من المهارات الفنية والإبداعية ويتطلب الكثير من الوقت والجهد لتعلمه، كما أنه مجال تنافسي ومكلف بشكل كبير إضافة لأن نجاح الألعاب الإلكترونية يعتمد على جودة فكرتها وتنفيذها وشعبيتها وبذل جهد في تسويقها وقد يستغرق وقتًا وجهدًا لكسب المال وتحقيق مبيعات جيدة.
</p>

<h3>
	هل يمكن أن أصبح مطور ألعاب دون شهادة جامعية؟
</h3>

<p>
	نعم، من الممكن أن تصبح مطور ألعاب بدون شهادة جامعية فالعديد من مطوري الألعاب الناجحين تعلّموا بشكل ذاتي فمصادر التعلم المتنوعة من دروس وكتب ودورات تدريبية متوفرة بكثرة عبر الإنترنت. الأهم هو أن يكون لديك الشغف والرغبة والجديّة في التعلّم فهذا كفيل لتصبح مطوّر ألعاب ناجحًا.
</p>

<h3>
	هل يحتاج تطوير الألعاب إلى خبرة في الرياضيات؟
</h3>

<p>
	نعم يحتاج تطوير الألعاب الإلكترونية إلى وجود خبرة في الرياضيات والجبر الخطي والمثلثات وبالرغم من أن محركات الألعاب تسهل على المطور الكثير من العمليات الرياضية إلا أن مبرمج الألعاب يحتاج لفهم أساسيات الرياضيات من أجل تحريك شخصيات اللعبة وجعلها تتفاعل مع بيئة اللعبة بالشكل الصحيح.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">تعرف على أشهر محركات الألعاب Game Engines</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D8%AA%D8%A7%D9%87%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AD%D8%B1%D9%83-%D9%8A%D9%88%D9%86%D9%8A%D8%AA%D9%8A-unity-r1700/" rel="">برمجة لعبة متاهة باستخدام محرك يونيتي Unity</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">نبذة عن صناعة الألعاب ومحرك Unity3D</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8%D8%9F-r2068/" rel="">ما هي برمجة الألعاب؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2146</guid><pubDate>Sun, 22 Oct 2023 11:00:00 +0000</pubDate></item><item><title>&#x623;&#x634;&#x647;&#x631; &#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628; &#x627;&#x644;&#x625;&#x644;&#x643;&#x62A;&#x631;&#x648;&#x646;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_09/--.png.dd28f05a18b54f71d05f06567be59d47.png" /></p>
<p>
	عالم الألعاب الإلكترونية كبير ومتنوع ويضم أنواعًا وتصنيفات مختلفة تناسب مع مختلف اهتمامات المستخدمين، فمهما كان مجال الألعاب الذي تفضله سواء كان التصويب وإطلاق النار أو الرياضة أو الخيال العلمي أو المحاكاة فستجد بالتأكيد ألعابًا عديدة تتناسب مع هذا اهتمامك.
</p>

<p>
	وإذا كنت مهتمًا لتصبح مبرمج ألعاب أو مصمم ألعاب فإنك بحاجة لمعرفة أهم أنواع الألعاب الإلكترونية التي يمكنك إنشاؤها وأهم السمات المميزة لكل نوع، لذا سنعرفك في مقالة اليوم على أبرز الأنواع الأساسية والأنواع الفرعية التي تندرج تحتها الألعاب الإلكترونية والخصائص والسمات المميزة لكل نوع من هذه الأنواع.
</p>

<h2>
	أهمية الألعاب الإلكترونية في سوق العمل
</h2>

<p>
	تعد صناعة الألعاب الإلكترونية من المجالات الرائجة والمربحة في سوق العمل، وبحسب موقع الإحصاءات <a href="https://www.statista.com/outlook/amo/media/games/worldwide#revenue" rel="external nofollow">ستاتيستا Statista</a> فإن إيرادات سوق الألعاب العالمي قد يبلغ في عام 2023 ما يقارب 490 مليار دولار أمريكي بمعدل نمو سنوي بنسبة 8.84٪ ويتوقع أن يصل عدد مستخدمي الألعاب بحلول عام 2027 إلى 4.3 مليار شخص.
</p>

<p>
	لهذا السبب يتزايد اهتمام استوديوهات الألعاب وشركات ألعاب الحاسوب والجوال وشركات وحدات التحكم بالألعاب بتطوير ألعاب مختلفة وطرحها في الأسواق والمتاجر المتخصصة، ويزداد بالمقابل الطلب على مصممي ومطوري الألعاب وتطور سنويًا آلاف الألعاب الإلكترونية التي تندرج تحت أنواع وتصنيفات مختلفة سنويًا.
</p>

<h2>
	معايير تصنيف الألعاب الإلكترونية
</h2>

<p>
	إذا كنت مصمم ألعاب أو مطور ألعاب إلكترونية فستحتاج لمعرفة نوع اللعبة الإلكترونية التي ستطورها فهذا من شأنه أن يساعدك على تحديد موارد اللعبة بدقة، ومعرفة الجمهور المستهدف منها، وحجم الطلب عليها في سوق العمل ودراسة منافسيك والتميز عنهم.
</p>

<p>
	كما يساعدك هذا على نشر لعبتك في التصنيف المناسب لها في متاجر الألعاب أو المنصات المتخصصة، ويمكِّن المستخدمين من العثور على الألعاب التي يفضلونها بين الكمّ الهائل من الألعاب الموجودة في السوق.
</p>

<p>
	تصنف الألعاب الإلكترونية وفق العديد من التصنيفات الأساسية والفرعية مختلفة بناء على عدة معايير من أهمها:
</p>

<ul>
	<li>
		<strong>أسلوب اللعب وهدفه</strong>: هذا المعيار أحد المعايير الأساسية في تصنيف الألعاب الإلكترونية حيث تتنوع الأهداف التي تصمم الألعاب من أجلها فهناك على سبيل المثال ألعاب محاكاة وألعاب تقمص أدوار وألعاب استراتيجية وألعاب إطلاق نار وغيرها الكثير وتختلف الطرق والأساليب التي يلعب بها المستخدمون ويتفاعلون مع بعضهم البعض بحسب كل لعبة.
	</li>
	<li>
		<strong>عدد اللاعبين وطبيعتهم</strong>: فهناك ألعاب فردية Single-player وألعاب جماعية أو متعددة اللاعبين تلعب عبر الإنترنت Massively Multi-player Online Games والتي تعرف اختصارًا بألعاب MMO وهذه بدورها يمكن أن تكون ألعاب تقمص أدوار جماعية MMORPG أو ألعاب إطلاق نار جماعية من منظور الشخص الأول MMOFPS أو ألعاب جماعية استراتيجية في الوقت الفعلي MMORTS …إلخ. كما أن هناك ألعابًا تعاونية يلعب فيها اللاعب ضد بيئة اللعب نفسها أو بمعنى آخر ضد <a href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel="">الذكاء الاصطناعي</a> المضمن في اللعبة وتعرف باسم ألعاب Player versus Environment أو اختصارًا PvE أو ألعاب تلعب كلاعب بشري ضد لاعب آخر لتحقيق الفوز أو تحقيق أهداف معينة في اللعبة وتعرف باسم Player versus Player أو اختصارًا PvP.
	</li>
	<li>
		<strong>أسلوب السرد وتقنياته</strong>: والمقصود به أسلوب سرد أحداث اللعبة فهناك ألعاب خيال علمي وألعاب واقعية وألعاب عسكرية وألعاب رعب، وهناك تقنيات مختلفة للسرد فقد يكون سرد أحداث اللعبة خطيًا <strong>Linear Narrative</strong> أي أن قصة اللعبة محددة من البداية ولها ترتيب معين لا يتغير مع تصرفات اللاعب، أو غير خطي <strong>Non-Linear Narrative</strong> حيث تحدد الإجراءات التي يقوم بها اللاعب طريقة سير القصة.
	</li>
	<li>
		<strong>نوع منصة اللعب</strong>: أو بمعنى آخر نوع الجهاز أو العتاد أو النظام البرمجي الذي تستهدفه اللعبة، فهناك ألعاب مخصصة للهواتف الذكية أو غيرها من الأجهزة المحمولة وهي اليوم أحد أشهر أنواع الألعاب وألعاب مخصصة للعب على الحواسيب، وألعاب موجهة لوحدات التحكم بالألعاب مثل بلاي ستيشن PlayStation وإكس بوكس Xbox ونينتيدو Nintendo Switch، وألعاب تلعب من داخل متصفح الويب ولكل نوع تقنياته وموارده.
	</li>
	<li>
		<strong>الفئة العمرية المستهدفة</strong>: فهناك ألعاب مخصصة للكبار وأخرى مخصصة للأطفال، ويجب على الجهة المطورة والناشرة للعبة التأكد من أن الألعاب مناسبة للفئة العمرية التي تستهدفها، فإذا كانت اللعبة موجهة للأطفال فيجب التأكد من خلوها من أي مخاطر على الأطفال وعدم عرضها لأي محتوى أو إعلانات لا تناسبهم.
	</li>
	<li>
		<strong>الغرض من اللعب</strong>: فبالرغم من أن معظم الألعاب تصمم لأغراض ترفيهية، إلا أن هناك ألعابًا مصممة لأغراض تعليمية وتهدف لتعزز المهارات المعرفية والاجتماعية والجسدية وهذه الألعاب في الغالب تستهدف الأطفال وهناك ألعاب محاكاة هدفها السماح للاعب بتجربة أمور واقعية ضمن بيئة افتراضية تحاكي البيئة الفعلية.
	</li>
	<li>
		<strong>منظور اللعب Perspective</strong>: فالألعاب الإلكترونية تتعدد حسب المنظور أو نقطة ارتكاز الكاميرا ضمن اللعبة فهناك ألعاب التمرير الجانبي التي تعرض اللعبة من زاوية الكاميرا الجانبية وتتبع اللاعب أثناء تحركه يسارًا أو يمينًا، وألعاب من أعلى إلى أسفل Top-down أو ما يعرف أيضًا باسم عرض عين الطائر birds-eye view أو عرض المروحية helicopter view حيث تعرض اللعبة من الأعلى وتنظر للأسفل حيث تكون الكاميرا مثبتة في موضع ثابت في الأعلى مع دوران مع أو بدون دوران، وألعاب تعرض اللعبة من منظور الشخص الأول First-person بمعنى أنها تتضمن كاميرا تحاكي رؤية بطل اللعبة أو من منظور الشخص الثالث وفيها يمكن رؤية شخصية اللاعب وتتبع الكاميرا حركة اللاعب.
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135914" href="https://academy.hsoub.com/uploads/monthly_2023_09/----.png.2e5621e93233a33d31c6b15351d50363.png" rel=""><img alt="تصنيف الألعاب الإلكترونية" class="ipsImage ipsImage_thumbnailed" data-fileid="135914" data-ratio="48.50" data-unique="km7vulva1" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/----.thumb.png.ee6ce88c55290161528b2717760055f9.png"> </a>
</p>

<p>
	تملك الألعاب التي تندرج تحت نفس النوع سمات وخصائص مشتركة تميزها وتحددها عن غيرها، والجدير بالملاحظة أن بعض الألعاب الإلكترونية قد تندرج تحت عدة تصنيفات مختلفة بذات الوقت ومن الضروري أن تفهم كمطور ألعاب أو مصمم ألعاب خصائص كل نوع كي تتمكن من إنشاء لعبتك وتصنيفها بالشكل الصحيح.
</p>

<h2>
	أهم أنواع الألعاب الإلكترونية
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135915" href="https://academy.hsoub.com/uploads/monthly_2023_09/--.png.e4a44a594008a382d5f8afc2fc5f5994.png" rel=""><img alt="أنواع الألعاب الإلكترونية" class="ipsImage ipsImage_thumbnailed" data-fileid="135915" data-ratio="62.50" data-unique="l70e37u81" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/--.thumb.png.f1a70c45a2f235d64a235556c07a3464.png"> </a>
</p>

<p>
	في هذه الفقرة سنشرح أبرز أنواع الألعاب الإلكترونية بالاعتماد أسلوب اللعب أو الطريقة التي يتفاعل بها اللاعب مع اللعبة بشكل أساسي ونتعرف على أهم مميزاتها وأنواعها الفرعية، ونعطي أمثلة على بعض أشهر الألعاب التي تندرج تحتها.
</p>

<p>
	إليك قائمة بأبرز أنواع الألعاب الإلكترونية التي سنتطرق للحديث عنها في فقراتنا التالية:
</p>

<ol>
	<li>
		ألعاب صندوق الرمل وألعاب العالم المفتوح
	</li>
	<li>
		ألعاب تقمص الأدوار
	</li>
	<li>
		الألعاب الرياضية
	</li>
	<li>
		ألعاب المحاكاة والسباق
	</li>
	<li>
		الألعاب الاستراتيجية
	</li>
	<li>
		ألعاب التصويب وإطلاق النار
	</li>
	<li>
		الألعاب اليومية غير الرسمية
	</li>
	<li>
		ألعاب الألغاز والألعاب المنطقية
	</li>
	<li>
		ألعاب المنصات
	</li>
	<li>
		ألعاب الحركة أو الأكشن
	</li>
	<li>
		الألعاب القتالية
	</li>
	<li>
		ألعاب المغامرات
	</li>
	<li>
		ألعاب الآركيد Arcade
	</li>
</ol>

<p>
	لنتعرف على أهم مميزات وخصائص كل نوع من هذه الأنواع.
</p>

<h3>
	1. ألعاب صندوق الرمل Sandbox والعالم المفتوح Open World
</h3>

<p>
	يطلق اسم ألعاب صندوق الرمل أو العاب الساند بوكس Sandbox على الألعاب الإلكترونية الإبداعية التي تتيح للاعب حرية اللعب بالطريقة أو الأسلوب الذي يحلو له واسمها مشتق من اسم صندوق الرمل الذي يتيح للأطفال إنشاء أي شيء يريدونه تقريبًا بداخله، ففي هذا النوع من الألعاب لا تكون أحداث اللعبة وشخصياتها الأساسية وأهدافها محددة وثابتة في بداية اللعب بل تكون متروكة لرغبة اللاعب وتفضيلاته ليخصصها كما يشاء.
</p>

<p>
	غالبًا ما ترتبط ألعاب صندوق الرمل Sandbox بمصطلح مشابه وهو ألعاب العالم المفتوح Open World والتي يقصد بها الألعاب التي لا تكون فيها حركة اللاعب مقيدة في عالم اللعبة، بل يمكنه التجول بحرية ضمن عالم اللعبة الافتراضي واكتشافه كما يحلو له وبالأسلوب الذي يرغب فيه، والتعامل مع تحديات اللعبة وأهدافها بحرية دون وجود أسلوب لعب مخطط ومنظم.
</p>

<p>
	يستخدم هذا النوع من الألعاب الإلكترونية عادة في ألعاب محاكاة بناء المدن ومحاكاة الحياة الواقعية وألعاب اكتشاف الفضاء والكواكب ومن الأمثلة البارزة على هذا النوع من الألعاب نذكر:
</p>

<ul>
	<li>
		Minecraft
	</li>
	<li>
		Terraria
	</li>
	<li>
		No Man's Sky
	</li>
	<li>
		The Elder Scrolls V: Skyrim
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135920" href="https://academy.hsoub.com/uploads/monthly_2023_09/sandbox-games.png.ca7cbfd66885c4df79e4b6499a6702c8.png" rel=""><img alt="ألعاب صندوق الرمل Sandbox والعالم المفتوح Open World" class="ipsImage ipsImage_thumbnailed" data-fileid="135920" data-ratio="57.25" data-unique="yfe2ksbe7" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/sandbox-games.thumb.png.19b350f85f7631a9661387f18495fc28.png"> </a>
</p>

<h3>
	2. ألعاب تقمص الأدوار Role-Playing Games
</h3>

<p>
	ألعاب تقمص الأدوار Role-Playing Game أو اختصارًا ألعاب آر بي جي RPG هي الألعاب الإلكترونية التي تتميز بوجود لاعب يتقمص دور الشخصية الرئيسية التي تتفاعل داخل عالم اللعبة ويساعدها على تحقيق أهدافها، ويستخدم هذا النوع من الألعاب الإلكترونية عادة في ألعاب المغامرات والألعاب القتالية وألعاب التصويب و ألعاب الفضاء والخيال العلمي.
</p>

<p>
	تتشابه هذه الألعاب في طريقة لعبها مع ألعاب الطاولة وألعاب البطاقات التقليدية كلعبة شراء العقارات حيث يتقمص اللاعب دور الشخصية التي يلعبها ويزيد من قوتها وخبرتها خلال سير اللعبة ويحاول التغلب على التحديات التي يواجهها وكلما أكمل عددًا أكبر من المهام ستزيد نقاط قوته.
</p>

<p>
	قد تكون ألعاب تقمص الأدوار فردية أو جماعية تضم عدة اللاعبين يلعبون معًا عبر الإنترنت في الوقت الفعلي وتسمى في هذه الحالة بألعاب MMORPG وهي اختصار لعبارة Massively Multiplayer Online Role-Playing Game وهذا يجعلها أكثر إثارة وحماسًا.
</p>

<p>
	ومن أشهر ألعاب تقمص الأدوار نذكر:
</p>

<ul>
	<li>
		Monster Hunter Rise
	</li>
	<li>
		Persona 4 Golden
	</li>
	<li>
		Dragon Age: Origins
	</li>
	<li>
		BattleTech
	</li>
	<li>
		Star Wars Galaxies
	</li>
	<li>
		Elder Scrolls
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135921" href="https://academy.hsoub.com/uploads/monthly_2023_09/RPG-games.png.993f122fee816b6f8858a5313628fadc.png" rel=""><img alt="ألعاب تقمص الأدوار Role-Playing Games" class="ipsImage ipsImage_thumbnailed" data-fileid="135921" data-ratio="57.25" data-unique="r9i49re2t" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/RPG-games.thumb.png.02b4051bcf57d5ee20b45ceb15fc1935.png"> </a>
</p>

<p>
	يمكن أن تصمم ألعاب تقمص الأدوار كذلك بحيث في ذات الوقت ألعاب صندوق رمل فتصنف على أنها ألعاب Sandbox RPGs وفي هذه الحالة لا تتضمن اللعبة قصة محددة ثابتة بل تتيح للاعب عدة خيارات لتصميم وتخصيص الشخصية التي يتقمصها بحرية وتمكنه من اختيار أسلوب اللعب الذي يفضله وتحديد طبيعة المهام التي سيقوم به مثل لعبة Skyrim و Pokémon Scarlet &amp; Violet و Terraria.
</p>

<h3>
	3. الألعاب الإلكترونية الرياضية Sports Games
</h3>

<p>
	الألعاب الرياضية هي ألعاب تحاكي الرياضيات التقليدية فهي تمكنك من لعب الرياضية التي تفضلها سواء كانت رياضة كرة القدم أو كرة السلة وأنت جالس في مكانك، وهي واحدة من أشهر أنواع الألعاب الإلكترونية وأكثرها شيوعًا وتفضيلًا بين المستخدمين لا سيما حين تلعب عادة بشكل جماعي ضمن فرق متنافسة.
</p>

<p>
	من الأمثلة على الألعاب الرياضية نذكر:
</p>

<ul>
	<li>
		FIFA 23
	</li>
	<li>
		Out Of The Park Baseball 2023
	</li>
	<li>
		Football Manager
	</li>
	<li>
		Madden 23
	</li>
	<li>
		Art of Rally
	</li>
	<li>
		MLB
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135918" href="https://academy.hsoub.com/uploads/monthly_2023_09/sport-games.png.37d939e0010c050b20cf8ab9b72373e4.png" rel=""><img alt="الألعاب الإلكترونية الرياضية Sports Games" class="ipsImage ipsImage_thumbnailed" data-fileid="135918" data-ratio="57.25" data-unique="6tn64zo9f" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/sport-games.thumb.png.35d9de4f8ce1e3f1b96a4d3052bd70a4.png"> </a>
</p>

<p>
	وما يزيد الألعاب الرياضية حماسة هو أنها قد تعتمد على تقنيات ووحدات تحكم تمكن اللعب من الحركة خلال اللعب مثل أنظمة Wii التي أصدرتها شركة نينتندو Nintendo التي تتيح للاعب التحرك لمحاكاة ممارسة الرياضة بشكل فعلي والتمرين خلال اللعب بدلًا من البقاء جالسًا ومن أشهر أنواع الألعاب المخصصة للعب بهذه الطريقة سلسلة ألعاب Madden NFL و NBA 2K.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135916" href="https://academy.hsoub.com/uploads/monthly_2023_09/wii-games.png.png.7bafcf0e3e289745cbdf825f2dcaa4b0.png" rel=""><img alt="الألعاب الإلكترونية الرياضية" class="ipsImage ipsImage_thumbnailed" data-fileid="135916" data-ratio="53.50" data-unique="uyd8k4dc7" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/wii-games.png.thumb.png.61588c3f06aadf0418dca39408bf063f.png"></a>
</p>

<h3>
	4. ألعاب المحاكاة والسباق Racing and Simulation
</h3>

<p>
	ألعاب المحاكاة Simulation هي الألعاب التي تمكنك من تحقيق ما تريده في واقع افتراضي مشابه للواقع الفعلي، على سبيل المثال يمكنك من خلال هذا النوع من الألعاب الإلكترونية محاكاة مهام الطبخ والزراعة والغوص وتربية الحيوانات وقيادة السيارات أو المشاركة في سباق الدراجات النارية أو تجربة قيادة طائرة أو الغوص في أعماق المحيطات و غيرها من الهوايات التي تفضلها والتي قد لا تتمكن من مزاولتها في حياتك اليومية.
</p>

<p>
	من الأمثلة على هذا النوع من الألعاب نذكر:
</p>

<ul>
	<li>
		Gran Turismo
	</li>
	<li>
		Microsoft Flight Simulator
	</li>
	<li>
		Animal Crossing-New Horizons
	</li>
	<li>
		DiRT Rally
	</li>
	<li>
		FlightGear
	</li>
	<li>
		Trainz Railroad Simulator 2022
	</li>
	<li>
		Farming Simulator 2022
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135923" href="https://academy.hsoub.com/uploads/monthly_2023_09/racing-simulation-games.png.e6967209a2bb8b36475b1c2e484f1903.png" rel=""><img alt="ألعاب المحاكاة والسباق" class="ipsImage ipsImage_thumbnailed" data-fileid="135923" data-ratio="57.25" data-unique="mv9646v7d" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/racing-simulation-games.thumb.png.f4c3629c266aead7725c73e8a481ec09.png"></a>
</p>

<h3>
	5. الألعاب الإلكترونية الاستراتيجية Strategy Games
</h3>

<p>
	الألعاب الاستراتيجية هي ألعاب تتطلب تفكيرًا مسبقًا لتحقيق الهدف المطلوب من اللعب وكانت تستخدم سابقًا في تصميم الألعاب التقليدية مثل لعبة الشطرنج وهي اليوم تستخدم في الألعاب الإلكترونية التي تحتاج وقتًا طويلًا وتخطيطًا دقيقًا للربح.
</p>

<p>
	تقسم الألعاب الاستراتيجية إلى عدة أنواع فرعية بحسب طريقة اللعب ومن بين هذه الأنواع:
</p>

<ul>
	<li>
		الألعاب الاستراتيجية التي تلعب في الوقت الحقيقي Real-time strategy
	</li>
	<li>
		الألعاب الاستراتيجية المبنية على تبادل الدور Turn-based strategy
	</li>
	<li>
		ألعاب 4X.
	</li>
</ul>

<p>
	لنتعرف على الفرق بين كل نوع من هذه الأنواع بمزيد من التفصيل.
</p>

<h4>
	الألعاب الاستراتيجية التي تلعب في الوقت الحقيقي
</h4>

<p>
	تحاكي الألعاب الاستراتيجية في الوقت الحقيقي Real-time strategy أو ما يعرف اختصارًا بألعاب RTS ساحات المعارك والحروب وتلعب في الوقت الفعلي أي أنك تلعب في وقت واحد مع فريقك، ويتميز أسلوب اللعب فيها بوجود مناورات تكتيكية توجب على اللاعب الذي يلعب دور قائد المعركة توجيه فريقه واتخاذ القرارات ومهاجمة الأعداء وإنشاء الوحدات الدفاعية وتعديل استراتيجيته باستمرار مع تقدم اللعب.
</p>

<p>
	من أبرز الأمثلة البارزة على ألعاب استراتيجية في الوقت الحقيقي نذكر:
</p>

<ul>
	<li>
		Dune II
	</li>
	<li>
		DOTA 2
	</li>
	<li>
		League of Legends
	</li>
	<li>
		Plants vs. Zombies
	</li>
	<li>
		StarCraft
	</li>
	<li>
		World In Conflict
	</li>
	<li>
		Dawn of War
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135922" href="https://academy.hsoub.com/uploads/monthly_2023_09/Real-time-strategy-games.png.7140494e3b7930e813e593f1adf6b203.png" rel=""><img alt="الألعاب الاستراتيجية التي تلعب في الوقت الحقيقي" class="ipsImage ipsImage_thumbnailed" data-fileid="135922" data-ratio="57.25" data-unique="75jf9h6ml" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Real-time-strategy-games.thumb.png.13b527c90dff1db7845b3a444e8d0cea.png"> </a>
</p>

<h4>
	الألعاب الاستراتيجية المبنية على تبادل الدور
</h4>

<p>
	الألعاب الاستراتيجية المبنية على تبادل الدور Turn-based Strategy Games أو اختصارًا TBS هي ألعاب يتناوب فيها فريق اللاعبين في اللعب لتحقيق الفوز بدلًا من اللعب معًا بذات الوقت حيث يُسمح للاعب لعبة بتحليل وتخطيط اللعبة قبل البدء، وعندما يبدأ دوره باللعب يسمح له بالقيام بعدد محدود من الحركات أو الهجمات، ومن ثم يتيح لخصمه فرصة الرد. تتطلب هذه الألعاب الكثير من التخطيط والتأني فأي خطوة خاطئة قد تسبب خسارة اللاعب.
</p>

<p>
	من أبرز الأمثلة على هذا النوع من الألعاب:
</p>

<ul>
	<li>
		Jagged Alliance
	</li>
	<li>
		X-COM
	</li>
	<li>
		The Battle for Wesnoth
	</li>
	<li>
		Fire Emblem
	</li>
	<li>
		Final Fantasy Tactics
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135917" href="https://academy.hsoub.com/uploads/monthly_2023_09/Turn-based-strategy-games.png.c11ecf25670de84baa1a6a090026bd97.png" rel=""><img alt="الألعاب الإلكترونية الاستراتيجية المبنية على تبادل الدور" class="ipsImage ipsImage_thumbnailed" data-fileid="135917" data-ratio="57.25" data-unique="eh9fiuxfy" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Turn-based-strategy-games.thumb.png.fdffd56121bd548e38bc8315b04a38b1.png"> </a>
</p>

<h4>
	ألعاب 4X
</h4>

<p>
	أخيرًا ألعاب 4X هي ألعاب استراتيجية تعتمد على تبادل الأدوار TBS أو تلعب في الزمن الحقيقي RTS لكنها تركز على موضوعات أكثر تعقيدًا من النوعين السابقين فهي تتضمن أفكارًا معقدة وطويلة الأمد مثل بناء مستعمرات خاصة باللاعبين والاهتمام بأمور الاقتصاد والبحث العلمي والحياة الاجتماعية. وقد جاء اسمها من اختصار الكلمات التالية (eXplore, eXpand, eXploit, eXterminate) التي تصف طريقة لعبها حيث يتعين على اللاعب استكشاف Explore عوالم وموارد متنوعة والتوسع Expand من خلال بناء مستوطناتهم واستغلال Exploit الموارد بذكاء للتقدم والتفوق Exterminate على خصومهم..
</p>

<p>
	من أبرز الأمثلة على ألعاب 4X الاستراتيجية نذكر:
</p>

<ul>
	<li>
		Master of Orion
	</li>
	<li>
		Age of Empire
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135932" href="https://academy.hsoub.com/uploads/monthly_2023_09/4x-games.png.10f99f516e605e08ba83c8e3de650bb9.png" rel=""><img alt="ألعاب 4X" class="ipsImage ipsImage_thumbnailed" data-fileid="135932" data-ratio="57.25" data-unique="osnt2j00z" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/4x-games.thumb.png.4d2c8158fd5fac29275a20baf86df851.png"> </a>
</p>

<h3>
	6. ألعاب التصويب وإطلاق النار Shooting Games
</h3>

<p>
	ألعاب إطلاق النار هي ألعاب إلكترونية يستخدم فيها اللاعب أسلحة بعيدة المدى خلال اللعب، ويجب عليه التحرك بشكل مستمر ومواصلة الهجوم لقتل خصومه وتجنب هجماتهم القاضية.
</p>

<p>
	قد تكون ألعاب إطلاق النار ألعاب فردية مثل Battlefield 2042 أو Call of Duty أو متعددة اللاعبين أي أنها تضم فريق مكون من عدة شخصيات وتستلزم وجود تنسيق بينهم.
</p>

<p>
	تصنف ألعاب إطلاق النار أيضًا إلى عدة أصناف فرعية حسب منظور اللعب بشكل أساسي وهي
</p>

<h4>
	ألعاب التصويب من منظور الشخص الأول FPS
</h4>

<p>
	إذا كنت تتحكم بشخصية اللعب وترى بيئة اللعب من حولك كما لو كنت تنظر من خلال عيونها فحينها يطلق على هذه الألعاب اسم ألعاب التصويب من منظور الشخص الأول First-Person Shooters أو اختصارًا FPS.
</p>

<h4>
	ألعاب من منظور الشخص الثالث TPS
</h4>

<p>
	إذا كان التصويب يتم بحيث يمكنك رؤية شخصية اللعب بالكامل وكنت تتحكم فيها كما لو كنت تقف خلفها وترى بيئة اللعب من مسافة بعيدة وترى كل المعدات التي تستخدمها حينها يطلق على هذه الألعاب اسم ألعاب من منظور الشخص الثالث Third-Person Shooters أو اختصارًا TPS.
</p>

<p>
	ومن أبرز الأمثلة على ألعاب إطلاق النار المشهورة نذكر:
</p>

<ul>
	<li>
		Fortnit
	</li>
	<li>
		Team Fortress 2
	</li>
	<li>
		Overwatch
	</li>
	<li>
		Paladins
	</li>
	<li>
		Apex Legends
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135919" href="https://academy.hsoub.com/uploads/monthly_2023_09/Shooting-games.png.e86480d7e6ecdd344035ebdcb3d3b548.png" rel=""><img alt="ألعاب من منظور الشخص الثالث TPS" class="ipsImage ipsImage_thumbnailed" data-fileid="135919" data-ratio="57.25" data-unique="iixz948s6" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Shooting-games.thumb.png.5c29758ed206c28d066128955a922cc0.png"> </a>
</p>

<h3>
	7. ألعاب الألغاز والألعاب المنطقية Puzzle games
</h3>

<p>
	تهدف ألعاب الألغاز إلى تحفير <a href="https://academy.hsoub.com/programming/general/%D8%A3%D9%87%D9%85%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D8%B1-%D8%A7%D9%84%D9%85%D9%86%D8%B7%D9%82%D9%8A-%D9%81%D9%8A-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r2095/" rel="">التفكير المنطقي</a> للاعبين وتعزز مهاراتهم في حل المشكلات عن طريق طرح ألغاز وتحديات منطقية ومفاهيمية تحفز العقل وتطور التفكير، وتعتمد عادة على التدرج في صعوبة التحديات فعند إكمال كل لغز سيقدم للاعب لغز أكثر صعوبة ويستلزم المزيد من التفكير.
</p>

<p>
	تلقى هذه الألعاب على بساطتها وسهولتها رواجًا كبيرًا بين أوساط المستخدمين ومن أبرزها الأمثلة عليها:
</p>

<ul>
	<li>
		Sudoku
	</li>
	<li>
		Tetris 99
	</li>
	<li>
		Jigsaws
	</li>
	<li>
		Tetris
	</li>
	<li>
		Myst
	</li>
	<li>
		Words with Friends
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135924" href="https://academy.hsoub.com/uploads/monthly_2023_09/Puzzle-games.png.2650b8a5559cdf3d8a1ea875e549e55d.png" rel=""><img alt="ألعاب الألغاز والألعاب المنطقية" class="ipsImage ipsImage_thumbnailed" data-fileid="135924" data-ratio="57.25" data-unique="1nbpjfa6y" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Puzzle-games.thumb.png.e1f0190200e92e2f70253e9ceb59c20c.png"> </a>
</p>

<p>
	ومن أنواعها الفرعية ألعاب الأغراض المخفية Hidden Object Puzzle Adventure أو اختصار HOPA وهي ألعاب تحفز اللاعب على العثور على أشياء مختلفة مخفية في صورة ما، وعادةً ما تكون هذه الأشياء مخبأة بشكل جيد وصعبة الرؤية بسبب التمويه أو الاكتظاظ في الصورة، ومن الأمثلة عليها:
</p>

<ul>
	<li>
		Hidden Folks
	</li>
	<li>
		Milo And The Magpies
	</li>
	<li>
		Hidden City
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135926" href="https://academy.hsoub.com/uploads/monthly_2023_09/hidden-object-puzzle-adventure-games.png.d881e029ad3cdf5eb753ea016ad1ccc6.png" rel=""><img alt="ألعاب الألغاز الإلكترونية" class="ipsImage ipsImage_thumbnailed" data-fileid="135926" data-ratio="57.25" data-unique="r3hek6r7w" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/hidden-object-puzzle-adventure-games.thumb.png.9c6158538bfdbc2d5f6767730428345d.png"> </a>
</p>

<h3>
	8. الألعاب اليومية غير الرسمية Casual Games
</h3>

<p>
	مع انتشار الهواتف المحمولة في كل مكان في المجتمع، زاد الطلب على نوع جديد من الألعاب يعرف بالألعاب غير الرسمية Casual أو ألعاب الكسالى والخاملين Idle Games وهي ألعاب موجهة للاعبين الذين ليس لديهم وقت للعب ألعاب طويلة وصعبة ويحتاجون فقط لبعض التسلية وقضاء وقت سريع لا يتجاوز عدة دقائق على الهاتف خلال انتظار ممل في طابور أو في تنقلهم بالمواصلات حيث تتميز هذه الألعاب بكونها ألعاب بسيطة وسهلة اللعب ولا تفرض على اللاعب قواعد صارمة أو استراتيجيات صعبة.
</p>

<p>
	كل ما يحتاجه اللاعب للفوز في هذه الألعاب هو القيام ببضع نقرات على الشاشة أو الإجابة على أسئلة بسيطة للحصول على النقاط وشراء عناصر تساعده على الحصول على نقاط جديدة بسرعة أكبر، وغالبًا ما تحتوي على حفظ تلقائي ومزامنة يسمح للاعب بتصغيرها أو وضعها في وضع السكون أو إيقافها دون خسارة نقاطه وهي تمنح الكثير من المكافآت مع الوقت لتشجيع اللاعب على مواصلة اللعب.
</p>

<p>
	أمثلة على هذا النوع من الألعاب:
</p>

<ul>
	<li>
		Cookie Clicker
	</li>
	<li>
		Idle Miner Tycoon
	</li>
	<li>
		Doge Miner
	</li>
	<li>
		Cats and Soup
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135928" href="https://academy.hsoub.com/uploads/monthly_2023_09/casual-games.png.e3c2a390fe23a5da284e12d6fea1112f.png" rel=""><img alt="الألعاب الالكترونية اليومية غير الرسمية" class="ipsImage ipsImage_thumbnailed" data-fileid="135928" data-ratio="57.25" data-unique="hly58xib4" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/casual-games.thumb.png.36aabec01807591598130d231d8e5547.png"> </a>
</p>

<h3>
	9. ألعاب المنصات Platform games
</h3>

<p>
	ألعاب المنصات هي نوع من الألعاب الإلكترونية المرحة والممتعة التي تعتمد في أسلوب اللعب على القفز والتسلق ضمن بيئة اللعبة بشكل أساسي وتتطلب من اللاعب الانتقال بين عدة منصات معلقة وتجنب أي خصوم أو عقبات خلال تنقله، يمكن للشخصية في هذا النوع من الألعاب القفز لمسافات تبلغ عدة أضعاف ارتفاعها كما يمكنها التحكم في حركتها في الجو وتحديد الارتفاع ومسافة القفز التي تريدها حسب ما يتطلب الوضع.
</p>

<p>
	كما تعد ألعاب ميترويدفانيا Metroidvania نوعًا فرعيًا من ألعاب الحركة والمغامرات أو ألعاب المنصات ويأتي اسمها من جمع اسم سلسلتي ألعاب قديمة Metroid باسم Castlevania فهي ألعاب تركز على الاستكشاف وتتميز بوجود خرائط لعوالم كبيرة مترابطة يمكن للاعب استكشافها وتسجل تقدمه أثناء الاستكشاف، وقد يصل خلال استكشافه لأماكن سرية أو يعلق في أماكن ذات أبواب مغلقة لا يمكنه فتحها إلا بعد الحصول على أسلحة أو قدرات خاصة أو بعد الحوار مع عنصر أو شخصية معينة وبعدها يتم فتح هذه الأقسام ويتابع تقدمه.
</p>

<p>
	ومن أشهر أنواع ألعاب المنصات نذكر:
</p>

<ul>
	<li>
		Super Mario Bros
	</li>
	<li>
		Captain Toad’s Treasure Tracker
	</li>
	<li>
		Donkey Kong
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135925" href="https://academy.hsoub.com/uploads/monthly_2023_09/Platform-games.png.bad114c2225f9ff11baed228a51934f7.png" rel=""><img alt="ألعاب المنصات" class="ipsImage ipsImage_thumbnailed" data-fileid="135925" data-ratio="57.25" data-unique="wbfm00fo8" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/Platform-games.thumb.png.0579ceb9d5c8aeda50db8c4aca46f9ba.png"> </a>
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلة صناعة الألعاب ثنائية وثلاثية الأبعاد وابتكر ألعاب ممتعة تفاعلية ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<h3>
	10. ألعاب الحركة أو الأكشن Action Games
</h3>

<p>
	كانت معظم الألعاب الإلكترونية في البداية تعتبر ألعاب أكشن وهي ألعاب تتضمن تحديات جسدية وتحتاج لحركة سريعة ودائمة وتتطلب وجود مهارات حركية لدى اللاعب كي يتحكم في أحداث اللعبة بسرعة من خلال التنسيق بين اليد والعين، ورغم ظهور العديد من أنواع الألعاب الإلكترونية فيما بعد لا يزال هذا الأسلوب من اللعب يستخدم في العديد من الألعاب لاسيما ألعاب القتال وألعاب التصويب وألعاب المنصات.
</p>

<p>
	من الأمثلة على ألعاب الحركة نذكر:
</p>

<ul>
	<li>
		Mortal Kombat 1
	</li>
	<li>
		Red Dead Redemption II
	</li>
	<li>
		Baldur's Gate III
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135931" href="https://academy.hsoub.com/uploads/monthly_2023_09/action-games.png.48da4aadb67f88ced44f65060961b52c.png" rel=""><img alt="ألعاب الحركة أو الأكشن" class="ipsImage ipsImage_thumbnailed" data-fileid="135931" data-ratio="57.25" data-unique="tmyaef3gk" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/action-games.thumb.png.9a0dc310307b1137f2808212e5e18fde.png"> </a>
</p>

<h3>
	11. الألعاب القتالية Fighting games
</h3>

<p>
	السمة المميزة للألعاب القتالية هي وجود شخصية تتبارز ضد عدد محدود من الخصوم أو الأعداء الموجودين على مسافة قريبة منها وغالبًا ما تكون هذه الألعاب متعدد اللاعبين وهي لا تستخدم أسلحة أو إطلاق نار بل تعتمد على استخدام الفنون القتالية كالملاكمة والجودو والعراك بالأيدي.
</p>

<p>
	من أشهر الأمثلة على الألعاب القتالية:
</p>

<ul>
	<li>
		Mortal Kombat
	</li>
	<li>
		Street Fighter
	</li>
	<li>
		Samurai Shodown
	</li>
	<li>
		Super Smash Bros
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135927" href="https://academy.hsoub.com/uploads/monthly_2023_09/Fighting-games.png.d952975a3355ed36aef43f031d643294.png" rel=""><img alt="الألعاب الالكترونية القتالية" class="ipsImage ipsImage_thumbnailed" data-fileid="135927" data-ratio="57.25" data-unique="gm3gvatpm" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/Fighting-games.thumb.png.bfa1896f88f0f1c9769a3c9db9715038.png"> </a>
</p>

<h3>
	12. ألعاب المغامرات Adventure Games
</h3>

<p>
	تتميز ألعاب المغامرات بوجود رواية أو قصة تفاعلية يأخذ فيها اللاعب دور بطل القصة ويقود مغامرة يستكشف فيها بيئة اللعب وقد يواجه بعض المخاطر التي عليه تفاديها ويحل بعض الألغاز ليتقدم في اللعبة.
</p>

<p>
	من أشهر الأمثلة على ألعاب المغامرات:
</p>

<ul>
	<li>
		Steve's World
	</li>
	<li>
		Puzzle Room Escape
	</li>
	<li>
		Stellar Mines: Space Miner
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135929" href="https://academy.hsoub.com/uploads/monthly_2023_09/Adventure-games.png.1c9ede4e1d15e8172003dac0b6d3be07.png" rel=""><img alt="ألعاب المغامرات" class="ipsImage ipsImage_thumbnailed" data-fileid="135929" data-ratio="57.25" data-unique="ytbo63rvn" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/Adventure-games.thumb.png.83d1a4f382fd1ff1033f54597e8389a0.png"> </a>
</p>

<p>
	لا تتضمن ألعاب المغامرات بطبيعتها عناصر قتالية لكن يمكن أن تدمج ألعاب المغامرات مع ألعاب القتال كما في لعبة Prototype2 ولعبة Grand Theft Auto3 بحيث تجمع اللعبة بين القتال والاستكشاف وتتضمن محاربة بعض الوحوش والحصول على الغنائم خلال اللعب لجعلها أكثر حماسة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="135930" href="https://academy.hsoub.com/uploads/monthly_2023_09/Adventure-fight-games.png.2de3cc532f11da4824b5d561334999c4.png" rel=""><img alt="ألعاب المغامرات الالكترونية" class="ipsImage ipsImage_thumbnailed" data-fileid="135930" data-ratio="57.25" data-unique="jiclz8c5t" style="width: 400px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/Adventure-fight-games.thumb.png.61336bd93c2fb05fb4bba08d0d130019.png"> </a>
</p>

<h3>
	13. ألعاب الآركيد Arcade
</h3>

<p>
	ألعاب الآركيد Arcade هي ألعاب فيديو تعمل على أجهزة مخصصة تسمى آلات الآركيد، وكانت هذه الألعاب شائعة في الستينيات والسبعينيات والثمانينيات من القرن الماضي وتتميز بشخصيات بسيطة وأساليب لعب متنوعة وسهلة مثل ألعاب الإطلاق التي تتطلب من اللاعب إطلاق النار على الأعداء أو أهداف أخرى، وألعاب السباق البسيطة وألعاب القتال، وبالرغم من أن ألعاب الآركيد لم تعد شائعة اليوم  بكثرة إلا أنها لا تزال تحظى ببعض الشعبية لاسيما في صالات الألعاب ومراكز التسوق والمتنزهات العامة.<br>
	ومن أشهر الأمثلة على هذا النوع من الألعاب:
</p>

<ul>
	<li>
		Pac-Man
	</li>
	<li>
		Donkey Kong
	</li>
	<li>
		Dragon’s Lair
	</li>
</ul>

<p>
	كانت هذه أبرز أنواع الألعاب الإلكترونية، وهناك بلا شك العديد من الأنواع الأخرى لكننا ركزنا على الأنواع الرائجة بين أوساط المستخدمين والمطلوبة في سوق العمل.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في مقال اليوم على أهمية صناعة الألعاب الإلكترونية في سوق العمل واكتشفنا مختلف أنواع الألعاب الإلكترونية وأهم مميزاتها وخصائصها والألعاب المشهورة التي تنتمي لكل نوع، فإذا كنت مطور ألعاب وتنوي البدء بتطوير لعبة جديدة نأمل أن يساعدك هذا المقال على إيجاد النوع المناسب لجمهورك المستهدف والبدء على تنفيذه.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">تعرف على أشهر محركات الألعاب Game Engines</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">تعرف على أشهر لغات برمجة الألعاب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%81%D8%B6%D9%84-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D8%AC-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-r2227/" rel="">تعرف على أفضل برنامج تصميم الألعاب الإلكترونية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">مطور الألعاب: من هو وما هي مهامه</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2136</guid><pubDate>Tue, 19 Sep 2023 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x623;&#x634;&#x647;&#x631; &#x645;&#x62D;&#x631;&#x643;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628; Game Engines</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_09/--.png.0494595753ba4f7b47a5ba8919b74dda.png" /></p>
<p>
	هل أنت مهتم بتطوير الألعاب، وتود التعرف على مفهوم محرك الألعاب وأفضل أنواع محركات الألعاب Game Engines التي توفر لك بيئة عمل متكاملة يمكنك من خلالها برمجة الألعاب بسهولة واحترافية؟ نعرّفك في هذه المقالة على أبرز محركات الألعاب ونوضح أهم مميزاتها وعيوبها لتختار منها ما يناسبك وتنطلق في مجال صناعة الألعاب.
</p>

<h2>
	مدخل إلى برمجة الألعاب
</h2>

<p>
	قبل التعمق في شرح مفهوم محرك الألعاب لنتحدث بإيجاز عن خطوات تطوير وبرمجة الألعاب، حيث تضم عملية تطوير الألعاب عدة مراحل لا تقتصر فقط على المهارات البرمجية والرياضية، بل تحتاج لوجود مهارات فنية وإبداعية، والقدرة على ابتكار أفكار لعب مشوقة، وسرد اللعبة بطريقة واضحة تبين للاعب قوانين اللعبة وطريقة اللعب بها.
</p>

<p>
	قد تختلف مراحل تطوير الألعاب بحسب نوع اللعبة ومستواها ومنصة اللعب بها، إلا أنها تمر بمجموعة من المراحل الأساسية تشمل:
</p>

<ol>
	<li>
		التخطيط للعبة ووضع تصور عام لها وتحديد نوعها ومميزاتها وطريقة اللعب بها والمستويات التي تتضمنها والمنصة التي ستعمل عليها.
	</li>
	<li>
		تصميم اللعبة فبمجرد الانتهاء من مرحلة التخطيط للعبة تبدأ مرحلة التصميم وتحديد الشكل الذي ستظهر به هل هي ثنائية الأبعاد 2D أم ثلاثية الأبعاد 3D وشكل الشخصيات ونمط رسمها وهل ستصمم الشخصيات من الصفر أم ستستورد من مصدر جاهز.
	</li>
	<li>
		برمجة اللعبة في هذه المرحلة تتم كتابة المنطق البرمجي الذي يجعل اللعبة تعمل مع تحديد الأدوات أو التقنيات اللازمة لتحقيق ذلك، وهنا أمام المطور خياران إما البدء بكتابة كافة الأكواد البرمجية اللازمة لعمل اللعبة من الصفر بإحدى <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a> وهذا سيستغرق وقتًا وجهدًا كبيرين وهو يصلح لبرمجة الألعاب البسيطة أو استخدام محركات ألعاب متخصصة تساعد مبرمج الألعاب في أداء المهام التطويرية وتمكنه من تطوير ألعاب عالية الجودة بأقل جهد.
	</li>
	<li>
		اختبار اللعبة حيث بعد الانتهاء من برمجة اللعبة يجب اختبارها وتجربة اللعب بها والتأكد من أنها تعمل بالشكل المطلوب وإصلاح أي أخطاء تظهر فيها.
	</li>
	<li>
		نشر اللعبة على المنصات أو المتاجر الخاصة بها وإتاحتها للمستخدمين، على سبيل المثال إذا قمت بإنشاء لعبة تعمل على الجوال تحتاج لتحميلها على متجر تطبيقات جوجل بلاي ومتجر تطبيقات آبل.
	</li>
</ol>

<p>
	بالنسبة للألعاب البسيطة يمكن أن يكون مصمم اللعبة ومبرمج اللعبة هو الشخص نفسه، أم في الألعاب المتقدمة فيكون هناك فريق تطوير متخصص مكون من مجموعة أفراد الذين يعملون معًا لإنشاء وتطوير الألعاب كالمصممين الذين يبتكرون تصاميم اللعبة والمطورين الذين يكتبون الكود البرمجي لها ومهندسين لإنشاء أصوات اللعبة ومصممي مستويات اللعبة وأحيانًا كتَّاب سيناريو ومنتجين ومخرجين وغيرهم من الأشخاص المختصين بحسب مستوى اللعبة ودرجة تعقيدها.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" id="ips_uid_1493_5" src="https://academy.hsoub.com/applications/core/interface/index.html" title="ما هي برمجة الألعاب" width="930" data-embed-src="https://www.youtube.com/embed/O5suGXMNMdU"></iframe>
</p>

<h2>
	ما هو محرك الألعاب Game Engine؟
</h2>

<p>
	محرك الألعاب game engine أو ما يعرف بإطار عمل الألعاب game framework هو البيئة المسؤولة عن تشغيل الألعاب، إذ يوفر للمبرمجين <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل </a> برمجي يتضمن التعليمات البرمجية الأساسية والأدوات الجاهزة والمكتبات المضمنة التي توفر كافة الوظائف التي يحتاجها المطور لتطوير وتخصيص ونشر الألعاب بسرعة وسهولة.
</p>

<p>
	يعد محرك الألعاب أساس إنشاء وتشغيل الألعاب المختلفة، واختياره خطوة أولى لتطوير الألعاب باختلاف أنواعها، ويمكن تشبيه محرك الألعاب بمحرك السيارة فكما أن محرك السيارة هو ما يشغل هيكل السيارة ويجعلها تتحرك فهو ما يوفر البنية التحتية الرقمية اللازمة لتشغيل عناصر اللعبة وجعلها تعمل بالشكل المطلوب.
</p>

<p>
	لقد أحدثت محركات الألعاب تحولًا جذريًا في مجال تطوير الألعاب فقبل ظهورها كان مطور الألعاب يحتاج لتصميم كل تفاصيل لعبته الألعاب من الألف إلى الياء وكتابة كافة التعليمات البرمجية المطلوبة لتصميم الألعاب ونشرها على المنصات المختلفة، لكن باستخدام محركات الألعاب لن تكون مضطرًا لكتابة الكثير من التعليمات البرمجية المعقدة لتجعل لعبتك تعمل بالشكل المطلوب وستتمكن من خلال برنامج واحد إنشاء ألعاب متعددة المنصات تعمل على أجهزة الحاسوب الشخصية والأجهزة المحمولة ووحدات التحكم بالألعاب consoles ومنصات الواقع الافتراضي VR platforms، فكل ما تحتاجه لتصميم لعبة متكاملة اليوم هو تعلم استخدام أحد محركات الألعاب ومعرفة أساسية بإحدى لغات البرمجة التي يدعمها هذا المحرك.
</p>

<h2>
	مكونات محرك الألعاب
</h2>

<p style="text-align: center;">
	<img alt="محرك الألعاب.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="134478" data-ratio="95.60" data-unique="rqqv9d2qg" style="width: 300px; height: auto;" width="553" src="https://academy.hsoub.com/uploads/monthly_2023_09/1309648070_.jpg.4a1f1d082519348170c980e03ce2b383.jpg">
</p>

<p>
	يتضمن محرك الألعاب عادة مجموعة من المكونات أو المحركات الفرعية التي تتفاعل مع بعضها البعض لتجعل عناصر أو كائنات اللعبة تقوم بكافة الوظائف الضرورية التي تحتاجها، وأهم هذه المحركات:
</p>

<ul>
	<li>
		محرك الفيزياء Physics Engine
	</li>
	<li>
		محرك التصيير أو الإخراج Rendering Engine
	</li>
	<li>
		محرك الرياضيات Math Engine
	</li>
	<li>
		محرك الصوت Sound Engine
	</li>
	<li>
		محرك الشبكة Networking Engine
	</li>
	<li>
		محرك الذكاء الاصطناعي AI Engine
	</li>
</ul>

<p>
	لنتناول بإيجاز دور كل محرك من هذه المحركات والوظائف التي يقدمها.
</p>

<h3>
	1. محرك الفيزياء Physics Engine
</h3>

<p>
	المسؤول عن جعل عناصر اللعبة تظهر بطريقة واقعية عندما تسقط أو تصدم ببعضها البعض أو عند إطلاق قذيفة أو انسكاب سوائل وغيرها من التصرفات.
</p>

<h3>
	2. محرك التصيير أو الإخراج Rendering Engine
</h3>

<p>
	يعرف كذلك باسم المحرك الرسومي graphic engine وهو مسؤول بشكل أساسي عن إخراج رسومات اللعبة بشكل ثنائي الأبعاد 2D أو ثلاثي الأبعاد 3D.
</p>

<h3>
	3. محرك الرياضيات Math Engine
</h3>

<p>
	المسؤول عن توفير الوظائف الرياضية مثل حساب المسافة أو حساب السرعة وغيرها من العمليات الرياضية التي تفيدك في سياق التحكم في شخصيات اللعبة.
</p>

<h3>
	4. محرك الصوت Sound Engine
</h3>

<p>
	المسؤول عن تحميل وتشغيل ملفات الصوت والتأثيرات الصوتية داخل اللعبة وتحسينها والتحكم بها.
</p>

<h3>
	5. محرك الشبكة Networking Engine
</h3>

<p>
	الذي يتيح لك استخدام الشبكات لتطوير ألعاب متعددة اللاعبين multiplayer games ما يجعل اللعبة أكثر حماسًا وتفاعلية.
</p>

<h3>
	6. محرك الذكاء الاصطناعي AI Engine
</h3>

<p>
	وهو المسؤول عن تقديم توصيات أو اتخاذ قرارات في اللعبة بناءً على سلوك اللاعب.
</p>

<p>
	قد لا تستخدم كافة هذه المحركات في تصميم لعبتك إذ يعتمد الأمر على طبيعة اللعبة التي تطورها والمميزات التي توفرها. دعنا نتعرف في الفقرات التالية ما هي أهم محركات الألعاب ونكتشف أبرز مميزاتها لتختار منها ما يناسبك.
</p>

<h2>
	أشهر محركات الألعاب
</h2>

<p>
	هناك العديد من محركات الألعاب التي توفر إمكانيات ومميزات مختلفة وتستهدف منصات متعددة وتتناسب مع أنواع ومستويات ألعاب مختلفة، ويعتمد اختيار محرك الألعاب المناسب على متطلبات اللعبة التي تود تطويرها مثل نوع اللعبة، والمنصة التي تستهدفها، ونوع الجهاز الذي ستعمل عليه، وغيرها من العوامل.
</p>

<p>
	وإليك قائمة بأبرز محركات الألعاب:
</p>

<ol>
	<li>
		محرك الألعاب Unity Engine
	</li>
	<li>
		محرك الألعاب Unreal Engine
	</li>
	<li>
		محرك الألعاب Godot Engine
	</li>
	<li>
		محرك الألعاب GameMaker Engine
	</li>
	<li>
		محرك الألعاب Open 3D
	</li>
	<li>
		محرك الألعاب jMonkey Engine
	</li>
	<li>
		محرك الألعاب FrostBite
	</li>
</ol>

<p>
	لنتعرف بمزيد من التفصيل على كل محرك من بين هذه المحركات ونكتشف أبرز مميزاته وعيوبه.
</p>

<h3>
	1. محرك الألعاب Unity Engine
</h3>

<p>
	محرك يونتي <a href="https://unity.com/" rel="external nofollow">Unity Engine</a> هو واحد من أشهر محركات الألعاب طورته شركة Unity Technologies لتصميم ألعاب فيديو متكاملة الوظائف ومتعددة المنصات، يتميز محرك ألعاب Unity بالمرونة وسهولة الاستخدام ويناسب مطوري الألعاب المبتدئين والخبراء على حد سواء، كما أنه يعمل على كافة أنواع الأجهزة سواء أجهزة الحاسوب أو الجوال أو وحدات تحكم الألعاب الأخرى ويتوافق مع مختلف أنظمة التشغيل، وهو خيار مثالي لبرمجة ألعاب الهواتف المحمولة وألعاب الويب وسطح المكتب خفيفة الحجم.
</p>

<p>
	كما يوفر محرك Unity العديد من الميزات والوظائف المضمنة التي تساعد المطورين في تصميم ألعاب احترافية، مثل منصة تطوير ثنائية وثلاثية الأبعاد لبرمجة الألعاب، وميزات اكتشاف الاصطدام والفيزياء المضمنة، وعرض رسومات الألعاب بشكل ممتاز حتى على الأجهزة ذات الجودة المنخفضة، كما يوفر متجر ألعاب خاص به <a href="https://assetstore.unity.com/" rel="external nofollow">Unity Asset Store</a> ليتيح للمطورين إنشاء وبيع الألعاب ومحلقاتها ومواردها المختلفة مثل التأثيرات الصوتية والبصرية والبيئات ثنائية وثلاثية الأبعاد وغيرها من العناصر التي تحتاجها لتصميم وبرمجة ألعاب احترافية بسرعة وبأقل جهد.
</p>

<p style="text-align: center;">
	<img alt="شعار Unity Engine" class="ipsImage ipsImage_thumbnailed" data-fileid="134367" data-ratio="56.15" data-unique="q80nyygpn" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/Unity-Engine.png.2422fb800a057cb464dcf5d017cad3ad.png">
</p>

<p>
	يتميز محرك ألعاب يونيتي Unity عن غيره من محركات الألعاب بأنه يستخدم عدة صناعات أخرى غير صناعة الألعاب مثل التصوير السينمائي والهندسة المعمارية وتصميم السيارات وغيرها من الصناعات، وهو متوفر بإصدار شخصي مجاني <a href="https://unity.com/products/unity-personal" rel="external nofollow">Unity Personal</a> مخصص للأفراد والهواة والمؤسسات الصغيرة للمشاريع التي تدرّ أرباحًا تقل عن 200000 دولار سنويًا، وإصدار آخر احترافي <a href="https://store.unity.com/configure-plan/unity-pro" rel="external nofollow">Unity Pro</a> تبلغ تكلفته الشهرية 185 دولار وتكلفته السنوية 2040 دولار -أثناء كتابة المقال- لكل مقعد أو مستخدم، مع فترة تجريبية مجانية مدتها 30 يومًا.
</p>

<p>
	وقد <a href="https://blog.unity.com/news/plan-pricing-and-packaging-updates" rel="external nofollow">أعلنت شركة Unity Technologies</a><span style="display: none;">   </span> مؤخرًا فرض رسوم جديدة على المطورين بداية من الأول من يناير 2024 لزيادة ربحيتها وبأنها ستتقاضى رسومًا من المطورين في كل مرة يتم فيها تنزيل ألعابهم أي أن الرسوم ستفرض على المطور إما عندما تتجاوز إيرادات لعبته مبلغ 200000 دولار سنويًا  أو عندما يبلغ عدد مرات تثبيت لعبته 200000 تثبيت لكنها تراجعت سريعًا عن قرار فرض رسوم مقابل عدد مرات التثبيت بعد أن تعرضت لانتقادات واحتجاجات واسعة من قبل المطورين وصناع الألعاب الذين يستخدمون محرك الألعاب يونتي Unity، ووضحت أن القرار سيبطق على الإصدارات المستقبلية من المحرك فقط في حال اختار المطور تحديثه.
</p>

<p>
	من أشهر الألعاب المطورة باستخدام محرك ألعاب Unity نذكر:
</p>

<ul>
	<li>
		Pokémon Go
	</li>
	<li>
		Cuphead
	</li>
	<li>
		Angry Birds 2+‎
	</li>
	<li>
		Temple Run
	</li>
	<li>
		Monument Valley
	</li>
	<li>
		Lara Croft Go
	</li>
	<li>
		Pillars of Eternity
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134245" href="https://academy.hsoub.com/uploads/monthly_2023_09/unity-games.png.7891c22ed95d837a726b23e265c44d10.png" rel=""><img alt="ألعاب محرك Unity" class="ipsImage ipsImage_thumbnailed" data-fileid="134245" data-ratio="62.50" data-unique="i0vw4r0da" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/unity-games.thumb.png.6fc91537837c3bcd0bd7867a2ac56126.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134134" href="https://academy.hsoub.com/uploads/monthly_2023_09/unity-games.png.86323cc527447e6ebefb6c9c18c7703e.png" rel=""> </a>
</p>

<h3>
	2. محرك الألعاب Unreal Engine
</h3>

<p>
	محرك ألعاب أن ريل <a href="https://www.unrealengine.com/" rel="external nofollow">Unreal Engine</a> هو محرك تطوير ألعاب مفتوح المصدر طورته شركة Epic Games عام 1988وهو يستخدم لإنشاء مختلف أنواع الألعاب الإلكترونية متعددة المنصات، ويتميز بكونه سهل الاستخدام وموثق بشكل جيد وواضح حيث يوفر للمطورين مجموعة شاملة من الموارد والشروحات التعليمية التي تساعدهم على تعلم استخدام المحرك بسرعة، إلى جانب ذلك يوفر مكتبة ألعاب متنوعة يمكن للمطور أن يحمِّل ما يشاء منها من مصادر ويسرّع تطوير ألعابه.
</p>

<p>
	لا يستخدم محرك Unreal عادة في تصميم وبرمجة الألعاب البسيطة فهو يعتمد على لغة البرمجة C++‎ لإضافة المنطق للألعاب وهي لغة صعبة نسبيًا للمبتدئين، لذا يناسب هذا المحرك مطوري الألعاب المحترفين الذين يستفيدون من أدائه العالي في برمجة الألعاب الثقيلة الحجم ذات الرسومات المتقدمة القريبة للواقع، والألعاب متعددة اللاعبين، وألعاب الواقع الافتراضي VR وألعاب الذكاء الاصطناعي التي تتطلب الكثير من الموارد وتعمل عليها فرق تطوير كبيرة والتي تعرف باسم ألعاب <strong>AAA Games</strong> كما يستخدم كذلك في مجالات أخرى مثل <a href="https://andreaugustobr.medium.com/how-unreal-engine-is-changing-the-automotive-industry-completely-2b8f4ce80460" rel="external nofollow">صناعة السيارات</a> حيث يساعد في إنشاء تصاميم ثلاثية الأبعاد مفصلة وتفاعلية للسيارات ومحاكاتها قبل البدء بتصنيعها مما يساعد في اختيار التصميم الأنسب.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134133" href="https://academy.hsoub.com/uploads/monthly_2023_09/Unreal-Engine.png.181588000113351ea53f7de9d6919cf3.png" rel=""><img alt="Unreal Engine" class="ipsImage ipsImage_thumbnailed" data-fileid="134133" data-ratio="56.15" data-unique="hajfltkxd" style="width: 500px; height: auto;" width="800" src="https://academy.hsoub.com/uploads/monthly_2023_09/Unreal-Engine.png.181588000113351ea53f7de9d6919cf3.png"></a>
</p>

<p>
	يمكن تنزيل محرك Unreal Engine واستخدامه بشكل مجاني والبدء باستخدامه لتطوير ألعابك الخاصة دون دفع أي تكاليف، لكنك ستدفع رسوم ملكية بنسبة تساوي 5% عندما تحقق لعبتك أرباح تزيد على مليون دولار.
</p>

<p>
	من أشهر الألعاب المطورة باستخدام محرك ألعاب Unreal نذكر:
</p>

<ul>
	<li>
		Fortnite
	</li>
	<li>
		PUBG
	</li>
	<li>
		Gears of War
	</li>
	<li>
		Mortal Kombat
	</li>
	<li>
		Borderlands
	</li>
	<li>
		Tetris Effect
	</li>
	<li>
		Yoshi's Crafted World
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134246" href="https://academy.hsoub.com/uploads/monthly_2023_09/unreal-games.png.150aa52de34d108aa138ae346c45b630.png" rel=""><img alt="ألعاب مطورة عبر Unreal Engine" class="ipsImage ipsImage_thumbnailed" data-fileid="134246" data-ratio="62.50" data-unique="hi1bt0bej" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/unreal-games.thumb.png.66683ba2d19cbb664e3b542ae47a992e.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134132" href="https://academy.hsoub.com/uploads/monthly_2023_09/unreal-games.png.e9ffe086a1cc29a042a017d5aea0cd42.png" rel=""> </a>
</p>

<h3>
	3. محرك الألعاب Godot Engine
</h3>

<p>
	محرك الألعاب جودو <a href="https://godotengine.org/" rel="external nofollow">Godot Engine</a> هو برنامج مفتوح المصدر لتصميم الألعاب طوره المبرمجان الأرجنتينيان جوان لينيتسكي Juan Linietsky وأرييل مانزور Ariel Manzur عام 2014 بهدف تطوير محرك فعال ومرن يناسب المطورين المبتدئين والمحترفين على حد سواء ويسمح لهم بإنشاء وتخصيص ألعابهم بسهولة كبيرة، حيث يعتمد محرك ألعاب جودو على لغة البرمجة <a href="https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/index.html" rel="external nofollow">GDScript</a> وهي لغة بسيطة وسهلة المقروئية تشبه في تركيبتها لغة بايثون <a href="https://wiki.hsoub.com/Python" rel="external">python</a>، كما يسمح للمطورين بكتابة منطق ألعابهم بلغات برمجة أخرى مختلفة مثل <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++‎</a> أو <a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-c-r597/" rel="">C#</a>‎ أو روبي <a href="https://wiki.hsoub.com/Ruby" rel="external">Ruby</a>.
</p>

<p>
	يتضمن محرك ألعاب جودو العديد من الميزات أبرزها توفير بيئة تطوير ألعاب ثنائية وثلاثية الأبعاد، وأدوات لإنشاء وإخراج الرسومات وعرضها، ومحرر شيفرات مدمج، ومشغل للملفات الصوتية، ومحرك فيزياء، وغيرها من الميزات ضمن واجهة رسومية بسيطة وسهلة الاستخدام تعتمد السحب والإفلات، كما يدعم محرك ألعاب جودو منصات متعددة فهو يسمح بتصميم ألعاب متوافقة مع أنظمة ويندوز ولينكس وماك وأندرويد Android وآي أو إس iOS كما يسمح بتصدير الألعاب بصيغة <a href="https://academy.hsoub.com/files/13-%D9%86%D8%AD%D9%88-%D9%81%D9%87%D9%85-%D8%A7%D9%94%D8%B9%D9%85%D9%82-%D9%84%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-html5/" rel="">HTML5</a> لتناسب الويب.
</p>

<p style="text-align: center;">
	<img alt="محرك الألعاب Godot Engine" class="ipsImage ipsImage_thumbnailed" data-fileid="134141" data-ratio="56.15" data-unique="b411e3f3q" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/Godot-Engine.png.8c2c0e870f627a243578fef160b3dc4d.png">
</p>

<p>
	يعتمد محرك الألعاب جودو على مفهوم العقد Nodes والمشاهد scenes، فاللعبة في جودو ليست سوى مجموعة من مشهد أو مجموعة من المشاهد وكل مشهد عبارة عن شجرة من العقد، تشكل العقد الوحدات أو اللبنات الأساسية لبناء اللعبة والعقدة هي كائن يمثل وظيفة ما فقد تعرض العقدة الرسومات، أو تشغل الرسوم المتحركة، أو تشغل صوت أو تمثل نموذجًا ثلاثي الأبعاد لكائن ما لذا تضاف العقد للعبة حسب الوظيفة التي تحتاجها، كما تحتوي العقدة على مجموعة من الخصائص لتخصيص سلوكها ويمكنك تجميع العقد ودمجها لإنشاء عقد أكبر وأكثر تعقيدًا.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلتك في برمجة وتطوير الألعاب ثنائية وثلاثية الأبعاد وصمم ألعاب تفاعلية ممتعة<br>
			ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<p>
	يعد محرك ألعاب جودو المحرك المفضل للمطورين ذوي الميزانية المحدود الراغبين في دخول عالم تطوير الألعاب لكونه يوفر حلًا مجانيًا قويًا لإنشاء ألعاب احترافية، ولكونه محرك مفتوح المصدر فهو يملك مجتمع دعم نشيط يضم آلاف المطورين الذين يوفرون الكثير من الشروحات والدروس التعليمية والنصائح ومنتديات الدعم التي تساعدك في حال واجهتك أي مشكلة في تطوير ألعابك.
</p>

<p>
	من أبرز الألعاب المطورة باستخدام محرك ألعاب Godot:
</p>

<ul>
	<li>
		Kingdoms of the Dump
	</li>
	<li>
		Cruelty Squad
	</li>
	<li>
		Dome Keeper
	</li>
	<li>
		Cassette Beasts
	</li>
	<li>
		Luck Be a Landlord
	</li>
	<li>
		Commander Keen in Keen Dreams
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134242" href="https://academy.hsoub.com/uploads/monthly_2023_09/godot-games.png.425631c33f07e2587f87ab5a86b31427.png" rel=""><img alt="ألعاب عبر محرك Godot Engine" class="ipsImage ipsImage_thumbnailed" data-fileid="134242" data-ratio="62.50" data-unique="5s0ywq5aj" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/godot-games.thumb.png.6da3f648246cb19909cbd4e60d636090.png"></a>
</p>

<h3>
	4. محرك الألعاب GameMaker
</h3>

<p>
	محرك جيم ميكر <a href="https://gamemaker.io" rel="external nofollow">GameMaker</a> هو محرك ألعاب طوره بالأساس مبرمج الألعاب الهولندي مارك أوفرمارس Mark Overmars وصدر لأول مرة في 15 نوفمبر عام 1999 تحت اسم Animo وكان في بدايته عبارة عن أداة رسومية بإمكانيات محدودة، وبعدها منذ عام 2007 تولت شركة تطوير البرمجيات YoYo Games وأدخلت عليه تحسينات كثيرة تحويل إلى محرك ألعاب مخصص لإنشاء الألعاب ثنائية الأبعاد يستهدف المبتدئين وغير التقنيين حيث يسمح لهم ببرمجة الألعاب بطريقة سهلة وسريعة دون الحاجة لكتابة أي كود برمجي من خلال واجهة رسومية سهلة الاستخدام، لكن بالطبع فإن امتلاك خلفية برمجية سيمكنك من استخدام المحرك بكفاءة أعلى وتطوير الألعاب بشكل أفضل.
</p>

<p>
	يملك محرك GameMaker لغة برمجة مضمنة خاصة به تسمى لغة <a href="https://manual.gamemaker.io/monthly/en/GameMaker_Language/GameMaker_Language_Index.htm" rel="external nofollow">GML</a> تعتمد على لغات جافا سكريبت و C++‎ و C#‎ التي يتم دمجها بطرق محددة وبالتالي إذا كان لديك <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">أساس برمجي</a> جيد في هذه اللغات سيكون من السهل عليك تعلم هذه اللغة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134143" href="https://academy.hsoub.com/uploads/monthly_2023_09/GameMaker-Engine.png.9134af8095c554d01e07b0514b8df2e1.png" rel=""><img alt="محرك GameMaker" class="ipsImage ipsImage_thumbnailed" data-fileid="134143" data-ratio="56.15" data-unique="u9wmqxzcv" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/GameMaker-Engine.png.9134af8095c554d01e07b0514b8df2e1.png"></a>
</p>

<p>
	يتضمن GameMaker العديد من الميزات والوظائف المدمجة مثل محرر صور لإنشاء السبرايت sprites (وهي الرسومات أو النقوش المتحركة التي تظهر ضمن اللعبة) كما يتيح لك استيراد الصور المنشأة في محرر خارجي وتحويلها إلى كائنات ضمن اللعبة وإضافة إجراءات أو وظائف برمجية لها وهو يدعم عشرات أنظمة تشغيل ويندوز ولينكس وماك وأندرويد و iOS إلى جانب منصات الألعاب مثل بلاي ستيشن PlayStation  وإكس بوكس Xbox وسويتش Switch وغيرها.
</p>

<p>
	يمكنك تحميل محرك الألعاب GameMaker مجانًا لكنك مجبر على الترقية لأحد <a href="https://gamemaker.io/en/get" rel="external nofollow">الخطط المدفوعة</a> إذا كنت ترغب في الاستفادة منه بشكل فعلي وتصدير ألعابك إلى منصات معينة، حيث تبدأ الخطط المدفوعة من 5 دولارات شهريًا
</p>

<p>
	يناسب محرك الألعاب GameMaker إنشاء وتطوير أنواع مختلفة من الألعاب مثل الألعاب الحركية من نمط أعلى لأسفل top-down action games وألعاب الألغاز، وألعاب فن البكسل Pixel Art.
</p>

<p>
	ومن أشهر الألعاب المطورة باستخدام المحرك GameMaker:
</p>

<ul>
	<li>
		Post Void
	</li>
	<li>
		Undertale
	</li>
	<li>
		Hyper Light Drifter
	</li>
	<li>
		Spelunky
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134241" href="https://academy.hsoub.com/uploads/monthly_2023_09/gamemaker-games.png.a056cc4e9600de4d993f7cb3c68dc6bd.png" rel=""><img alt="ألعاب مطورة باستخدام GameMaker" class="ipsImage ipsImage_thumbnailed" data-fileid="134241" data-ratio="62.50" data-unique="a1hvavjge" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/gamemaker-games.thumb.png.c699524426dfa2cd6850a8ff6d072b8e.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134142" href="https://academy.hsoub.com/uploads/monthly_2023_09/gamemaker-games.png.0b82e59302e8e17fbec8280c64864c5e.png" rel=""> </a>
</p>

<h3>
	5. محرك الألعاب Open 3D
</h3>

<p>
	محرك أوبن ثري دي <a href="https://o3de.org/" rel="external nofollow">Open 3D</a> أو اختصارًا O3DE هو محرك تطوير ألعاب ثلاثي الأبعاد مفتوح المصدر متكامل الميزات طورته مؤسسة Open 3D Foundation حيث يتيح للمطورين إنشاء ألعاب عالية الدقة AAA وعوالم ثلاثية الأبعاد عالية الدقة ذات جودة سينمائية وهو إصدار محدث من محرك ألعاب أمازون Amazon Lumberyard المشتق من محركها السابق CryEngine ويوزع بموجب ترخيص Apache 2.0 ويدعم محرك O3DE حاليًا نظامي التشغيل ويندوز ولينكس فقط.
</p>

<p>
	أطلق الإصدار الأولي من محرك الألعاب Open 3D في يوليو/تموز عام 2021 وصدر أول إصدار مستقر منه في 12 مايو/أيار عام 2022 ورغم حداثته إلا أنه تمكن من منافسة محركات الألعاب التقليدية مثل Unity وUnreal Engine فقد احتفظ بأفضل مميزات المحرك Amazon Lumberyard وأضاف له العديد من المميزات مثل واجهة مستخدم قابلة للتوسيع وحزم برمجية جاهزة والعديد من المميزات والمكونات التي يمكن أن تختار ما تحتاج منها وتضيفه للعبتك دون الحاجة لتضمين المكونات غير الضرورية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134136" href="https://academy.hsoub.com/uploads/monthly_2023_09/Open-3D-Engine.png.81c9dc3877375f9e736b2b016f3dd283.png" rel=""><img alt="Open 3D" class="ipsImage ipsImage_thumbnailed" data-fileid="134136" data-ratio="56.15" data-unique="glkk3k8gu" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/Open-3D-Engine.png.81c9dc3877375f9e736b2b016f3dd283.png"></a>
</p>

<p>
	يدعم Open 3D Engine لغات البرمجة C++‎ وبايثون Python ولوا Lua وهو مجاني بالكامل ولا يتطلب دفع أي رسوم أو التزامات تجارية كما يتضمن العديد من الميزات مثل عارض متعدد المنصات يسمى Atom يمكن توسيعه ليناسب متطلبات لعبتك ودعم المحاكاة الفيزيائية لإضافة الواقعية إلى عناصر اللعبة، كما يوفر أسلوبين لإضافة المنطق لألعابك إما من خلال واجهة مرئية تسمى Script Canvas أو من خلال لغة برمجة سريعة وخفيفة الوزن تسمى Lua ورغم أن شعبيته لاتزال أقل من غيره من محركات الألعاب نظرًا لحداثته إلا أنه ينبئ بمستقبل واعد.
</p>

<p>
	لازال محرك O3DE حديث العهد وعدد الألعاب المطور باستخدامه محدود ومن أشهر الألعاب المطورة باستخدام O3DE نذكر:
</p>

<ul>
	<li>
		Deadhaus Sonata
	</li>
	<li>
		Planet Survival Game
	</li>
	<li>
		Planet Storm
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134244" href="https://academy.hsoub.com/uploads/monthly_2023_09/O3DE-games.png.62a3c9cbd26df3f92033c176a2216919.png" rel=""><img alt="ألعاب مطورة عبر O3DE" class="ipsImage ipsImage_thumbnailed" data-fileid="134244" data-ratio="62.50" data-unique="vdqukr98d" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/O3DE-games.thumb.png.ba945c00f99ddeb4037d586037a566bf.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134137" href="https://academy.hsoub.com/uploads/monthly_2023_09/O3DE-games.png.808e64a641107f83f2756a60a61dc4fd.png" rel=""> </a>
</p>

<h3>
	6. محرك الألعاب jMonkeyEngine
</h3>

<p>
	<a href="https://jmonkeyengine.org/" rel="external nofollow">jMonkeyEngine</a> أو ما يعرف اختصارًا بـ jME هو محرك مفتوح المصدر يعتمد على لغة البرمجة جافا <a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%85%D8%A7-%D9%87%D9%8A%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-java-r1515/" rel="">Java</a> يستخدم لتطوير الألعاب ثلاثية الأبعاد طور الإصدار الأول منه Mark Powell عام 2003 وبعدها ساهم عدد كبير من الأشخاص بشكل كبير في تطوير هذا المحرك، والإصدار الحالي منه هو 3.6.
</p>

<p>
	يتميز محرك jMonkeyEngine بسهولة استخدامه وملائمته للمبتدئين توثيقه الجيد، والميزة المهمة هي أنه محرك متعدد المنصات يمكن استخدامه لتصميم ألعاب تعمل على مختلف المنصات وأنظمة التشغيل مثل ويندوز Windows ولينكس Linux وماك macOS وراسيبيري باي Raspberry Pi وأندرويد Android و آي أو إس iOS لكنه يتطلب وجود معرفة برمجية لتسهيل تطوير الألعاب.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134138" href="https://academy.hsoub.com/uploads/monthly_2023_09/jMonkeyEngine.png.a20d6f20dba3915451e9788e370d8a2f.png" rel=""><img alt="محرك الألعاب jMonkeyEngine" class="ipsImage ipsImage_thumbnailed" data-fileid="134138" data-ratio="56.13" data-unique="m2z9d83mq" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/jMonkeyEngine.png.a20d6f20dba3915451e9788e370d8a2f.png"></a>
</p>

<p>
	يستخدم هذا المحرك مكتبة Lightweight Java Game Library أو اختصارًا LWJGL بشكل افتراضي لإخراج الرسومات وعرضها ويتطلب تثبيته على جهازك وجود بطاقة فيديو متوافقة مع OpenGL 2 وتثبيت عُدة تطوير جافا بإصدار JDK 6 أو أعلى.
</p>

<p>
	يتميز محرك ألعاب jMonkeyEngine بسهولة استخدامه وتعلمه لذا فهو يستخدم من قبل العديد من المؤسسات التعليمية واستوديوهات الألعاب التجارية، ومن أشهر الألعاب المطورة باستخدامه:
</p>

<ul>
	<li>
		Skullstone Mythruna
	</li>
	<li>
		Boardtastic 2
	</li>
	<li>
		Lightspeed Frontier
	</li>
	<li>
		3079
	</li>
	<li>
		3089
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134243" href="https://academy.hsoub.com/uploads/monthly_2023_09/jMonkeyEngine-games.png.65911fbefa9a66f92c52afcb5511e755.png" rel=""><img alt="ألعاب مطورة عبر محرك الألعاب jMonkeyEngine" class="ipsImage ipsImage_thumbnailed" data-fileid="134243" data-ratio="62.50" data-unique="x7ihjf3gi" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/jMonkeyEngine-games.thumb.png.e1018678c9e4e14b6b8c39206ce00a9b.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134139" href="https://academy.hsoub.com/uploads/monthly_2023_09/jMonkeyEngine-games.png.b42ed260b5c55df07c3488d947a3f045.png" rel=""> </a>
</p>

<h3>
	7. محرك الألعاب Frostbite
</h3>

<p>
	فروست بايت <a href="https://www.ea.com/frostbite" rel="external nofollow">Frostbite</a> هو محرك ألعاب مكتوب بلغة C++‎ و C#‎ طورته شركة DICE الشهيرة ثم استحوذت عليه شركة Electronic Arts لاستخدامه في تطوير ألعابها أي أنه محرك داخلي غير مرخص للعامة ومخصص حصريًا لتطوير ألعاب Electronic Arts لكننا ذكرناه لشهرة الألعاب المطورة باستخدامه وخصيصًا الألعاب المعتمدة على مبدأ إطلاق النار من منظور الشخص الأول First-person shooter أو اختصارًا FPS ومن أبرزها لعبة كرة القدم فيفا كما يمكن تشغيل الألعاب المطورة باستخدامه على نظام التشغيل ويندوز وأجهزة بلاي ستيشن 3 وبلاي ستيشن 4 وأجهزة Xbox 360 و Xbox one.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134145" href="https://academy.hsoub.com/uploads/monthly_2023_09/Frostbite-Engine.png.5f07ce3d188aca05c0fb65e6cf47001e.png" rel=""><img alt="محرك Frostbite" class="ipsImage ipsImage_thumbnailed" data-fileid="134145" data-ratio="56.15" data-unique="9dycc0co8" style="width: 500px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/Frostbite-Engine.png.5f07ce3d188aca05c0fb65e6cf47001e.png"></a>
</p>

<p>
	يوفر محرك Frostbite العديد من الميزات من بينها محرك فيزياء ومحرك رسومات قادر على عرض رسوم متحركة عالية الجودة وتوفير صوت HDR يغير مستوى المؤثرات الصوتية داخل اللعبة ويركز على الأصوات الأكثر أهمية، مثل أصوات إطلاق النار وسير المركبات الأمر الذي يجعل الألعاب نابضة بالحياة وقريبة للواقعية.
</p>

<p>
	ومن أشهر الألعاب المطورة باستخدام محرك Frostbite نذكر:
</p>

<ul>
	<li>
		سلسلة ألعاب FIFA
	</li>
	<li>
		سلسلة ألعاب Star wars
	</li>
	<li>
		سلسلة ألعاب Battlefield
	</li>
	<li>
		Need For Speed
	</li>
	<li>
		Army of Two
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134240" href="https://academy.hsoub.com/uploads/monthly_2023_09/Frostbite-games.png.4d93cdececd88a7e650adf0e1a4dccc0.png" rel=""><img alt="ألعاب مطورة عبر Frostbite" class="ipsImage ipsImage_thumbnailed" data-fileid="134240" data-ratio="62.50" data-unique="1yu31jaiq" style="width: 500px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Frostbite-games.thumb.png.956b20e0a86a8c9746cc9c07463eb28e.png"></a><a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134144" href="https://academy.hsoub.com/uploads/monthly_2023_09/Frostbite-games.png.afe0b64df898e888ff068baac0ed3027.png" rel=""> </a>
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في مقال اليوم على أهم محركات الألعاب أو البرامج المستخدمة في تصميم وتطوير الألعاب وتعرفنا على أبرز مميزاتها ولغات البرمجة التي تستخدمها والمنصات والبيئات التي تدعمها، لتختار من بينها البرنامج المناسب لميزانيتك ومتطلبات لعبتك ومستوى خبرتك البرمجية وابدأ رحلة إنشاء الألعاب فهي مجال ممتع ومجزي بذات الوقت.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">تعرف على أشهر لغات برمجة الألعاب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D8%AA%D8%A7%D9%87%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AD%D8%B1%D9%83-%D9%8A%D9%88%D9%86%D9%8A%D8%AA%D9%8A-unity-r1700/" rel="">برمجة لعبة متاهة باستخدام محرك يونيتي Unity</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">نبذة عن صناعة الألعاب ومحرك Unity3D</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/" rel="">مدخل إلى صناعة ألعاب المتصفح</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2100</guid><pubDate>Wed, 06 Sep 2023 13:09:00 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x631;&#x641; &#x639;&#x644;&#x649; &#x623;&#x634;&#x647;&#x631; &#x644;&#x63A;&#x627;&#x62A; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628;</title><link>https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_09/1313429358_.png.dffe58e176fd7b30b84d897404ceb6d4.png" /></p>
<p>
	تتنوع لغات البرمجة وتتعدد استخداماتها لتناسب التخصصات البرمجية المختلفة، فبعض لغات البرمجة تفيد لتكون لغات برمجة ألعاب أكثر من غيرها، وبعضها الآخر يناسب تطوير التطبيقات، ومنها ما يلائم الذكاء الاصطناعي، وبعضها ينفع لتحليل البيانات أو الويب، فلكل تخصص برمجي لغات وتقنيات خاصة به، وفي مقال اليوم سنركز على لغات برمجة الألعاب.
</p>

<p>
	فإذا كنت ترغب في تعلم برمجة الألعاب، وتتساءل ما هي أفضل لغات برمجة الألعاب يمكنك تعلمها وما هي أبرز مميزاتها، وما الوظائف والمكتبات والأدوات المساعدة التي توفرها لمطوري الألعاب وما الخطوات الصحيحة لبرمجة الألعاب؟ فهذا المقال لك.
</p>

<h2>
	ما هي برمجة الألعاب؟
</h2>

<p>
	برمجة الألعاب هي عملية تحويل الألعاب من فكرة مجردة إلى برنامج أو تطبيق يمكنك اللعب به على أحد المنصات وذلك باستخدام أدوات وتقنيات مساعدة كبرامج التصميم و<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محركات الألعاب</a>، أو باستخدام <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> في حال رغبت بتطوير لعبتك من الصفر وهذا صعب جدًا وخاصة في الألعاب المتقدمة.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" id="ips_uid_1493_5" src="https://academy.hsoub.com/applications/core/interface/index.html" title="ما هي برمجة الألعاب" width="930" data-embed-src="https://www.youtube.com/embed/O5suGXMNMdU"></iframe>
</p>

<p>
	تمر برمجة الألعاب عادة بمجموعة من المراحل تشمل:
</p>

<ol>
	<li>
		كتابة فكرة اللعبة وشخصياتها وطريقة اللعب وقواعد الربح والخسارة.
	</li>
	<li>
		التخطيط للعبة وكتابة سيناريو اللعبة وطريقة اللعب بها والموارد اللازمة لتنفيذها ونمط رسوماتها والجمهور المستهدف منها والمنصة المستهدفة التي ستعمل عليها.
	</li>
	<li>
		البدء ببرمجة اللعبة وتنفيذ فكرتها باستخدام الأدوات والتقنيات المناسبة كمحركات الألعاب وبرامج تصميم الرسومات ولغات البرمجة.
	</li>
	<li>
		اختبار اللعبة والتأكد من أنها تعمل بشكل صحيح وإصلاح أي أخطاء أو عيوب إن وجدت.
	</li>
	<li>
		نشر اللعبة على المنصة المستهدفة سواء الحاسوب أو الجوال أو الويب أو بلاي ستيشن PlayStation أوإكس بوكس Xbox أو غيرها.
	</li>
	<li>
		صيانة اللعبة ودعمها وتحديثها وتحسينها بصورة مستمرة وإصلاح أي مشكلات تظهر لاحقًا.
	</li>
</ol>

<p>
	يمكن أن يقوم شخص واحد بكل هذه المهام في حال برمجة الألعاب البسيطة، لكن في حال برمجة الألعاب الاحترافية المتكاملة التي تمتلك بيئة ضخمة وعدة شخصيات وأحداث وقواعد فهذه تعمل عليها فرق عمل تضم مبرمجين ومصممي رسوميات ومهندسي صوت وكتاب وغيرهم.
</p>

<h2>
	ما أفضل لغات برمجة الألعاب؟
</h2>

<p>
	هناك العديد من لغات برمجة الألعاب، ومن أبرز هذه اللغات:
</p>

<ol>
	<li>
		C++‎
	</li>
	<li>
		C#‎
	</li>
	<li>
		Java
	</li>
	<li>
		Python
	</li>
	<li>
		HTML
	</li>
	<li>
		JavaScript
	</li>
	<li>
		Lua
	</li>
	<li>
		Swift
	</li>
</ol>

<p>
	لنتناول بمزيد من التفصيل كل لغة من هذه اللغات وأهميتها في برمجة الألعاب ونكتشف أبرز الألعاب المطورة باستخدامها.
</p>

<p style="text-align: center;">
	<img alt="أفضل لغات برمجة الألعاب" class="ipsImage ipsImage_thumbnailed" data-fileid="134124" data-ratio="56.13" data-unique="l6ycxuq95" style="width: 400px; height: auto;" width="807" src="https://academy.hsoub.com/uploads/monthly_2023_09/game-programming-languages.png.821d45fb3945b4aae33fcd4dd4189136.png">
</p>

<h3>
	1. لغة برمجة C++‎
</h3>

<p>
	تعد لغة <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++‎</a> من أشهر لغات برمجة الألعاب فهي لغة قوية وسريعة تدعم عرض الرسومات المعقدة ومعالجة كمية كبيرة من البيانات، كما توفر العديد من أدوات تصحيح الأخطاء التي تكتشف المشكلات البرمجية وتساعد على تحسين أداء التطبيقات المطورة باستخدامها.
</p>

<p>
	وهي لغة منخفضة المستوى فهذا يجعلها أقرب إلى طبقة العتاد ويساعد المطورين على برمجة ألعاب سريعة وعالية الأداء تستفيد من موارد الجهاز بالشكل الأمثل كما أنها لغة برمجة كائنية التوجه <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel=""><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه"><abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></abbr></a> فهي تمكن المطورين من تنظيم التعليمات البرمجية ضمن مكونات قابلة لإعادة الاستخدام وسهلة الصيانة.
</p>

<p>
	ومن المميزات البارزة للغة C++‎ أنها اللغة التي يستخدمها <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محرك الألعاب</a> الشهير Unreal Engine كما تدعمها معظم محركات الألعاب الأخرى مثل Godot و CryEngine و Source، كما أنها لغة قابلة للتشغيل عبر منصات متعددة وتملك مجتمع دعم كبير عبر الإنترنت وتوفر الكثير من المكتبات والأطر المساعدة في مجال تطوير الألعاب، لكنها لغة صعبة التعلم لذا لا يفضلها المطورون المبتدئون في برمجة الألعاب.
</p>

<p>
	ومن أشهر الألعاب التي طورت باستخدام لغة C++‎ نذكر لعبة Counter Strike و World of Warcraft و King Quest.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134480" href="https://academy.hsoub.com/uploads/monthly_2023_09/Cpp-games.png.02c2e52a134c3c759ede6c3446cc74d6.png" rel=""><img alt="Cpp-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134480" data-ratio="62.43" data-unique="twe0bx8cu" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/Cpp-games.thumb.png.376915f8e74b05d351cf1c093a85075e.png"></a>
</p>

<p style="text-align: center;">
	 
</p>

<h3>
	2. لغة برمجة C#‎
</h3>

<p>
	تتميز لغة C#‎ بكونها واحدة من أشهر لغات برمجة الألعاب فهي لغة برمجة قوية وكائنية التوجه <a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-programming-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-r328/" rel="">oop</a> طورتها مايكروسوفت كجزء من <a href="https://academy.hsoub.com/programming/c-sharp/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AF%D9%88%D8%AA-%D9%86%D8%AA-r311/" rel="">إطار عمل دوت نت NET.</a> وهي توفر الكثير من المزايا المتقدمة وتتيح للمبرمج الألعاب التحكم في موارد الجهاز كما توفر مجموعة كبيرة من المكتبات والأدوات اللازمة لتطوير التطبيقات المختلفة، وتتوافق لغة C# ‎ مع محرك الألعاب الشهير Unity Engine وهو محرك ألعاب شائع يفضله العديد من مطوري الألعاب ويمكن استخدامها مع محركات ألعاب أخرى مثل محرك Unreal Engine ومحرك Godot.
</p>

<p>
	تعد لغة C#‎ من اللغات الملائمة جدًا لبرمجة وتطوير الألعاب فهي تتشابه في ميزاتها مع لغة C++‎ في السرعة والفعالية لكنها أبسط وأسهل منها في التعلم والاستخدام، ورغم كونها لا توفر نفس مستوى التحكم الدقيق بالعتاد الذي توفره لغة C++‎ لكنها لغة شائعة في برمجة الألعاب وتسمح للمطورين بالتركيز على إنشاء ألعاب عالية الجودة دون الغوص في تفاصيل فنية معقدة.
</p>

<p>
	ومن أشهر الألعاب المطورة باستخدام C#‎ نذكر لعبة Stardew Valley و HearthStone و Cuphead و Dead Island.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134171" href="https://academy.hsoub.com/uploads/monthly_2023_09/csharp-games.png.0e501877b59999025ea94c261f6b4261.png" rel=""><img alt="csharp-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134171" data-ratio="62.57" data-unique="2sns1l8i7" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/csharp-games.thumb.png.aad542a7e91b8b275623ac1355c2cb99.png"></a>
</p>

<p style="text-align: center;">
	 
</p>

<h3>
	3. لغة Java
</h3>

<p>
	تعد لغة جافا <a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D9%85%D8%A7-%D9%87%D9%8A%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-java-r1515/" rel="">Java</a> من أشهر لغات البرمجة متعددة الأغراض وهي تستخدم في العديد من المجالات ومن ضمنها استخداماها في برمجة الألعاب، ومن أبرز مميزات لغة جافا هو كونها لغة سهلة التعلم وتدعم ميزات تساعد على زيادة سرعة وكفاءة البرامج مثل تعدد الخيوط <a href="https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%8A%D9%88%D8%B7-threads-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1483/" rel="">threads</a> والمعالجة على التوازي، كما توفر مكتبات وأطر تطوير ألعاب قوية مثل libGDX للألعاب ثنائية الأبعاد و jMonkeyEngine للألعاب ثلاثية الأبعاد، ويمكن تشغيل الألعاب المطورة باستخدامها على العديد من المنصات بفضل ميزة آلة جافا الافتراضية <a href="https://academy.hsoub.com/programming/java/%D8%A2%D9%84%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-%D8%A7%D9%84%D8%A7%D9%81%D8%AA%D8%B1%D8%A7%D8%B6%D9%8A%D8%A9-java-virtual-machine-r964/" rel="">JVM</a>.
</p>

<p>
	قد لا تكون لغة جافا شائعة في مجال صناعة الألعاب مثل C++‎ أو C#‎ لكن العديد من الألعاب الكبيرة متعددة المنصات مثل ماين كرافت Minecraft الشهيرة لا تزال تستخدمها، ومن أشهر الألعاب المطورة باستخدامها Star Wars Galaxies و Runescape و Powder Game و Roboforge.
</p>

<p style="text-align: center;">
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134477" href="https://academy.hsoub.com/uploads/monthly_2023_09/java-games.png.f76fbca22c4fe3abe3df2759085b7fdb.png" rel=""><img alt="java-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134477" data-ratio="62.43" data-unique="1tb01fy0v" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/java-games.thumb.png.336d2f32fccc2cfc80855d5ef8b3e0bc.png"></a>
</p>

<h3>
	4. لغة Python
</h3>

<p>
	لغة البرمجة بايثون <a href="https://wiki.hsoub.com/Python" rel="external">Python</a> هي لغة برمجة متعددة الأغراض و<a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D9%87%D9%84-%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">سهلة التعلم</a> تناسب العديد من <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">التطبيقات</a> وتوفر العديد من <a href="https://academy.hsoub.com/programming/python/%D8%A3%D9%87%D9%85-10-%D9%85%D9%83%D8%AA%D8%A8%D8%A7%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-%D8%A7%D9%84%D8%B5%D8%BA%D9%8A%D8%B1%D8%A9-r654/" rel="">المكتبات</a>، وهي تستخدم أيضًا في مجال برمجة وتطوير الألعاب حيث توفر العديد من مكتبات الرسومات الأساسية والشبكات والصوت التي تساعد مطوري الألعاب وتسهل عملهم مثل مكتبة PyGame و Pyglet و Kivy و PANDA3D، كما أن لغة GDScript المستخدمة في محرك ألعاب جودو Godot تتشابه كثيرًا مع لغة بايثون وبالتالي فإن تعلم بايثون سيسهل البدء في إنشاء ألعاب باستخدام محرك الألعاب جودو Godot.
</p>

<div class="banner-container ipsBox ipsPadding">
	<div class="inner-banner-container">
		<p class="banner-heading">
			دورة تطوير الألعاب
		</p>

		<p class="banner-subtitle">
			ابدأ رحلة صناعة الألعاب ثنائية وثلاثية الأبعاد وابتكر ألعاب ممتعة تفاعلية ومليئة بالتحديات.
		</p>

		<div>
			<a class="ipsButton ipsButton_large ipsButton_primary ipsButton_important" href="https://academy.hsoub.com/learn/game-development/" rel="">اشترك الآن</a>
		</div>
	</div>

	<div class="banner-img">
		<a href="https://academy.hsoub.com/learn/game-development/" rel=""><img alt="دورة تطوير الألعاب" src="https://academy.hsoub.com/learn/assets/images/courses/game-development.png"></a>
	</div>
</div>

<p>
	فإذا كنت تبحث عن لغة برمجة ألعاب بسيطة سهلة التعلم وذات شهرة كبيرة وتملك مجتمعًا كبيرًا ونشطًا عبر الإنترنت فإن لغة بايثون Python خيار مناسب للحصول على نتائج سريعة، لكن لغة بايثون لا تتحكم في العتاد أو إدارة الذاكرة بنفس كفاءة لغة C++‎ وهي أبطأ من لغات البرمجة الأخرى لذا فهي لا تناسب الألعاب عالية الأداء.
</p>

<p>
	ومن الألعاب المشهورة التي طورت باستخدام لغة بايثون نذكر World of Tanks و Battlefield 2 و Civilization IV و Vega Strike.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134176" href="https://academy.hsoub.com/uploads/monthly_2023_09/python-games.png.96c2d0cf43c0815060626bad7331aabe.png" rel=""><img alt="python-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134176" data-ratio="62.57" data-unique="aru8zzggj" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/python-games.thumb.png.daf444193b82fd6e03cf934daac55bdc.png"></a>
</p>

<p>
	 
</p>

<h3>
	5. لغة HTML
</h3>

<p>
	تستخدم <a href="https://wiki.hsoub.com/HTML" rel="external">لغة HTML</a> بشكل أساسي في إنشاء <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8%D8%9F-r2094/" rel="">صفحات الويب</a> ويجب استخدامها إلى جانب لغة CSS ولغة جافا سكريبت -وهي الثلاثي الذهبي للويب- كإحدى لغات برمجة الألعاب وبشكل خاص ألعاب المتصفحات المتوافقة مع مختلف المنصات، حيث تعمل الألعاب المبنية باستخدام HTML على كل الحواسيب الشخصية والجوالات والأجهزة اللوحية وأجهزة التلفزيون الذكية أي أينما وُجد متصفح ويب.
</p>

<p>
	ولا تزال ألعاب المتصفح مطلوبة بشدة بالرغم التقدم الهائل في تقنيات وأدوات تصميم الألعاب ومن أشهر الألعاب المطورة باستخدام HTML نذكر A Grain of Truth و Dune 2 و RowserQuest و Cookie Clicker.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134172" href="https://academy.hsoub.com/uploads/monthly_2023_09/html-games.png.0426c8c4bd928f398c4a8aab815bcbed.png" rel=""><img alt="html-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134172" data-ratio="62.57" data-unique="4shamuh9f" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/html-games.thumb.png.9d2d7b1927f737dae5a3debe565dbb14.png"></a>
</p>

<h3>
	6. لغة برمجة JavaScript
</h3>

<p>
	تعد لغة جافا سكريبت <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> من لغات البرمجة عالية المستوى والمستخدمة بشكل أساسي في تطوير الويب وإضافة تأثيرات تفاعلية على صفحات الويب، كما يمكن أن تستخدم جافا سكريبت في <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/" rel="">تطوير ألعاب المتصفح</a> حيث توفر جافا سكريبت العديد من المكتبات وأطر العمل التي تساعد المبرمجين على تطوير ألعاب الويب التي تعمل على أي متصفح مثل <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/" rel="">WebGL</a> وهي عبارة عن واجهة برمجة تطبيقات جافا سكريبت لعرض رسومات ثنائية وثلاثية الأبعاد على المتصفح، ومحرك ألعاب الويب Phaser ومكتبات Three.JS و Babylon.js و Impact.js.
</p>

<p>
	كما تعتمد لغة جافا سكريبت على مفهوم <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D9%81%D9%88%D9%8A%D8%B6-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%AA%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1142/" rel="">الأحداث events</a> وهذا يجعلها مناسبة لكتابة التعليمات البرمجية غير المتزامنة ويساعد مطوري الألعاب على إنشاء ألعاب عالية الأداء وسريعة الاستجابة وقادرة على التعامل مع العديد من الطلبات وتوفر تجربة مستخدم سلسلة.
</p>

<p>
	ومن أشهر الألعاب المطورة باستخدام لغة البرمجة جافا سكريبت نذكر Bejeweled و HexGl و CrossCode و Polycraft و Swoop.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134174" href="https://academy.hsoub.com/uploads/monthly_2023_09/javascript-games.png.dd111ca59e39c71e512eb7b9aedc65ea.png" rel=""><img alt="javascript-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134174" data-ratio="65.00" data-unique="ctdn59cxz" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/javascript-games.thumb.png.11a6c023120234dc9fc3eda54b7bdcbc.png"></a>
</p>

<p style="text-align: center;">
	 
</p>

<h3>
	7. لغة برمجة Lua
</h3>

<p>
	لربما تسمع باسم لغة البرمجة لوا <a href="https://www.lua.org/about.html" rel="external nofollow">Lua</a> لأول مرة وهو يعني القمر باللغة البرتغالية، لكنك في الغالب سمعت بأسماء الألعاب الشهيرة المطورة بالاستعانة بها مثل Roblox و Angry Birds و World of Warcraft، تتميز لغة Lua بكونها مفتوحة المصدر ومبنية على لغة البرمجة سي C وهي لغة سريعة وفعالة وخفيفة الحجم ومتعددة المنصات وتدعم <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A5%D8%AC%D8%B1%D8%A7%D8%A6%D9%8A%D8%A9/" rel="">البرمجة الإجرائية</a> والبرمجة الوظيفية والبرمجة كائنية التوجه كما تدعمها عدة محركات ألعاب مثل Open 3D و Solar 2d لذا تعد لغة مثالية لبرمجة الألعاب وتعديلها وتخصيصها بسرعة وسهولة.
</p>

<p>
	إضافة لذلك تتميز هذه اللغة بسهولة تعلمها حيث يمكن للأطفال تعلمها لبرمجة الألعاب الخاصة بهم، كما تستخدم في مجالات أخرى تتطلب السرعة والكفاءة مثل تطبيقات الويب وتحليل البيانات وبرمجة أنظمة الشبكات مثل CISCO و Nmap وغيرها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134175" href="https://academy.hsoub.com/uploads/monthly_2023_09/lua-games.png.0ef5784746a7531b82acdf7a61f2e2c5.png" rel=""><img alt="lua-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134175" data-ratio="62.57" data-unique="3blca433d" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/lua-games.thumb.png.21320cb1eaf9aa3d9587013669e4d7bd.png"></a>
</p>

<p style="text-align: center;">
	 
</p>

<h3>
	8. لغة Swift
</h3>

<p>
	تعد لغة البرمجة سويفت Swift من آبل لغة مثالية لتطوير الألعاب والتطبيقات التي تعمل على أنظمة ماك macOS وiOS وiPadOS وwatchOS وtvOS.وهي تتميز بكونها لغة برمجة حديثة سهلة التعلم والاستخدام وعالية الأداء وتوفر العديد من المكتبات الرسومية ثنائية وثلاثية الأبعاد مثل SpriteKit وSceneKit و GameplayKit التي تمكن المطورين من إضافة رسومات عالية الجودة وهذا يجعلها لغة مثالية لبرمجة الألعاب الكبيرة والمعقدة.
</p>

<p>
	من محدوديات لغة سويفت Swift أنها تقتصر على منصات آبل Apple ولا تمكنك من تطوير ألعاب تعمل على منصات أخرى لكنها تفوقت برغم حداثتها على لغة Objective-C المستخدمة أيضًا في تطوير تطبيقات لأنظمة تشغيل آبل وفاقتها في السرعة والأداء. ومن أشهر الألعاب المطورة باستخدام Swift نذكر Crossy Road و Flappy Bird و 2048.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="134177" href="https://academy.hsoub.com/uploads/monthly_2023_09/swift-games.png.961214dbcb6b9bc2fc11e8e942af96ea.png" rel=""><img alt="swift-games.png" class="ipsImage ipsImage_thumbnailed" data-fileid="134177" data-ratio="62.57" data-unique="6dl3zrpqs" style="width: 400px; height: auto;" width="900" src="https://academy.hsoub.com/uploads/monthly_2023_09/swift-games.thumb.png.4325ab8623ba872a74f3c1ec9300a083.png"></a>
</p>

<h2>
	كيف تختار أفضل لغة برمجة لتطوير الألعاب؟
</h2>

<p>
	كما شرحنا سابقًا هناك العديد من لغات البرمجة المختلفة التي يمكنك استخدامها لتطوير الألعاب ومن أجل اختيار اللغة التي تناسب احتياجاتك عليك في البداية أن تحدد متطلباتك وهدفك من تعلم تطوير الألعاب بدقة ثم تختار بناء على ذلك لغة البرمجة الأنسب لتحقيق هذا الهدف.
</p>

<p>
	حيث يعتمد اختيار لغة برمجة الألعاب على طبيعة اللعبة التي تريد تطويرها، فإذا كان هدفك تطوير لعبة بسيطة ثنائية أو ثلاثية الأبعاد، فيمكنك في هذه الحالة استخدام لغة البرمجة بايثون Python أو لغة جافا سكريبت JavaScript أو لوا Lua.
</p>

<p>
	وإذا كان هدفك تطوير لعبة احترافية عالية الأداء تتضمن عمليات محاكاة معقدة وتتطلب قدرًا كبيرًا من الذاكرة فستحتاج حينها إلى الاعتماد على أحد محركات الألعاب التي تسهل لك العمل كما ذكرنا سابقًا وحينها ستكون مقيدًا باستخدام إحدى لغات البرمجة التي يدعمها هذا المحرك، فلكل <span ipsnoautolink="true">محرك ألعاب مجموعة لغات برمجة محددة </span>يمكنه التعامل معها، على سبيل المثال يمكن أن تستخدم لغة C++‎ أو لغة برمجة مرئية تسمى Blueprints مع محرك الألعاب Unreal Engine أو تستخدم لغة البرمجة C#‎ أو لغة برمجة مرئية تسمى Bolt مع محرك ألعاب يونتي Unity.
</p>

<p>
	كما أن تحديد المنصة التي تستهدفها لعبتك قد يساعدك في تحديد لغة البرمجة الأفضل، فإذا كنت ترغب في إنشاء ألعاب تعمل على الحواسيب المكتبية سيكون من المناسب لك استخدام لغة C++‎ أو بايثون أو جافا، وفي حال كان هدفك تطوير لعبة تعمل على أنظمة أندرويد Android ففي هذه الحالة تعد لغة جافا خيارًا مناسبًا، أما إن كنت تنوي تطوير ألعاب لأنظمة iOS فعليك حينها اختيار لغة Swift، وفي حال كان هدفك هو برمجة ألعاب الويب فاستخدم لغة جافا سكريبت JavaScript أو بايثون Python.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعرفنا في مقال اليوم على أفضل لغات برمجة الألعاب الإلكترونية، ومميزات كل لغة من بينها، وأبرز الألعاب المطورة باستخدامها، ووضحنا في ختام المقال أن اختيار لغة برمجة لعبة يعتمد على عدة عوامل من بينها المنصة التي تستهدفها اللعبة ومدى تعقيدها ومستوى صعوبتها ونوعها، لذا قبل أن تحدد اللغة التي سوف تستخدمها في تطوير لعبتك حدد كافة متطلبات اللعبة بشكل دقيق ثم اختر اللغة الأنسب لتلبية هذه المتطلبات.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">مطور الألعاب: من هو وما هي مهامه</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A3%D9%81%D9%83%D8%A7%D8%B1-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%81%D9%8A%D8%AF%D9%8A%D9%88/" rel="">كيف تحصل على أفكار ألعاب فيديو ناجحة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D8%AA%D8%A7%D9%87%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AD%D8%B1%D9%83-%D9%8A%D9%88%D9%86%D9%8A%D8%AA%D9%8A-unity-r1700/" rel="">برمجة لعبة متاهة باستخدام محرك يونيتي Unity</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D9%83%D8%B1%D8%A7%D8%AA%D8%B4-r1697/" rel="">برمجة لعبة تفاعلية باستخدام سكراتش</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%86%D8%A8%D8%B0%D8%A9-%D8%B9%D9%86-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-unity3d-r126/" rel="">نبذة عن صناعة الألعاب ومحرك Unity3D</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2099</guid><pubDate>Fri, 01 Sep 2023 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x623;&#x644;&#x639;&#x627;&#x628;&#x61F;</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8%D8%9F-r2068/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/703180650_.png.894d5aa60b0fa11e555b84cfe7fbe79d.png" /></p>
<p>
	في هذا الفيديو سنتحدث عن برمجة الألعاب والتي تعد أحد أشهر التخصصات في عالم البرمجة، كما سنتحدث عن الفرق بين تصميم الألعاب وبرمجة الألعاب. إذ أن تصميم الألعاب هو المرحلة الأولى من برمجة الألعاب. كما سنتحدث عن أشهر محركات يتم تطوير اللعبة من خلالها مثل يونيتي Unity وأنريل Unreal وغيرها من الأمور.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" id="ips_uid_6253_16" src="https://academy.hsoub.com/applications/core/interface/index.html" title="ما هي برمجة الألعاب" width="1072" data-embed-src="https://www.youtube.com/embed/O5suGXMNMdU"></iframe>
</p>

<p>
	تعلم برمجة ألعاب باستخدام سكراتش وأساسيات البرمجة والتطوير في <a href="https://academy.hsoub.com/learn/computer-science" rel="">دورة أساسيات علوم الحاسوب من أكاديمية حسوب</a>.
</p>

<h2>
	اقرأ أيضًا:
</h2>

<ul>
	<li>
		<p>
			تعرف على أشهر <a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a>
		</p>
	</li>
</ul>
]]></description><guid isPermaLink="false">2068</guid><pubDate>Thu, 19 Jan 2023 15:00:00 +0000</pubDate></item><item><title>&#x628;&#x631;&#x645;&#x62C;&#x629; &#x644;&#x639;&#x628;&#x629; &#x645;&#x62A;&#x627;&#x647;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x645;&#x62D;&#x631;&#x643; &#x64A;&#x648;&#x646;&#x64A;&#x62A;&#x64A; Unity</title><link>https://academy.hsoub.com/programming/game-development/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%85%D8%AA%D8%A7%D9%87%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AD%D8%B1%D9%83-%D9%8A%D9%88%D9%86%D9%8A%D8%AA%D9%8A-unity-r1700/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_09/63108b81e99f5_-------Unity.png.a0cd365398ef7330b5d951cede6b8524.png" /></p>
<p>
	سنعمل في هذا المقال على إنشاء لعبة متاهة مرئية باستخدام <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محرك الألعاب</a> الشهير يونيتي Unity، بحيث تكون الشخصية الرئيسية هي روبوت نتحكم بحركته، وسنتعلم الأدوات اللازمة لتطوير اللعبة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107167" href="https://academy.hsoub.com/uploads/monthly_2022_09/step1_gameScreenshot.png.7be69dca00154024ce0d8a28c367d656.png" rel=""><img alt="step1_gameScreenshot.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107167" data-unique="n1xbq6lwu" src="https://academy.hsoub.com/uploads/monthly_2022_09/step1_gameScreenshot.png.7be69dca00154024ce0d8a28c367d656.png"></a>
</p>

<p>
	سنتعلم في هذا المشروع ما يلي:
</p>

<ul>
	<li>
		كيفية إنشاء أشكال ثلاثية الأبعاد.
	</li>
	<li>
		كيفية تغيير لون وحجم وموضع الكائنات.
	</li>
	<li>
		كيفية تعديل طريقة عرض اللعبة بحيث تتبع حركة اللاعب.
	</li>
	<li>
		كيفية إضافة شيفرة برمجية إلى الكائنات للتحكُّم في حركتها وتصرفاتها.
	</li>
</ul>

<p>
	ستحتاج في هذا المشروع إلى:
</p>

<ul>
	<li>
		عتاد: حاسوب يعمل بنظام ويندوز أو ماك، قادر على تشغيل يونيتي.
	</li>
	<li>
		برمجيات: محرر يونيتي، ويفضل تنصيبه مع تطبيق Unity Hub، الذي يتيح لك تثبيت عدة إصدارات من محرر يونيتي وإدارة الإضافات extensions. قد تستغرق عملية التنزيل وقتًا طويلًا نظرًا لحجم البرنامج الكبير نسبيًا، لذلك ننصحك بتنزيله وتنصيبه قبل بدء المشروع.
	</li>
</ul>

<h2>
	إعداد المشروع
</h2>

<p>
	أولًا، افتح محرر يونتي وانقر على<strong>New</strong> لإنشاء مشروع جديد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107154" href="https://academy.hsoub.com/uploads/monthly_2022_09/New_Unity.png.71e14792d706a4b6e1ae32053ca06452.png" rel=""><img alt="New_Unity.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107154" data-unique="bn9i26j9w" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/New_Unity.thumb.png.64bec47a694c6ed1b819cb178ac9eb02.png"></a>
</p>

<p>
	ثانيًا، سمِّ المشروع "Beginner Unity Sushi"، أو أي اسمٍ آخر تفضله، ثم انقر على خيار إنشاء المشروع Create Project وانتظر إلى أن يظهر مشروعك على الشاشة.
</p>

<p>
	ثالثًا، انقر على قائمة تخطيط الصفحة <strong>Layout</strong> الموجودة أعلى الزاوية اليمنى للشاشة، ثم اختر الوضع الافتراضي <strong>Default</strong>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107168" href="https://academy.hsoub.com/uploads/monthly_2022_09/step3_layout.png.f4abe82872d03d56b090bbd7725be87b.png" rel=""><img alt="step3_layout.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107168" data-unique="rvydl9pnq" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step3_layout.thumb.png.efaca10ac9027b27d7fde5fe7550aa66.png"></a>
</p>

<p>
	رابعًا، تأكد من وجود مجلد المشاهد "scenes" في نافذة الممتلكات <strong>Assets</strong>؛ وفي حال عدم وجوده، أنشِئه عن طريق النقر على شريط القائمة <strong>menu</strong> الموجود أعلى القائمة، ثم النقر على شريط الممتلكات <strong>Assets</strong> الموجود في اليسار. انقر بعدها على خيار إنشاء <strong>Create</strong>، ثم على مجلد <strong>Folder</strong>، وسمّ المجلد "scenes".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107169" href="https://academy.hsoub.com/uploads/monthly_2022_09/step3_scenes.png.9e061e637828467dac28a74e983dd81c.png" rel=""><img alt="step3_scenes.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107169" data-unique="u8likni98" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step3_scenes.thumb.png.7be4a69e25a49323200e021677813ae5.png"></a>
</p>

<p>
	خامسًا، حان الآن وقت حفظ المشهد الأولي المرفق مع المشروع وذلك من القائمة العلوية بالنقر على ملف <strong>File</strong>، ثم احفظ المشهد باسم <strong>Save Scene as</strong> وسمّه "MazeRoboBegins" واحفظه في مجلد المشاهد "scenes" ضمن مجلد "Assets".
</p>

<p>
	ننصحك بحفظ المشروع بعد كل تعديلٍ تجريه عليه، وذلك بالنقر على <strong>File</strong> من القائمة أعلى الشاشة، ثم النقر على خيار <strong>Save Scenes</strong>، كما يمكنك اختصارًا النقر على مفتاحي <strong>Ctrl</strong> و <strong>S</strong> في أجهزة الويندوز، ومفتاحي <strong>Cmd</strong> و <strong>S</strong> في أجهزة ماك.
</p>

<h2>
	إنشاء الشخصية الرئيسية
</h2>

<p>
	ستكون الشخصية الرئيسية في لعبتنا عبارة عن رجل آلي نتحكم في حركته ضمن المتاهة، ولكن علينا تصميمه أولًا! أولًا، اصنع جسم الرجل الآلي بحيث يكون له شكل الكبسولة، وذلك بالنقر على الخيارات التالية بالترتيب: <strong>GameObject &gt; 3D Object &gt; Capsule</strong>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107171" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_capsule.png.98413511bf2181ab4f6f6153d8e37f64.png" rel=""><img alt="step4_capsule.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107171" data-unique="saj9silcm" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_capsule.png.98413511bf2181ab4f6f6153d8e37f64.png"></a>
</p>

<p>
	ثانيًا، انقر على جسم الرجل الآلي، وستظهر لك نافذة وحدة المراقب <strong>Inspector</strong>، حيث يمكنك إعداد الكائنات وتغيير خصائصها. سمِّ الكبسولة "MazeRobo" بكتابة اسم الكائن أعلى نافذة المراقب inspector كما هو موضح أدناه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107152" href="https://academy.hsoub.com/uploads/monthly_2022_09/InspectorWindow.png.5c3580cfc07edeca3f228111d00a1483.png" rel=""><img alt="InspectorWindow.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107152" data-unique="wczi6k3xu" src="https://academy.hsoub.com/uploads/monthly_2022_09/InspectorWindow.png.5c3580cfc07edeca3f228111d00a1483.png"></a>
</p>

<p>
	ثالثًا، انقر على رمز المسنن في مربع التحويل <strong>Transform</strong> في نافذة وحدة المراقب، ثم اختر إعادة الضبط <strong>Reset</strong> وذلك لوضع الكائن في منتصف منصة العرض.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107174" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_Transform.png.268767a7bd5fa6da9ffb19b90f22379f.png" rel=""><img alt="step4_Transform.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107174" data-unique="ppvxw0ec8" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_Transform.png.268767a7bd5fa6da9ffb19b90f22379f.png"></a>
</p>

<p>
	رابعًا، لا زلنا بحاجةٍ إلى مزيد من الأشكال لتكوين رجلنا الآلي. لذلك، أضف مكعبًا Cube بالنقر على الخيارات التالية <strong>GameObject &gt; 3D Object &gt; Cube</strong> ثم أضف كرةً على النحو التالي: <strong>GameObject &gt; 3D Object &gt; Sphere</strong>، ثم غيِّر اسم المكعب إلى "Shades" والكرة إلى "Nose".
</p>

<p>
	خامسًا، لاحظ ظهور الكائنات الثلاثة ضمن قائمة على يسار الشاشة، انقر على الكائن "Nose" واسحبه ثم أفلته فوق "MazeRobo" كي يتحرك بحركته، وافعل المثل مع الكائن "Shades"، كما هو موضح أدناه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107172" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_moveObjects.png.900e6b5dc626d722ec5340b4479d4115.png" rel=""><img alt="step4_moveObjects.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107172" data-unique="qlya07zay" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_moveObjects.png.900e6b5dc626d722ec5340b4479d4115.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107170" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_afterMove.png.d683bebf1cc367724e3549c11b04df64.png" rel=""><img alt="step4_afterMove.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107170" data-unique="s22rtqk9o" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_afterMove.png.d683bebf1cc367724e3549c11b04df64.png"></a>
</p>

<p>
	وبهذه الطريقة يمكننا تجميع الاشكال والحصول على شخصيات متكاملة من أشكال بسيطة.
</p>

<p>
	سادسًا، انقر على الكائن "Shades" ولاحظ وجود ثلاث إحداثيات <strong>(X, Y, Z)</strong> في نافذة المراقب inspector في قسم <strong>Transform</strong> تتحكم بموضع الكائن.
</p>

<p>
	غَيّر قيم الإحداثيات وشاهد ما الذي سيحدث، وضَع الرمز <strong>~</strong> أمام بعض القيم، ثم اعتمد القيم التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_92" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.64</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.42</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107175" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_TransformPosition.png.ba19f931bcc7a20c099a89e42eaf9962.png" rel=""><img alt="step4_TransformPosition.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107175" data-unique="5a6n6nmsl" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_TransformPosition.png.ba19f931bcc7a20c099a89e42eaf9962.png"></a>
</p>

<p>
	سابعًا، أسند قيم الإحداثيات التالية للكائن "Nose":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_94" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.5</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.5</span></pre>

<p>
	الآن، يجب علينا تعديل شكل الكائنين لنحصل على شكلٍ مشابهٍ للرجل الآلي، وذلك بتعديل الحجم <strong>Scale</strong> وفقًا للقيم التالية للكائن "Shades":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_96" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.64</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.16</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.16</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107176" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_TransformScale.png.26807e776da444be1aeb74354d969b34.png" rel=""><img alt="step4_TransformScale.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107176" data-unique="jzmkisktz" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_TransformScale.png.26807e776da444be1aeb74354d969b34.png"></a>
</p>

<p>
	والقيم التالية للكائن "Nose":
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_98" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.16</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.16</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.16</span></pre>

<p>
	ليصبح لدينا الرجل الآلي التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107173" href="https://academy.hsoub.com/uploads/monthly_2022_09/step4_robot.png.f430f4cb11efe95f9c3e733252b8aff7.png" rel=""><img alt="step4_robot.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107173" data-unique="hhzbv9aw2" src="https://academy.hsoub.com/uploads/monthly_2022_09/step4_robot.png.f430f4cb11efe95f9c3e733252b8aff7.png"></a>
</p>

<h2>
	تلوين الرجل الآلي
</h2>

<p>
	أولًا، أنشئ مجلدًا جديدًا بالنقر على الخيارات التالية بالترتيب: <strong>Assets &gt; Create &gt; Folder</strong>، انقر بالزر الأيمن للفأرة عليه ثم انقر على خيار إعادة التسمية <strong>Rename</strong> وسمّه "Materials".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107180" href="https://academy.hsoub.com/uploads/monthly_2022_09/step5_rename.png.24232b3a23d9de8e590b7113b7687a8e.png" rel=""><img alt="step5_rename.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107180" data-unique="rbtze01an" style="width: 260px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step5_rename.png.24232b3a23d9de8e590b7113b7687a8e.png"></a>
</p>

<p>
	ثانيًا، أنشئ مادتين جديدتين بالنقر على <strong>Assets &gt; Create &gt; Material</strong> وسمّهما "EyeBlack" و "NoseRed". لاحظ ظهور المادتين اللتين أنشأتهما في مجلد المواد "Materials" في نافذة المشروع <strong>Project</strong> أسفل الشاشة، وفي حال وجدتهما خارجه، فاسحبهما إلى داخل المجلد "Materials".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107178" href="https://academy.hsoub.com/uploads/monthly_2022_09/step5_materialsFolder.png.7518c6e642feaca680c2d69a4c788081.png" rel=""><img alt="step5_materialsFolder.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107178" data-unique="6udx9mvla" style="width: 380px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step5_materialsFolder.png.7518c6e642feaca680c2d69a4c788081.png"></a>
</p>

<p>
	يمكن تغيير لون مادة ما عن طريقة تغيير قيمة بياضها <strong>albedo</strong> في نافذة المراقب inspector، بالنقر على المستطيل الأبيض بجانب أداة اختيار اللون، ثم انتقاء اللون المناسب.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107151" href="https://academy.hsoub.com/uploads/monthly_2022_09/colour_picker.png.ea5057115413a125d21fff92d82867e9.png" rel=""><img alt="colour_picker.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107151" data-unique="aoe5dh5n6" src="https://academy.hsoub.com/uploads/monthly_2022_09/colour_picker.png.ea5057115413a125d21fff92d82867e9.png"></a>
</p>

<p>
	ثالثًا، اختر اللون الأسود لمادة العين "EyeBlack" والأحمر لأنف الرجل الآلي "NoseRed".
</p>

<p>
	رابعًا، انقر على الكائن "Shades" ثم انقر على خيار <strong>the Materials</strong> في قسم <strong>Mesh Renderer</strong>، وانقر بعدها على الدائرة الصغيرة بجانب العنصر "0 Element" واختر منها "EyeBlack".
</p>

<p>
	الآن، أصبح لدى الرجل الآلي نظارات شمسية سوداء.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107177" href="https://academy.hsoub.com/uploads/monthly_2022_09/step5_chooseMaterial.png.d85e10a73aaba7495f7021e92cd948d5.png" rel=""><img alt="step5_chooseMaterial.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107177" data-unique="63v42ywzu" src="https://academy.hsoub.com/uploads/monthly_2022_09/step5_chooseMaterial.png.d85e10a73aaba7495f7021e92cd948d5.png"></a>
</p>

<p>
	خامسًا، كرِّر الخطوة السابقة واختر "NoseRed".
</p>

<p>
	الآن، أصبح لدى الرجل الآلي نظارات شمسية وأنف أحمر.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107179" href="https://academy.hsoub.com/uploads/monthly_2022_09/step5_mazeRoboInColour.png.ca1952f441da553fc58d47b4c991f152.png" rel=""><img alt="step5_mazeRoboInColour.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107179" data-unique="inckus3dy" src="https://academy.hsoub.com/uploads/monthly_2022_09/step5_mazeRoboInColour.png.ca1952f441da553fc58d47b4c991f152.png"></a>
</p>

<h3>
	التحكم بالرجل الآلي
</h3>

<p>
	يجب عليك إضافة مكوّن الجسم الصلب <strong>RigidBody</strong> لتتمكن من تحريك الرجل الآلي.
</p>

<p>
	أولًا، انقر على الرجل الآلي، ثم على <strong>Component &gt; Physics &gt; Rigidbody</strong> للتحكم بالرجل الآلي في اللعبة.
</p>

<p>
	لاحظ أنه عند النقر على الرجل الآلي سيظهر قسم الجسم الصلب <strong>RigidBody</strong> في نافذة المراقب <strong>Inspector</strong>. انقر على قسم القيود <strong>Constraints</strong> لفتحه، ثم فعّل خيار تثبيت الدوران <strong>Freeze Rotation</strong> على محاور الإحداثيات الثلاث، وفعّل تثبيت الموقع <strong>Freeze Position</strong> على محور <strong>Y</strong> فقط.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107181" href="https://academy.hsoub.com/uploads/monthly_2022_09/step5_RigidbodyConstraints.png.a4a6641822de4e0b0a163bad8b07379d.png" rel=""><img alt="step5_RigidbodyConstraints.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107181" data-unique="5l2w78kwo" src="https://academy.hsoub.com/uploads/monthly_2022_09/step5_RigidbodyConstraints.png.a4a6641822de4e0b0a163bad8b07379d.png"></a>
</p>

<p>
	أصبحت الآن الشخصية الرئيسية للعبة جاهزة، لكن بإمكانك إضفاء طابع شخصي عليها عن طريق تغيير الألوان أو إضافة مزيدٍ من الأشكال إليها باستخدام خيار الكائنات ثلاثية <strong>3D Objects</strong> الأبعاد كما في الخطوة السابقة، وحين تصبح راضيًا عن هيئة الرجل الآلي، انتقل إلى الخطوة التالية.
</p>

<h2>
	إنشاء عالم اللعبة
</h2>

<p>
	سنعمل في هذه الخطوة على إنشاء عالم اللعبة، أو المنصة التي سيتحرك عليها الرجل الآلي. أولًا، أضف الكائن <strong>Quad</strong> ليكون بمثابة الأرضية للعبة، وذلك بالنقر على الخيارات التالية: <strong>GameObject &gt; 3D Object &gt; Quad</strong>، وسمِّ الكائن "Ground" أي أرضية.
</p>

<p>
	ثانيًا، اضبط قيمة الدوران على محور <strong>X</strong> على القيمة <strong>90</strong> في مربع التحويل <strong>Transform</strong> في نافذة المراقب ثم عدّل الحجم للكائن <strong>Scale</strong> وفق القيم التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_100" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40.96</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">40.96</span><span class="pln">

Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107182" href="https://academy.hsoub.com/uploads/monthly_2022_09/step6_groundTransform.png.448c16ab00f64c655fb9980f79489dd5.png" rel=""><img alt="step6_groundTransform.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107182" data-unique="q6tuu2jev" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step6_groundTransform.png.448c16ab00f64c655fb9980f79489dd5.png"></a>
</p>

<p>
	لاحظ أن وضعية الرجل الآلي تحتاج إلى تعديل، إذ يظهر منتصفه عالقًا في الأرضية.
</p>

<p>
	ثالثًا، عدّل إحداثيات الموضع للرجل الآلي من نافذة التحويل <strong>Transform</strong> وفقًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_102" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107183" href="https://academy.hsoub.com/uploads/monthly_2022_09/step6_MazeRoboOnGround.png.72d27159ed74fb02c523c2fcc639a9f5.png" rel=""><img alt="step6_MazeRoboOnGround.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107183" data-unique="lw7l5krph" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step6_MazeRoboOnGround.png.72d27159ed74fb02c523c2fcc639a9f5.png"></a>
</p>

<p>
	رابعًا، أضف مكعبًا Cube بالنقر على الخيارات التالية <strong>GameObject &gt; 3D Object &gt; Cube</strong> ليكون بمثابة حائطٍ في المتاهة، ثم أسند إليه إحداثيات الموضع التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_104" style=""><span class="pln">X </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pln">
Y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.5</span><span class="pln">
Z </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	خامسًا، غيّر مقياس الحجم <strong>Y Scale</strong> للكائن الجديد إلى القيمة <strong>3</strong>، ثم سمِّ الكائن "Wall".
</p>

<p>
	سادسًا، أنشئ مادةً جديدةً للحائط <strong>Assets &gt; Create &gt; Materials</strong> وغيّر قيمة البياض albedo لإعطائها اللون الأزرق، ثم سمّها "WallBlue".
</p>

<p>
	سابعًا، أسند المادة الزرقاء "WallBlue" للحائط "Wall" عن طريق سحبها وإفلاتها فوق الحائط، أو من خيار <strong>MeshRender &gt; Materials</strong> من نافذة المراقب.
</p>

<p>
	سنعمل في الخطوات التالية على تحويل هذا الحائط إلى متاهة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107184" href="https://academy.hsoub.com/uploads/monthly_2022_09/step6_Wall.png.18860b5fa7448d87e387038a64ff1b1e.png" rel=""><img alt="step6_Wall.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107184" data-unique="lfnz408ut" style="width: 580px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step6_Wall.png.18860b5fa7448d87e387038a64ff1b1e.png"></a>
</p>

<h2>
	تحريك الرجل الآلي
</h2>

<p>
	سنكتب، في هذه الخطوة، الشيفرة اللازمة لتحريك الرجل الآلي.
</p>

<p>
	أولًا، أنشئ مجلدًا جديدًا من نافذة المشروع <strong>Project</strong> بالنقر على <strong>Assets &gt; Create &gt; Folder</strong>، وسمِّ المجلد "Scripts".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107188" href="https://academy.hsoub.com/uploads/monthly_2022_09/step7_ScriptsFolder.png.ce5e10ad7c3988cdb56298e6d8b21d30.png" rel=""><img alt="step7_ScriptsFolder.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107188" data-unique="8zlp4b9q4" src="https://academy.hsoub.com/uploads/monthly_2022_09/step7_ScriptsFolder.png.ce5e10ad7c3988cdb56298e6d8b21d30.png"></a>
</p>

<p>
	ثانيًا، أنشئ مجلدًا داخل مجلد Scripts لكتابة الشيفرة <a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-c-r597/" rel="">بلغة #C</a> بالنقر على <strong>Assets &gt; Create &gt; C# Script</strong> وسمّه "RoboMover".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107187" href="https://academy.hsoub.com/uploads/monthly_2022_09/step7_NewScript.png.8f13c2aaec785faf21bcd9f2a9e8eca0.png" rel=""><img alt="step7_NewScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107187" data-unique="w9i5wmcbk" src="https://academy.hsoub.com/uploads/monthly_2022_09/step7_NewScript.png.8f13c2aaec785faf21bcd9f2a9e8eca0.png"></a>
</p>

<p>
	ثالثًا، انقر مزدوجًا على مجلد RoboMover لفتحه في المحرر ولاحظ أنك ستحصل على الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_39" style=""><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Collections</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Collections</span><span class="pun">.</span><span class="typ">Generic</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">UnityEngine</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RoboMover</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MonoBehaviour</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// تُستخدم هذه الدالة للتهيئة</span><span class="pln">

  </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="pun">}</span><span class="pln">

</span><span class="com">//تُستدعى دالة التعديل مرةً واحدةً عند تصيير كل إطار</span><span class="pln">

  </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنلقي نظرةً معمقةً على الشيفرة لنفهم آلية عملها:
</p>

<p>
	تهيئ الأسطر الثلاثة الأولى البرنامج للعمل.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_41" style=""><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Collections</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Collections</span><span class="pun">.</span><span class="typ">Generic</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">UnityEngine</span><span class="pun">;</span></pre>

<p>
	يُعّرف السطر التالي الصنف <code>RoboMover</code> من النوع العام public وتُكتب محتويات الصف داخل القوسين <code>{ }</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_44" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RoboMover</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MonoBehaviour</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	صرّحنا بعدها عن دالتين هما دالة البدء <code>Start</code> ودالة التعديل <code>Update</code>، ولاحظ أنهما فارغتان الآن، إذ سنُعدّلهما فيما بعد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_46" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	<strong>الدالة Function</strong>: هي مجموعةٌ من التعليمات موجهةٌ للحاسوب ليُنفذ أمرًا ما، وتُسمى باسمٍ يدل على عملها. فعلى سبيل المثال، كثيرًا ما نستخدم الأمر "أعّد لي كوبًا من الشاي" في حياتنا اليومية والذي يماثل الدالة، إذ يعلم هنا الشخص الخطوات اللازمة لتحضير كوب الشاي وليس علينا تذكيره بها في كل مرة، فقط علينا ذكر الأمر؛ وكذلك الأمر بالنسبة للحاسوب، يكفي ذكر الأمر أو الدالة مع خطوات التنفيذ مرةً واحدةً، ثم نكتفي بعدها باستدعاء الدالة عن طريق ذكر اسمها فقط.
</p>

<p>
	لاحظ أن الدالة هنا من النوع الفارغ <code>void</code> أي أنها لا تعيد قيمةً بعد تنفيذها، على عكس مثال إعداد كوب الشاي، ولكن لو طلبنا إضافة الحليب على الشاي، هنا يكون نوع الدالة فارغًا لأنها تغيّر من خواص كوب الشاي فقط ولا تعيد لنا شيئًا.
</p>

<p>
	بعد التصريح عن نوع الدالة، يجب أن نذكر اسمها متبوعًا بقوسين دائريين <strong>()</strong> ولنا أن نتركهما فارغين أو نمرّر فيهما معاملات أو وسطاء الدالة، كأن نقول "حضّر لي كوبًا من الشاي (مع مكعبين من السكر)"، ثم نضع بعد ذلك التعليمات التي يجب أن تنفذها الدالة داخل القوسين <strong>{}</strong>، مثل اِغلِ الماء، ضع الماء في إبريق الشاي، أضِف أكياس الشاي، وهكذا.
</p>

<p>
	رابعًا، أضف الأسطر التالية على الشيفرة داخل الصنف، واحذف دالة البدء <code>() void Start</code> لأننا لن نحتاجها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_48" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RoboMover</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MonoBehaviour</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">float</span><span class="pln"> moveSpeed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4.0f</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Rigidbody</span><span class="pln"> rb</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Transform</span><span class="pln"> tf</span><span class="pun">;</span></pre>

<p>
	أضفنا ثلاثة متغيرات variables على الشيفرة لتسهيل استدعاء ما تدل عليه، إليك شرحًا موجزًا لعملها:
</p>

<ul>
	<li>
		المتغير <strong>moveSpeed</strong>: يدل على سرعة الحركة وهو رقم عشري من النوع العائم Float (عدد عشري).
	</li>
	<li>
		المتغير <strong>rb</strong>: يدل هذا المتغير إلى مركبة الجسم الصلب للرجل الآلي.
	</li>
	<li>
		المتغير <strong>tf</strong>: يشير هذا المتغير إلى مكون التحويل Transform.
	</li>
</ul>

<p>
	خامسًا، أضف الأسطر التالية إلى دالة التعديل <code>Update</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_50" style=""><span class="com">// تُستدعى دالة التعديل مرةً واحدةً عند لكل إطار</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Vector3</span><span class="pln"> desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Horizontal"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0.0f</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Vertical"</span><span class="pun">));</span><span class="pln">
  desiredDirection </span><span class="pun">=</span><span class="pln"> moveSpeed </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
  desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">.</span><span class="pln">deltaTime </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
  rb</span><span class="pun">.</span><span class="typ">MovePosition</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rb</span><span class="pun">.</span><span class="pln">position </span><span class="pun">+</span><span class="pln"> desiredDirection</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُنشئ السطر الأول شعاعًا للمسافة المطلوبة <code>desiredDirection</code>، وهو مكونٌ من ثلاث مركبات للإحداثيات، اثنتان منهما للاتجاهات التي يدخلها اللاعب <code>Input</code>، والمركبة الثالثة هي العمق depth وقيمتها ثابتة <code>0.0</code>.
</p>

<p>
	بعدها نضرب المسافة <code>desiredDirection</code> بمتغير السرعة <code>moveSpeed</code>، ثم نضرب المسافة <code>desiredDirection</code> بالمتغير <code>Time.deltaTime</code> والذي يشير للزمن منذ آخر عملية تعديل، ما يضمن أن الإحداثيات تتغير بدقة مهما كان نوع الجهاز الذي يُشغِّل اللعبة.
</p>

<p>
	إذًا، سيتحرك الرجل الآلي "MazeRobo" من خلال القيمة المحسوبة والمُخزنة في <code>desiredDirection</code> بالإتجاه الذي نحدّده وبخطوات صغيرة، عند كل تحديثٍ للشاشة.
</p>

<p>
	لا تنسى حفظ الشيفرة بالنقر على قائمة ملف File، ثم على حفظ Save. سادسًا، اسحب ملف الشيفرة <strong>RoboMover</strong> وأفلته فوق كائن <strong>MazeRobo</strong> في القائمة التسلسلية <strong>Hierarchy</strong>، كما هو موضح أدناه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107186" href="https://academy.hsoub.com/uploads/monthly_2022_09/step7_dragScript.png.2e4a5392c225238755d91727932c3e70.png" rel=""><img alt="step7_dragScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107186" data-unique="cof7kcnqc" src="https://academy.hsoub.com/uploads/monthly_2022_09/step7_dragScript.thumb.png.3ba05c4ef7a873d2796cdbb6fc712c78.png"></a>
</p>

<p>
	سيظهر قسم خاص بالشيفرة "RoboMover" في نافذة المراقب أسفل قسم الجسم الصلب "Rigidbody":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107153" href="https://academy.hsoub.com/uploads/monthly_2022_09/MazeRobo_Inspector.png.6fdd23ea8ac09362dbbc9307b90c49d2.png" rel=""><img alt="MazeRobo_Inspector.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107153" data-unique="q2g5ruixh" src="https://academy.hsoub.com/uploads/monthly_2022_09/MazeRobo_Inspector.png.6fdd23ea8ac09362dbbc9307b90c49d2.png"></a>
</p>

<p>
	لاحظ وجود حقلين فارغين في قسم "RoboMover" هما <strong>rb</strong> و <strong>tf</strong> الذين يشيران إلى الجسم الصلب <strong>Rigidbody</strong> والتحويل <strong>Transform</strong> على الترتيب. انقر عليهما واسحبهما إلى الحقلين الفارغين كي تحصل على القيم المطلوبة لتحريك الرجل الآلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107185" href="https://academy.hsoub.com/uploads/monthly_2022_09/step7_DragOntoScript.png.6cd85f296dcfaf448c4740f3768eedd8.png" rel=""><img alt="step7_DragOntoScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107185" data-unique="8m0l0b6ls" src="https://academy.hsoub.com/uploads/monthly_2022_09/step7_DragOntoScript.png.6cd85f296dcfaf448c4740f3768eedd8.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107155" href="https://academy.hsoub.com/uploads/monthly_2022_09/Script_Vars.png.ae54dd5f835786ff95933b00474d17e8.png" rel=""><img alt="Script_Vars.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107155" data-unique="7sgkq9ivq" src="https://academy.hsoub.com/uploads/monthly_2022_09/Script_Vars.png.ae54dd5f835786ff95933b00474d17e8.png"></a>
</p>

<p>
	أصبحت الآن جاهزًا للعب. انقر على زر اللعب Play الموجود في منتصف واجهة يونيتي، واستخدم مفاتيح الأسهم لتحريك الرجل الآلي، وانقر على زر Play مرةً أخرى لإيقاف اللعبة.
</p>

<h2>
	تحسين الحركة
</h2>

<p>
	سنعمل في هذه الخطوة على تحسين حركة الرجل الآلي، إذ أنه يمشي مستقيمًا ولا يستدير أو يلتفت حوله.
</p>

<p>
	أولًا، أضف السطر التالي على الشيفرة تحت دالة <code>rb.MovePosition</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_52" style=""><span class="pln">rb</span><span class="pun">.</span><span class="typ">MoveRotation</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Quaternion</span><span class="pun">.</span><span class="typ">LookRotation</span><span class="pln"> </span><span class="pun">(</span><span class="pln">desiredDirection</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pun">.</span><span class="pln">up</span><span class="pun">));</span></pre>

<p>
	إذ يجعل هذا السطر الرجل الآلي MazeRobo ينظر إلى وجهته.
</p>

<p>
	ثانيًا، شغّل اللعبة وتحقق من حركة الرجل الآلي.
</p>

<p>
	لاحظ أنه أصبح يستدير باتجاه حركته، لكن سرعان ما يعود إلى الاتجاه الأصلي عند توقفه عن الحركة. سنعمل على إصلاح ذلك فيما يلي، ولكن علينا أولًا فهم سبب حدوث ذلك؟
</p>

<p>
	تعتمد يونيتي القيمة <strong>0</strong> إتجاهًا افتراضيًا، لذلك عندما لا يُدخل اللاعب قيمةً، أي عندما لا يحرك الرجل الآلي، تكون قيمة الإدخال <strong>0</strong> ويتجه الرجل الآلي بالإتجاه الافتراضي، لذلك يجب علينا تعديل الشيفرة بحيث يستدير الرجل الآلي فقط وفقًا لمدخلات اللاعب. إذًا، سنعدل على الشيفرة بحيث نجعل الرجل الآلي يتحرك ويستدير فقط إذا كانت قيمة الإدخال من اللاعب أكبر من القيمة <strong>0.01</strong>.
</p>

<p>
	ثالثًا، ضع جزء الشيفرة المتعلق بالإتجاه داخل تعليمة <code>if</code> ليُنفَّذ عند تحقق الشرط. سنغير الشرط فيما بعد، لكن اجعله الآن محققًا دائمًا بتمرير القيمة <code>true</code> مكان الشرط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_54" style=""><span class="com">// تُستدعى دالة التعديل مرةً واحدةً لكل إطار</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">Vector3</span><span class="pln"> desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Horizontal"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0.0f</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Vertical"</span><span class="pun">));</span><span class="pln">
      desiredDirection </span><span class="pun">=</span><span class="pln"> moveSpeed </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
      desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">.</span><span class="pln">deltaTime </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
      rb</span><span class="pun">.</span><span class="typ">MovePosition</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rb</span><span class="pun">.</span><span class="pln">position </span><span class="pun">+</span><span class="pln"> desiredDirection</span><span class="pun">);</span><span class="pln">
      rb</span><span class="pun">.</span><span class="typ">MoveRotation</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Quaternion</span><span class="pun">.</span><span class="typ">LookRotation</span><span class="pln"> </span><span class="pun">(</span><span class="pln">desiredDirection</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pun">.</span><span class="pln">up</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن، شغّل اللعبة مرةً أخرى وتحقق من حركة الرجل الآلي.
</p>

<p>
	رابعًا، أضف الأسطر التالية على دالة التعديل <code>Update</code> للحصول على القيمة المطلقة <strong>absolute value</strong> لمدخلات اللاعب، أي قيمة الرقم دون إشارته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_56" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="typ">float</span><span class="pln"> inputHorizontal </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Mathf</span><span class="pun">.</span><span class="typ">Abs</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Horizontal"</span><span class="pun">));</span><span class="pln">
</span><span class="typ">float</span><span class="pln"> inputVertical </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Mathf</span><span class="pun">.</span><span class="typ">Abs</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Vertical"</span><span class="pun">));</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	عندما تعطي الكائن أمرًا بالحركة للأمام فإن يونيتي يفسر هذا الأمر على أنه رقم موجب (<strong>1</strong>)، أما عندما تعطي أمرًا بالحركة للخلف فإن يونيتي يفسره على أنه رقم سالب (<strong>1-</strong>)، ولأننا نريد فقط تريد حجم الرقم، بغض النظر عن إشارته، استخدمنا القيمة المطلقة للرقم، إذ أن <strong>القيمة المطلقة</strong> لرقمٍ ما هي القيمة الموجبة للرقم أو الصفر.
</p>

<p>
	الآن، علينا تعديل شروط تعليمة <code>if</code> بحيث تتحقق فيما إذا كانت قيمة <code>inputHorizontal</code> أكبر من <strong>0.01</strong> أو إذا كانت قيمة <code>inputVertical</code> أكبر من <strong>0.01</strong>، وسنحتاج إلى استخدام العامل <strong>أو or</strong>والذي نمثله باستخدام شرطتين عموديتين <strong>||</strong> في <a href="https://academy.hsoub.com/programming/c-sharp/%D8%AE%D8%B7%D9%88%D8%A7%D8%AA%D9%83-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%89-%D9%85%D8%B9-%D9%84%D8%BA%D8%A9-%D8%B3%D9%8A-%D8%B4%D8%A7%D8%B1%D8%A8-c-r312/" rel="">لغة سي شارب #C</a>، إذ تُوضع الشرطتين بين الحالتين اللتين نود التحقق منهما، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_59" style=""><span class="pln">condition A </span><span class="pun">||</span><span class="pln"> condition B</span></pre>

<p>
	أما للعامل <strong>و</strong> فنستخدم الرمز التالي "&amp;&amp;".
</p>

<p>
	عدّل تعليمة <code>if</code> لتبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_61" style=""><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputHorizontal </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.01f</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> inputVertical </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.01f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	بعد هذا التعديل، يجب أن يستدير الرجل الآلي باتجاه حركته ويبقى كذلك، وإليك شيفرة دالة التعديل كاملةً كي تتحقق منها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_63" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="typ">float</span><span class="pln"> inputHorizontal </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Mathf</span><span class="pun">.</span><span class="typ">Abs</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Horizontal"</span><span class="pun">));</span><span class="pln">
  </span><span class="typ">float</span><span class="pln"> inputVertical </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Mathf</span><span class="pun">.</span><span class="typ">Abs</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Vertical"</span><span class="pun">));</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">inputHorizontal </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.01f</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> inputVertical </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.01f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">Vector3</span><span class="pln"> desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Horizontal"</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0.0f</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Input</span><span class="pun">.</span><span class="typ">GetAxis</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Vertical"</span><span class="pun">));</span><span class="pln">
    desiredDirection </span><span class="pun">=</span><span class="pln"> moveSpeed </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
    desiredDirection </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">.</span><span class="pln">deltaTime </span><span class="pun">*</span><span class="pln"> desiredDirection</span><span class="pun">;</span><span class="pln">
    rb</span><span class="pun">.</span><span class="typ">MovePosition</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rb</span><span class="pun">.</span><span class="pln">position </span><span class="pun">+</span><span class="pln"> desiredDirection</span><span class="pun">);</span><span class="pln">
    rb</span><span class="pun">.</span><span class="typ">MoveRotation</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Quaternion</span><span class="pun">.</span><span class="typ">LookRotation</span><span class="pln"> </span><span class="pun">(</span><span class="pln">desiredDirection</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pun">.</span><span class="pln">up</span><span class="pun">));</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p style="text-align: center;">
	<img alt="step8_RoboFacingCamera.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107189" data-unique="o6bj0ptzu" style="" src="https://academy.hsoub.com/uploads/monthly_2022_09/step8_RoboFacingCamera.png.829660afcbe4d7534853d93b8b488442.png">
</p>

<h2>
	ملاحقة الكاميرا
</h2>

<p>
	سنعمل في هذه الخطوة على تعديل نطاق عرض الكاميرا بحيث تلاحق حركة الرجل الآلي.
</p>

<p>
	أولًا، انقر على الكاميرا الرئيسية <strong>Main Camera</strong> في نافذة القائمة التسلسلية <strong>Hierarchy</strong> من نافذة المراقب inspector، وأسند القيم التالية لمركبة الموضع، والدوران، والحجم، بالترتيب:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107193" href="https://academy.hsoub.com/uploads/monthly_2022_09/step9_SelectMainCamera.png.bbea80428cc43f69ec7c4eb1c3af10f9.png" rel=""><img alt="step9_SelectMainCamera.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107193" data-unique="tzb57p2cx" src="https://academy.hsoub.com/uploads/monthly_2022_09/step9_SelectMainCamera.png.bbea80428cc43f69ec7c4eb1c3af10f9.png"></a>
</p>

<ul>
	<li>
		الموضع:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_65" style=""><span class="pln">X</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Y</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
Z</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">5</span></pre>

<ul>
	<li>
		الدوران:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_67" style=""><span class="pln">X</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60</span><span class="pln">
Y</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Z</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span></pre>

<ul>
	<li>
		الحجم:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_69" style=""><span class="pln">X</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
Y</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
Z</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107192" href="https://academy.hsoub.com/uploads/monthly_2022_09/step9_MainCameraTransform.png.3c0171a1ec11ad8de5ebcdeab91fd513.png" rel=""><img alt="step9_MainCameraTransform.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107192" data-unique="0lqvw5agm" style="width: 650px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step9_MainCameraTransform.png.3c0171a1ec11ad8de5ebcdeab91fd513.png"></a>
</p>

<p>
	شغّل اللعبة لتتحقق من حركة الكاميرا، وستلاحظ أنها لا تتبع حركة الرجل الآلي بعد، ولتحقيق ذلك يجب عليك تحديث موضع الكاميرا في كل إطار، بإضافة الشيفرة التي سنوردها أدناه.
</p>

<p>
	ثانيًا، أنشئ مجلدًا جديدًا لحفظ الشيفرة داخل مجلد Scripts بالنقر على <strong>Assets &gt; Create &gt; C# Script</strong> وسمّه "CameraMover".
</p>

<p>
	أضف المتغيرات الثلاث التالية داخل الصنف <code>CameraMover</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_72" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CameraMover</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MonoBehaviour</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Transform</span><span class="pln"> tf</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Transform</span><span class="pln"> playerTransform</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Vector3</span><span class="pln"> distanceBetweenPlayerAndCam</span><span class="pun">;</span></pre>

<p>
	تتبِّع الأسطر السابقة التي أضفناها حركة ما يلي:
</p>

<ul>
	<li>
		موضع الكاميرا <code>tf</code>.
	</li>
	<li>
		موضع الرجل الآلي <code>playerTransform</code>.
	</li>
	<li>
		إحداثيات الموضع بين الكاميرا والرجل الآلي <code>distanceBetweenPlayerAndCam</code>.
	</li>
</ul>

<p>
	ثالثًا، حدِّد المسافة الابتدائية بين الكاميرا والرجل الآلي بإضافة السطر التالية على دالة البدء <code>Start</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_74" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">Start</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  distanceBetweenPlayerAndCam </span><span class="pun">=</span><span class="pln"> tf</span><span class="pun">.</span><span class="pln">position </span><span class="pun">-</span><span class="pln"> playerTransform</span><span class="pun">.</span><span class="pln">position</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	رابعًا، أضف السطر التالي لدالة <code>Update</code> للحفاظ على المسافة ذاتها في كل الإطارات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_76" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">Update</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  tf</span><span class="pun">.</span><span class="pln">position </span><span class="pun">=</span><span class="pln"> playerTransform</span><span class="pun">.</span><span class="pln">position </span><span class="pun">+</span><span class="pln"> distanceBetweenPlayerAndCam</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	خامسًا، أضف الشيفرة للكاميرا، وذلك بالنقر على خيار الكاميرا الأساسية <strong>Main Camera</strong> من القائمة، ثم اسحب شيفرة الصنف <code>CameraMover</code> وأفلتها فوق الكاميرا، ثم انقر على خيار الكاميرا الأساسية <strong>Main Camera</strong> من القائمة واسحبه إلى الحقل "Tf" في نافذة المراقب، واسحب <strong>MazeRobo</strong> إلى الحقل "Player Transform"، كما هو موضح أدناه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107191" href="https://academy.hsoub.com/uploads/monthly_2022_09/step9_dragFromHierarchyOntoScript.png.fe5c54d888e94a245e474ecc8b77fa53.png" rel=""><img alt="step9_dragFromHierarchyOntoScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107191" data-unique="3kgzyaz30" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step9_dragFromHierarchyOntoScript.thumb.png.ec48371049a6c3e6e6122c375f49c45d.png"></a>
</p>

<p>
	والآن، شغّل اللعبة ولاحظ كيف تلاحق الكاميرا حركة الرجل الآلي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107190" href="https://academy.hsoub.com/uploads/monthly_2022_09/step9_CameraFollowing.png.abbf6a5abc84fa0b64719e1ce60e70c7.png" rel=""><img alt="step9_CameraFollowing.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107190" data-unique="lu04wlf3q" src="https://academy.hsoub.com/uploads/monthly_2022_09/step9_CameraFollowing.png.abbf6a5abc84fa0b64719e1ce60e70c7.png"></a>
</p>

<h2>
	إضافة مزيد من العناصر
</h2>

<p>
	سنضيف الآن كرةً على المتاهة ليلعب بها الرجل الآلي.
</p>

<p>
	أولًا، أنشئ كرةً بالنقر على <strong>GameObject &gt; 3D Object &gt; Sphere</strong> وسمّها "Ball".
</p>

<p>
	ثانيًا، أسند القيم التالية لموضع الكرة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_80" style=""><span class="pln">X</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Y</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
Z</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span></pre>

<p>
	ثالثًا، أنشئ مادةً لونها أخضر وسمّها "BallGreen"، ثم طبِّقها على الكرة بسحبها وإفلاتها عليها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107156" href="https://academy.hsoub.com/uploads/monthly_2022_09/step10_AddGreenBall.png.f1f4a68967874052102a4835a264c648.png" rel=""><img alt="step10_AddGreenBall.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107156" data-unique="fzzmr8jhk" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step10_AddGreenBall.thumb.png.e6d0c3879a716a0a5235a214052eb2e4.png"></a>
</p>

<p>
	شغّل اللعبة، وستلاحظ أن الكرة لا تتحرك عندما يلامسها الرجل الآلي. سنعمل على إصلاح ذلك فيما يلي.
</p>

<p>
	رابعًا، انقر على الكرة وفعّل خيار الجسم الصلب <strong>Rigidbody</strong> وذلك من <strong>Component &gt; Physics &gt; Rigidbody</strong>.
</p>

<p>
	الآن، شغّل اللعبة واختبر حركة الكرة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107157" href="https://academy.hsoub.com/uploads/monthly_2022_09/step10_RollingBall.png.73760b1c4df8d12a1830a2235f3ae120.png" rel=""><img alt="step10_RollingBall.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107157" data-unique="k85ipwupk" src="https://academy.hsoub.com/uploads/monthly_2022_09/step10_RollingBall.png.73760b1c4df8d12a1830a2235f3ae120.png"></a>
</p>

<h2>
	الفوز
</h2>

<p>
	بعد أن أصبحت لدينا العناصر الرئيسية للعبة جاهزةً، علينا أن نحدد طريقةً للفوز.
</p>

<p>
	أولًا، أضف مكعبًا وسمّه "WinZone" ولوّنه بلونٍ مناسب، ثم حدِّده من القائمة التسلسلية وانقر لتحديد خيار <strong>Is Trigger</strong> من قسم <strong>Box Collider</strong> من نافذة المراقب:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107160" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_BoxColliderTrigger.png.f40a4c718ca240676aaed60fb4ed2df3.png" rel=""><img alt="step11_BoxColliderTrigger.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107160" data-unique="pef5nz8mn" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_BoxColliderTrigger.png.f40a4c718ca240676aaed60fb4ed2df3.png"></a>
</p>

<p>
	ثانيًا، أسند القيم التالية لموضع المكعب الجديد:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_83" style=""><span class="pln">X</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">5</span><span class="pln">
Y</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
Z</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span></pre>

<p>
	الآن سنكتب شيفرةً تتيح للمكعب "WinZone" التحسُّس للكرة عندما تلمسه، لذلك يجب علينا وضع علامة على الكرة.
</p>

<p>
	ثالثًا، انقر على الكرة في القائمة التسلسلية، ثم انقر على خيار الوسم <strong>Tag</strong> في نافذة المراقب:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107159" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_BallTagProperty.png.3b485616582e6cd353779015c4c4d073.png" rel=""><img alt="step11_BallTagProperty.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107159" data-unique="u80geghhd" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_BallTagProperty.png.3b485616582e6cd353779015c4c4d073.png"></a>
</p>

<p>
	رابعًا، انقر على خيار إضافة وسم <strong>Add Tag</strong> ثم انقر على الرمز <strong>+</strong> لإضافة وسمٍ جديد وسمّه "Ball".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107158" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_AddTag.png.7c9a978cc1b812a65ca1292708f514e5.png" rel=""><img alt="step11_AddTag.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107158" data-unique="9tdcvnj8a" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_AddTag.png.7c9a978cc1b812a65ca1292708f514e5.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107164" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_NewTagBall.png.63b0e6851c5bb33b63e5c5ace0accd3c.png" rel=""><img alt="step11_NewTagBall.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107164" data-unique="cweclatl8" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_NewTagBall.png.63b0e6851c5bb33b63e5c5ace0accd3c.png"></a>
</p>

<p>
	خامسًا، انقر مرةً ثانيةً على الكرة في القائمة التسلسلية، ثم انقر على حقل الوسم <strong>Tag</strong> في نافذة المراقب مرةً ثانية واِختر الوسم الجديد الذي أضفناه.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107161" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_ChooseBallTag.png.50273d1d3b1b4d178c44bc29ed9b2c56.png" rel=""><img alt="step11_ChooseBallTag.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107161" data-unique="3ysh0qdj5" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_ChooseBallTag.png.50273d1d3b1b4d178c44bc29ed9b2c56.png"></a>
</p>

<p>
	الآن، سنضيف بعض المؤثرات للاحتفال بفوز اللاعب.
</p>

<p>
	سادسًا، أنشئ <strong>Particle System</strong> بالنقر على <strong>GameObject &gt; Effects &gt; Particle System</strong> وسمّه "Fireworks" أي ألعاب نارية.
</p>

<p>
	سابعًا، انقر على كائن الألعاب النارية وألغِ تحديد المربع بجانب اسمه في نافذة المراقب، وذلك لإخفاء الكائن.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107165" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_uncheckFireworks.png.9dcac98c8cab32ddace10d0c69ba1f1d.png" rel=""><img alt="step11_uncheckFireworks.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107165" data-unique="opx7z9y93" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_uncheckFireworks.png.9dcac98c8cab32ddace10d0c69ba1f1d.png"></a>
</p>

<p>
	ثامنًا، اختر اللون الأولي <strong>Start Color</strong> للألعاب النارية من نافذة المراقب، ثم أسند لإحداثيات الموضع قيمًا مطابقةً لقيم المكعب "WinZone".
</p>

<p>
	تاسعًا، أنشئ مجلدًا داخل مجلد Scripts لكتابة الشيفرة بلغة <strong>#C</strong> وسمّه WinZone، ثم امسح منه دالتي <code>Start</code> و <code>Update</code> وأضف عليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7922_85" style=""><span class="kwd">public</span><span class="pln"> </span><span class="typ">GameObject</span><span class="pln"> fireworks</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">OnTriggerEnter</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Collider</span><span class="pln"> col</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">col</span><span class="pun">.</span><span class="pln">transform</span><span class="pun">.</span><span class="typ">CompareTag</span><span class="pln"> </span><span class="pun">(</span><span class="str">"Ball"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fireworks</span><span class="pun">.</span><span class="typ">SetActive</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">true</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتحقق الشيفرة المُضافة من ملامسة أي جسم صلب للمكعب "WinZone" وتسند المتغير <code>col</code> للجسم الصلب، أما إذا كان الجسم الصلب هو الكرة، فسيظهر الكائن <code>fireworks</code> لتنطلق الألعاب النارية.
</p>

<p>
	عاشرًا، احفظ ملف الشيفرة ثم اسحبه وأفلته فوق <strong>WinZone</strong> في القائمة التسلسلية، ثم انقر على <strong>WinZone</strong> واسحب كائن الالعاب النارية الموجود أدناه إلى قسم الألعاب النارية "fireworks" في نافذة المراقب، كما هو موضح:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107162" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_DragFireworksIntoScript.png.fbd36e1b46ee3904583700d94ffc59a8.png" rel=""><img alt="step11_DragFireworksIntoScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107162" data-unique="qygkrmya3" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_DragFireworksIntoScript.thumb.png.cffe9106c910dff3fc17ae20d7f99b8d.png"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107163" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_FireworksInScript.png.6a3163569a306631721df17e65e4bd97.png" rel=""><img alt="step11_FireworksInScript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107163" data-unique="70fh3jb2g" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_FireworksInScript.png.6a3163569a306631721df17e65e4bd97.png"></a>
</p>

<p>
	أخيرًا، احفظ اللعبة ثم شغّلها واستمتع بتجربة اللعبة التي أنشأتها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="107166" href="https://academy.hsoub.com/uploads/monthly_2022_09/step11_WinningFireworks.png.21b4f2fc7beb48e5e1826151bed00fe3.png" rel=""><img alt="step11_WinningFireworks.png" class="ipsImage ipsImage_thumbnailed" data-fileid="107166" data-unique="1wo3yzcge" src="https://academy.hsoub.com/uploads/monthly_2022_09/step11_WinningFireworks.png.21b4f2fc7beb48e5e1826151bed00fe3.png"></a>
</p>

<h2>
	ترقية اللعبة
</h2>

<p>
	لاحظ أن المتاهة التي أنشأناها ليست مكتملة، ومهمتك الآن هي العمل على إكمالها وإضافة مزيدٍ من المكعبات وتعديل مركبات الحجم والموضع لتكون بمثابة جدران للمتاهة، ووضع مكعب الفوز في مكان يصعُب الوصول إليه.
</p>

<p>
	لا تنسى مشاركة اللعبة مع أصدقائك.
</p>

<h2>
	خاتمة
</h2>

<p>
	بهذا تكون قد أنشأت لعبتك الأولى على محرك الألعاب الشهير يونتي، تهانينا.
</p>

<p>
	ننصحك بالاستمرار والإطلاع على دروس <a href="https://academy.hsoub.com/tags/%D9%85%D8%AF%D8%AE%D9%84%20%D8%A5%D9%84%D9%89%20unity3d/" rel="">صناعة الألعاب باستخدام يونيتي</a> الموجودة على أكاديمية حسوب.
</p>

<p>
	إذا واجهت مشاكل مع يونيتي فيمكنك الحصول على الدعم والمساعدة عبر إضافة سؤالك في قسم الأسئلة والأجوبة في <a href="https://academy.hsoub.com/questions/" rel="">أكاديمية حسوب</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://projects.raspberrypi.org/en/projects/cd-beginner-unity-sushi/0" rel="external nofollow">Robot maze</a> من <a href="https://raspberrypi.org/" rel="external nofollow">الموقع الرسمي لراسبيري باي</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%B0%D9%87%D9%86%D9%8A-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D9%83%D8%B1%D8%A7%D8%AA%D8%B4-r1699/" rel="">برمجة لعبة اختبار ذهني باستخدام سكراتش</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D9%83%D8%B1%D8%A7%D8%AA%D8%B4-r1697/" rel="">برمجة لعبة تفاعلية باستخدام سكراتش</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%88%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%84%D8%B9%D8%A8%D8%A9-%D9%82%D9%81%D8%B2-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D9%83%D8%B1%D8%A7%D8%AA%D8%B4-r1668/" rel="">تصميم وبرمجة لعبة قفز باستخدام سكراتش</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8/" rel="">لغات برمجة الألعاب</a>
	</li>
	<li>
		تعرف على أشهر <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">محركات الألعاب Game Engines</a><br>
		 
	</li>
</ul>
]]></description><guid isPermaLink="false">1700</guid><pubDate>Sat, 08 Oct 2022 16:05:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x633;&#x644;&#x627;&#x644;&#x645; &#x648;&#x62E;&#x62A;&#x627;&#x645; &#x627;&#x644;&#x644;&#x639;&#x628;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%84%D9%85-%D9%88%D8%AE%D8%AA%D8%A7%D9%85-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-r772/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc32c921a7_----.jpg.553cec69d2bcfd53e7a9b223bdfbd3c3.jpg" /></p>

<p>
	سيكون من الجيد أن نحدّ من قدرة اللاعب على التحرك للأعلى إلّا من خلال القفز عبر الفجوات أو على الصناديق. ليست هذه هي الخيارات الوحيدة المتاحة. لا يزال يتعين علينا معرفة المزيد عن المصاعد والأدراج والسلالم. لذلك، دعنا نُنشئ سُلّمًا!
</p>

<p>
	إليك ما سنعمل عليه في هذه المرحلة:
</p>

<ul>
<li>
		إنشاء أول سلّم
	</li>
	<li>
		السماح للاعبين بتسلق السلالم
	</li>
	<li>
		السماح للاعبين بالوقوف والقفز على السلالم
	</li>
</ul>
<h2>
	إنشاء أول سلّم
</h2>

<p>
	لنبدأ إنشاء سلّمنا بنسخ صنف الصندوق Box:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_7" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pun">;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pln"> from </span><span class="str">"./ladder"</span><span class="pun">;</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"ladder.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight </span><span class="pun">-</span><span class="pln"> </span><span class="lit">192</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">192</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"box.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            </span><span class="lit">136</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight </span><span class="pun">-</span><span class="pln"> </span><span class="lit">191</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	ستحتاج إلى إنشاء صورة ladder.png للسلم؛ بالنسبة لي، اخترت استخدام شكلٍ بسيطٍ بمقاسات 64x192 بيكسيل. تأكد من إضافة الصورة إلى اللعبة قبل إضافة اللاعب وإلا سيكون الشكل الخاص بالسلم أمام الشكل الخاص اللاعب.
</p>

<p>
	ستلاحظ أن اللاعب يصطدم بالسلم، كما لو كان صندوقًا. سنحتاج إلى إضافة بعض الجوالب إلى الصناديق والسلالم حتى يستطيع كشف التصادمات من تحديد ما إذا كانوا ستستمر بالاصطدام مع بعضها بعضًا …
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_11" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
    me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
    me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
    me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">


    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نعطي للصندوق و السلم خاصية الاصطدام بحيث يتمكّن اللاعب من التحرّك في تجاهلٍ للاصطدامات بالكائنات التي يجب ألا يصطدم بها اللاعبون. إذا كنا سنسمح بوجود عدة لاعبين في نفس اللعبة أو المستوى، فسنضيف أيضًا خاصية الاصطدام إلى اللاعب. هذا ما لم نكن نرغب في تصادم لاعبين متعددين مع بعضهم بعضًا.
</p>

<p>
	<iframe allowfullscreen="" frameborder="0" height="720" scrolling="auto" title="Making Games → Ladders" width="968" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137673699&amp;url=https%3A%2F%2Fvimeo.com%2F137673699&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532684238_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<h2>
	السماح للاعبين بتسلق السلالم
</h2>

<p>
	لكي يصعد اللاعب السلالم، يجب أن نكون قادرين على معرفة ما إذا كان يحاول تسلق أحدها في لحظة ما. يتعين علينا أيضًا تعليق الجاذبية والحركة الجانبية حتى لا يسقط أو ينزلق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_13" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumpVelocity </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">40</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbingSpeed </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">

           </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX

            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY
        </span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> onLadder </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

        state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> me </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">var</span><span class="pln"> you </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">


            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

                   </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Ladder"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    onLadder </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">]</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">40</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="pun">}</span><span class="pln">

                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbingSpeed</span><span class="pun">;</span><span class="pln">
                    </span><span class="pun">}</span><span class="pln">

                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">40</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbingSpeed</span><span class="pun">;</span><span class="pln">
                    </span><span class="pun">}</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">onLadder</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumpVelocity</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">


        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">;</span></pre>

<p>
	نبدأ بإضافة خاصية جديدة سنسميها التسلق (climbing). ستكون قيمتها صحيحة "true" عندما يكون اللاعب في وضع تسلق السلم. ننشِئ أيضًا متغيرًا onLadder محلي، حتى نتمكن من معرفة ما إذا كان لا يزال واقفًا على سلم.
</p>

<p>
	أثناء كشف التصادمات المعتاد، نلاحظ ما إذا كان الكائن الذي يصطدم به اللاعب هو سلم أم لا. إذا كان الأمر كذلك، وكان السهم مضغوطًا لأعلى، نبدأ في التسلق. تبدأ عملية التسلق فقط إذا كان السهم مضغوطًا لأعلى، ولهذا السبب نحتاج إلى هذا المتغير المحلي. نعيد ضبط سرعة اللاعب والخصائص المتعلقة بالقفز. ونغير كذلك بشكل مباشر مستطيلَ اللاعب.
</p>

<p>
	إذا تم الضغط على السهم للأعلى، فإنّنا نرفع اللاعب لأعلى. إذا تم الضغط لأسفل، فإنّنا نحرّك اللاعب لأسفل حتى يصبح الجزء السفلي من اللاعب أدنى من الجزء السفلي للسلم. هذا يجعل السلالم السفلية لا تتيح للاعب أن يتجاهل التصادم مع الأرض.
</p>

<p>
	<iframe allowfullscreen="" class="cp t u ig ak" frameborder="0" height="720" scrolling="auto" title="Making Games → Ladders" width="968" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137673699&amp;url=https%3A%2F%2Fvimeo.com%2F137673699&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532684238_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<h2>
	السماح للاعبين بالوقوف على السلالم
</h2>

<p>
	لا تزال هناك مشكلة في السلالم. في اللحظة التي نصل فيها إلى القمة، نسقط مرة أخرى. لقد عطلنا تصادمات السلالم، لذلك نحتاج إلى طريقة للوقوف في الجزء العلوي منها حتى نتمكن من القفز أو الانتقال إلى المنصة التالية. دعنا ننقل منطق التصادم إلى الصناديق والسلالم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_15" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Box</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    collides</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> collides </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

        state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name </span><span class="pun">!==</span><span class="pln"> </span><span class="str">"Player"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            let edges </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getEdges</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> object</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!(</span><span class="pln">
                edges</span><span class="pun">.</span><span class="pln">boxTop </span><span class="pun">&gt;</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerBottom </span><span class="pun">||</span><span class="pln">
                edges</span><span class="pun">.</span><span class="pln">boxRight </span><span class="pun">&lt;</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerLeft </span><span class="pun">||</span><span class="pln">
                edges</span><span class="pun">.</span><span class="pln">boxBottom </span><span class="pun">&lt;</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerTop </span><span class="pun">||</span><span class="pln">
                edges</span><span class="pun">.</span><span class="pln">boxLeft </span><span class="pun">&gt;</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerRight
            </span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                collides </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> collides</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    getEdges</span><span class="pun">(</span><span class="pln">box</span><span class="pun">,</span><span class="pln"> player</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"boxLeft"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"boxRight"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">width</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"boxTop"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"boxBottom"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> box</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">height</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"playerLeft"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"playerRight"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">width</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"playerTop"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"playerBottom"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">height
        </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    collidesInDirection</span><span class="pun">(</span><span class="pln">box</span><span class="pun">,</span><span class="pln"> player</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        let edges </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">getEdges</span><span class="pun">(</span><span class="pln">box</span><span class="pun">,</span><span class="pln"> player</span><span class="pun">);</span><span class="pln">
        let offsetLeft </span><span class="pun">=</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerRight </span><span class="pun">-</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">boxLeft</span><span class="pun">;</span><span class="pln">
        let offsetRight </span><span class="pun">=</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">boxRight </span><span class="pun">-</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerLeft</span><span class="pun">;</span><span class="pln">
        let offsetTop </span><span class="pun">=</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerBottom </span><span class="pun">-</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">boxTop</span><span class="pun">;</span><span class="pln">
        let offsetBottom </span><span class="pun">=</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">boxBottom </span><span class="pun">-</span><span class="pln"> edges</span><span class="pun">.</span><span class="pln">playerTop</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">offsetLeft</span><span class="pun">,</span><span class="pln"> offsetRight</span><span class="pun">,</span><span class="pln"> offsetTop</span><span class="pun">,</span><span class="pln"> offsetBottom</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> offsetTop</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"↓"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">offsetLeft</span><span class="pun">,</span><span class="pln"> offsetRight</span><span class="pun">,</span><span class="pln"> offsetTop</span><span class="pun">,</span><span class="pln"> offsetBottom</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> offsetBottom</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"↑"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">offsetLeft</span><span class="pun">,</span><span class="pln"> offsetRight</span><span class="pun">,</span><span class="pln"> offsetTop</span><span class="pun">,</span><span class="pln"> offsetBottom</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> offsetLeft</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"→"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">offsetLeft</span><span class="pun">,</span><span class="pln"> offsetRight</span><span class="pun">,</span><span class="pln"> offsetTop</span><span class="pun">,</span><span class="pln"> offsetBottom</span><span class="pun">)</span><span class="pln"> </span><span class="pun">===</span><span class="pln"> offsetRight</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"←"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"unknown"</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">;</span></pre>

<p>
	يستطيع صنف الصندوق <code>Box</code> الآن حساب ما إذا كان سيتصادم مع اللاعب. بمجرد اكتشاف التصادم بين لاعب وصندوق، يمكننا تنفيذ الدالّة التابع <code>collidesInDirection</code>. سنحصل على سهمٍ أنيقٍ UTF-8 يشير إلى الاتجاه الذي كان اللاعب يتحرك فيه قبل حدوث التصادم. أثناء إجراء هذا التغيير، حدث أنّ صنف السلم لا يقوم بأي شيء مختلف عن صنف الصندوق. يحدث مفهوم التسلق في فئة "اللاعب"، وبالتالي فإن فئة "السلم" يمكن أن تكون امتدادًا لفئة "الصندوق":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_17" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Box</span><span class="pln"> from </span><span class="str">"./box"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pln"> extends </span><span class="typ">Box</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Ladder</span><span class="pun">;</span></pre>

<p>
	يبدو صنف اللّاعب أكثر أناقةً وتنظيمًا بعد نقل منطق التصادم خارجه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9735_19" style="">
<span class="pln">animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY
    </span><span class="pun">);</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> onLadder </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

    state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">collides</span><span class="pun">(</span><span class="pln">state</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            let type </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">constructor</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
            let direction </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">collidesInDirection</span><span class="pun">(</span><span class="pln">object</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Ladder"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                onLadder </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

                let player </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
                let ladder </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">]</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">40</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    let limit </span><span class="pun">=</span><span class="pln"> ladder</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">height </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">

                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbingSpeed</span><span class="pun">,</span><span class="pln">
                        limit
                    </span><span class="pun">);</span><span class="pln">

                    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">player</span><span class="pun">.</span><span class="pln">y </span><span class="pun">===</span><span class="pln"> limit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                    </span><span class="pun">}</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">40</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> player</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&lt;</span><span class="pln"> ladder</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> ladder</span><span class="pun">.</span><span class="pln">height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbingSpeed</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Box"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">direction </span><span class="pun">===</span><span class="pln"> </span><span class="str">"↓"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">direction </span><span class="pun">===</span><span class="pln"> </span><span class="str">"↑"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">direction </span><span class="pun">===</span><span class="pln"> </span><span class="str">"←"</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">direction </span><span class="pun">===</span><span class="pln"> </span><span class="str">"→"</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">onLadder</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">38</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumpVelocity</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">climbing</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لم يتغير مفهوم السلم على الأغلب، باستثناء أن اللاعب لن يصل أبدًا إلى أعلى بيكسل في أعلى درجات السلم. هكذا نمنع اللاعب من السقوط بمجرد وصوله إلى القمة. هذا يعني أنك ستحتاج إلى جعل بداية سلالمك في البيكسل الأوّل فوق المنصة التي تتوقع أن يتحرّك عليها اللاعب. وهذا يعني أيضًا أنه لا يمكن للاعب القفز من السلالم.
</p>

<p>
	يبدو الآن منطق التصادم المتعلّق بالصندوق أنقى وأبسط بكثير! وماهي النتيجة؟ سلالمٌ تعمل بشكل جيد.
</p>

<p>
	<iframe allowfullscreen="" class="cp t u ig ak" frameborder="0" height="720" scrolling="auto" title="Making Games → Ladders" width="968" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137680213&amp;url=https%3A%2F%2Fvimeo.com%2F137680213&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532693140_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<h2>
	ختام اللعبة: ماذا بعد؟
</h2>

<p>
	لقد علمتني هذه المقالات القليلة الكثير من الأمور، أو لِنَقُل أنّهما أمران بارزان على وجه التحديد.
</p>

<p>
	الأول هو أن هناك قدرًا لا حصر له من الأشياء التي يمكننا إضافتها أو تغييرها في ألعابنا. والثاني هو أن هذا النشاط مربحٌ ومتعبٌ في الوقت ذاته.
</p>

<p>
	لقد انطلقت من رغبةٍ في معرفة كيفية صنع لعبة منصة بسيطة، وبعدها قمنا معا بتغطية كل شيء تقريبا نحتاجه لبناء تلك اللعبة. لا أريد التوقف هنا، رغم ذلك. أريد أن أستمر في التعلم وصقل مهاراتي. أريد أن أستمر في مشاركة تلك التجارب معك.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://medium.com/@assertchris/ladders-dd9795eb4e74" rel="external nofollow">Ladders</a> لصاحبه Christopher Pitt
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/game-development/%D8%A7%D9%84%D8%AC%D8%A7%D8%B0%D8%A8%D9%8A%D8%A9-r771/" rel="">الجاذبية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/" rel="">مدخل إلى ألعاب المتصفح</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">772</guid><pubDate>Mon, 03 Feb 2020 13:03:01 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x62C;&#x627;&#x630;&#x628;&#x64A;&#x629; &#x641;&#x64A; &#x627;&#x644;&#x644;&#x639;&#x628;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%AC%D8%A7%D8%B0%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-r771/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc33d5ae79_--.jpg.9e53e833060932406e490bd97d4b32fb.jpg" /></p>

<p>
	سنعمل هذه المرة على بنية الشيفرة لدينا، ونضيف الجاذبية إلى لعبتنا. ويجدر الذكر أننا قمنا بالفعل بمعظم العمل اللازم لتحقيق الجاذبية.
</p>

<p>
	إليك ما سنعمل عليه في هذه المرحلة:
</p>

<ul>
<li>
		تنظيف الشيفرة الموجودة لدينا
	</li>
	<li>
		إضافة الجاذبية إلى لعبتنا
	</li>
	<li>
		السماح للاعبين بالقفز
	</li>
</ul>
<h2>
	تنظيف الشيفرة الموجودة لدينا
</h2>

<p>
	نحن بحاجة لتنظيف بعض الأشياء! دعنا في البداية نبدّل موضعي x و y إضافةً إلى العرض والارتفاع (بالنسبة للصندوق وللاعب) مع PIXI.Rectangle. إنّ لديهما هذه الخصائص، ولكنهما يتفاعلان أيضًا مع باقي عناصر PIXI بطرق مثيرة للاهتمام.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_6" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Box</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_8" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">


    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

           </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

        state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> me </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">var</span><span class="pln"> you </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">move</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">

    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">;</span></pre>

<p>
	هل لاحظت هذا المقدار من الشيفرة الذي نستطيع حذفه؟ لقد أصبحت عمليات الموازنة طويلة قليلاً، لكن لا شيء يمكن إصلاحه من خلال متغير محليّ واحد أو اثنين. أدركتُ أيضًا أنه يمكننا تغيير قيم x و y الابتدائية من أجل التحريك. بعد ذلك، أرغب في تغليف (encapsulation) الحدث والعارض والمسرح في صنف (class) جديدة خاصّة باللعبة (Game):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_10" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Game</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"keys"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
            </span><span class="str">"clicks"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
            </span><span class="str">"mouse"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
            </span><span class="str">"objects"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">get</span><span class="pln"> stage</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_stage</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_stage </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newStage</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_stage</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">set</span><span class="pln"> stage</span><span class="pun">(</span><span class="pln">stage</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_stage </span><span class="pun">=</span><span class="pln"> stage</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    newStage</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Container</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">get</span><span class="pln"> renderer</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_renderer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_renderer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newRenderer</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_renderer</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">set</span><span class="pln"> renderer</span><span class="pun">(</span><span class="pln">renderer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">_renderer </span><span class="pun">=</span><span class="pln"> renderer</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    newRenderer</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="pln">autoDetectRenderer</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">,</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newRendererOptions</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    newRendererOptions</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"antialias"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"autoResize"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"transparent"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"resolution"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> caller </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            requestAnimationFrame</span><span class="pun">(</span><span class="pln">caller</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">renderer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderer</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">stage </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">stage</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                object</span><span class="pun">.</span><span class="pln">animate</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderer</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">stage</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">

        caller</span><span class="pun">();</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    addEventListenerToElement</span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">keyCode</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keyup"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">keyCode</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mousedown"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">which</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="str">"clientX"</span><span class="pun">:</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">,</span><span class="pln">
                </span><span class="str">"clientY"</span><span class="pun">:</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY
            </span><span class="pun">};</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mouseup"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">which</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mousemove"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">mouse</span><span class="pun">.</span><span class="pln">clientX </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">mouse</span><span class="pun">.</span><span class="pln">clientY </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    addRendererToElement</span><span class="pun">(</span><span class="pln">element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        element</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderer</span><span class="pun">.</span><span class="pln">view</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    addObject</span><span class="pun">(</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">object</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Game</span><span class="pun">;</span></pre>

<p>
	لاحِظ دالّتي الجالب والضابط الخاصتين بصنفٍ ES6. إنهما مفيدتان لملء التبعيات الاختيارية حسب الحاجة. يمكننا تجاهل المصيّر والمسرح إذا كنا بحاجة إلى ذلك، ولكن لديهما قيم افتراضية معقولة أيضًا.
</p>

<p>
	هذا، على الأغلب، مجرد نقل للشيفرة التي كانت في <code>main.js</code> إلى <code>game.js</code>. الاختلاف الوحيد الملحوظ هو أننا لم نعد نحتاج إلى إضافة الأشكال إلى المسرح بشكل منفصل عن إضافة الكائنات إلى الحالة (state).
</p>

<p>
	أنا محتارٌ حول هذا الموضوع. فمن ناحية، يكون الأمر أكثر وضوحًا إذا أضفناها إلى المسرح يدويًا. ومن ناحية أخرى، هل سنضيف أشكالًا (مرتبطة بالكائنات) دون إضافة الكائنات؟ لا أعتقد ذلك.
</p>

<p>
	ربما سنعود ونغير ذلك. في الوقت الحالي، تبدو الشيفرة أنظف قليلاً. إذن، كيف تبدو <code>main.js</code> الآن؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_12" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Game</span><span class="pln"> from </span><span class="str">"./game"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> from </span><span class="str">"./player"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Box</span><span class="pln"> from </span><span class="str">"./box"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> game </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Game</span><span class="pun">();</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"box.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">152</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"player.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"box.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">248</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addEventListenerToElement</span><span class="pun">(</span><span class="pln">window</span><span class="pun">);</span><span class="pln">
game</span><span class="pun">.</span><span class="pln">addRendererToElement</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">);</span><span class="pln">
game</span><span class="pun">.</span><span class="pln">animate</span><span class="pun">();</span></pre>

<p>
	هذا يبدو أفضل بكثير! لدينا سيطرة كافية لتعيين نقاط الانطلاق لكل كائنٍ في اللعبة. ولكن بعد الإطار الأول، تبدأ الدالّة التابع <code>()animate</code> في العمل. ستبدأ أشياء مثل الجاذبية والتصادمات في التحكم في كيفية تقدم اللعبة. لقد كان الأمر هكذا دائمًا، لذلك يبدو هذا الملف كذلك أيضًا.
</p>

<p>
	كان بإمكاننا أن نحصُر الأحداث والعارض في مجموعة صغيرة من العناصر. كما كنا نستطيع إضافة أي عدد من الكائنات إلى اللعبة من هنا. كل شيء آخر مرتبط باللعبة يوجد داخل فئة اللعبة. وكل شيء آخر مرتبط باللاعب أو الصندوق يوجد داخل الفئة الخاصّة به. هكذا تبدو الأمور أنيقة ومنظمة!
</p>

<h2>
	إضافة الجاذبية إلى لعبتنا
</h2>

<p>
	أحد الأشياء التي تجعل ألعاب المنصة ممتعةً هو وجود قدرٍ معتدلٍ من الأجسام في محيط اللعب. دعنا نضيف الجدران والأرضية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_14" style="">
<span class="kwd">var</span><span class="pln"> game </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Game</span><span class="pun">();</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">-</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

game</span><span class="pun">.</span><span class="pln">addObject</span><span class="pun">(</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"player.png"</span><span class="pln">
        </span><span class="pun">),</span><span class="pln">
        </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Rectangle</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="lit">64</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	بدلاً من مربعين أحمرين، لدينا ثلاثة مستطيلات رفيعة. إنها تتصادم بنفس الطريقة. الآن، دعنا نرى كيف نضيف هذه الجاذبية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_16" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> rectangle</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle </span><span class="pun">=</span><span class="pln"> rectangle</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumpVelocity </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">50</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY
        </span><span class="pun">);</span><span class="pln">

        state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> me </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">var</span><span class="pln"> you </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
                me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">;</span></pre>

<p>
	نبدأ بإنشاء مجموعة من الخصائص لتتناسب مع تلك التي أنشأناها لتتبع الحركة الأفقية. لا نحتاج إلى احتكاك عمودي، إذ أنّ هذا المستوى من التفاصيل يُحذَف غالبا من ألعاب المنصّات.
</p>

<p>
	علينا أيضًا أن نتتبع التصادمات العمودية والأفقية. عندما يكون التصادم بين اللاعب والمنصة أو الأرضية، فإننا نوقف حركة الهبوط. وعندما يكون مع السقف، فإننا نستبدل الحركة الصعودية بقوة الجاذبية.
</p>

<h2>
	السماح للاعبين بالقفز
</h2>

<p>
	القفز هو ببساطة مقاومة للجاذبية لفترة قصيرة:
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5827_20" style="">
<span class="pln">animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">
 
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityY
    </span><span class="pun">);</span><span class="pln">
 
    state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
 
        </span><span class="kwd">var</span><span class="pln"> me </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> you </span><span class="pun">=</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">;</span><span class="pln">
 
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
            me</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
            me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
            me</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
 
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

               </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
 
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationY</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
 
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
 
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> you</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> me</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
 
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">32</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumpVelocity</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">jumping </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">grounded </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
 
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityY</span><span class="pun">;</span><span class="pln">
 
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rectangle</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد قمنا هنا بتعيين مفتاح المسافة من أجل حركة القفز. نضيف فحص لوحة المفاتيح بعد فحص التصادم لأننا نريد لاعبنا أن يقفز فقط إذا كان يقف على منصة أو أرضية. يمكنك الآن إنشاء مستوياتٍ انطلاقًا من الصناديق. تستطيع كذلك إعطاءها بنيةً مرئيةً، والقفز من حولها. تمتع بقضاء بعض الوقت في إنشاء المستوى والقفز من خلاله!
</p>

<p>
	<iframe allowfullscreen="" class="fq n o fp x" frameborder="0" height="720" scrolling="auto" title="jumping" width="968" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137466509&amp;url=https%3A%2F%2Fvimeo.com%2F137466509&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532393133_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://medium.com/@assertchris/gravity-60cddcbf03e" rel="external nofollow">Gravity </a> لصاحبه Christopher Pitt
</p>

<h2>
	اقرأ أيضًا
</h2>

<p>
	المقال التالي: <a href="https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%84%D9%85-%D9%88%D8%AE%D8%AA%D8%A7%D9%85-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-r772/" rel="">إنشاء السلالم وختام اللعبة</a>
</p>

<p>
	المقال السابق: <a href="https://academy.hsoub.com/programming/game-development/%D9%83%D8%B4%D9%81-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D8%AF%D9%85%D8%A7%D8%AA-r770/" rel="">كشف التصادمات</a>
</p>
]]></description><guid isPermaLink="false">771</guid><pubDate>Mon, 27 Jan 2020 13:05:00 +0000</pubDate></item><item><title>&#x643;&#x634;&#x641; &#x627;&#x644;&#x62A;&#x635;&#x627;&#x62F;&#x645;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/game-development/%D9%83%D8%B4%D9%81-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D8%AF%D9%85%D8%A7%D8%AA-r770/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc34ceacf0_---.jpg.adcccfcd65af2ad6489cebb0b780d8ea.jpg" /></p>

<p>
	لقد حان الوقت لكي نتحدث عن كشف التصادمات (Detection Collision). إنه يؤثر على الأجزاء الظاهرة في لعبتنا، مثل الجدران التي لا يمكننا المرور عبرها ومثل الأرضيات التي لا يمكننا السقوط من خلالها. كما أنه يؤثر على الأجزاء المخفية في لعبتنا مثل قذائف الأسلحة ونقاط التفتيش.
</p>

<p>
	لن نصل إلى مفهوم الجاذبية بعد، ولن ننظر إلى صحة اللاعب أو استرداد حياته (الدم والأرواح). تعدّ الأرضيات والقذائف ونقاط التفتيش مثيرة للاهتمام، ولكنها تستحق أقسامًا خاصة بها. سنعمل على إنشاء كائنات غير نافذة (لا يمكن العبور من خلالها). سنتعلم طرقًا لمعرفة ما إذا كان جسمان يشغلان نفس الحيّز المكانيِّ.
</p>

<p>
	لقد قضيت بعض الوقت أبحث في هذا الموضوع. يبدو أن هناك العديد من الطرق لحل مشكلة جسمين يشغلان نفس المكان. بعض هذه الطرائق يسهل شرحها وتنفيذها وهي التي سنلقي نظرة عليها، والطرائق الأخرى ليست سهلةً ولا تزال حديثة العهد رغم ذلك.
</p>

<p>
	<iframe allowfullscreen="" class="cp t u hc ak" frameborder="0" height="720" scrolling="auto" title="Making Games → Collision Detection" width="972" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137681307&amp;url=https%3A%2F%2Fvimeo.com%2F137681307&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532694589_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<p>
	إليك ما سنعمل عليه في هذه المرحلة: *إنشاء أول صنف (class) غير متعلقة باللاعب.
</p>

<ul>
<li>
		الكشف عن التصادمات المتعلقة بالدائرة.
	</li>
	<li>
		الكشف عن التصادمات المتعلقة بالمستطيل.
	</li>
</ul>
<h2>
	إنشاء صناديق
</h2>

<p>
	اللاعب هو كائنٌ من العديد من الكائنات التي سوف تتواجد على الشاشة في آنٍ واحدٍ. ولعبتنا هذه هي لعبة منصة، لذلك يمكننا أن نتوقع منصة واحدة على الأقل على الشاشة.
</p>

<p>
	لدى المنصات بعض الخصائص المثيرة للاهتمام. فهي تسمح في بعض الأحيان للاعبين بالسقوط من خلالها كما هو الحال عندما تكون واقفًا على منصة وترجع للخلف وتقفز في الوقت ذاته. تأخذ بعض الألعاب هذه السلسلة على أنك تريد السقوط من خلال المنصّة.
</p>

<p>
	تسمح بعض الألعاب للاعبين بالقفز في أسفل المنصات. وهذا يتيح الحركة العمودية دون وجود ثغرات في المنصات العلوية.
</p>

<p>
	وفي بعض الأحيان، تكون المنصات متحرّكة!
</p>

<p>
	تعتبر المنصّات فريدةً جدًا إلى حدّ أننا سنقضي بضعة أقسام في تنفيذ سلوكياتها المختلفة فقط. سوف نركز الآن على كائن مشترك آخر هو الصندوق الشامل (generic box).
</p>

<p>
	فكّر في هذا الصّندوق كمولّد للمنصّة. قد يشترك في بعض وظائفه مع المنصّة، ولكن السبب الرئيسي لوجوده هو الأشياء التي تتصادم معها وبالخصوص الكائنات مثل اللاعب.
</p>

<p>
	قد لا تبدو الصناديق التي سنُنشئها مثل الصناديق الحقيقية. عندما نصل إلى تطبيق الجاذبية، سنحتاج إلى صندوق عريضٍ ورفيعٍ لمنع اللاعب من السقوط خارج محيط اللعبة. وسنحتاج إلى صناديق طويلة ورفيعة لمنع اللاعب من الركض على جوانب أرضية اللعبة. سنصنع منها الجدران. وقد نصنع منها أيضًا صناديق فعلية كبيرة وخشبية تصلح للقفز عليها للوصول إلى أشياء أعلى.
</p>

<p>
	حسنًا، لقد تحدّثت بما يكفي.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2147_6" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Box</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> width</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> height</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

 </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">;</span></pre>

<p>
	لإنشاء هذا الصّنف، نسخت ولصقت فئة "اللّاعب" وحذفت مجموعة من الأشياء. لقد كان عليّ أن أضيف إليها كذلك خاصيتي العرض والارتفاع. سوف نصل إلى ذلك بعد قليلٍ.
</p>

<p>
	بعد ذلك، نحتاج إلى إضافة صندوقين إلى مسرح اللّعبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2147_8" style="">
<span class="kwd">var</span><span class="pln"> player_sprite </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"player.png"</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> player </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">(</span><span class="pln">
    player_sprite</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">200</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> barrel_sprite1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"barrel.png"</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> barrel1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
    barrel_sprite1</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">152</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> barrel_sprite2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"barrel.png"</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> barrel2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Box</span><span class="pun">(</span><span class="pln">
    barrel_sprite2</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">*</span><span class="pln"> </span><span class="lit">3</span><span class="pun">/</span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">248</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pun">,</span><span class="pln">
    </span><span class="lit">64</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">player_sprite</span><span class="pun">);</span><span class="pln">
stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">barrel_sprite1</span><span class="pun">);</span><span class="pln">
stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">barrel_sprite2</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"renderer"</span><span class="pun">:</span><span class="pln"> renderer</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"stage"</span><span class="pun">:</span><span class="pln"> stage</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"keys"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"clicks"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"mouse"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"objects"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        player</span><span class="pun">,</span><span class="pln">
        barrel1</span><span class="pun">,</span><span class="pln">
        barrel2
    </span><span class="pun">]</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	هذا غريب، أليس كذلك! لقد أنشأتُ نسختين جديدتين من الصّندوق، وأطلقت عليهما اسم براميل. ذلك لأننا على وشك أن نلقي نظرة على التصادمات المتعلقة بالدائرة.
</p>

<h2>
	كشف التصادمات المتعلقة بالدائرة
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="33009" href="https://academy.hsoub.com/uploads/monthly_2019_12/Collison_detection.png.95e83241185347569b5d8d680790fc90.png" rel=""><img alt="Collison_detection.png" class="ipsImage ipsImage_thumbnailed" data-fileid="33009" data-unique="d0iakyvj3" src="https://academy.hsoub.com/uploads/monthly_2019_12/Collison_detection.thumb.png.549cf1c7ad4b06c3678b3e8f93f68c47.png"></a>
</p>

<p>
	أريدك أن تنشئ دوائر لهذه الصناديق القليلة الأولى لأننا سندرس أولاً كشف التصادمات المتعلقة بالدوائر رغم أنّ الصندوق يتميّز بالعرض والارتفاع بدلاً من الشّعاع الذي يُميّز الدائرة. ولكن، لن نستخدم هذا النوع من الكشف عن التصادمات في كثير من الأحيان ما لم تكن في منصة اللعبة الكثير من الدوائر.
</p>

<p>
	لنر كيف يعمل هذا النوع من الكشف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2147_10" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">width </span><span class="pun">=</span><span class="pln"> width</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln"> height</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// left</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// right</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

        state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> deltaX </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">-</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">var</span><span class="pln"> deltaY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> distance </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">sqrt</span><span class="pun">(</span><span class="pln">
                deltaX </span><span class="pun">*</span><span class="pln"> deltaX </span><span class="pun">+</span><span class="pln"> deltaY </span><span class="pun">*</span><span class="pln"> deltaY
            </span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">distance </span><span class="pun">&lt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">width </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">width </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">move</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">;</span></pre>

<p>
	أول شيء يتعين علينا القيام به هو تحديد العرض والارتفاع. رغم أننا ندعي أن اللاعبين والصناديق عبارة عن دوائر، فإننا نحتاج فقط إلى نصف العرض كشعاع للدائرة.
</p>

<p>
	بعد ذلك، نتحقق من كل كائن في الطبقة (state). يمكننا تجاهل اللاعب لأننا لسنا بحاجة لمعرفة متى يصطدم شيء ما بنفسه. ولكن سيكون علينا، مع ذلك، أن نتحقق من كلّ الكائنات الأخرى.
</p>

<p>
	تصطدم دائرتان عندما تكون المسافة بين مركزيهما أقلّ من مجموع شعاعيهما معًا. تكون نقطتاهما الأصليتان متقاربتان جدًا بحيث تتداخل خطوطهما.
</p>

<p>
	نفحص سريعًا لمعرفة ما إذا كان الاتجاه الذي يتحرك فيه اللاعب هو حيث يتواجد الصندوق. إذا كان الأمر كذلك، فإننا نمنع اللاعب من التحرك في هذا الاتجاه.
</p>

<p>
	جرّبها، فمن الممتع جدًا أن ترى كيف تعيق الأشكال غير المربّعة بعضها بعضًا. بالطبع يجب أن تكون جميعها دوائر مثالية حتى تعمل هذه الخوارزمية البسيطة.
</p>

<h2>
	كشف التصادمات المتعلّقة بالمستطيل
</h2>

<p>
	يكون كشف التصادمات بالنسبة للمستطيلات سهلاً مثل الدوائر. امضِ قُدُمًا واستبدل صورة البرميل بصورة صندوق. يمكنك حتى ضبط شيفرة bootstrap لتعكس شكلا مربّعًا للصناديق.
</p>

<p>
	هذه المرة، سنتعامل مع اللاعب باعتباره مستطيلًا. بدلاً من استعمال الشّعاع، سنحتاج إلى التحقق مما إذا كانت هناك فراغات بين المستطيل الذي يمثّل اللاعب وأيّ صندوق. نحن نسمي هذا الكشف عن التصادم في المربع المحيط المحاذي للمحور (axis-aligned bounding box) أو AABB للاختصار.
</p>

<p>
	إذا لم يكن هناك فراغ، وكان اللاعب يريد التحرك في اتجاه الصندوق، فإننا نمنع حدوث ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2147_12" style="">
<span class="kwd">var</span><span class="pln"> move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

state</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">((</span><span class="pln">object</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">

   </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&amp;&amp;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">width </span><span class="pun">&gt;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&amp;&amp;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">&lt;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&amp;&amp;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> object</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            move </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">move</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذه بعض الطرق البسيطة للكشف عن التصادمات، ولكن هناك طرق أخرى. هناك طريقة تعتمد على الإسقاط في الرياضيات المتجهية لتحديد التداخل. وهناك طريقة أخرى تفحص كل خطّ في زوجٍ من المضلّعات لمعرفة ما إذا كان هناك تقاطع للخطوط. إنّها طريقة غريبة.
</p>

<p>
	ويمكنك كذلك تجربة مجموعات من الدوائر تتصادم معًا. قد يكون الأمر ممتعًا. سوف أشغّل قليلاً هذه الدائرة الخضراء الصغيرة لتتحرّك نحو هذه الصناديق الحمراء الصغيرة. نلتقي فيما بعد…
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://medium.com/@assertchris/collision-detection-b8bf655cb672" rel="external nofollow">Collision Detection</a> لصاحبه Christopher Pitt
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/game-development/%D8%A7%D9%84%D8%AC%D8%A7%D8%B0%D8%A8%D9%8A%D8%A9-r771/" rel="">الجاذبية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/game-development/%D8%AC%D9%84%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%84%D8%A7%D8%B9%D8%A8-r769/" rel="">جلب المدخلات من اللاعب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">770</guid><pubDate>Thu, 02 Jan 2020 10:17:56 +0000</pubDate></item><item><title>&#x62C;&#x644;&#x628; &#x627;&#x644;&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x645;&#x646; &#x627;&#x644;&#x644;&#x627;&#x639;&#x628;</title><link>https://academy.hsoub.com/programming/game-development/%D8%AC%D9%84%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%84%D8%A7%D8%B9%D8%A8-r769/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc36192d8e_-.jpg.528ea5c0d724c7ef00b84baacf4cefb3.jpg" /></p>

<p>
	ما هو الفرق بين الفيلم واللعبة؟ إنّه يكمن في إمكانية جلب المدخلات من اللاعب! في الواقع، من أهمّ الأشياء في تصميم الألعاب هو أنّه في كثير من الأحيان تُعرّف اللعبة من خلال كيفية استقبالها لمدخلات اللاعب.
</p>

<p>
	تعتمد ألعاب السباق على إدخال ثابت ودقيق. إذا رفعت أصابعك عن لوحة المفاتيح، أو رفعت قدمك عن الدواسة، فستفقد قوة الدّفع. وإذا لم تدخل تجميعة المفاتيح الصحيحة، فسوف تتعطل عملية القيادة.
</p>

<p>
	تحتاج ألعاب المنصّات platform games (مثل اللعبة التي نُنشئها) إلى إدخالٍ من كلتا اليدين. غالبًا ما يكون الجانب الأيمن من لوحة المفاتيح مخصّصًا للحركة. أما الجانب الأيسر من لوحة المفاتيح فيكون غالبًا مخصّصًا لإجراءات اللاعب، مثل إطلاق النار أو فتح الأبواب.
</p>

<p>
	ربما ترغب في تصميم لعبة منصة مثل <a href="https://terraria.org/" rel="external nofollow">Terraria</a>، والتي تستخدم الفأرة لإجراءات اللاعب والتصويب على الهدف. ربما تريد استخدام WASD لتحريك اللاعب على الشاشة. هيا بنا إلى العمل!
</p>

<p>
	إليك ما سنعمل عليه في هذه المرحلة:
</p>

<ul>
<li>
		نقل صنف اللاعب إلى وحدة نمطية
	</li>
	<li>
		الكشف عن الأحداث الخاصّة بلوحة المفاتيح والفأرة
	</li>
	<li>
		التسارع والتباطؤ
	</li>
</ul>
<h2>
	إنشاء الوحدات
</h2>

<p>
	لقد أنشأنا سابقًا صنف اللاعب وجعلناها مسؤولة عن حركة اللاعب. ولكننا تركناها في ملف جافاسكربت الرئيسي، وهذا سيجعل الأمر فوضويًا عندما يزداد عدد الفئات لدينا. لذلك سنُنشئ لها وحدة خاصّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9865_6" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">;</span></pre>

<p>
	يمكن أن تلاحظ أنّ فئة اللاعب مماثلة لتلك التي أنشأناها من قبل. الجزء المهم هنا هو <code>export default Player</code>. هذا يجعل فئة اللاعب قابلة للاستيراد بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9865_8" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> from </span><span class="str">"./player"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> player </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">(</span><span class="pln">
    sprite</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	هذا أسلوب شائع لتقسيم الشيفرة، وغالبًا ما ينقل الفئات الفردية إلى ملفات خاصة بها. إنه يحافظ على بساطة الأشياء، ويُكسِبنا القدرة على إعادة استخدام الشيفرة بدون نسخ ولصق.
</p>

<p>
	لا تنس أن تتحقق من أن الشّكل ما زال يتحرك عبر الشاشة. ومثلما ذكرنا من قبل، يمكنك بدء اختبارٍ للخادم باستعمال <code>php -S 127.0.0.1:8000</code>.
</p>

<h2>
	الكشف عن المدخلات
</h2>

<p>
	عندما حاولت كشف المدخلات لأول مرة، حاولت إضافة مُستمعات الأحداث إلى جميع الكائنات. حاولت إضافة مستمعات للاعب وأخرى للمسرح وهذا أخرج الأمور عن السيطرة.
</p>

<p>
	تكمن الحيلة في كشف الأحداث في المستوى العلوي، وحفظ تفاصيلها في كائن خاصّ بحالة اللعبة (game state object). لقد أنشأنا من قبل هذا النوع من الكائنات الخاصّ بحالة اللعبة، وقمنا بتمريره إلى الدالة الوظيفية <code>animate()‎</code> الخاصّة بتحريك اللاعب. دعنا نتوسع في هذه الحالة:
</p>

<ul>
<li>
		الملف <a href="https://medium.com/@assertchris/player-input-5bc1b0d80f54" rel="external nofollow">main.js</a>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9865_10" style="">
<span class="kwd">var</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"renderer"</span><span class="pun">:</span><span class="pln"> renderer</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"stage"</span><span class="pun">:</span><span class="pln"> stage</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"keys"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"clicks"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
    </span><span class="str">"mouse"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keydown"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">keyCode</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"keyup"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">keyCode</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mousedown"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">which</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"clientX"</span><span class="pun">:</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"clientY"</span><span class="pun">:</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY
    </span><span class="pun">};</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mouseup"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="pln">event</span><span class="pun">.</span><span class="pln">which</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"mousemove"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">mouse</span><span class="pun">.</span><span class="pln">clientX </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">mouse</span><span class="pun">.</span><span class="pln">clientY </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

animate</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> animate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    requestAnimationFrame</span><span class="pun">(</span><span class="pln">animate</span><span class="pun">);</span><span class="pln">

    player</span><span class="pun">.</span><span class="pln">animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">);</span><span class="pln">

    renderer</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">stage</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بدأنا بإضافة المصيّر والحالة إلى كائن حالة اللعبة. لقد أضفنا الآن المفاتيح والنقرات وخصائص الفأرة والتي تتعقب الأزرار والحركات.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		بالنسبة لهذا الجزء التالي، كان عليّ أن أضبط شيفرة CSS الخاصة بالملفّ <code>index.html</code> لتأخذ اللوحة القماشية موضعًا ثابتا. هذا يتيح تتبع حركة الفأرة بدقّة أكثر. تستطيع فحص الشيفرة لرؤية التغيير الحاصل.
	</p>
</blockquote>

<p>
	بينما نضيف المزيد من الكائنات إلى اللعبة، سنمرّر كائن حالة اللعبة إلى كل منها. ويمكنها استخدامه لتعرف ما يجب عليها فعله عندما يتفاعل اللاعب مع اللعبة. دعنا نوقف حركة اللاعب الحالية ونضيف حركةً تعتمد على المُدخلات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9865_12" style="">
<span class="pln">animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// left يسار</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
            </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">–</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// right يمين</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">-</span><span class="pln"> </span><span class="lit">64</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="lit">1</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// left click نقرة يسار</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">clicks</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هناك تغيير فعلي بسيط في الدالّة <code>()animate</code>. نترقب المفتاحين السهميين، ونتحرك إذا ضغط اللاعب على أحدهما. نتحقق أيضًا مما إذا نقر اللاعب على الفأرة، ونحرّك اللاعب على الفور إذا كان الأمر كذلك.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		لا تولي اهتماما للدّوال الرياضية وللرقم السحري 64. فهذه الأشياء موجودة فقط لمنع اللاعب من الخروج من الشاشة، وسنزيلها عندما نبدأ في بناء الجدران …
	</p>
</blockquote>

<h2>
	حركة اللاعب الطبيعية
</h2>

<p>
	يستطيع اللاعب التحرك الآن قليلاً. لكنه لا يحسّ أن الأمور جيدة رغم ذلك. في اللحظة التي نترك فيها مفتاح السهم، فإنه يتوقف وحسب. كما أنّ سرعته تبقى على نسق واحد هو النسق البطيئٍ.
</p>

<p>
	ما نحتاج إليه هو بعض التسارع للسماح للاعب بتسريع حركته في اتجاهٍ ما. يمكننا أيضًا استخدام بعض الاحتكاك لإبطاء اللاعب عندما لا نرغب في التسارع. دعنا نضيف هذه الأمور:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9865_14" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">


        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">


   animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">37</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// left</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">-</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX </span><span class="pun">*</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">[</span><span class="lit">39</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// right</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">accelerationX</span><span class="pun">,</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">maximumVelocityX
            </span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX </span><span class="pun">*=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">frictionX</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">velocityX</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هيّا بنا! دعنا نراجع هذا في بضع خطوات:
</p>

<ol>
<li>
		لقد أنشأنا مجموعة من الخصائص: السرعة والسرعة القصوى والتسارع والاحتكاك. لقد وضعناها على قيمٍ افتراضية معقولة. لا تتردد في تجربة قيمها حتى تتأكد فعلًا أنها كذلك.
	</li>
	<li>
		يمكننا أن نبدأ في تتبع تسارع لاعبنا في أي من الاتجاهين. إذا ضغطنا على المفتاح الأيسر، فسنبدأ بتسريع اللاعب في هذا الاتجاه. هناك تسارع أعظمي يمكن أن يصل إليه اللاعب، لذلك لا يتجاوزه.
	</li>
	<li>
		في غياب نوع من القوة المضادة، سيستمر اللاعب في التحرك في نفس الاتجاه. هذا يشبه ما يحدث في الفضاء حيث لا توجد مقاومة الهواء أو الجاذبية لمواجهة القوّة الدافعة.
	</li>
</ol>
<p>
	نعرّف هذه القوة المضادة على أنها احتكاك، ونضاعف بها السرعة. إذا لم يكن هناك تسارع، فهذا يعني أن القوّة الدافعة تؤول نحو الصفر. إنه يعطي انطباعًا أن اللاعب قد توقف.
</p>

<p>
	<iframe allowfullscreen="" class="cp t u ig ak" frameborder="0" height="720" scrolling="auto" title="Making Games → Player Input" width="972" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137681201&amp;url=https%3A%2F%2Fvimeo.com%2F137681201&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532694452_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://medium.com/@assertchris/player-input-5bc1b0d80f54" rel="external nofollow">Player Input</a> لصاحبه Christopher Pitt
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/game-development/%D9%83%D8%B4%D9%81-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D8%AF%D9%85%D8%A7%D8%AA-r770/" rel="">كشف التصادمات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/game-development/%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-r768/" rel="">حلقة اللعبة التكرارية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">769</guid><pubDate>Thu, 02 Jan 2020 10:18:13 +0000</pubDate></item><item><title>&#x62D;&#x644;&#x642;&#x629; &#x627;&#x644;&#x644;&#x639;&#x628;&#x629; &#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-r768/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc373c61d8_--.jpg.775916c706e42e1b9a9750391c807c00.jpg" /></p>

<p>
	الحلقات التكرارية هي جزء أساسي من كلّ لعبة. سنهيّئ في هذا المقال المسرح للعبتنا من خلال إنشاء مخطّط قويٍّ لسير العمل وبيئة متينة كذلك. سنطّلع على بعض المكتبات المفيدة، كما سننشئ أوّل شخصية لنا في اللعبة. إنه لأمرٌ ممتعٌ!
</p>

<p>
	<iframe allowfullscreen="" class="cp t u hc ak" frameborder="0" height="720" scrolling="auto" title="Making Games → The Game Loop" width="968" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F137681095&amp;url=https%3A%2F%2Fvimeo.com%2F137681095&amp;image=http%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F532694286_960.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=vimeo"></iframe>
</p>

<p>
	إليك ما سنعمل عليه في هذه المرحلة:
</p>

<ul>
<li>
		تهييئ مسرح اللعبة
	</li>
	<li>
		إنشاء وعرض الأشكال
	</li>
	<li>
		فهم وبناء حلقات اللعبة
	</li>
</ul>
<h2>
	تهييئ مسرح اللعبة
</h2>

<p>
	إن هناك الكثير من الأشياء التي ينبغي التفكير فيها عند إنشاء لعبة قائمة على المتصفح. سنتعلم التقنيات التي تعمل مع العديد من المنصات واللغات المختلفة.
</p>

<p>
	سنستخدم أيضًا مُحرّك عرضٍ ثنائي الأبعاد يسمى Pixi.js. إنّه ليس مُحرّك ألعاب أو مُحرّك أجسام مادّية. ربّما لا يزال يتعين علينا أن نعرف أكثر كيف تعمل الأجسام المادّية ومكوّنات اللّعبة، ولكن على الأقل لن نضيع الوقت في تناقضات المتصفح. يمكننا أن نأخذ هذا الخيار عندما لا يكون لدينا ما هو أفضل للقيام به. في الوقت الحالي، سنخلق بيئة للمحرّك Pixi كي يعمل فيها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2916_6" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"browserify main.js -t babelify --outfile main.dist.js"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"watch"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"watchify main.js -t babelify --outfile main.dist.js"</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"dependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"pixi.js"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^3.0"</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"devDependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"babel"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^5.4"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"babelify"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^6.1"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"browserify"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^10.2"</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"watchify"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^3.2"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أريد أن أكون قادرًا على استخدام ميزات ES6. لذلك، سنحوّل شيفرة ES6 إلى شيفرة ES5 احترازًا حتى يشمل الدعم المتصفحات القديمة. الأدوات التي سنستخدمها في ذلك هي <a href="https://babeljs.io" rel="external nofollow">Babel</a> و <a href="http://browserify.org" rel="external nofollow">Browserify</a> و <a href="https://github.com/substack/watchify" rel="external nofollow">Watchify</a>.
</p>

<p>
	سوف يترجم Babel شيفرة ES6 إلى شيفرة ES5. أمّا Browserify فسيربط جميع وحدات ES6 الخاصة بنا أي ملفّاتنا جافاسكربت فيما بينها، وذلك باستخدام صيغة الاستيراد (import) في حين سيعمل Watchify على تفعيل كلّ من Babel وBrowserify عندما تتغير ملفاتنا.
</p>

<p>
	سنستعمل أيضًا الإصدار 3.0 من Pixi كما سنستعمل سكريبتين NPM سيكونان مجرّد اختصار للأوامر التي قد نُدخلها في الطّرفيّة. وهكذا، بدلاً من كتابة <code>browserify ... main.dist.js</code> نكتب فقط <code>npm run build</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2916_17" style="">
<span class="dec">&lt;!doctype html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
    </span><span class="tag">&lt;head&gt;</span><span class="pln">
        </span><span class="tag">&lt;style&gt;</span><span class="pln">
            html</span><span class="pun">,</span><span class="pln"> body </span><span class="pun">{</span><span class="pln">
                margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
                cursor</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">;</span><span class="pln">
                background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#000;</span><span class="pln">
                overflow</span><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="tag">&lt;/style&gt;</span><span class="pln">
    </span><span class="tag">&lt;/head&gt;</span><span class="pln">
    </span><span class="tag">&lt;body&gt;</span><span class="pln">
        </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"node_modules/pixi.js/bin/pixi.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
        </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"main.dist.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	قد تتساءل هل سنحتاج إلى تضمين كلّ ملفّ جافاسكربت أنشأناه. كلّا، لأن Browserify يربط جميع ملفات جافاسكربت التي تُستورَد إلى main.js فيما بينها ثم يُحوّلها بواسطة Babel، مما يؤدي إلى ملفٍّ واحدٍ. سنحتاج فقط لاستيراد هذا الملف.
</p>

<p>
	ورّبما تتساءل أيضًا عن العناصر التي سنعرضها في لعبتنا. ستندمج الشيفرة التي نكتبها لعرض لعبتنا تلقائيًا في نص الملفّ.
</p>

<p>
	يمكنك عرض هذه الملفات بالانتقال إلى مجلّدها في الطّرفية، وتنفيذ الأمر التالي: <code>php -S 127.0.0.1:8000</code>. يشغّل هذا الأمر خادمَ اختبارٍ PHP في عنوان URL يمكنك وضعه في متصفحك. ستحتاج إلى ذلك قبل أن تتمكن من تحميل صور الأشكال، لذا جرِّب ذلك الآن.
</p>

<h2>
	إنشاء الأشكال
</h2>

<p>
	الأشكال اسمٌ شائعٌ للكائنات المرئية في اللعبة. نستطيع تحريكها على شاشة اللعبة رغم أنها غالباً ما تكون مسؤولة عن تحريك نفسها، كما نستطيع التفاعل معها كذلك.
</p>

<p>
	ماريو هو أحد هذه الأشكال، والمنصّات التي يمشي عليها أشكالٌ أيضًا، كما أنّ الغيوم في الخلفية أشكالٌ كذلك. فكِّر في الأشكال بعدِّها شرائحَ من ملفّ التصميم الذي نرسمه بناءً على هياكل البيانات المجردة. وتمتلك هياكل البيانات المجردة هذه موقعًا في الشّاشة، وأحيانًا تكون لديها سرعةٌ، كما أنّها هي التي نُطبِّق عليها قواعد اللعبة. إنها تمثل مصادر قوّتنا وأعداءَنا.
</p>

<p>
	إذن كيف نُنشِئها؟ لنبدأ بإنشاء صورة PNG صغيرة. نستخدم صيغة PNG لأنها تسمح لنا بجعل أجزاء من نسيج الشّكل شفافةً. يمكنك استخدام صور JPEG لأشكالك إذا كنت ترغب بذلك.
</p>

<p>
	بعد ذلك، نحتاج إلى إنشاء أداةِ عرضٍ ومسرحٍ وشكلٍ من الأشكال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2916_19" style="">
<span class="kwd">var</span><span class="pln"> renderer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="pln">autoDetectRenderer</span><span class="pun">(</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">,</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"antialias"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"autoResize"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"transparent"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"resolution"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">renderer</span><span class="pun">.</span><span class="pln">view</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> sprite </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="str">"player.png"</span><span class="pun">);</span><span class="pln">
sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> stage </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Container</span><span class="pun">();</span><span class="pln">
stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">);</span><span class="pln">

animate</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> animate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    requestAnimationFrame</span><span class="pun">(</span><span class="pln">animate</span><span class="pun">);</span><span class="pln">

    renderer</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">stage</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	حسنًا، تحدث أمور كثيرة هنا، دعنا نلقي نظرة على هذه الشيفرة على مراحل:
</p>

<p>
	1- نُنشِئ المصيّر، وهو أداة تُحوّل العناصر المجرّدة في Pixi (أي الأشكال والأنسجة وغيرها) إلى رسومات قماشية أو رسومات WebGL وتعرضها. ليس علينا أن نتفاعل معها، ولكن يجب أن يكون لدينا دائمًا عارضٌ لعرض عناصر Pixi الخاصة بنا.
</p>

<p>
	نطلب من العارض أن يغطّي نافذةَ المتصفح كاملة بالطول والعرض. إننا نطلب ذلك من أجل تنقية وضوح الرسومات باستعمال مضادات التعرج (Anti Aliasing) ورفعها إلى دقة شبكية العين. نطلب ذلك أيضا للحصول على خلفية شفافة وتغيير حجم جميع الرسومات لتلائم الشاشة.
</p>

<p>
	2- بعدها، نُنشِئ نسخة جديدة للفئة PIXI.Sprite، باستخدام الصورة PNG التي أنشأناها سابقًا. بشكل افتراضي، تكون النسخة في الموضع x = 0 و y = 0. ويمكننا وضعها في وسط الشاشة بدلًا من ذلك.
</p>

<p>
	يتعين علينا إنشاء حاوية جذرية للأشكال والتي تسمى غالبًا مسرحًا، ثم إلحاق الشّكل بالمسرح. إنّ الأمر أقل تعقيدًا مما قد يبدو عليه. فكِّر في الأمر مثل صفحات HTML. يكون لدى الصفحة دائمًا عنصرٌ جذريٌّ HTML يحتوي جميع العناصر الأخرى التي نضيف إليه. إنّه نفس الشيء هنا.
</p>

<p>
	3- أخيرًا، ننشئ دالّةً للتحريك ونحرص على أن يعرض العارض المسرح والشّكل معًا.
</p>

<p>
	نستخدم الدالّة <code>requestAnimationFrame()‎</code> كطريقة للعرض دون إعاقة سلسلة جافاسكربت. إنّ هناك نقاشًا طويلًا يمكن أن نخوضه حول هذا الموضوع. في الوقت الحالي، من المهم فقط أن تعرف أن الدالّة <code>requestAnimationFrame()‎</code> تُنفّذ عدة مرات في الثانية.
</p>

<p>
	ويتجلى الهدف بالنسبة للعبتنا هنا في عرض ما بين 30 و 60 إطارًا في الثانية، مع القيام بكل أنواع الحسابات في الخلفية. هذه هي الدّالّة التي نحتاج إلى استخدامها حتى يسير كل شيء بسلاسة.
</p>

<h2>
	حلقات اللعبة
</h2>

<p>
	سوف تتحكم حلقة اللعبة في تدفق لعبتنا. إنها عملية متكررة لقراءة المُدخلات، وحساب التغييرات في الحال وتقديم المُخرجات إلى الشاشة.
</p>

<p>
	كلّ ما قُمنا به حتى الآن هو عرض صورة ثابتة أي إعداد السقالة فحسب. دعنا نتحرك قليلا! بادئ ذي بدء، سنُنشِئ فئة لاعبٍ، حتى نتمكن من تتبع موضع اللاعب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2916_21" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Player</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite </span><span class="pun">=</span><span class="pln"> sprite</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">&gt;</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">sprite</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذا ما تبدو عليه أصناف جافاسكريبت في ES6. تمتلك فئة المشغل مُنشئًا (constructor) نستخدمه لتخزين مرجعٍ يحيل على الشَّكل ويخزّن كذلك إحداثيتي x و y البدئيتين، كما أنّها تمتلك كذلك دالّةً وظيفية <code>animate()‎</code> سنستدعيها عدة مرات في الثانية. يمكننا استخدام الدّالة لمعرفة ما إذا كان اللاعب يحتاج إلى تغيير موضعه أو القيام بشيء آخر. في هذه الحالة، نُحرّك موضع x للشّكل قليلاً. إذا تحرك اللاعب/الشّكل من الجانب الأيمن من الشاشة، فإننا نعيده إلى الجانب الأيسر منها.
</p>

<p>
	ينبغي علينا أيضًا أن نغيّر كيفية إنشاء الشّكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2916_23" style="">
<span class="kwd">var</span><span class="pln"> sprite </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> PIXI</span><span class="pun">.</span><span class="typ">Sprite</span><span class="pun">.</span><span class="pln">fromImage</span><span class="pun">(</span><span class="str">"player.png"</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> player </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Player</span><span class="pun">(</span><span class="pln">
    sprite</span><span class="pun">,</span><span class="pln"> 
    window</span><span class="pun">.</span><span class="pln">innerWidth </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> 
    window</span><span class="pun">.</span><span class="pln">innerHeight </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

stage</span><span class="pun">.</span><span class="pln">addChild</span><span class="pun">(</span><span class="pln">sprite</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"renderer"</span><span class="pun">:</span><span class="pln"> renderer</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"stage"</span><span class="pun">:</span><span class="pln"> stage
</span><span class="pun">};</span><span class="pln">

animate</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> animate</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    requestAnimationFrame</span><span class="pun">(</span><span class="pln">animate</span><span class="pun">);</span><span class="pln">

    player</span><span class="pun">.</span><span class="pln">animate</span><span class="pun">(</span><span class="pln">state</span><span class="pun">);</span><span class="pln">

    renderer</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">stage</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن، بدأنا نشاهد مفعول الحلقة في لعبتنا إذ نطلب من لاعبنا تحريك الشّكل عدة مرات في الثانية. يأخذ اللاعب في الاعتبار بعض منطقه الخاصّ، ويُعدّل الشّكل الخاصّ به كما يريد. يعرض العارض النتيجة في المُخرجات، وما نراه هو رسوم متحركة سلسة.
</p>

<p>
	الشيء الوحيد الذي ينقصنا لحدّ الآن هو الإدخال، لكننا سنصل إلى هذه المرحلة قريبًا!
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://medium.com/@assertchris/the-game-loop-86e1b64cb45d" rel="external nofollow">The Game Loop</a> لصاحبه Christopher Pitt
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/game-development/%D8%AC%D9%84%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%84%D8%A7%D8%B9%D8%A8-r769/" rel="">جلب المدخلات من اللاعب</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/" rel="">مدخل إلى صناعة ألعاب المتصفح</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">768</guid><pubDate>Thu, 02 Jan 2020 10:18:49 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x635;&#x646;&#x627;&#x639;&#x629; &#x623;&#x644;&#x639;&#x627;&#x628; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D;</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%86%D8%A7%D8%B9%D8%A9-%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-r767/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_01/5e0dc3a146b71_----.jpg.79e0aa1ac5e145cda5c25a3cc458629f.jpg" /></p>
<p>
	شهد قطاع صناعة الألعاب في الأونة الأخيرة تطورًا كبيرًا وفي كلّ عام يزداد الإقبال عليها أكثر مما قبل؛ فصُمّمت الألعاب الإلكترونية في عام 1960، إذ كانت تحتاج لحواسيب ضخمة لم تكُ متاحة للعموم آنذاك. وبعد ذلك بعشر سنوات تطورت الألعاب لتصبح تجارية في عام 1970، وذلك مع مجيء أول أجهزة الألعاب الإلكترونية والحواسيب المنزلية. ونظرًا إلى القدرات المنخفضة للحواسيب آنذاك كان بإمكان مطوّر واحد أن يُنتج لعبة بكاملها.
</p>

<p>
	ولكن عند مطلع القرن 21 ومع تزايد قدرات الحواسيب على معالجة البيانات، وتصاعد توقعات المستهلك أصبح من المستحيل أن ينتج مطور واحد لعبة تناسب هذا العصر بل ستحتاج إلى فريق عمل متكامل من منتجين ومصممين ومبرمجين ومهندسي صوت ومؤلفين موسيقيين ومصممي المراحل والعديد من الإختصاصات الأخرى لإنتاج لعبة تناسب هذا العصر.
</p>

<p>
	يوجد في وقتنا الحالي العديد من منصات الألعاب، مثل أجهزة البلايستيشن (PlayStation) أو أجهزة الإكس بوكس (Xbox) إذ أن لكل منصة منصة ألعاب صُممت لتُعلب عليها فقط، والبعض الأخر من الألعاب مخصصة لأجهزة الحواسيب (مثل الويندوز أو الماك أو اللينكس)، أو بعض الألعاب الأخرى المخصصة لمتصفح الوِب (تدعى ألعاب المتصفح [Browser Game]) والّتي سنناقشها اليوم ونعلمك كيفية إنشاء لعبة بسيطة تعمل على المتصفح.
</p>

<h2>
	ألعاب المتصفح (Browser Game)
</h2>

<p>
	عادةً ما تُعرف ألعاب المتصفح بألعاب الوِب، وهي نمط من الألعاب الّتي تُلعب باستخدام متصفح الإنترنت (مثل غوغل كروم أو أوبرا أو أي متصفح أخر) وذلك من خلال طلب عنوان موقع اللعبة، وبعد تحميل الموقع تظهر لدينا اللعبة ويمكننا بعدها البدء باللعب.
</p>

<p>
	غالبًا ما تُصمم هذه الألعاب باستخدام تقنيات الوِب القياسية (مثل: HTML5، و CSS3، و JavaScript وغيرها) أو بتقنيات أخرى مثل <a href="https://ar.wikipedia.org/wiki/%D8%A3%D8%AF%D9%88%D8%A8%D9%8A_%D9%81%D9%84%D8%A7%D8%B4" rel="external nofollow">أدوبي فلاش</a> ولكن جميع هذه التقنيات لديها إمكانيات محدودة؛ وذلك بسبب مسائل التكاملية والجودة مع المتصفح، ولكن مع ذلك فإن هذه التقنيات هي الّتي تجعل هذه الألعاب تعمل على جميع المتصفحات.
</p>

<p>
	واجهت ألعاب المتصفح منذ بدايتها العديد من التحديات، بعضها من ناحية الرسوميات، وبعضها الأخر من ناحية الأداء والسرعة، وبعضها من ناحية الضغط على المخدمات الّتي تستضيف هذه الألعاب (وذلك بسبب كثرة العناصر المحملة من ملفاتٍ وصورٍ والعديد من المكونات الأخرى الموجودة في اللعبة). ولكن ما لبثت هذه التحديات بالظهور حتى أُوجدت لها حلولٌ عديدة فعّالة، ولكن مع ذلك فإنها لم تستطع أن تنافس الألعاب التقليدية وخصوصًا مع الفارق الكبير بين طريقة تعامل كلّ منهم مع موارد الحاسوب.
</p>

<p>
	حجزت ألعاب المتصفح لنفسها مكانًا في الألعاب التنافسية متعددة اللاعبين (مثل <a href="https://www.chess.com" rel="external nofollow">لعبة الشطرنج</a> و<a href="https://www.gamedesire.com/ar/game/pool-8" rel="external nofollow">لعبة البلياردو</a> وعلى غرارها من الألعاب)، وهي عادةً ما تركز على الجانب الإجتماعي من اللعبة أكثر من اللعبة بحد ذاتها، إذ تمنح إمكانية الدردشة بين اللاعبين أثناء اللعب، وإمكانية إنشاء ملفاتهم الشخصية (User Profile)، وبالإضافة إلى نظام تنافسي مبني على النقاط والكؤوس مما يعزز روح المنافسة ويضيف متعةً أخرى للعبة.
</p>

<h2>
	نشأة وتاريخ صناعة ألعاب المتصفح وتطورها
</h2>

<p>
	ظهرت ألعاب متصفح الوِب في بداية التسعينات من القرن الماضي ولكن لم تبدأ بالانتشار إلا في عام 1996 تزامنًا مع ظهور برنامج Macromedia Flash (المستخدم لتعديل الرسوميات) ولغة البرمجة أكشن سكربت (<a href="https://en.wikipedia.org/wiki/ActionScript" rel="external nofollow">Action Script</a>) وسرعان ما شكّلا مع بعضهما أول أدوات صناعة ألعاب المتصفح آنذاك.
</p>

<p>
	وبعد عام واحد أطلقت شركة <a href="https://en.wikipedia.org/wiki/Sun_Microsystems" rel="external nofollow">Sun Microsystems</a> موقعها الخاص هوت جافا (<a href="https://en.wikipedia.org/wiki/HotJava" rel="external nofollow">HotJava</a>) لاستضافة الشيفرات البرمجية المحمولة للغة جافا (Java applet) وتعمل هذه الألعاب على جميع المتصفحات الّتي تدعم لغة جافا، والّذي كان شرارة البدء لعصر ألعاب المتصفح.
</p>

<p>
	وبعد النجاح الكبير لألعاب المتصفح والّذي لوحظ من خلال الازدياد الكبير لعدد الأشخاص المنضمين لمواقع ألعاب المتصفح والإقبال الشديد عليها، مما أدى لاهتمام بعض الشركات الكبرى لهذا النمط من الألعاب من بينها شركة ياهو والّتي انضمت إلى هذا المجال لتطلق موقعها <a href="https://en.wikipedia.org/wiki/Yahoo!_Games" rel="external nofollow">Yahoo! Games</a> في عام 1998، والّذي يحتوي على العديد من الألعاب ولتصبح بذلك من أوائل شركات صناعة ألعاب المتصفح آنذاك. وفي عام 2016 أعلنت الشركة عن إغلاق الموقع بسبب عدم تمكن الفرق البرمجية لشركة ياهو من حل المشاكل المتزايد للتقنيات المستخدمة في بناء الألعاب وعدم تلبية هذه الألعاب لمتطلبات الوِب الحديثة كلّ هذه العوامل أدت إلى إغلاق موقع في شهر فبراير من عام 2016.
</p>

<h2>
	الفرق بين ألعاب المتصفح والألعاب التقليدية
</h2>

<p>
	تختلف ألعاب المتصفح عن الألعاب التقليدية بعدة نواحي أهمها:
</p>

<h3>
	1. طريقة اللعب
</h3>

<p>
	إن ألعاب المتصفح تتطلب الاتصال الدائم بالإنترنت طوال زمن اللعب لأنه من دون الاتصال بالإنترنت لا يمكن تشغيل الألعاب وذلك لأنها مخزنة على مخدمات موجودة عبر الإنترنت وليس في الحاسوب الشخصي. على عكس الألعاب التقليدية إذ أن أغلبها لا يتطلب اتصالًا دائمًا بالإنترنت.
</p>

<p>
	وعلى صعيد أخر في <a href="https://www.ncbi.nlm.nih.gov/pubmed/19260776" rel="external nofollow">دراسة</a> أجراها باحثون من جامعة ماينتس الألمانية على 8203 شخص من لاعبي لعبة المتصفح الشهيرة ترافيان (<a href="https://www.travian.com" rel="external nofollow">Travian</a>) تبين لهم أن ألعاب المتصفح يُستمتع بها أساسًا بسبب الجانب الاجتماعي منها الّذي ينطوي عليه خصائص الوقت، والمرونة العالية في العب، وسهولة الاستخدام، والتنافس بين اللاعبين، وكما أشارت الدراسة نفسها أن سهولة الوصول إلى هذا النوع من الألعاب (لعبة ترافيان-وبشكل عام جميع ألعاب المتصفح) أدت إلى زيادة عدد مرات فتح اللعبة بالموازنة مع الألعاب التقليدية، ولكن مدة جلسات اللعب المتواصلة قصيرة.
</p>

<h3>
	2. مصادر الدخل للألعاب
</h3>

<p>
	يختلف اعتماد ألعاب المتصفح على مصادر الدخل فمنها من يعتمد على عرض إعلانات داخل اللعبة (مثل إعلانات غوغل أدسنس وغيرها)، أو إلى عرض عمليات الشراء داخل اللعبة للحصول على مميزات أو نقاطٍ تتفوق بها على المنافسين، ومنها من تعتمد على الاشتراك الشهري أو السنوي، والبعض الأخر يعتمد على شراء اللعبة لمرة واحدة فقط. وفي بعض الحالات النادرة تكون الألعاب مجانية بالكامل.
</p>

<p>
	وفي المقابل فإن غالبية الألعاب التقليدية تعتمد على شراء اللعبة لمرة واحدة بالإضافة لعمليات الشراء داخل اللعبة في حال كانت تُلعب على الإنترنت.
</p>

<h3>
	3. استخدام موارد الحاسوب
</h3>

<p>
	تعدّ ألعاب المتصفح ذات رسوميات منخفضة بالموازنة مع الألعاب التقليدية وذلك من كونها تتعامل مع إمكانيات المتصفح والموارد الّتي يستخدمها، على عكس الألعاب التقليدية الّتي تتعامل مع موارد الجهاز تعاملًا مباشرًا ولكن على صعيد أخر تستهدف ألعاب المتصفح شريحة كبيرة من المستخدمين وعلى كافة الأجهزة وخصوصًا أصحاب الأجهزة الضعيفة والمتوسطة.
</p>

<p>
	وعلى صعيدٍ آخر إن غالبية الألعاب التقليدية تحجز مساحة كبيرة من سعة القرص الصلب على عكس ألعاب المتصفح، كما تستهلك الألعاب التقليدية قدرًا كبيرًا من ذاكرة الوصول العشوائي (RAM) بالموازنة مع ألعاب المتصفح مما يجعل ألعاب المتصفح خفيفة جدًا على موارد الحاسوب مهما كانت مواصفاته.
</p>

<h2>
	مشاكل وحلول
</h2>

<p>
	وكما ذكرنا سابقًا عانت ألعاب المتصفح العديد من المشاكل فما أن تُحلّ مشكلة حتى تظهر أخرى. وإن من أبرز المشاكل الّتي واجهتها هي:
</p>

<h3>
	معالجة الرسوميات
</h3>

<p>
	إن تصاعد توقعات المستهلكين أثقلت كاهل المطورين من ناحية رفع جودة الألعاب وتعزيز تجربة المستخدم، وفي ظل الإمكانيات المحدودة لألعاب المتصفح والّتي جعلت من عملية مواكبة تطور الألعاب عمليةً شاقةً جدًا. ومن أكثر المشاكل الّتي تواجه مطوري ألعاب المتصفح هي معالجة الرسوميات ذات الأبعاد الثنائية أو الثلاثية والّتي شكلت لفترة طويلة سدًا منيعًا في تطور هذا النمط من الألعاب.
</p>

<p>
	كان ذلك إلى أن جاءت تقنية WebGL والّتي سمحت لنا بكتابة رسوميات ثلاثية الأبعاد في صفحات الوِب باستخدام جافا سكربت (JavaScript) عبر العنصر <a href="https://wiki.hsoub.com/HTML/canvas" rel="external">canvas</a> (وكما تحدثنا في عدة <a href="https://academy.hsoub.com/tags/webgl/" rel="">مقالات</a> عن هذه التقنية وأهميتها). ولكن تقنية WebGL لا تُنشِئ «عناصر» على الصفحة، إذ تتعامل مباشرةً مع البكسلات؛ ولذا نقول عن تقنية WebGL أنّها تقنيةٌ منخفضة المستوى: إذ أنّها توفِّر تحكمًا دقيقًا بالفضاء ثلاثي الأبعاد.
</p>

<p>
	والجدير بالذكر أن هذه التقنية، WebGL، مبنية على الواجهة البرمجية OpenGL ES والّتي هي نسخة فرعية من OpenGL. <strong>ولكن ماهي OpenGL؟</strong> (Open Graphics Library) هي عبارة عن واجهة برمجية رسومية مستقلة تعمل على مختلف أنظمة التشغيل، ومتوافقة مع عدة لغات برمجية، وصُممت لإنتاج رسوميات ثنائية وثلاثية البعد سواءً المعقدة منها أو البسيطة من خلال تركيبها من مكونات هندسية بسيطة مثل المضلعات أو المثلثات أو المستقيمات …إلخ، وكما أنها تشكّل همزة الوصل بين وحدة المعالجة المركزية CPU ووحدة معالجة الرسوميات GPU.
</p>

<p>
	أما <strong>OpenGL ES</strong> (والتي تعرف اختصارًا للعبارة Open Graphics Library for Embedded Systems) فهي نسخة فرعية من OpenGL الرئيسية، ومبنية خصوصًا للأنظمة المدمجة مثل: الأجهزة الذكية وأجهزة التابلت …إلخ. وهي الّتي بنيت عليها تقنية WebGL.
</p>

<p>
	ومع أن WebGL مبنية على OpenGL ولكن يوجد فرق بين إمكانيات كلٍّ منهما وهذه بعض النقاط الّتي تختلف فيها WebGL عن OpenGL.
</p>

<p>
	تملك WebGL المميزات التالية:
</p>

<ul>
	<li>
		مبنية بلغة جافا سكربت.
	</li>
	<li>
		تُستخدم خصيصًا لمعالجة رسوميات المتصفح.
	</li>
	<li>
		إمكانياتها قليلة بالموازنة مع OpenGL لأنها مبينة على نسخة فرعية من OpenGL وهي OpenGL ES.
	</li>
	<li>
		سهلة التعلم والاستخدام.
	</li>
</ul>

<p>
	أما OpenGL فلديها المميزات التالية:
</p>

<ul>
	<li>
		مبنية بلغة C.
	</li>
	<li>
		تُستخدم خصيصًا لمعالجة رسوميات <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8/" rel="">تطبيقات سطح المكتب</a> والألعاب.
	</li>
	<li>
		إمكانياتها كثيرة نظرًا لأنها تتخاطب مع العتاد تخاطبًا مباشرًا.
	</li>
	<li>
		صعبة التعلم والاستخدام.
	</li>
</ul>

<p>
	وبناءً على ذلك تعدّ WebGL خيارًا جيدًا لمعالجة الرسوميات في المتصفح وتصييرها.
</p>

<h3>
	الضغط على الخادم
</h3>

<p>
	تعدّ مشكلة الضغط على المخدم وتوقفه عن العمل من أبرز المشاكل المطروحة، إذ أن بنية ألعاب المتصفح المؤلفة من ملفاتٍ (HTML أو CSS أو JavaScript أو أي ملفات أخرى) وصورٍ والمقاطع الصوتية وفي بعض الأحيان مقاطع فيديو تجعل من استقرار المخدم المضيف وبقائه بالخدمة مهمةً صعبةً للغاية بل شبه مستحيلة، وخصوصًا في حال استقبال الموقع عددًا كبيرًا من الزوار في آنٍ واحد.
</p>

<p>
	ولقد ظهر في الأونة الأخير حلٌ عملي ومناسب جدًا لهذه المشكلة وهو استخدام الاستضافة السحابية. ولكن ما هي الاستضافة السحابية؟ هي خدمة استضافة تُمكّن العملاء من الاستفادة من خدماتها بقدر ما يحتاجون إليه، اعتمادًا على مطالب مواقعهم على الإنترنت، وأنهم سيدفعون فقط مقابل ما يستخدمونه. وتعتمد الاستضافة السحابية على مفهوم موازنة الحمل (Load Balancing) والّذي يوزع الأحمال (الزوار) على أكثر من خادوم لتحقيق أكبر سرعة استجابة لموقع الوِب.
</p>

<p>
	ومن أبرز المميزات الّتي تقدمها الاستضافة السحابية هي:
</p>

<ol>
	<li>
		الوثوقية: بدلًا من استضافة الموقع على خادم واحد مادي يستضاف الموقع على قسم افتراضي إذ يستمد موارده من شبكةٍ واسعةٍ من الخوادم المادية. أي أنه في حال توقف أحد الخوادم لن يؤثر ذلك على توافر الموقع وسوف يستمر بسحب الموارد من شبكة الخوادم المتبقية.
	</li>
	<li>
		المرونة: تبقى موارد الموقع متاحة حتى في حال ارتفاع حركة الزوار أو ازدياد الطلبات على الموقع، أو طلب موارد إضافية تبقى إمكانية الوصول للموارد سلسة.
	</li>
	<li>
		الدفع على قدر الاستخدام: يدفع العميل فقط على قدر ما يستخدم، أي ليس هنالك أي هدر في حال كان الطلب أقل من المعتاد.
	</li>
</ol>

<h2>
	صناعة ألعاب المتصفح
</h2>

<p>
	تستخدم العديد من اللغات البرمجية لتصميم ألعاب المتصفح ولكل لغة خواص معينة تميزها عن الأخرى. فعلى سبيل المثال يمكنك بناء لعبة على محرك Unity وذلك باستخدام برنامج Unity3D باستخدام لغة #C أو لغة ++C. والّذي يمكنك بناء ألعاب متميزة نظرًا لإمكانياته القوية والكبيرة (ولقد تناولنا في <a href="https://academy.hsoub.com/programming/game-development/unity3d/" rel="">سلسلة</a> سابقة عن أبرز مميزات هذا البرنامج ننصحك بالاطلاع عليها).
</p>

<p>
	وكما يمكنك استخدام تقنيات الوِب القياسية مثل HTML5/CSS أو PHP أو حتى لغة جافاسكربت (JavaScript)، والّتي تعدّ من الخيارات الجيدة لبناء هذه النوع من الألعاب نظرًا من كونها تتيح إمكانية عالية لتفاعل المستخدم مع الموقع (في حالتنا اللعبة). وكما لديها العديد من أُطر العمل المتاحة وشعبية كبيرة تجعلها من أبرز اللغات لتطور ألعاب المتصفح.
</p>

<p>
	وبعد أن تعرفنا عن ماهية ألعاب المتصفح، وتجولنا في تاريخها ونشأتها، وبيّنا أهم الفروقات بينها وبين الألعاب التقليدية، وناقشنا أهم المشاكل الّتي تتعرض لها والحلول المناسبة، ما رأيك بأن نُكّمل هذا المشوار ونبدأ ببناء أول لعبة لنا؟ بكل تأكيد أنت متحمس لخوض هذه المغامرة ومعرفة تفاصيلها إذًا اِربط الأحزمة واستعد للانطلاق.
</p>

<p>
	سنستخدم لغة جافاسكربت لإنشاء هذه اللعبة. وذلك لإنّها تتطلّب مجهودًا قليلًا بالموازنة مع بقية الخيارات المتاحة وتعمل في كلّ البيئات. سوف ننطلق من لا شيء وننشئ لعبةً ممتعة دون أن نستغرق أي وقت يُذكر.
</p>

<p>
	تتألف هذه السلسلة حول صناعة لعبة عبر جافاسكربت من خمس مقالات هي:
</p>

<ol>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-r768/" rel="">حلقات اللعبة التكرارية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%AC%D9%84%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D9%84%D8%A7%D8%B9%D8%A8-r769/" rel="">جلب المدخلات من اللاعب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%83%D8%B4%D9%81-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D8%AF%D9%85%D8%A7%D8%AA-r770/" rel="">كشف التصادمات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A7%D9%84%D8%AC%D8%A7%D8%B0%D8%A8%D9%8A%D8%A9-r771/" rel="">الجاذبية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%84%D9%85-%D9%88%D8%AE%D8%AA%D8%A7%D9%85-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-r772/" rel="">إنشاء السلالم وختام اللعبة</a>
	</li>
</ol>

<p>
	نرجو لك قراءة ممتعة!
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/game-development/%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-r768/" rel="">حلقات اللعبة التكرارية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/game-development/%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%84%D8%B9%D8%A7%D8%A8-game-engines/" rel="">تعرف على أشهر محركات الألعاب Game Engines</a><br>
		 
	</li>
</ul>
]]></description><guid isPermaLink="false">767</guid><pubDate>Mon, 30 Dec 2019 13:08:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x634;&#x627;&#x634;&#x629; &#x627;&#x644;&#x644;&#x645;&#x633; &#x641;&#x64A; Unity3D &#x648;&#x627;&#x644;&#x62A;&#x635;&#x62F;&#x64A;&#x631; &#x644;&#x644;&#x647;&#x648;&#x627;&#x62A;&#x641; &#x627;&#x644;&#x630;&#x643;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/game-development/%D9%85%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%B4%D8%A7%D8%B4%D8%A9-%D8%A7%D9%84%D9%84%D9%85%D8%B3-%D9%81%D9%8A-unity3d-%D9%88%D8%A7%D9%84%D8%AA%D8%B5%D8%AF%D9%8A%D8%B1-%D9%84%D9%84%D9%87%D9%88%D8%A7%D8%AA%D9%81-%D8%A7%D9%84%D8%B0%D9%83%D9%8A%D8%A9-r142/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d-6.jpg.4dc5da90a59f4c7cf7c73b4bee6b092e.jpg" /></p>

<p dir="rtl"><strong style="line-height: 22.3999996185303px;">ملاحظة</strong><span style="line-height: 22.3999996185303px;">: يمكن تحميل الملفات المصدرية لكامل هذه السلسلة عبر </span><a rel="external nofollow" style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/tree/master/AngryAnimals%20Game">حساب أكاديمية حسوب على Github</a><span style="line-height: 22.3999996185303px;">، يمكن أيضا تحميل </span><a rel="external nofollow" style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/releases/tag/v0.1.0">ملف APK لتجريب اللعبة على أجهزة Android</a><span style="line-height: 22.3999996185303px;">.</span></p><p dir="rtl" style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d-6.jpg.59da4fbf959c05998571b8f7f6590a68.jpg"><img data-fileid="3720" alt="unity3d-6.thumb.jpg.ec8e70bc26d15e2b4c7b" src="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d-6.thumb.jpg.ec8e70bc26d15e2b4c7bd0d7bc0607a9.jpg"></a></p><h2 dir="rtl">استقبال مدخلات شاشة اللمس</h2><p dir="rtl">استقبال المدخلات من شاشة اللمس تختلف عن استقبال مدخلات الفأرة أو لوحة المفاتيح. فأنت هنا تتعامل مع شاشة تستقبل عدة لمسات، وتتعامل مع أحداث مثل وضع الإصبع وتحريكه ورفعه، أو وضع أصبعين وتقريبهما أو إبعادهما عن بعضهما. كل هذه الأنماط من الإدخال سيكون عليك التعرف عليها وتنفيذ ما يناسبها من أوامر.</p><p dir="rtl">لنبدأ أولا مع مدخلات عناصر واجهة المستخدم مثل الأزرار. ما الذي يجب علينا فعله لاستقبال المدخلات على هذه العناصر؟ لا شيء! فهذا الأمر يقوم به محرك Unity تلقائيا. أي أنك عندما تلمس زرا على الشاشة سيتعرف التطبيق على هذا الأمر كأنك ضغطت على الزر وينفذ الأمر أو الأوامر المرتبطة به.</p><p dir="rtl">لننتقل الآن للمدخلات الخاصة باللعبة. تذكر أننا قمنا بكتابة 3 بريمجات لاستقبال مدخلات الفأرة، وسنحتاج الآن لكتابة 3 مقابلها لاستقبال مدخلات شاشة اللمس. هذه البريمجات الثلاث هي:</p><ul dir="rtl"><li><span style="font-family:courier new,courier,monospace;">CameraMouseInput</span> والذي أضفناه لقوالب عناصر الخلفية والأرضية من أجل تحريك الكاميرا والتحكم بتقريبها وإبعادها.</li><li><span style="font-family:courier new,courier,monospace;">LauncherMouseInput</span> والذي أضفناه على قالب المقلاع بحيث يستقبل مدخلات اللاعب على المقذوفات ويحدد اتجاه التصويب وشدته ويطلق المقذوف حين إفلاته.</li><li><span style="font-family:courier new,courier,monospace;">SpecialAttackMouseInput</span> والذي أضفناه على قوالب المقذوفات من أجل تنفيذ الهجوم الخاص عند الضغط على زر الفأرة بعد الإطلاق.</li></ul><p dir="rtl">الموضوع ببساطة شديدة أننا مقابل كل بريمج إدخال من الفأرة سنكتب بريمج إدخال من شاشة اللمس ونضيفه على نفس القالب. القاسم المشترك بين قوالب استقبال مدخلات اللمس أنها ستقوم بالتحقق من بيئة تشغيل اللعبة، فإذا وجدت أن نظام التشغيل هو Android ستقوم بتدمير بريمجات استقبال مدخلات الفأرة الموجودة معها على نفس الكائن. أهمية هذه الخطوة تكمن في أن Unity يحاول محاكاة وجود فأرة على شاشات اللمس عن طريق تحويل اللمسات إلى مدخلات فأرة. هذا الأمر يؤدي إلى سلوك غير مرغوب لا يفيد في لعبتنا، لذا نتجنبه عن طريق حذف أي بريمج يقرأ من الفأرة.</p><p dir="rtl">لنبدأ مع بريمج التحكم بالكاميرا <span style="font-family:courier new,courier,monospace;">CameraTouchInput</span> والذي سنضيفه على قالبي عنصري الخلفية والأرضية حيث يوجد <span style="font-family:courier new,courier,monospace;">CameraMouseInput</span> أيضا. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class CameraTouchInput : MonoBehaviour
{

     //سرعة تحريك الكاميرا
     public float movementSpeed = 0.0075f;

    //سرعة التقريب والإبعاد
    public float zoomingSpeed = 0.00075f;

    //هي يلمس اللاعب الشاشة حاليا بإصبع واحد؟
    private bool singleTouch = false;

    //هل يلمس اللاعب الشاشة حاليا بأصبعين
    private bool doubleTouch = false;

    //مرجع لبريمج التحكم بالكاميرا
    CameraControl camControl;

    //تستدعى مرة عند بداية التشغيل
    void Start()
    {
        //قم بتدمير بريمج استقبال مدخلات الفأرة إن تم اكتشاف نظام تشغيل الهاتف الذكي
        if (Application.platform == RuntimePlatform.Android)
        {
            CameraMouseInput mouseInput = GetComponent&lt;CameraMouseInput&gt;();
            Destroy(mouseInput);
        }

        camControl = FindObjectOfType&lt;CameraControl&gt;();
    }

    //يتم استدعاؤها مرة عند تصيير كل إطار في وقت متأخر
    void LateUpdate()
    {
        UpdateSingleTouch();
        UpdateDragging();
        UpdateDoubleTouch();
        UpdateZooming();
    }

    //تتأكد من كون اللاعب يلمس الشاشة بإصبع واحد
    void UpdateSingleTouch()
    {
        if (Input.touchCount == 1)
        {
            Touch playerTouch = Input.touches[0];
            if (playerTouch.phase == TouchPhase.Began)
            {
                //قام اللاعب للتو بوضع إصبعه على الشاشة
                //هل تم وضع الإصبع على هذا الكائن تحديدا؟
                Vector2 touchPos = Camera.main.ScreenToWorldPoint(playerTouch.position);

                //اجلب مكوّن التصادم الخاص بهذا الكائن
                Collider2D myCollider = GetComponent&lt;Collider2D&gt;();

                //قم بتوليد شعاع قصير جدا ابتداء من موقع اللمس وباتجاه الأعلى واليمين
                //ومن ثم تحقق من كون هذا الشعاع قد اصطدم بمكوّن التصادم الخاص بهذا الكائن
                RaycastHit2D hit = Physics2D.Raycast(touchPos, Vector2.one, 0.1f);
                if (hit.collider == myCollider)
                {
                    //نعم لقد قام اللاعب بلمس هذا الكائن بإصبع واحد
                    singleTouch = true;
                }
            }
            else if (playerTouch.phase == TouchPhase.Ended ||
              playerTouch.phase == TouchPhase.Canceled)
            {
                //قام اللاعب للتو برفع إصبعه عن الشاشة
                singleTouch = false;
            }
        }
        else
        {
            //عدد الأصابع على الشاشة لا يساوي 1 أي أنه
            //لا يوجد هناك لمسة بإصبع واحد
            singleTouch = false;
        }
    }

    //تقوم بفحص تحريك اللاعب لإصبع واحد على الشاشة
    void UpdateDragging()
    {
        if (singleTouch)
        {
            Touch playerTouch = Input.touches[0];
            camControl.Move(playerTouch.deltaPosition * -movementSpeed);
        }
    }

    //تقوم بفحص قيام اللاعب باللمس بأصبعين
    void UpdateDoubleTouch()
    {
        //تأكد من عدم وجود لمسة بإصبع واحد حاليا
        if (!singleTouch)
        {
            if (Input.touchCount == 2)
            {
                doubleTouch = true;
            }
            else
            {
                doubleTouch = false;
            }
        }
    }

    //تقوم بتحديث التقريب والإبعاد مستخدمة حركة الأصبعين على الشاشة
    void UpdateZooming()
    {
        if (doubleTouch)
        {
            //على الشاشة A, Bمواقع الأصبعين المسميين
            //في كل من الإطار الحالي 2 والإطار السابق 1
            Vector2 posA1, posA2, posB1, posB2;
            Touch a, b;
            a = Input.touches[0];
            b = Input.touches[1];

            posA2 = a.position;
            posB2 = b.position;

            posA1 = a.position - a.deltaPosition;
            posB1 = b.position - b.deltaPosition;

            //تأكد من كون المسافة بين الأصابع قد زادت أو قلت منذ
            //الإطار السابق
            float currentDist = Vector2.Distance(posA2, posB2);
            float prevDist = Vector2.Distance(posA1, posB1);

            //طرح المسافة السابقة من الحالية سيعطينا
            //الإشارة الصحيحة للتقريب أو الإبعاد
            camControl.Zoom((currentDist - prevDist) * zoomingSpeed);
        }
    }
}
</pre><p dir="rtl">آلية عمل هذا البريمج تعتمد على أربعة خطوات رئيسية:</p><ul dir="rtl"><li>التحقق من لمس الشاشة بإصبع واحد.</li><li>ثم التحقق من تحريك الكاميرا باستخدام الإصبع.</li><li>ثم التحقق من لمس الشاشة بأصبعين.</li><li>وأخيرا التأكد من تنفيذ التقريب والإبعاد باستخدام الأصبعين.</li></ul><p dir="rtl">قراءة مدخلات شاشة اللمس تتم كالآتي: أولا نتعرف على عدد اللمسات على الشاشة عن طريق المتغير<span style="font-family:courier new,courier,monospace;"> Input.touchCount</span>، فإذا كان عدد اللمسات يساوي واحدا، فإن هذا يعني أن اللاعب يضع إصبعا على الشاشة واحتمال أن يقوم بتحريك الكاميرا وارد. نستخدم هنا المتغيرين <span style="font-family:courier new,courier,monospace;">singleTouch</span> و <span style="font-family:courier new,courier,monospace;">doubleTouch</span> من أجل تخزين عدد اللمسات التي اكتشفناها. هذه اللمسات تكون مخزنة في المصفوفة <span style="font-family:courier new,courier,monospace;">Input.touches</span> وهي مصفوفة تحتوي على عناصر من نوع Touch. هذا النوع من المتغيرات يحتوي على معلومات عن كل لمسة على الشاشة. أول هذه المعلومات التي سنتعامل معها هي <span style="font-family:courier new,courier,monospace;">Touch.phase</span> والتي تمثل المرحلة التي تمر بها اللمسة. فبمجرد أن يضع اللاعب إصبعه على الشاشة ستكون المرحلة هي <span style="font-family:courier new,courier,monospace;">TouchPhase.Began</span>. اللحظة الأولى للمس الشاشة مهمة جدا، حيث أنها اللحظة التي يجب علينا أن نتحقق من كون اللاعب قد وضع إصبعه على عنصر الخلفية أو الأرضية، وبالتالي نحدد إذا ما كنا سنسمح له بتحريك الكاميرا. فنحن لا نرغب بتحريك الكاميرا إذا كان اللاعب قد وضع إصبعه على المقذوف أو على زر الخروج مثلا.</p><p dir="rtl">التحقق من كون اللاعب قد وضع يده على عنصر الخلفية أو الأرضية يتم عبر الدّالة<span style="font-family:courier new,courier,monospace;"> ()UpdateSingleTouch</span>، حيث علينا أن نقوم أولا بتحويل موقع الإصبع من إحداثيات الشاشة إلى إحداثيات المشهد تماما كما سبق وفعلنا مع مؤشر الفأرة. بعد ذلك نقوم باستخراج مكوّن التصادم الخاص بهذا العنصر ومن ثم نستخدم بث الأشعة Ray Casting. بث الأشعة طريقة يستخدمها محرك الفيزياء من أجل الكشف عن تقاطع خط مستقيم مع كائن ما في المشهد، وسنستخدمها هنا لنرسم خطا قصيرا جدا من موقع اللمس إلى نقطة شديدة القرب منه، ونرى إن كان هذا الخط يتقاطع مع مكوّن التصادم الذي استخرجناه. يتم تنفيذ بث الأشعة عن طريق الدّالة <span style="font-family:courier new,courier,monospace;">()Physics2D.Raycast</span> والتي تأخذ 3 متغيرات: المتغير الأول هو موقع بداية الشعاع، والمتغير الثاني هو الاتجاه الذي سيسير فيه هذا الشعاع، بينما يحدد المتغير الثالث وهو قيمة رقمية أقصى مسافة يمكن أن يقطعها هذا الشعاع. وهنا تلاحظ استخدامنا لمسافة قصيرة جدا، وهي كافية حين يكون موقع البداية موجودا أصلا داخل مكوّن التصادم الذي يتم فحص التصادم معه. القيمة التي ترجعها هذه الدّالة هي من نوع <span style="font-family:courier new,courier,monospace;">RaycastHit2D</span>، وهي تحتوي على متغير لتخزين مكوّن التصادم الذي اصطدم به الشعاع.</p><p dir="rtl">بعد ذلك نفحص إذا ما كان المكوّن الذي اصطدم به الشعاع هو نفسه مكوّن التصادم الذي استخرجناه من العنصر الحالي، وإذا تحقق هذا الأمر فإننا نعتمد هذا اللمسة من قبل اللاعب على الخلفية أو الأرضية ونسمح له بالتالي بتحريك الكاميرا عن طريق تغيير قيمة <span style="font-family:courier new,courier,monospace;">singleTouch </span>إلى <span style="font-family:courier new,courier,monospace;">true</span>. في حالة كانت اللمسة في مرحلة أخرى مثل <span style="font-family:courier new,courier,monospace;">TouchPhase.Ended</span> أو <span style="font-family:courier new,courier,monospace;">TouchPhase.Canceled</span>، فإن هذا يعني أن اللاعب قد رفع إصبعه عن الشاشة، وبالتالي نعيد قيمة <span style="font-family:courier new,courier,monospace;">singleTouch</span> إلى <span style="font-family:courier new,courier,monospace;">false</span>. الأمر نفسه سيحدث في حال اكتشفنا أن عدد الأصابع الموجودة على الشاشة <span style="font-family:courier new,courier,monospace;">Input.touchCount </span>لا يساوي واحدا، بالتالي لن نسمح للاعب في هذه الحالة بتحريك الكاميرا.</p><p dir="rtl">الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateDragging</span> هي المسؤولة عن تحريك الكاميرا، لذا عليها أن تتأكد أولا من قيمة <span style="font-family:courier new,courier,monospace;">singleTouch</span> وبعد ذلك تقوم بتحريك الكاميرا بالمقدار <span style="font-family:courier new,courier,monospace;">playerTouch.deltaPosition </span>مضروبا في سرعة الحركة. لاحظ أننا هنا لا نحتاج لتخزين موقع اللمسة السابق حيث أن قيمة الإزاحة تأتينا مباشرة بعكس ما كان عليه الحال حين التعامل مع مؤشر الفأرة.</p><p dir="rtl">بعد ذلك تقوم الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateDoubleTouch</span> بالتحقق من كون اللاعب يضع أصبعين على الشاشة، وفي هذه الحالة تقوم مباشرة بتغيير قيمة <span style="font-family:courier new,courier,monospace;">doubleTouch</span> إلى <span style="font-family:courier new,courier,monospace;">true</span>. لاحظ أن اللمس بأصبعين ليس له أي مدلول في اللعبة سوى التقريب والإبعاد بخلاف اللمسة الواحدة التي يمكن أن تستخدم لأكثر من غرض. ولهذا السبب لا نحتاج للتحقق من مواقع الأصبعين بل يكفي وجودهما لمنع أي مدخلات أخرى غير التقريب والإبعاد.</p><p dir="rtl">أخيرا تقوم الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateZooming</span> بالتأكد من وجود أصبعين على الشاشة عبر المتغير <span style="font-family:courier new,courier,monospace;">doubleTouch</span> وبناء عليها تحسب 4 مواقع وهي كالتالي:</p><ul dir="rtl"><li><strong>posA1</strong>: موقع الإصبع الأول خلال الإطار السابق.</li><li><strong>posA2</strong>: موقع الإصبع الأول خلال الإطار الحالي.</li><li><strong>posB1</strong>: موقع الإصبع الثاني خلال الإطار السابق.</li><li><strong>posB2</strong>: موقع الإصبع الثاني خلال الإطار الحالي.</li></ul><p dir="rtl">لاحظ أننا قمنا بطرح الإزاحة من مواقع الأصابع الحالية حتى نحصل على مواقع الأصابع في الإطار السابق، وذلك لأننا لم نقم بتخزين هذه المواقع من الأساس. بعد ذلك نحسب المسافة بين الأصبعين في الإطار السابق <span style="font-family:courier new,courier,monospace;">prevDist</span> والإطار الحالي <span style="font-family:courier new,courier,monospace;">currentDist</span>. تذكر أن الدّالة <span style="font-family:courier new,courier,monospace;">()Zoom</span> في البريمج <span style="font-family:courier new,courier,monospace;">CameraControl</span> تقوم بالتقريب إذا أعطيناها قيمة سالبة وبالإبعاد إذا أعطيناها قيمة موجبة. من أجل ذلك نقوم بطرح المسافة السابقة من المسافة الحالية وضرب الناتج في سرعة التقريب والإبعاد <span style="font-family:courier new,courier,monospace;">zoomingSpeed</span>. بهذه الطريقة نضمن الحصول على قيمة موجبة إذا حرك اللاعب أصبعيه بعيدا عن بعضهما مما يؤدي للتقريب وقيمة سالبة إذا قرب اللاعب أصبعيه من بعضهما مما يؤدي للإبعاد، وهذا السلوك بطبيعة الحال هو المعتاد عند مستخدمي الهواتف الذكية والأجهزة اللوحية.</p><p dir="rtl">البريمج الثاني الذي سنتناوله في موضوع استقبال مدخلات شاشة اللمس هو الخاص بإطلاق المقذوفات. تذكر أننا قمنا بإضافة بريمج يسمى <span style="font-family:courier new,courier,monospace;">LauncherMouseInput</span> على قالب مقلاع إطلاق المقذوفات. البريمج الجديد يسمى <span style="font-family:courier new,courier,monospace;">LauncherTouchInput</span> وسنقوم بإضافته على نفس القالب من أجل تمكين اللاعب من إطلاق المقذوفات عن طريق اللمس. السرد التالي يوضح هذا البريمج:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class LauncherTouchInput : MonoBehaviour {

     //مرجع لبريمج إطلاق المقذوفات
     private Launcher launcher;

	   //تستدعى مرة واحدة عند بداية التشغيل
	   void Start () {
        //تقوم بتدمير بريمج قراءة مدخلات الفأرة في حال اكتشاف نظام تشغيل الهاتف
        if (Application.platform == RuntimePlatform.Android)
        {
            LauncherMouseInput mouseInput = GetComponent&lt;LauncherMouseInput&gt;();
            Destroy(mouseInput);
        }

        launcher = GetComponent&lt;Launcher&gt;();
	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
        UpdateTouchStart();
        UpdateDragging();
        UpdateRelease();
    }

    //تقوم بالتحقق من كون اللاعب قد وضع اصبعا واحدا
    //على المقذوف الحالي
    void UpdateTouchStart()
    {
        Projectile currentProj = launcher.currentProjectile;
        if (currentProj == null)
        {
            //لا يوجد ما يمكن فعله
            return;
        }

        if (Input.touchCount == 1)
        {
            Touch playerTouch = Input.touches[0];
            if (playerTouch.phase == TouchPhase.Began)
            {
                //قام اللاعب للتو بلمس الشاشة
                // تحقق من كون عملية اللمس تمت داخل حدود المقذوف
                Vector2 touchPos = Camera.main.ScreenToWorldPoint(playerTouch.position);

                //استخرج مكوّن التصادم الخاص بالمقذوف الحالي
                Collider2D projectileCollider = currentProj.GetComponent&lt;Collider2D&gt;();

                if (projectileCollider.bounds.Contains(touchPos))
                {
                    //تمت عملية اللمس داخل حدود المقذوف بالتالي يجب إمساكه
                    launcher.HoldProjectile();
                }
            }
        }
    }

    //تقوم بالتحقق من تحريك اللاعب لإصبعه على الشاشة أثناء إمساك المقذوف
    void UpdateDragging()
    {
        if (Input.touchCount == 1)
        {
            Vector2 touchWorldPos = Camera.main.ScreenToWorldPoint(Input.touches[0].position);
            launcher.DragProjectile(touchWorldPos);
        }
    }

    //تتحقق من رفع اللاعب إصبعه عن الشاشة
    void UpdateRelease()
    {
        if (Input.touchCount == 1)
        {
            Touch playerTouch = Input.touches[0];
            if (playerTouch.phase == TouchPhase.Ended ||
                playerTouch.phase == TouchPhase.Canceled)
            {
                launcher.ReleaseProjectile();
            }
        }
    }
}
</pre><p dir="rtl">ينفذ هذا البريمج ثلاث خطوات في كل عملية تحديث:</p><ol dir="rtl"><li>الخطوة الأولى عبر الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateTouchStart</span> والتي تتحقق من كون اللاعب قد لمس الشاشة للتو مستخدما إصبعا واحدا. في هذه الحالة تقوم الدّالة بحساب موقع اللمسة في فضاء المشهد ومن ثم فحص ما إذا كان هذا الموقع ضمن حدود مكوّن التصادم الخاص بالمقذوف الحالي المتواجد على مقلاع الإطلاق. إذا كانت هذه اللمسة فعلا داخل حدود المقذوف فهذا يعني أن اللاعب يريد إمساكه، وبالتالي تقوم الدّالة بإمساك المقذوف عبر استدعاء <span style="font-family:courier new,courier,monospace;">()HoldProjectile</span> من البريمج <span style="font-family:courier new,courier,monospace;">Launcher</span>.</li><li>الخطوة الثانية التي تنفذ عبر<span style="font-family:courier new,courier,monospace;"> ()UpdateDragging</span> تتعلق بوجود إصبع واحد على الشاشة، حيث تقوم بحساب موقع الإصبع في فضاء المشهد وتطلب من البريمج <span style="font-family:courier new,courier,monospace;">Launcher</span> تحريك المقذوف الحالي إلى هذا الموقع. تذكر أن الأمور الأخرى مثل التأكد من وجود مقذوف أو إذا ما كان ممسوكا أو تم إطلاقه تتم من خلال البريمج <span style="font-family:courier new,courier,monospace;">Launcher</span> نفسه بالتالي لا نحتاج لفحصها هنا، ولعلك تذكر أننا لم نفحصها أيضا في بريمج قراءة مدخلات الفأرة.</li><li>أخيرا تقوم الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateRelease</span> بالتحقق من كون اللاعب قد رفع إصبعا واحدا عن الشاشة، وذلك من خلال فحص مرحلة اللمس <span style="font-family:courier new,courier,monospace;">playerTouch.phase</span> إذا ما كانت تساوي <span style="font-family:courier new,courier,monospace;">Ended</span> أو <span style="font-family:courier new,courier,monospace;">Canceled</span> وهما الحالتان المتوقعتان حال رفع الإصبع. عند التأكد من هذا الأمر تقوم باستدعاء دالّة إطلاق المقذوف <span style="font-family:courier new,courier,monospace;">()ReleaseProjectile</span>.</li></ol><p dir="rtl">البريمج الأخير الذي يقرأ مدخلات شاشة اللمس هو البريمج الخاص بتنفيذ الهجوم الخاص للمقذوف بعد إطلاقه. هذا الهجوم يتم عبر لمس الشاشة مرة واحدة في أي موقع بعد إطلاق المقذوف. هذا البريمج يسمى <span style="font-family:courier new,courier,monospace;">SpecialAttackTouchInput</span> ويجب أن تتم إضافته لجميع قوالب المقذوفات التي أنشأناها. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class SpecialAttackTouchInput : MonoBehaviour {

	   //تستدعى مرة واحدة عند بداية التشغيل
	   void Start () {
        //قم بتدمير بريمج قراءة مدخلات الفأرة في حال اكتشاف نظام تشغيل الهاتف
        if (Application.platform == RuntimePlatform.Android)
        {
            SpecialAttackMouseInput mouseInput = GetComponent&lt;SpecialAttackMouseInput&gt;();
            Destroy(mouseInput);
        }
	   }
	
	   //تستدعى مرة واحدة عند تصيير كل إطار
	   void Update () {
        if (Input.touchCount == 1)
        {
            Touch playerTouch = Input.touches[0];
            if(playerTouch.phase == TouchPhase.Began)
            {
                SendMessage("PerformSpecialAttack");
            }
        }
	   }
}
</pre><p dir="rtl">يمكنك ملاحظة مدى بساطة هذا البريمج، حيث أن كل ما يفعله هو إرسال الرسالة <span style="font-family:courier new,courier,monospace;">PerformSpecialAttack</span> في حال قام اللاعب بلمس الشاشة مرة واحدة.</p><p dir="rtl">بهذا تكون اللعبة مكتملة لأجهزة الحاسب والهواتف الذكية، وبقي علينا تصديرها على شكل تطبيق مستقل.</p><h2 dir="rtl">تصدير اللعبة بعد إكمالها</h2><p dir="rtl">يوفر محرك Unity إمكانية تصدير الألعاب على مجموعة كبيرة من المنصات، وما يهمنا منها الآن هو منصتا الحاسب الشخصي والهواتف الذكية وتحديدا الأجهزة التي تعمل بنظام Android. تصدير اللعبة يتم عن طريق النافذة التي حددنا منها ترتيب المشاهد وهي:</p><p dir="rtl" style="text-align: center;"> <strong>File &gt; Build Settings</strong></p><p dir="rtl">بالنسبة للتصدير للحواسيب وأجهزة Mac اختر من القائمة اليسرى PC, Max &amp; Linux Standalone لتظهر أمامك الخيارات التالية:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/1.png.0bf6c86d9e19f57f7d979be2280f6a55.png"><img data-fileid="3701" class="ipsImage ipsImage_thumbnailed" alt="1.thumb.png.df98821262d71264b4487535bc90" src="https://academy.hsoub.com/uploads/monthly_2015_08/1.thumb.png.df98821262d71264b4487535bc90ed04.png"></a></p><p dir="rtl">أهم هذه الخيارات هو Target Platform والذي تحدد من خلاله نظام التشغيل المستهدف وخيار Architecture والذي يحدد نوع النظام التشغيل سواء كان 32 أو 64 بت. من المهم الانتباه إلى أن الخيار x86_64 يجعل اللعبة تعمل فقط على أنظمة 64 بت حيث أن وجود x86 في الاسم قد يضلل أحيانا فتظن أنه يشمل النظامين. إن كنت تستهدف النظامين 32 و 64 فابق على الخيار الأول x86. بعد ذلك يمكنك الضغط على Build ثم تختار مكان التخزين لتبدأ بعدها عملية التصدير.</p><p dir="rtl">بالنسبة للتصدير للهواتف الذكية الموضوع أصعب قليلا. سأتحدث هنا بالتفصيل عن طريقة التصدير لمنصة Android فقط لأنني للأسف لا أملك خبرة في التعامل مع أنظمة iOS. قبل التصدير لهذا النظام علينا القيام بتجهيز بعض الأدوات. الخطوة الأولى هو تحميل وتثبيت Android SDK وستحتاج هنا للإصدار الخامس حيث أن الإصدار الخامس من محرك Unity يحتاج لهذه النسخة. يمكنك تحميل المكتبات اللازمة من هذا الرابط <a rel="external nofollow" href="https://developer.android.com/sdk/index.html#Other">https://developer.android.com/sdk/index.html#Other</a>. عند التثبيت يفضل أن تختار موقعا سهلا مثل <span style="font-family:courier new,courier,monospace;">d:\AndroidSDK</span>.</p><p dir="rtl">بعد تثبيت Android SDK على جهازك عليك أن تقوم بتنزيل مكتبة واحدة على الأقل عن طريق تشغيل SDK Manager وهو التطبيق المصاحب لـ Android SDK. كل ما تحتاج إليه هنا هو اختيار SDK Platform للإصدار الأخير (حتى كتابة هذه الدروس الإصدار الأخير هو API22 5.1.1). وذلك موضح في الصورة التالة:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/2.png.6e95d2da0d358e6a33d8d93faae4756f.png"><img data-fileid="3702" class="ipsImage ipsImage_thumbnailed" alt="2.thumb.png.d4b8fa6ba79b26640ff0e99a9650" src="https://academy.hsoub.com/uploads/monthly_2015_08/2.thumb.png.d4b8fa6ba79b26640ff0e99a96502062.png"></a></p><p dir="rtl">بعد تنزيل وتثبيت المكتبة علينا أن نخبر Unity عن موقعها وذلك عبر الخيار:</p><p dir="rtl" style="text-align: center;"><strong> Edit &gt; Preferences </strong></p><p dir="rtl">ومن ثم اختيار External Tools من القائمة اليسرى. بعدها يمكنك تحديد المجلد الذي قمت بتثبيت Android SDK فيه عن طريق الخيار Android SDK Location كما ترى هنا:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/3.png.d9879e683b50a9fced4c64090893e8b6.png"><img data-fileid="3703" class="ipsImage ipsImage_thumbnailed" alt="3.thumb.png.836f78e957df8955a5c0494cf828" src="https://academy.hsoub.com/uploads/monthly_2015_08/3.thumb.png.836f78e957df8955a5c0494cf8285d15.png"></a></p><p dir="rtl">بما أن اللعبة ستعمل على شاشة الهاتف، يجب علينا أن نجبر النظام على تشغيلها في الوضع الأفقي وليس العمودي. هذا الخيار يمكن ضبطه من خلال القائمة:</p><p dir="rtl" style="text-align: center;"><strong> Edit &gt; Project Settings &gt; Player</strong></p><p dir="rtl">ومن ثم اختيار رمز نظام Android وفتح مجموعة الإعدادات المسماة Resolution and Presentation. بعدها يجب ضبط Default Orientation على الخيار Landscape Left كما هو موضح في الصورة التالية:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/4.png.0f8c68d2fc6e4d68e42042fb5f0ecfff.png"><img data-fileid="3704" class="ipsImage ipsImage_thumbnailed" alt="4.thumb.png.96dc3f8a99761b3083bc6444c700" src="https://academy.hsoub.com/uploads/monthly_2015_08/4.thumb.png.96dc3f8a99761b3083bc6444c700bb18.png"></a></p><p dir="rtl">الخطوة الأخيرة قبل التصدير هي تحديد معرف الحزمة، وهو عبارة عن اسم على شكل عنوان موقع إنترنت معكوس يبدأ بعنوان موقع الناشر وينتهي باسم المنتج، مثل <span style="font-family:courier new,courier,monospace;">com.Hsoub.Academy.AngryAnimals</span>. قد تبدو هذه الطريقة في التعريف غريبة بعض الشيء، لكنها موروثة من طريقة تعريف الحزم البرمجية بلغة Java والتي تعتبر اللغة الرئيسية لبرمجة التطبيقات على نظام Android. لا يشترط طبعا أن يكون موقع الإنترنت المستخدم حقيقيا، لكن المهم هو أن تتبع هذا التنسيق في تعريف الحزمة. لإضافة معرّف الحزمة ادخل إلى القائمة:</p><p dir="rtl" style="text-align: center;"> <strong>Edit &gt; Project Settings &gt; Player </strong></p><p dir="rtl">ومن ثم اختر رمز نظام Android من نافذة الخصائص وافتح مجموعة الإعدادات المسماة Other Settings كما هو موضح في الصورة التالية:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/5.png.c6ae26d2a036bc4d827d12214ecb6f00.png"><img data-fileid="3705" class="ipsImage ipsImage_thumbnailed" alt="5.thumb.png.1dd8756b3c926806292d98510cb7" src="https://academy.hsoub.com/uploads/monthly_2015_08/5.thumb.png.1dd8756b3c926806292d98510cb7fe79.png"></a></p><p dir="rtl">يمكنك بعدها كتابة معرّف الحزمة في الخانة <span style="font-family:courier new,courier,monospace;">PlayerSettings.bundleIdentifier</span> كما يمكنك تحديد الإصدار الأدنى الذي يدعمه التطبيق. يستحسن أن تضبط التوافق على الإصدار 4.0 من النظام حيث أنه لا زال شائعا في معظم الأجهزة المتوفرة.</p><p dir="rtl">بعدها يمكنك أخيرا العودة لشاشة التصدير:</p><p dir="rtl" style="text-align: center;"><strong> File &gt; Build Settings </strong></p><p dir="rtl">واختيار Android من القائمة اليسرى ومن ثم الضغط على Build واختيار موقع التصدير. سيكون الملف الناتج من نوع APK والذي يمكنك نسخه لجهازك المحمول وتنزيله وتشغيله. قد تضطر لتغيير إعدادات الجهاز حتى يسمح بتنزيل تطبيقات مجهولة المصدر (أي من مصدر غير متجر Google Play) وهذه الإعدادات تختلف من جهاز لآخر. بالنسبة لأجهزة Samsung ستجد هذا الخيار في أعدادات الحماية تحت بند إدارة الجهاز كما هو موضح هنا:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/6.png.68c24d835f77761f4397f989756a5947.png"><img data-fileid="3706" class="ipsImage ipsImage_thumbnailed" alt="6.thumb.png.2c6b48bb172c442d777a943fbf24" src="https://academy.hsoub.com/uploads/monthly_2015_08/6.thumb.png.2c6b48bb172c442d777a943fbf2480a2.png"></a></p><p dir="rtl">تهانينا! لقد قمت ببناء وتصدير لعبة كاملة على هاتفك الذكي أو جهازك اللوحي، ويمكنك الاستمتاع بلعبها ومشاركتها مع أصدقائك.</p><p dir="rtl" style="text-align: center;"> </p>
]]></description><guid isPermaLink="false">142</guid><pubDate>Tue, 11 Aug 2015 19:44:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x645;&#x642;&#x630;&#x648;&#x641;&#x627;&#x62A; &#x627;&#x644;&#x644;&#x639;&#x628;&#x629; &#x648;&#x622;&#x644;&#x64A;&#x629; &#x625;&#x637;&#x644;&#x627;&#x642;&#x647;&#x627; &#x641;&#x64A; Unity3D</title><link>https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D9%82%D8%B0%D9%88%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-%D9%88%D8%A2%D9%84%D9%8A%D8%A9-%D8%A5%D8%B7%D9%84%D8%A7%D9%82%D9%87%D8%A7-%D9%81%D9%8A-unity3d-r141/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d-5.png.e0ee5bebc484fd0ab48490835fc3250e.png" /></p>

<h2 dir="rtl">إنشاء المقذوفات</h2><p dir="rtl">قطعنا حتى الآن شوطا لا بأس به نحو إكمال ميكانيكيات اللعبة، حيث أصبح لدينا <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D9%85%D8%B4%D9%87%D8%AF-%D9%88%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%8A%D8%B1%D8%A7-%D9%81%D9%8A-unity3d-r131/">مشهد يمكننا التجول فيه وتقريب وإبعاد الكاميرا</a>، إضافة لإمكانية <a href="https://academy.hsoub.com/programming/general/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%B5%D9%88%D9%85-%D9%81%D9%8A-unity3d-r134/">بناء مرحلة داخل هذا المشهد مستخدمين الوحدات البنائية وأشكال الوحوش التي صنعناها</a>. الخطوة التالية هي أن نقوم بصنع مقلاع لإطلاق المقذوفات، بالإضافة إلى المقذوفات نفسها والتي سنستخدم لها صور الحيوانات الموجودة في المجلد <span style="font-family:courier new,courier,monospace;">Kenney.nl\AnimalPack</span>. هذه الحيوانات موضحة في الصورة التالية:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/0.png.5678285bc3575cef7167e4474b6f0ecd.png"><img data-fileid="3690" class="ipsImage ipsImage_thumbnailed" alt="0.thumb.png.c0db3cd18c89cbe22fa60c5eacd8" src="https://academy.hsoub.com/uploads/monthly_2015_08/0.thumb.png.c0db3cd18c89cbe22fa60c5eacd820cf.png"></a></p><p dir="rtl">علينا أن نقوم ببناء قالب مقذوف لكل صورة من هذه الصورة الأربعة. هذا القالب سيحتوي مبدئيا على المكوّن <span style="font-family:courier new,courier,monospace;">Sprite Renderer</span> والذي أصبح معروفا لدينا، إضافة للمكوّنين <span style="font-family:courier new,courier,monospace;">Rigid Body 2D</span> و <span style="font-family:courier new,courier,monospace;">Circle Collider 2D</span>. هذه المكوّنات كفيلة بتحويل كل صورة إلى كائن نشط فيزيائيا، وكل ما يلزمنا هو تعديل قيم الكتلة في مكوّن الجسم الصلب لتصبح 5 لكل واحد من هذه الصور، إضافة لتفعيل الخيار <span style="font-family:courier new,courier,monospace;">Is Kinematic</span> والذي يمنع استجابة الجسم الصلب للقوى الخارجية، وهو ما يلزمنا في البداية وسنقوم بتغييره لاحقا. الكتلة الكبيرة ضرورية لجعل هذه المقذوفات تحدث تأثيرا ملحوظا حين تصطدم بالوحدات البنائية أو الخصوم حال إطلاقها. بعد ذلك علينا أن نبدأ في كتابة وإضافة البريمجات اللازمة لهذه المقذوفات. البداية ستكون مع البريمج الرئيسي والأهم وهو <span style="font-family:courier new,courier,monospace;">Projectile</span>. والموضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class Projectile : MonoBehaviour {

//عدد الثواني التي سيعيشها المقذوف في المشهد بعد إطلاقه
public float lifeSpan = 7.5f;

//هل يُسمح للاعب بالتحكم بهذا المقذوف حاليا؟
private bool controllable = false;

//هل قام اللاعب بإمساك هذا المقذوف وإعداده للإطلاق؟
private bool held = false;

//هل تم إطلاق هذا المقذوف بالفعل؟
private bool launched = false;

//هل تم تنفيذ الهجوم الخاص بهذا المقذوف؟
private bool attackPerformed = false;

//متغير لتخزين موقع المقذوف لحظة إمساك اللاعب له وقبل سحبه استعدادا للإطلاق
private Vector2 holdPosition;

//يتم استدعاؤها مرة واحدة عند بداية التشغيل
void Start () {

}

//يتم استدعاؤها مرة عند تصيير كل إطار
void Update () {

}

//تسمح للاعب بالتحكم بهذا المقذوف شريطة ألا يكون قد تم إطلاقه فعلا
public void AllowControl()
{
    if (!launched)
    {
        controllable = true;
    }
}

//تستدعى عند بداية إمساك اللاعب للمقذوف استعدادا لإطلاقه
public void Hold()
{
    if (controllable &amp;&amp; !held &amp;&amp; !launched)
    {
        held = true;
        holdPosition = transform.position;
        //أرسل رسالة تخبر بإمساك اللاعب للمقذوف
        SendMessage("ProjectileHeld");
    }
}

//تقوم بإطلاق المقذوف مستخدمة مقدار القوة المزود
public void Launch(float forceMultiplier)
{
    if (controllable &amp;&amp; held &amp;&amp; !launched)
    {
        //احسب متجه الإطلاق
        Vector2 launchPos = transform.position;
        Vector2 launchForce = (holdPosition - launchPos) * forceMultiplier;
        //أضف قوة الإطلاق المحسوبة للجسم الصلب
        Rigidbody2D myRB = GetComponent&lt;Rigidbody2D&gt;();
        myRB.isKinematic = false;
        myRB.AddForce(launchForce, ForceMode2D.Impulse);
        //قم بضبط متغيرات الحالة الجديدة
        launched = true;
        held = false;
        controllable = false;
        //قم بتدمير المقذوف بعد انقضاء الثواني المحددة لبقائه في المشهد
        Destroy(gameObject, lifeSpan);
        //أرسل رسالة تخبر بحدوث الإطلاق
        SendMessage("ProjectileLaunched");
    }
}

//تقوم بتنفيذ الهجوم الخاص لهذا المقذوف بعد إطلاقه
public void PerformSpecialAttack()
{
    if (!attackPerformed &amp;&amp; launched)
    {
        //اسمح بالهجوم الخاص مرة واحدة فقط
        attackPerformed = true;
        SendMessage("DoSpecialAttack", SendMessageOptions.DontRequireReceiver);
    }
}

//قم بسحب المقذوف إلى الموقع المحدد شريطة أن يكون قابلا للتحكم به من قبل اللاعب
public void Drag(Vector2 position)
{
    if (controllable &amp;&amp; held &amp;&amp; !launched)
    {
        transform.position = position;
    }
}

//تخبر ما إذا اللاعب يمسك حاليا بالمقذوف استعدادا لإطلاقه
public bool IsHeld()
{
    return held;
}

//تخبر ما إذا تم إطلاق المقذوف بالفعل
public bool IsLaunched()
{
    return launched;
}
}
</pre><p dir="rtl">لاحظ أن المتغير العام الوحيد في هذا البريمج هو <span style="font-family:courier new,courier,monospace;">lifeSpan</span> والذي يحدد مدة بقاء المقذوف في المشهد بعد أن يتم إطلاقه. بخلاف ذلك لدبنا متغيرات الحالة وهي <span style="font-family:courier new,courier,monospace;">launched</span> و <span style="font-family:courier new,courier,monospace;">held</span><span style="font-family:courier new,courier,monospace;"> </span>و <span style="font-family:courier new,courier,monospace;">controllable</span> و <span style="font-family:courier new,courier,monospace;">attackPerformed</span>، وكل هذه المتغيرات خاصة ولا يمكن التحكم بها إلا عن طريق إرسال الرسائل أو استدعاء الدّوال. إضافة لهذا المتغير العام لدينا أربع متغيرات خاصة تعبر عن الأوضاع المختلفة التي يكون فيها المقذوف منذ بداية اللعبة وحتى يتم إطلاقه إلى أن يختفي أخيرا من المشهد. هذه المتغيرات هي <span style="font-family:courier new,courier,monospace;">controllable</span> و <span style="font-family:courier new,courier,monospace;">held</span> و <span style="font-family:courier new,courier,monospace;">launched</span> و <span style="font-family:courier new,courier,monospace;">attackPerformed</span> وقيمتها المبدئية هي <span style="font-family:courier new,courier,monospace;">false</span>. أوضاع المقذوف المختلفة تأتي على التسلسل التالي:</p><ul dir="rtl"><li>في بداية اللعبة يكون المقذوف موضوعا على الأرض بجانب مقلاع القذف، وفي هذه الأثناء يبقى ساكنا ولا يستطيع اللاعب التحكم به إلى أن يأتي دوره في الإطلاق. في هذه الحالة تكون قيمة المتغير <span style="font-family:courier new,courier,monospace;">controllable</span> تساوي <span style="font-family:courier new,courier,monospace;">false</span>، مما يمنع اللاعب من التحكم بالمقذوف.</li><li>بمجرد أن يحين دور المقذوف في الإطلاق ويتم وضعه على القاذف، يتم استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()AllowControl</span>، مما يغير قيمة <span style="font-family:courier new,courier,monospace;">controllable</span> إلى <span style="font-family:courier new,courier,monospace;">true</span> ويسمح للاعب بالتحكم بالمقذوف. حتى اللحظة تبقى المتغيرات الثلاث الأخرى على قيمتها <span style="font-family:courier new,courier,monospace;">false</span>.</li><li>بمجرد أن يقوم اللاعب بالضغط بزر الفأرة على المقذوف، يتم استدعاء الدّالة<span style="font-family:courier new,courier,monospace;"> ()Hold</span> والتي يفترض أن تقوم بتغيير قيمة متغير الإمساك <span style="font-family:courier new,courier,monospace;">held</span> إلى <span style="font-family:courier new,courier,monospace;">true</span>. بما أن هذا المتغير يعبر عن أن اللاعب يمسك بالمقذوف، فإنّه ينبغي التأكد أولا من أنه مسموح للاعب بالتحكم به وذلك عن طريق فحص قيمة <span style="font-family:courier new,courier,monospace;">controllable</span>، كما ينبغي التأكد من أنه غير ممسوك أصلا وذلك بفحص قيمة <span style="font-family:courier new,courier,monospace;">held</span> نفسها، وأخيرا يجب فحص قيمة <span style="font-family:courier new,courier,monospace;">launched</span> حتى يتم التأكد من أن المقذوف لم يتم إطلاقه بعد، وذلك لأنه لا يمكن إمساك المقذوف بعد إطلاقه. بعد التحقق من هذه الشروط الثلاث يتم تخزين الموقع الذي أمسك فيه اللاعب المقذوف في المتغير <span style="font-family:courier new,courier,monospace;">holdPosition</span> ومن ثم يتم إرسال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectileHeld</span> للتبليغ بأن المقذوف تم إمساكه.</li><li>بعد الإمساك يبدأ اللاعب بتحريك المقذوف من أجل تجهيزه للإطلاق، حيث يقوم بسحبه للخلف والأسفل استعدادا لإطلاقه. أثناء إمساك اللاعب للمقذوف يُسمح له باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()Drag</span> والتي يقوم من خلالها بتحريك المقذوف إلى موقع محدد. كما ترى فإنّ عملية التحريك عبر هذه الدّالة تعتمد على كون المقذوف قابلا للتحكم وممسوكا حاليا، إضافة إلى أنه يجب ألا يكون قد تم إطلاقه.</li><li>عندما يقوم اللاعب بإفلات المقذوف يتم استدعاء دالّة الإطلاق <span style="font-family:courier new,courier,monospace;">()Launch</span> والتي يمكن إعطاؤها قيمة رقمية تمثل معامل قوة الإطلاق. هذا المعامل يمكننا من عمل أكثر من مقلاع بقوى إطلاق مختلفة. عند استدعاء هذه الدّالة تقوم بالتحقق من كون المقذوف تحت تحكم اللاعب وأن اللاعب يمسكه حاليا، إضافة إلى أنه لم يتم إطلاقه حتى الآن. بعد تحقق هذه الشروط يتم حساب قوة الإطلاق عن طريق المسافة بين موقع إمساك المقذوف وموقع إفلاته وضربها بالمعامل المزوّد للدّالة، حيث أن شد المقذوف لمسافة أبعد سينتج عنه قوة إطلاق أكبر. بعدها يتم تفعيل الجسم الصلب مرة أخرى عن طريق ضبط المتغير <span style="font-family:courier new,courier,monospace;">isKinematic</span> إلى <span style="font-family:courier new,courier,monospace;">false</span> وبالتالي عودة تنشيط استجابة الجسم الصلب للقوى الخارجية قبل إضافة قوة الإطلاق له. بعد تنفيذ الإطلاق يتم تحديث متغيرات الحالة؛ حيث يمنع اللاعب من التحكم بالمقذوف عن طريق تغيير <span style="font-family:courier new,courier,monospace;">controllable</span> إلى <span style="font-family:courier new,courier,monospace;">false</span> ويتم تنشيط حالة الإطلاق عن طريق تغيير <span style="font-family:courier new,courier,monospace;">launched</span> إلى <span style="font-family:courier new,courier,monospace;">true</span> ويتم أيضا إعادة <span style="font-family:courier new,courier,monospace;">held</span> إلى <span style="font-family:courier new,courier,monospace;">false</span> حيث أن اللاعب لم يعد ممسكا بالمقذوف. أخيرا يتم إرسال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectileLaunched</span> من أجل إبلاغ البريمجات الأخرى بأن المقذوف قد تم إطلاقه.</li><li>بعد اطلاق المقذوف بقي هناك خطوة أخيرة يمكن للاعب القيام بها بخصوصه، وهي تنفيذ الهجوم الخاص بالمقذوف؛ كالانشطار إلى 3 مقذوفات أصغر أو مضاعفة السرعة أو غيرها. يمكن للاعب تنفيذ هذا الهجوم عن طريق استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()PerformSpecialAttack</span> والتي تتأكد من أن قيمة <span style="font-family:courier new,courier,monospace;">attackPerformed</span> هي <span style="font-family:courier new,courier,monospace;">false</span>؛ حيث أن تنفيذ هذا الهجوم مسموح مرة واحدة فقط. إضافة لهذا الشرط يجب التأكد من أن المقذوف تم إطلاقه بالفعل عن طريق فحص المتغير <span style="font-family:courier new,courier,monospace;">launched</span>؛ ذلك أن هذا الهجوم يمكن تنفيذه فقط بعد إطلاق المقذوف. كما تلاحظ فإنّ هذه الدّالة لا تقوم بتنفيذ الهجوم فعليا، عوضا عن ذلك تقوم بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">DoSpecialAttack</span> والتي سيقوم بريمج آخر باستقبالها وتنفيذ الهجوم الفعلي بناء عليها. بفصل استدعاء الهجوم عن تنفيذه نواصل عملنا على مبدأ فصل الاهتمامات ونمكّن أنفسنا من برمجة أكثر من نوع هجوم دون أن يؤثر ذلك على هيكل البريمج الأساسي.</li></ul><p dir="rtl">بخلاف هذه المراحل نلاحظ وجود الدّالتين <span style="font-family:courier new,courier,monospace;">()IsHeld</span> و <span style="font-family:courier new,courier,monospace;">()IsLaunched</span> واللتين تمكنان البريمجات الأخرى من قراءة قيم المتغيرات الخاصة ولكن دون تغيير قيمتها. قراءة هذين المتغيرين ستكون ذات أهمية للبريمجات التي يعتمد عملها على بريمج المقذوف كما سنرى بعد قليل. ملاحظة أخرى هي استخدام الخيار <span style="font-family:courier new,courier,monospace;">SendMessageOptions.DontRequireReceiver</span> عند إرسال الرسالة <span style="font-family:courier new,courier,monospace;">DoSpecialAttack</span> وبذلك لا نشترط وجود مستقبل للرسالة. السبب هو أن هذا الهجوم اختياري ولا بأس من وجود مقذوفات ليس لها أي هجوم خاص.</p><p dir="rtl">بهذا نكون قد تعرفنا على البريمج الأساسي للمقذوفات، وبقي علينا بعض البريمجات الصغيرة المساعدة للوظائف الثانوية.</p><p dir="rtl">البريمج الأول هو <span style="font-family:courier new,courier,monospace;">ProjectileSounds</span> وهو المسؤول عن أصوات المقذوفات. ما يفعله هذا البريمج ببساطة هو استقبال رسالتي الإمساك <span style="font-family:courier new,courier,monospace;">ProjectileHeld</span> والإطلاق <span style="font-family:courier new,courier,monospace;">ProjectileLaunched</span> وتشغيل الملف الصوتي المحدد لكل عملية. السرد التالي يوضح هذا البريمج:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;
 
public class ProjectileSounds : MonoBehaviour {
 
      //الملف الصوتي الخاص بعملية الإطلاق
      public AudioClip launchSound;
 
      //الملف الصوتي الخاص بعملية الإمساك
      public AudioClip holdSound;
 
 	   //تستدعى مرة واحدة عند بداية التشغيل
 	   void Start () {
 	
 	   }
 	
 	   //تستدعى مرة عند تصيير كل إطار
 	   void Update () {
 	    
 	   }
 
     void ProjectileHeld()
     {
         AudioSource.PlayClipAtPoint(holdSound, transform.position);
     }
 
     void ProjectileLaunched()
     {
         AudioSource.PlayClipAtPoint(launchSound, transform.position);
     }
 }</pre><p dir="rtl">البريمج الثاني الذي سنناقشه من بريمجات قالب المقذوف هو البريمج الخاص برسم مسار حركة المقذوف بعد إطلاقه. المسار المرسوم سيكون عبارة عن نقاط بينها مسافات ثابتة تمتد على طول المسار الذي قطعه المقذوف ابتداء من لحظة إفلاته عند مقلاع الإطلاق إلى آخر نقطة يصل إليها. قبل شرح البريمج سنقوم ببناء قالب يمثل كائن النقطة التي سنستخدمها لرسم المسار. لبناء القالب كل ما عليك هو إضافة كائن فارغ جديد للمشهد ومن ثم إضافة المكوّن <span style="font-family:courier new,courier,monospace;">SpriteRenderer</span> إليه. بعد ذلك قم بالضغط على زر الاستعراض للخانة <span style="font-family:courier new,courier,monospace;">Sprite</span> في المكوّن كما في الصورة، وقم بالنزول لآخر النافذة حيث ستجد في الأسفل مجموعة من الصور الافتراضية التي يستخدمها Unity من أجل بناء واجهة المستخدم. قم باختيار الصورة Knob ومن ثم أغلق النافذة. بعد ذلك قم بتسمية القالب الجديد باسم <span style="font-family:courier new,courier,monospace;">PathPoint</span> وتقليص حجمه على المحورين <strong>x</strong> و <strong>y</strong> إلى 0.75:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/1.png.2c28df205afc5fab5336935fa1f1b347.png"><img data-fileid="3691" class="ipsImage ipsImage_thumbnailed" alt="1.thumb.png.83b7b39916f98d3d4562f97168a6" src="https://academy.hsoub.com/uploads/monthly_2015_08/1.thumb.png.83b7b39916f98d3d4562f97168a6b0c6.png"></a></p><p dir="rtl">الآن أصبح بإمكاننا كتابة بريمج رسم المسار وإضافته لقالب المقذوف. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class PathDrawer : MonoBehaviour {

    //القالب المستخدم لرسم النقاط
    public GameObject pathPointPrefab;

    //المسافة بين كل نقطتين متتابعتين
    public float pointDistance = 0.75f;

    //الكائن الأب لكائنات نقاط المسار
    Transform pathParent;

    //متغير لتخزين موقع آخر نقطة تمت إضافتها
    Vector2 lastPointPosition;

    //متغير داخلي لمعرفة ما إذا كان المقذوف قد تم إطلاقه أم لا
    bool launched = false;

	   //تستدعى مرة واحدة عند بداية التشغيل
	   void Start () {
	       //Path ابحث عن الكائن الأب لنقاط المسار والمسمى
        pathParent = GameObject.Find("Path").transform;
	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
        if (launched)
        {
            float dist = Vector2.Distance(transform.position, lastPointPosition);
            if (dist &gt;= pointDistance)
            {
                //حان الوقت للإضافة نقطة جديدة
                AddPathPoint();
            }
        }
	   }

    void ProjectileLaunched()
    {
        //تم إطلاق المقذوف للتو لذا احذف المسار السابق
        for (int i = 0; i &lt; pathParent.childCount; i++)
        {
            Destroy(pathParent.GetChild(i).gameObject);
        }

        AddPathPoint();

        //قم بتحديث قيمة المتغير حيث أن المقذوف قد تم إطلاقه
        launched = true;
    }

    //تقوم بإضافة نقطة جديدة للمسار
    void AddPathPoint()
    {
        //قم بإنشاء نقطة جديدة مستخدما القالب
        GameObject newPoint = (GameObject)Instantiate(pathPointPrefab);
        //قم بوضع النقطة في الموقع الحالي للمقذوف
        newPoint.transform.position = transform.position;
        //قم بضبط الكائن الأب للنقطة
        newPoint.transform.parent = pathParent;
        //قم بتخزين موقع النقطة التي تمت إضافتها
        lastPointPosition = transform.position;
    }
}
</pre><p dir="rtl">يستخدم هذا البريمج القالب الذي أنشأناه للتو من أجل رسم النقاط على طول المسار، لذا سنحتاج لتحديد هذا القالب عبر المتغير <span style="font-family:courier new,courier,monospace;">pathPointPrefab</span>. بعد ذلك يمكننا عن طريق المتغير <span style="font-family:courier new,courier,monospace;">pointDistance</span> ضبط المسافة التي نرغب بها بين كل نقطتين متتابعتين، فكلما قلت هذه المسافة زاد عدد النقاط المرسومة. بعد ذلك سنحتاج لمرجع للكائن <span style="font-family:courier new,courier,monospace;">Path</span>، وهو كائن فارغ علينا إضافته لهرمية المشهد كابن للكائن الجذري. هذا الكائن سيكون هو الأب لجميع نقاط المسار، وهو يساعدنا في الوصول إليها دفعة واحدة لحذفها حين رسم مسار جديد كما سنرى بعد قليل. بما أننا سنحسب المسافة بين كل نقطتين متتابعتين أثناء حركة المقذوف لرسم المسار، علينا دائما أن نكون محتفظين بموقع آخر نقطة تم رسمها. هذا الموقع نخزنه في المتغير <span style="font-family:courier new,courier,monospace;">lastPointPosition</span>. أخيرا فإننا نعلم أن المسار لا يجب أن يتم رسمه إلا بعد إطلاق المقذوف، لذلك نستخدم المتغير <span style="font-family:courier new,courier,monospace;">launched</span> لنعرف من خلاله ما إذا تم هذا الإطلاق أم ليس بعد.</p><p dir="rtl">تذكر أنه عند إطلاق المقذوف سيقوم البريمج <span style="font-family:courier new,courier,monospace;">Projectile</span> بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectileLaunched</span>، والتي يستقبلها البريمج <span style="font-family:courier new,courier,monospace;">PathDrawer</span> عن طريق الدّالة التي تحمل نفس الاسم. بمجرد وصول الرسالة يتم حذف المسار المرسوم سابقا (إن وُجد) وذلك عن طريق حذف جميع أبناء الكائن الفارغ <span style="font-family:courier new,courier,monospace;">Path</span> والذي نحتفظ بمرجع له في المتغير <span style="font-family:courier new,courier,monospace;">pathParent</span>. بعد الانتهاء من الحذف نرسم نقطة في موقع الإطلاق عن طريق استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()AddPathPoint</span> ومن ثم يتم تغيير قيمة <span style="font-family:courier new,courier,monospace;">launched</span> إلى <span style="font-family:courier new,courier,monospace;">true</span>.</p><p dir="rtl">ما تقوم به الدّالة<span style="font-family:courier new,courier,monospace;"> ()AddPathPoint</span> هو إنشاء نقطة جديدة في الموقع الحالي للمقذوف باستخدام القالب <span style="font-family:courier new,courier,monospace;">pathPointPrefab</span> وإضافتها كابن للكائن <span style="font-family:courier new,courier,monospace;">Path</span> ومن ثم تخزين موقعها في المتغير <span style="font-family:courier new,courier,monospace;">lastPointPosition</span>. طالما أن كائن المقذوف موجود في المشهد سيتم استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()Update</span> في كل إطار، إلا أنها لن تقوم بأي شيء إلى أن تتغير قيمة <span style="font-family:courier new,courier,monospace;">launched</span> إلى <span style="font-family:courier new,courier,monospace;">true</span>. إذا تحقق هذا الشرط فهذا يعني أن المقذوف قد تم إطلاقه وبالتالي يجب أن يتم رسم المسار أثناء حركته؛ لذلك نقوم بحساب المسافة بين موقع المقذوف الحالي <span style="font-family:courier new,courier,monospace;">transform.position</span> وموقع رسم النقطة السابقة <span style="font-family:courier new,courier,monospace;">lastPointPosition</span>. إذا زادت هذه المسافة أو تساوت مع <span style="font-family:courier new,courier,monospace;">pointDistance</span> فإن الوقت يكون قد حان لإضافة نقطة جديدة لهذا يتم استدعاء <span style="font-family:courier new,courier,monospace;">()AddNewPoint</span>. الصورة التالية تمثل عملية رسم مسار المقذوف أثناء حركته:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/2.png.743cdf94cd628b4468b50928d7af7c83.png"><img data-fileid="3692" class="ipsImage ipsImage_thumbnailed" alt="2.thumb.png.97a68dafa843fccded186c53ddcb" src="https://academy.hsoub.com/uploads/monthly_2015_08/2.thumb.png.97a68dafa843fccded186c53ddcb63ca.png"></a></p><h2 dir="rtl">الهجمات الخاصة للمقذوفات</h2><p dir="rtl">لإكمال المقذوفات علينا صناعة الهجوم الخاص الذي يمكن للاعب تنفيذه بعد إطلاق المقذوف. هذا الهجوم له صور متعددة في اللعبة الأصلية Angry Birds والتي نقتبس منها في سلسلة الدروس هذه. سنكتفي نحن بمثالين لتوضيح كيفية بناء هذه الهجمات. الأول هو هجوم السرعة والذي سنعتمده للمقذوفات التي على شكل طيور، والذي يقوم بمضاعفة سرعة المقذوف مما يجعل تأثيره أكبر حين يصطدم بالوحدات البنائية أو الخصوم. الهجوم الثاني سنعتمده لمقذوفي الزرافة والفيل وهو الهجوم الانشطاري، حيث ينقسم المقذوف الأصلي إلى عدد من المقذوفات الأصغر حجما والتي يمكنها إصابة أكثر من هدف في أماكن متفرقة.</p><p dir="rtl">لنبدأ مع الهجوم الأسهل وهو هجوم السرعة. نظرا لكون منطق الهجمات يختلف تماما بين هجوم وآخر، علينا أن نفصل كل هجوم في بريمج منفصل. العامل المشترك الوحيد بين هذه الهجمات هو أنها ستستقبل الرسالة <span style="font-family:courier new,courier,monospace;">DoSpecialAttack</span> والتي يرسلها بريمج المقذوف <span style="font-family:courier new,courier,monospace;">Projectile</span> عندما يتم استدعاء الدّالة<span style="font-family:courier new,courier,monospace;"> ()PerformSpecialAttack</span> ويتم التحقق من الشروط اللازمة لتنفيذ هذا الهجوم. بريمج تنفيذ هجوم السرعة يسمى <span style="font-family:courier new,courier,monospace;">SpeedAttack</span>، وما يفعله هو جلب مكوّن الجسم الصلب ومن ثم مضاعفة سرعته بمقدار محدد دون تغيير اتجاهها. هذا البريمج موضح في السرد التالي. تذكر أن بريمجات الهجمات يجب أن تتم إضافتها إلى قوالب المقذوفات.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class SpeedAttack : MonoBehaviour {

     //قم بضرب السرعة الحالية للمقذوف بهذا
     //المقدار عند تنفيذ الهجوم
     public float speedFactor = 1.5f;

	   //يتم استدعاؤها مرة عند بداية التشغيل
	   void Start () {
	
	   }
	
	   //يتم استدعاؤها مرة عند تصيير كل إطار
	   void Update () {
	
	   }

    //وبناء عليها تنفّذ هجوم السرعة DoSpecialAttack تقوم باستقبال الرسالة
    public void DoSpecialAttack()
    {
        //اجلب مكوّن الجسم الصلب لكائن المقذوف
        Rigidbody2D myRB = GetComponent&lt;Rigidbody2D&gt;();

        //قم بضرب السرعة بمقدار المضاعفة ومن ثم اضبط سرعة الكائن على الناتج الجديد
        myRB.velocity = myRB.velocity * speedFactor;
    }
}
</pre><p dir="rtl">النوع الثاني من الهجمات الخاصة كما ذكرنا هو الهجوم الانشطاري، والذي يؤدي إلى تفتت المقذوف إلى مقذوفات أصغر حجما (شظايا)، والتي بدورها تتناثر على مساحة واسعة نسبيا. قبل الانتقال إلى البريمج الخاص بهذا الهجوم، نلاحظ أن تنفيذه سيحتاج لإنشاء كائنات جديدة وهي الشظايا التي ستتناثر جراء تنفيذ الهجوم. معنى هذا أننا سنحتاج لبناء قوالب لهذه الشظايا، وسيكون هناك قالبان تحديدا: واحد لشظايا مقذوف الفيل والآخر لشظايا مقذوف الزرافة. سأسمي هذين القالبين <span style="font-family:courier new,courier,monospace;">ElephantCluster</span> و <span style="font-family:courier new,courier,monospace;">GiraffeCluster</span>، وهما فعليا يتشابهان في كل شيء باستثناء الصورة المعروضة. هذان القالبان بسيطان حيث يحمل كل منهما صورة المقذوف الأصلي مع تصغير قياس الكائن إلى 0.75 على المحورين <strong>x</strong> و <strong>y</strong> وذلك لجعل الشظايا أصغر من المقذوف الأصلي. إضافة لذلك سنضيف مكوّن جسم صلب <span style="font-family:courier new,courier,monospace;">Rigid Body 2D</span> و مكوّن تصادم <span style="font-family:courier new,courier,monospace;">Circle Collider 2D</span>، وبهذا يصبح قالبا الشظايا جاهزين.</p><p dir="rtl">البريمج الذي سيطبق هذا النوع من الهجوم يسمى <span style="font-family:courier new,courier,monospace;">ClusterAttack</span> وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class ClusterAttack : MonoBehaviour {

    //القالب الذي سيستخدم لإنشاء الشظايا
    public GameObject clusterPrefab;

     //عدد الثواني التي ستعيشها كل شظية قبل تدميرها وحذفها من المشهد
    public float clusterLife = 4.0f;

    //كم عدد الشظايا التي ستنتج من هذا المقذوف
    public int clusterCount = 3;

	   //تستدعى مرة واحدة عند بداية التشغيل
	   void Start () {
	
	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
	
	   }

    //وبناء عليها تنفذ الهجوم الانشطاري DoSpecialAttack تعمل على استقبال الرسالة
    public void DoSpecialAttack()
    {
        //اجلب السرعة الحالية للمقذوف الأصلي
        Rigidbody2D myRB = GetComponent&lt;Rigidbody2D&gt;();
        float originalVelocity = myRB.velocity.magnitude;

        //قم بتخزين جميع مكوّنات التصادم الخاصة بالشظايا في هذه المصفوفة
        Collider2D[] colliders = new Collider2D[clusterCount];
        Collider2D myCollider = GetComponent&lt;Collider2D&gt;();

        for (int i = 0; i &lt; clusterCount; i++)
        {
            //قم بإنشاء شظية جديدة
            GameObject cluster = (GameObject)Instantiate(clusterPrefab);
            //قم بضبط الموقع والاسم والأب لكائن الشظية
            cluster.transform.parent = transform.parent;
            cluster.name = name + "_cluster_" + i;
            cluster.transform.position = transform.position;
            //قم بتخزين مكوّن تصادم الشظية في الموقع الحالي في المصفوفة
            colliders[i] = cluster.GetComponent&lt;Collider2D&gt;();
            //أهمل التصادم الذي يمكن أن يحص بين هذه الشظية والشظايا التي تم إنشاؤها قبلها
            //إضافة إلى التصادم الذي يمكن أن يقع بين الشظية والكائن الأصلي
            Physics2D.IgnoreCollision(colliders[i], myCollider);
            for (int a = 0; a &lt; i; a++)
            {
               Physics2D.IgnoreCollision(colliders[i], colliders[a]);
            }
            
            Vector2 clusterVelocity;
            //مع كل شظية جديدة نقوم بتقليل مركبة السرعة أفقيا وزيادتها عموديا من أجل ضمان تشتت الشظايا
            clusterVelocity.x = (originalVelocity / clusterCount) * (clusterCount - i);
            clusterVelocity.y = (originalVelocity / clusterCount) * -i;
            
            //اجلب كائن الجسم الصلب للشظية الجديدة
            Rigidbody2D clusterRB = cluster.GetComponent&lt;Rigidbody2D&gt;();
            clusterRB.velocity = clusterVelocity;
            //قم بتحديد كتلة الشظية لتساوي كتلة الكائن الأصلي
            clusterRB.mass = myRB.mass;
            //قم بتدمير الشظية بعد انقضاء العمر المحدد لها
            Destroy(cluster, clusterLife);
        }

        //قم أخيرا بتدمير كائن المقذوف الأصلي
        Destroy(gameObject);
    }
}
</pre><p dir="rtl">فكرة عمل هذا الهجوم تقوم على استقبال الرسالة <span style="font-family:courier new,courier,monospace;">DoSpecialAttack</span> ومن ثم إنشاء العدد المحدد من الشظايا باستخدام القالب المحدد لها. من أجل منع التصادم بين الشظايا وبعضها وأيضا بين الشظايا والمقذوف الأصلي - حيث من الممكن حدوث تصادم في اللحظة التي تسبق حذفه من المشهد – نقوم باستخدام الدّالة <span style="font-family:courier new,courier,monospace;">()Physics2D.IgnoreCollision</span> ونزودها بمكوّني التصادم اللذين نرغب بإهمال التصادمات بينها. لاحظ أننا عرفنا مصفوفة من مكوّنات التصادم من أجل تخزين مكوّنات جميع الشظايا، وعند إنشاء شظية جديدة نمر على مكوّنات تصادم الشظايا السابقة ونستدعي الدّالة المذكورة بين المكوّنين القديم والجديد من أجل إهمال التصادمات. الخطوة التالية تتعلق بسرعة حركة الشظية، حيث نأخذ مقدار سرعة المقذوف الأصلي ونضربه كل مرة بقيمة مختلفة لنحصل على المركّبتين الأفقية والعمودية للسرعة الجديدة. هاتان المركبتان تتغيران من شظية لأخرى، حيث تبدأ الشظية الأولى بمركبة أفقية عالية وعمودية منخفضة، ومن ثم تبدأ هذه القيم بالتغير حيث تزداد القيمة العمودية نحو الأسفل تدريجيا وتقل الأفقية، مما ينتج عنه تشتت المقذوفات بطريقة تشبه ما تراه في الصورة أدناه (قمت في هذه الصورة بزيادة عدد الشظايا لتوضيح الفكرة):</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/3.png.92d38ebfb32160a6ceb1bc2530c1ed61.png"><img data-fileid="3693" class="ipsImage ipsImage_thumbnailed" alt="3.thumb.png.f97547a34356979121c07a05c10f" src="https://academy.hsoub.com/uploads/monthly_2015_08/3.thumb.png.f97547a34356979121c07a05c10f4405.png"></a></p><p dir="rtl">لاحظ أن الشظايا تنتشر مبتعدة عن بعضها انطلاقا من موقع انشطار المقذوف الأصلي. بعد ذلك نقوم بضبط كتلة كل شظية لتصبح مساوية لكتلة المقذوف الأصلي. صحيح أنه من المنطقي أن نقوم بقسمة الكتلة على عدد الشظايا من أجل توزيعها بشكل متساو، إلا أن نسخ الكتلة الأصلية لجميع الشظايا سيعطيها قوة تدمير أكبر مما يمنح الهجوم الخاص أفضليته المرجوة.</p><h2 dir="rtl">صناعة قاذف الإطلاق</h2><p dir="rtl">لننتقل الآن إلى القاذف وهو المقلاع الذي سيطلق هذه المقذوفات نحو أهدافها. للأسف فإن حزمة الرسومات التي بين أيدينا لا تحتوي على صورة مقلاع، لذا سنحاول استخدام بعض الأشكال الخشبية والمعدنية لصنع شكل بسيط يشبهه. سأستخدم هنا 3 مستطيلات خشبية ومثلثا حجريا لصنع الشكل الذي تراه في الصورة التالية. هذه الكائنات يجب أن توضع كأبناء لكائن فارغ واحد يحتويها جميعا، ويجب أيضا تعديل قيمة <span style="font-family:courier new,courier,monospace;">Order in Layer</span> في مكوّن <span style="font-family:courier new,courier,monospace;">Sprite Renderer</span> الخاص بالمثلث وجعلها 1، وذلك حتى يظهر أمام القطع الخشبية كما هو موضح في الصورة:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/4.png.efc30c42d4c07ec0c41d1f2dba097833.png"><img data-fileid="3694" class="ipsImage ipsImage_thumbnailed" alt="4.thumb.png.72ea5a95f8b65375d3391af49176" src="https://academy.hsoub.com/uploads/monthly_2015_08/4.thumb.png.72ea5a95f8b65375d3391af49176f2ab.png"></a></p><p dir="rtl">إضافة للصور الأربعة التي قمنا بتحجيمها وتدويرها لصنع المقلاع، هناك 3 كائنات فارغة تشير الخطوط الملونة إلى مواقعها. هذه الكائنات الفارغة ذات فائدة برمجية سنراها بعد قليل. حيث يمثل الكائن <span style="font-family:courier new,courier,monospace;">LaunchPos</span> مكان وضع المقذوف قبل إطلاقه، ويمثل الكائنان <span style="font-family:courier new,courier,monospace;">RightEnd</span> و <span style="font-family:courier new,courier,monospace;">LeftEnd</span> موقعي طرفي الشريط المطاطي الذي سيدفع المقذوفات حين إطلاقها. المقلاع بشكله الحالي جاهز لصنع النسخة الأولية من القالب، والتي سنقوم بإضافة بعض البريمجات والمكوّنات الأخرى إليها.</p><p dir="rtl">أول هذه البريمجات هو البريمج الرئيسي الذي يعمل على إطلاق المقذوفات على الأهداف. لنتعرف على هذا البريمج المسمى <span style="font-family:courier new,courier,monospace;">Launcher</span> في السرد التالي ومن ثم نناقش تفاصيل وظائفه:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class Launcher : MonoBehaviour {

     //معامل قوة الإطلاق الخاصة بهذا القاذف
     public float launchForce = 1.0f;
    
     //أقصى طول يمكن لحبل القاذف المطاطي أن يمتد إليه
    public float maxStretch = 1.0f;

    //الموقع الذي سيتم وضع المقذوف الحالي فيه قبل أن يمسكه اللاعب
    public Transform launchPosition;

    //المقذوف الحالي الموضوع على القاذف
    public Projectile currentProjectile;

    //هل تم إطلاق جميع المقذوفات الموجودة في المشهد؟
    private bool projectilesConsumed = false;

	   //تستدعى مر واحدة عند بداية التشغيل
	   void Start () {

	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
        if (projectilesConsumed)
        {
            //لا يوجد ما يمكن فعله
            return;
        }

        if (currentProjectile != null)
        {
		    //إن لم يكن المقذوف الحال قد تم إطلاقه ولم يتم أيضا إمساكه من قبل اللاعب
		    //فقم حينها بجلب المقذوف إلى الموقع المخصص للإطلاق
            if (!currentProjectile.IsHeld() &amp;&amp; !currentProjectile.IsLaunched())
            {
                BringCurrentProjectile();
            }
        }
        else
        {
		    //لا يوجد أي مقذوف حاليا على القاذف
		    //قم بالبحث عن أقرب مقذوف وإحضاره لموقع الإطلاق
            currentProjectile = GetNearestProjectile();
            if (currentProjectile == null)
            {
			//تم استهلاك كل المقذوفات، أرسل رسالة تخبر بذلك
                projectilesConsumed = true;
                SendMessageUpwards("ProjectilesConsumed");
            }
        }
	   }

    //تقوم بالبحث عن أقرب مقذوف للقاذف وإرجاعه
    Projectile GetNearestProjectile()
    {
        Projectile[] allProjectiles = FindObjectsOfType&lt;Projectile&gt;();
        
        if (allProjectiles.Length == 0)
        {
            //لم يعد هناك أي مقذوفات
            return null;
        }

        //قم بالبحث عن أقرب مقذوف وإرجاعه
        Projectile nearest = allProjectiles[0];
        float minDist = Vector2.Distance(nearest.transform.position, transform.position);

        for (int i = 1; i &lt; allProjectiles.Length; i++)
        {
         float dist = Vector2.Distance(allProjectiles[i].transform.position, transform.position);
            if (dist &lt; minDist)
            {
                minDist = dist;
                nearest = allProjectiles[i];
            }
        }

        return nearest;
    }

    //تقوم بتحريك المقذوف الحالي خطوة واحدة وبشكل سلس نحو موقع الإطلاق
    void BringCurrentProjectile()
    {
        //اجلب المواقع التي سيتحرك المقذوف بينها
        Vector2 projectilePos = currentProjectile.transform.position;
        Vector2 launcherPos = launchPosition.transform.position;

        if (projectilePos == launcherPos)
        {
            //المقذوف في موقع الإطلاق فعلا، لا داعي لتحريكه
            return;
        }
	       //استخدم الاستيفاء الخطي مع الوقت المنقضي بين الإطارات من أجل الحركة السلسة
        projectilePos = Vector2.Lerp(projectilePos, launcherPos, Time.deltaTime * 5.0f);
        //ضع المقذوف في موقعه الجديد
        currentProjectile.transform.position = projectilePos;

        if (Vector2.Distance(launcherPos, projectilePos) &lt; 0.1f)
        {
	     //المقذوف أصبح قريبا جدا، ضعه مباشرة في موقع الإطلاق
            currentProjectile.transform.position = launcherPos;
            currentProjectile.AllowControl();
        }
    }

    //تقوم بإمساك المقذوف الحالي
    public void HoldProjectile()
    {
        if (currentProjectile != null)
        {
            currentProjectile.Hold();
        }
    }

    //تقوم بسحب المقذوف الحالي لموقع جديد
    public void DragProjectile(Vector2 newPosition)
    {
        
        if (currentProjectile != null)
        {
            //تأكد من عدم تجاوز الحد الأقصى لشد الحبل المطاطي
            float currentDist = Vector2.Distance(newPosition, launchPosition.position);
            
            if (currentDist &gt; maxStretch)
            {
                //قم بتغيير الموقع المزود إلى أبعد نقطة مسموح بها على امتداده
                float lerpAmount = maxStretch / currentDist;
                newPosition = Vector2.Lerp(launchPosition.position, newPosition, lerpAmount);
            }

            //ضع المقذوف في الموقع الجديد
            currentProjectile.Drag(newPosition);
        }
                
    }

    //تقوم بإفلات المقذوف الحالي وإطلاقه إذا كان اللاعب يمسكه
    public void ReleaseProjectile()
    {
        if (currentProjectile != null)
        {
            currentProjectile.Launch(launchForce);
        }
    }
}
</pre><p dir="rtl">المتغيرات العامّة في هذا البريمج هي <span style="font-family:courier new,courier,monospace;">launchForce</span> والذي يمثل قوة الإطلاق و <span style="font-family:courier new,courier,monospace;">maxStretch</span> وهو أقصى مسافة مسموح بها بين المقذوف وموقع الإطلاق أثناء الشد (أي أقصى امتداد للخيط المطاطي) و <span style="font-family:courier new,courier,monospace;">launchPosition</span> وهو متغير لتخزين كائن موقع الإطلاق المسمى <span style="font-family:courier new,courier,monospace;">LaunchPos</span> الذي سبق وأضفناه لقالب المقلاع حين قمنا بإنشائه. أخيرا لدينا مرجع للمقذوف الحالي الموجود على القاذف وهو <span style="font-family:courier new,courier,monospace;">currentProjectile</span>.</p><p dir="rtl">في كل دورة تحديث تقوم الدّالة <span style="font-family:courier new,courier,monospace;">()Update</span> بفحص ما إذا كان هناك مقذوف حالي أم لا، وفي حالة عدم وجوده فإنها تقوم باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()GetNearestProjectile</span> والتي تبحث عن أقرب المقذوفات للقاذف وتقوم بإرجاعه. إذا لم تجد هذه الدّالة أية مقذوفات في المشهد فإنها تعيد القيمة null وفي هذه الحالة يقوم البريمج بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectilesConsumed</span> نحو أعلى هرمية المشهد من أجل إبلاغ البريمجات التي تتحكم بحالة اللعبة بأن اللاعب قد استنفد جميع مقذوفاته في هذه المرحلة. حين استنفاد جميع المقذوفات يتم تغيير قيمة المتغير <span style="font-family:courier new,courier,monospace;">projectilesConsumed</span> إلى <span style="font-family:courier new,courier,monospace;">true</span> مما يعني أنّ الدّالة <span style="font-family:courier new,courier,monospace;">()Update</span> لن تقوم بعمل أي شيء بعد الآن. أمّا في حالة وجود مقذوف حالي لم يقم اللاعب بإمساكه أو إطلاقه بعد، فإن <span style="font-family:courier new,courier,monospace;">()Update</span> تقوم باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()BringCurrentProjectile</span> والتي تعمل على تحريك المقذوف الحالي نحو موقع الإطلاق بشكل سلس (تذكر أن الموقع الأصلي للمقذوفات هو على الأرض بجانب المقلاع). عند وصول المقذوف للموقع <span style="font-family:courier new,courier,monospace;">launchPosition</span> فإنّ هذه الدّالة ستتوقف تلقائيا عن تحريكه حتى لو استمر استدعاؤها من قبل<span style="font-family:courier new,courier,monospace;"> ()Update</span>.</p><p dir="rtl">سأتحدث هنا بقليل من التفصل عن الدّالة <span style="font-family:courier new,courier,monospace;">()BringCurrentProjectile</span> حتى أشرح الآلية التي تستخدمها من أجل تحقيق الحركة السلسة للمقذوف من موقعه الحالي باتجاه موقع الإطلاق. الحركة السلسة في محركات الألعاب تعتمد على عامل الزمن المنقضي بين كل إطارين متتابعين، وهو في Unity المتغير <span style="font-family:courier new,courier,monospace;">Time.deltaTime</span>. إضافة لهذا المتغير سنحتاج لدّالة تحسب الاستيفاء الخطي Linear Interpolation بين قيمتين مختلفتين. لكن ما هو الاستيفاء الخطي؟ هو ببساطة عبارة عن قيمة محصورة بين حدين أسفل وأعلى. هذه القيمة قد تكون رقما مجردا بين رقمين، أو موقعا بين موقعين، أو لونا بين لونين، إلخ. لكن أين تقع هذه القيمة بالتحديد بين الحدين؟ ما يحدد هذا الموقع هو قيمة الاستيفاء، وهي قيمة كسرية بين الصفر والواحد، فكلما زادت القيمة كان الناتج أقرب للحد الأعلى، وكلما قلت كان الناتج أقرب للحد الأدنى وهكذا. فمثلا لو أردنا حساب الاستيفاء بين العددين صفر و 10، وكانت قيمة الاستيفاء هي 0.6، فإن الناتج سيكون العدد 6، وإذا كانت قيمة الاستيفاء 0.45 فإنّ الناتج سيكون العدد 4.5 وهكذا.</p><p dir="rtl">نقوم بحساب الموقع الجديد للمقذوف أثناء سيره باتجاه موقع الإطلاق مستخدمين هذه التقنية، وفي هذه الحالة فإن الاستيفاء يتم بين الحد الأدنى وهو الموقع الحالي للمقذوف <span style="font-family:courier new,courier,monospace;">projectilePos</span> والحد الأقصى أي الهدف الذي نرغب بالوصول إليه وهو موقع الإطلاق <span style="font-family:courier new,courier,monospace;">launcherPos</span>. قيمة الاستيفاء قليلة نسبيا أي أنها أقرب للهدف وهي عبارة عن الوقت المنقضي منذ تصيير الإطار السابق مضروبا في 5. أهمية استخدام قيمة الوقت هنا تكمن في حقيقة أن الإطارات لا يتم تصييرها جميعا بنفس السرعة، فهناك عوامل عديدة تؤثر في سرعة الأداء بالتالي فإن الزمن بين الإطارات ليس ثابتا وقد يزيد وينقص. بالتالي وللحفاظ على سرعة حركة ثابتة علينا أن نضرب بقيمة الوقت والتي تزيد كلما قل عدد الإطارات في الثانية الواحدة وتقل بالعكس، مما يجعل سرعة الحركة التي يراها اللاعب ثابتة بغض النظر زاد عدد الإطارات في الثانية أم قل.</p><p dir="rtl">الدّوال الثلاث <span style="font-family:courier new,courier,monospace;">()HoldProjectile</span> و <span style="font-family:courier new,courier,monospace;">()DragProjectile</span> و <span style="font-family:courier new,courier,monospace;">()ReleaseProjectile</span> تقوم باستدعاء دوال الإمساك <span style="font-family:courier new,courier,monospace;">()Hold</span> و التحريك <span style="font-family:courier new,courier,monospace;">()Drag</span> و الإطلاق <span style="font-family:courier new,courier,monospace;">()Launch</span> للمقذوف الحالي <span style="font-family:courier new,courier,monospace;">currentProjectile</span>. الدّالة التي تحتاج لبعض الشرح هنا هي <span style="font-family:courier new,courier,monospace;">()DragProjectile</span> وذلك لأنها تحتوي على خطوة إضافية غير موجودة في البريمج <span style="font-family:courier new,courier,monospace;">Projectile</span>، ألا وهي التحقق من كون بعد المقذوف عن موقع الإطلاق الأولي أثناء سحبه للخلف لا يتجاوز الطول المسموح به لتمدد الحبل المطاطي للمقلاع. هذا التمدد معرّف في المتغير <span style="font-family:courier new,courier,monospace;">maxStretch</span>. الطريقة التي سنعتمدها لفرض هذا الحد الأقصى للطول يجب أن تراعي سهولة التحكم أيضا، فلو سحب اللاعب المؤشر أبعد من الطول المسموح يجب ألا ينسحب معه المقذوف، إلا أنه في نفس الوقت يجب أن يبقى قادرا على تغيير زاوية الإطلاق. من أجل تحقيق هذه الآلية سنستخدم الاستيفاء الخطي مرة أخرى وهذا الاستخدام موضح في السطرين 131 و 132.</p><p dir="rtl">الفكرة هي أن نحسب المسافة بين موقع الإطلاق والموقع الحالي للمؤشر <span style="font-family:courier new,courier,monospace;">currentDist</span> ومقارنته بالحد الأقصى للتمدد وهو <span style="font-family:courier new,courier,monospace;">maxStretch</span>. فإذا تجاوزت هذه المسافة الحد المسموح، سنقوم بقسمة <span style="font-family:courier new,courier,monospace;">maxStretch</span> على <span style="font-family:courier new,courier,monospace;">currentDist</span>، وبالتالي نحصل على نسبة الاستيفاء اللازمة بين موقع الإطلاق الأصلي <span style="font-family:courier new,courier,monospace;">launchPosition.position</span> و الموقع الحالي للمؤشر <span style="font-family:courier new,courier,monospace;">newPosition</span>. بطبيعة الحال ستقل هذه القيمة بزيادة بعد المؤشر عن موقع الإطلاق، وبالتالي تحافظ على مسافة ثابتة عن موقع الإطلاق وهي المسافة التي تساوي <span style="font-family:courier new,courier,monospace;">maxStretch</span>. وبتنفيذ الاستيفاء نحصل على الموقع الجديد الصحيح newPosition دون أن نؤثر على سلاسة الحركة، ومن ثم نستخدم الدّالة <span style="font-family:courier new,courier,monospace;">()Drag</span> لتحريك المقذوف. من الضروري استخدام هذه الدّالة وليس تحريك المقذوف مباشرة وذلك لأنها تتحقق من الشروط من حيث كون المقذوف ممسوكا من قبل اللاعب ولم يتم إطلاقه، وهي شروط الحركة حسب قواعد اللعبة.</p><p dir="rtl">بعد الانتهاء من كتابة البريمج علينا أن نضيفه إلى الكائن الفارغ <span style="font-family:courier new,courier,monospace;">Launcher</span> وهو الجذر لكل كائنات القطع التي يتكون منها المقلاع. البريمج التالي الذي سنضيفه سيقوم برسم الحبل المطاطي بين طرفي المقلاع والمقذوف. لكن قبل الانتقال للبريمج علينا أن نضيف المكوّن المسؤول عن رسم الخط الذي سيمثل هذا الحبل. المكوّن الذي سنضيفه يسمى <span style="font-family:courier new,courier,monospace;">Line Renderer</span> ويمكن إضافته كالعادة من الزر <span style="font-family:courier new,courier,monospace;">Add Component</span> ومن ثم كتابة اسم المكوّن كما في الصورة التالية. يقوم هذا المكوّن برسم خط متصل بين مجموعة من النقاط المحددة له عبر المصفوفة <span style="font-family:courier new,courier,monospace;">positions</span> مبتدئا بأول نقطة في المصفوفة إلى آخر نقطة:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/5.png.5c9f6bcdd77bd6912e1fadcc978ed401.png"><img data-fileid="3695" class="ipsImage ipsImage_thumbnailed" alt="5.thumb.png.b98b41da7f54df036bf610ff2af7" src="https://academy.hsoub.com/uploads/monthly_2015_08/5.thumb.png.b98b41da7f54df036bf610ff2af7fea7.png"></a></p><p dir="rtl">بعد إضافة المكوّن علينا أن نعدل بعض قيمه: فأولا علينا تغيير عدد النقاط التي ترسم الخط positions إلى 3 ومن ثم نجعله أقل سماكة عن طريق تغيير كل من <span style="font-family:courier new,courier,monospace;">Start Width</span> و <span style="font-family:courier new,courier,monospace;">End Width</span> إلى 0.1، وأخيرا سنقوم بتغيير لونه للأحمر عند بدايته ونهايته (يمكنك بالطبع اختيار أي لون آخر). هذه الإعدادات موضحة في الصورة التالية:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/6.png.043a85719aa87d0150b900b33d82ffa1.png"><img data-fileid="3696" class="ipsImage ipsImage_thumbnailed" alt="6.thumb.png.84e116f8753aabc20d1293209ed4" src="https://academy.hsoub.com/uploads/monthly_2015_08/6.thumb.png.84e116f8753aabc20d1293209ed40d13.png"></a></p><p dir="rtl">لننتقل الآن للبريمج <span style="font-family:courier new,courier,monospace;">LauncherRope </span>وهو المسؤول عن رسم هذا الخط بين طرفي المقلاع والمقذوف. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class LauncherRope : MonoBehaviour {

     //موقع الطرف الأيسر للحبل
     public Transform leftEnd;

     //موقع الطرف الأيمن للحبل
    public Transform rightEnd;

    //مرجع لبريمج القاذف
    Launcher launcher;

    //مرجع لمكوّن تصيير الخط المضاف للكائن
    LineRenderer line;

	   //تستدعى مرة عند بداية التشغيل
	   void Start () {
        launcher = GetComponent&lt;Launcher&gt;();
        line = GetComponent&lt;LineRenderer&gt;();
	       //قم بإخفاء الخط في البداية بتعطيل مكوّنه
        line.enabled = false;
	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
        //أظهر الخط فقط في حال كان المقذوف ممسوكا من قبل اللاعب
        if (launcher.currentProjectile != null &amp;&amp;
            launcher.currentProjectile.IsHeld())
        {
            if (!line.enabled)
            {
                line.enabled = true;
            }
            //قم برسم الخط ابتداء من الطرف الأيسر فالمقذوف فالطرف الأيمن
            line.SetPosition(0, leftEnd.position);
            line.SetPosition(1, launcher.currentProjectile.transform.position);
            line.SetPosition(2, rightEnd.position);
        }
        else
        {
            line.enabled = false;
        }
	   }
}
</pre><p dir="rtl">يمكنك أن تلاحظ مدى بساطة هذا البريمج، فكل ما يقوم به هو تعطيل مكوّن رسم الخط في البداية، ومن ثم يقوم بفحص حالة المقذوف الحالي (إن وُجد). في حال كان هذا المقذوف ممسوكا من قبل اللاعب يتم تفعيل المكوّن <span style="font-family:courier new,courier,monospace;">LineRenderer</span> مما يجعل الخط مرئيا، ومن ثم يقوم بضبط مواقع رسم الخط. تذكر الكائنين الفارغين اللذين أضفناهما كإبنين للمقلاع وهما <span style="font-family:courier new,courier,monospace;">RightEnd</span> و <span style="font-family:courier new,courier,monospace;">LeftEnd</span>. سنستخدم المرجعين <span style="font-family:courier new,courier,monospace;">leftEnd</span> و <span style="font-family:courier new,courier,monospace;">rightEnd</span> المعرّفين في البريمج ونربطهما عن طريق المستعرض بهذين الكائنين. بالتالي فإننا نكون قد حددنا موقع النقطة الأولى والأخيرة للخط المرسوم. بقي أن نحدد موقع النقطة الوسطى وهي بطبيعة الحال موقع المقذوف. لاحظ أننا نستخدم الدّالة <span style="font-family:courier new,courier,monospace;">()SetPosition</span> ونعطيها ترتيب الموقع في المصفوفة متبوعا بالنقطة التي نريد أن يكون فيها هذا الموقع. عند تشغيل اللعبة وإمساك المقذوف سيظهر هذا الخط بالشكل التالي:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/7.png.598101291a57229c77200380f0e7bf75.png"><img data-fileid="3697" class="ipsImage ipsImage_thumbnailed" alt="7.thumb.png.2f4a42754b44c612b1ce10142ffa" src="https://academy.hsoub.com/uploads/monthly_2015_08/7.thumb.png.2f4a42754b44c612b1ce10142ffa2ea9.png"></a></p><p dir="rtl">بهذا تكون مهام مقلاع القذف المطلوبة قد اكتملت، وبقي علينا أن نضيف بريمجا لقراءة مدخلات اللاعب بحيث يتمكن من استخدام الفأرة من أجل إطلاق المقذوفات. هذا البريمج يسمى <span style="font-family:courier new,courier,monospace;">LauncherMouseInput</span> ومهمته قراءة مدخلات الفأرة من اللاعب وتحويلها لأوامر للبريمج <span style="font-family:courier new,courier,monospace;">Launcher</span>. السرد التالي يوضح هذا البريمج:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class LauncherMouseInput : MonoBehaviour {

     //مرجع لبريمج الإطلاق
     private Launcher launcher;

	   //تستدعى مرة واحدة عند بداية التشغيل
	   void Start () {
        launcher = GetComponent&lt;Launcher&gt;();
	   }
	
	   //تستدعى مرة عند تصيير كل إطار
	   void Update () {
        CheckButtonDown();
        CheckDragging();
        CheckButtonUp();
	   }

    void CheckButtonDown()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //تم ضغط زر الفأرة الأيسر للتو
            //هل يوجد مقذوف حالي؟
            if (launcher.currentProjectile != null)
            {
                //قم بتحويل موقع المؤشر من إحداثيات الشاشة إلى إحداثيات فضاء المشهد
                Vector2 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                //قم باستخراج مكوّن التصادم من الكائن
                Collider2D projectileCol = launcher.currentProjectile.GetComponent&lt;Collider2D&gt;();
                //هل يقع مؤشر الفأرة ضمن حدود مكوّن التصادم الخاص بالمقذوف؟
                if (projectileCol.bounds.Contains(mouseWorldPos))
                {
                    //نعم، أي أنه تم ضغط زر الفأرة فوق المقذوف
                    //قم بإمساك المقذوف
                    launcher.HoldProjectile();
                }
            }
        }
    }

    //تقوم بفحص ما إذا كان اللاعب يسحب الفأرة مستخدما الزر الأيسر
    void CheckDragging()
    {
        if (Input.GetMouseButton(0))
        {
            Vector2 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            launcher.DragProjectile(mouseWorldPos);
        }
    }

    //تفحص ما إذا كان قد تم رفع الضغط عن زر الفأرة الأيسر
    void CheckButtonUp()
    {
        if (Input.GetMouseButtonUp(0))
        {
            //تم رفع الضغط عن الزر الأيسر
            //قم بإطلاق المقذوف
            launcher.ReleaseProjectile();
        }
    }
}
</pre><p dir="rtl">تقوم دالّة التحديث <span style="font-family:courier new,courier,monospace;">()Update</span> في هذا البريمج باستدعاء ثلاث دوال أخرى على الترتيب وهي <span style="font-family:courier new,courier,monospace;">()CheckButtonDown</span> ثم <span style="font-family:courier new,courier,monospace;">()CheckDragging</span> ثم <span style="font-family:courier new,courier,monospace;">()CheckButtonUp</span>. في الدّالة <span style="font-family:courier new,courier,monospace;">()CheckButtonDown</span> يتم التأكد أولا من وجود مقذوف على المقلاع، فإن وُجد هذا المقذوف يتم تحويل موقع مؤشر الفأرة من إحداثيات الشاشة إلى إحداثيات المشهد، ومن ثم فحص ما إذا كان هذا الموقع يقع ضمن حدود مكوّن التصادم الخاص بالمقذوف. تحقق هذا الشرط معناه أن اللاعب قد ضغط بزر الفأرة الأيسر على المقذوف وبالتالي فإنه أمسكه، لذا يتم استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()Hold</span> من البريمج <span style="font-family:courier new,courier,monospace;">Launcher</span>. في الدّالة <span style="font-family:courier new,courier,monospace;">()CheckDragging</span> يتم التحقق من بقاء زر الفأرة الأيسر مضغوطا، وفي هذه الحالة يتم تحريك المقذوف إلى موقع المؤشر عبر استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()DragProjectile</span>. تذكر أنّ هذه الدّالة تمنع تجاوز المقذوف للحد الأقصى لتمدد الحبل المطاطي، بالتالي وبغض النظر عن موقع المؤشر سيبقى المقذوف ضمن هذا الحد. أخيرا فإنّ الدّالة <span style="font-family:courier new,courier,monospace;">()CheckButtonUp</span> تقوم بفحص ما إذا أفلت اللاعب زر الفأرة الأيسر، وفي هذه الحالة تستدعي الدّالة <span style="font-family:courier new,courier,monospace;">()ReleaseProjectile </span>من بريمج القاذف حتى يتم إطلاق المقذوف. الشكل التالي يمثل المكوّنات النهائية لقالب مقلاع الإطلاق:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/8.png.1144526f1efb718d4afaa473fa0fb460.png"><img data-fileid="3698" class="ipsImage ipsImage_thumbnailed" alt="8.thumb.png.fc8ab33ea296b12138c5f185f296" src="https://academy.hsoub.com/uploads/monthly_2015_08/8.thumb.png.fc8ab33ea296b12138c5f185f296d448.png"></a></p><p dir="rtl">حسنا، لدينا الآن خلفية وأرضية ووحدات بنائية وخصوم وقاذف ومقذوفات، أي أن جميع عناصر اللعبة باتت جاهزة، ويمكننا أن نجرب بناء مشهد واللعب به. الصورة التالية توضح المرحلة المتقدمة التي وصلنا لها بعد هذا الجهد المضني!</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/9.png.f59f2872ad7633ea56832b1b2e4421f0.png"><img data-fileid="3699" class="ipsImage ipsImage_thumbnailed" alt="9.thumb.png.53867a52b3ba4577b32c0f54dbcc" src="https://academy.hsoub.com/uploads/monthly_2015_08/9.thumb.png.53867a52b3ba4577b32c0f54dbcc929e.png"></a></p>
]]></description><guid isPermaLink="false">141</guid><pubDate>Sun, 09 Aug 2015 19:52:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x648;&#x627;&#x62C;&#x647;&#x629; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x648;&#x623;&#x648;&#x636;&#x627;&#x639; &#x627;&#x644;&#x644;&#x639;&#x628;&#x629; (modes) &#x641;&#x64A; Unity3d</title><link>https://academy.hsoub.com/programming/game-development/%D8%A8%D9%86%D8%A7%D8%A1-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%88%D8%A3%D9%88%D8%B6%D8%A7%D8%B9-%D8%A7%D9%84%D9%84%D8%B9%D8%A8%D8%A9-modes-%D9%81%D9%8A-unity3d-r140/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d-4.png.1518cceb4d127f9f9984b730dd95b426.png" /></p>

<p dir="rtl">بعد أن <a href="https://academy.hsoub.com/programming/general/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%B5%D9%88%D9%85-%D9%81%D9%8A-unity3d-r134/">انتهينا من الكائنات والقوالب اللازمة للعبة</a>، سنقوم بإضافة مشهد جديد للمشروع من أجل صنع القائمة الرئيسية، ومن ثم سنقوم بإضافة بعض النوافذ والأزرار التي تسمح للاعب بالتنقل بين اللعبة والقائمة الرئيسية.</p><p dir="rtl"><strong style="line-height: 22.3999996185303px;">ملاحظة</strong><span style="line-height: 22.3999996185303px;">: يمكن تحميل الملفات المصدرية لكامل هذه السلسلة عبر </span><a rel="external nofollow" style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/tree/master/AngryAnimals%20Game">حساب أكاديمية حسوب على Github</a><span style="line-height: 22.3999996185303px;">، يمكن أيضا تحميل </span><a rel="external nofollow" style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/releases/tag/v0.1.0">ملف APK لتجريب اللعبة على أجهزة Android</a><span style="line-height: 22.3999996185303px;">.</span></p><h2 dir="rtl">بناء الشاشة الرئيسية والواجهة</h2><p dir="rtl">لإضافة مشهد جديد اضغط <span style="font-family:courier new,courier,monospace;">Control+N</span> ومن ثم قم بحفظ هذا المشهد باسم <span style="font-family:courier new,courier,monospace;">MenuScene</span>. آلية التنقل بين المشاهد في محرك Unity تعتمد على رقم كل مشهد في ترتيب بناء اللعبة. هذا الترتيب يمكن الوصول إليه عن طريق القائمة:</p><p dir="rtl" style="text-align: center;"><strong> File &gt; Build Settings </strong></p><p dir="rtl">النافذة التي ستظهر هي المسؤولة عن ترتيب المراحل في اللعبة وتصديرها. ما يهمنا الآن هو الترتيب. قم بسحب المشهدين <span style="font-family:courier new,courier,monospace;">MenuScene</span> و <span style="font-family:courier new,courier,monospace;">GameScene</span> من مستعرض المشروع إلى القائمة <span style="font-family:courier new,courier,monospace;">Scenes in Build</span> كما ترى في الصورة التالية. من المهم هنا مراعاة الترتيب حيث يأخذ المشهد <span style="font-family:courier new,courier,monospace;">MenuScene</span> الرقم 0 والمشهد <span style="font-family:courier new,courier,monospace;">GameScene</span> الرقم 1.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image00.png.1f55ce05bea9654729b60bd0a689c510.png"><img data-fileid="3642" class="ipsImage ipsImage_thumbnailed" alt="image00.thumb.png.40b179f3490dd4f8ef84cd" src="https://academy.hsoub.com/uploads/monthly_2015_08/image00.thumb.png.40b179f3490dd4f8ef84cd57d2aaf1ce.png"></a></p><p dir="rtl">بعد إضافة المشاهد قم بإغلاق النافذة حيث سيتم الحفظ تلقائيا. بعد ذلك سنقوم ببناء القائمة الرئيسية للعبة، والتي ستحتوي على زرين هما "ابدأ اللعب" و "خروج". الأول سيعرض للاعب مجموعة من المراحل ليختار أحدها ليلعبها، والثاني سيخرج من البرنامج نهائيا. إضافة لذلك سنضيف نصا على الشاشة وهو اسم اللعبة وليكن "الحيوانات الغاضبة" مثلا. سنكرر هذا النص مرتين بحيث نضع نسخة أمام الأخرى ونصغرها ومن ثم نغير ألوانهما لدرجات مختلفة. هذا سيؤدي لأن يظهر النص الخلفي كأنه ظل. لنر الآن كيف تتم إضافة كائنات واجهة المستخدم في Unity.</p><p dir="rtl">عناصر واجهة المستخدم في محرك Unity تندرج تحت القائمة:</p><p dir="rtl" style="text-align: center;"> <strong>Game Object &gt; UI</strong></p><p dir="rtl">لنبدأ أولا بصورة خلفية للشاشة الرئيسية. هذه الخلفية تتم إضافتها عن طريق لوح:</p><p dir="rtl" style="text-align: center;"><strong>Game Object &gt; UI &gt; Panel</strong> </p><p dir="rtl">بعد أن تضيف هذا اللوح للمشهد، ستلاحظ أن Unity قد قام بإضافته كإبن لكائن جديد اسمه <span style="font-family:courier new,courier,monospace;">Canvas</span>، وقام أيضا بإضافة كائن آخر اسمه <span style="font-family:courier new,courier,monospace;">EventSystem</span>. هذان الكائنان جزء من الآلية المتبعة لبناء واجهة المستخدم، حيث يعتبر <span style="font-family:courier new,courier,monospace;">Canvas</span> الكائن الجذري لجميع كائنات الواجهة، ويقوم <span style="font-family:courier new,courier,monospace;">EventSystem</span> بتسهيل عملية استقبال مدخلات اللاعب على عناصر الواجهة بغض النظر عن نوع أداة التحكم التي يستخدمها. ما يهمنا الآن هو الكائن الذي أضفناه نحن وهو <span style="font-family:courier new,courier,monospace;">Panel</span> والذي ستلاحظ أنه تلقائيا قد ملأ إطار الواجهة كاملا. وأنه يحتوي على مكوّن من نوع <span style="font-family:courier new,courier,monospace;">Image</span> وهو عبارة عن صورة يتم عرضها على الواجهة.</p><p dir="rtl">قبل الخوض في خطوات بناء الواجهة لنتعرف معا على الآلية المستخدمة للإبقاء على عناصرها في أماكنها وأحجامها الصحيحة بغض النظر عن قياس الشاشة التي تعرض اللعبة عليها. المكوّن المسؤول عن هذه الآلية هو <span style="font-family:courier new,courier,monospace;">RectTransform</span> والذي ستراه في كائنات واجهة المستخدم بدلا من المكوّن <span style="font-family:courier new,courier,monospace;">Transform</span> الموجود في كائنات المشهد الأخرى. هذا المكوّن موضح في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image01.png.e9de857e2bd7069eb53369aa78b5cd0f.png"><img data-fileid="3643" class="ipsImage ipsImage_thumbnailed" alt="image01.thumb.png.d9ec46ca2888ce97062130" src="https://academy.hsoub.com/uploads/monthly_2015_08/image01.thumb.png.d9ec46ca2888ce97062130304e4ec7de.png"></a></p><p dir="rtl">أكثر ما يعنينا في هذا المكوّن هو متغيرا الحجم <span style="font-family:courier new,courier,monospace;">Scale</span> على المحورين <strong>x</strong> و <strong>y</strong>، إضافة إلى نوع وموقع نقطة الارتكاز لكل عنصر من عناصر واجهة المستخدم. لنتحدث بقليل من التفصيل عن طريقة الارتكاز التي عن طريقها يتم تحديد موقع العنصر على الشاشة ولنطّلع أولا على الصورة التالية التي تمثل الخيارات المتوفرة للارتكاز:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image02.png.a604ef3825debbb5771d9a3b0232d774.png"><img data-fileid="3644" class="ipsImage ipsImage_thumbnailed" alt="image02.thumb.png.3fcde25e0704816a5435a7" src="https://academy.hsoub.com/uploads/monthly_2015_08/image02.thumb.png.3fcde25e0704816a5435a70deacfb716.png"></a></p><p dir="rtl">أول ما يمكن ملاحظته هو إمكانية تحديد نوع الارتكاز بشكل مختلف أفقيا وعموديا، حيث يمكننا استخدام التمدد <span style="font-family:courier new,courier,monospace;">stretch</span> والذي يجعل العنصر مربوطا من زواياه الأربع وبالتالي يجب أن تبقى هذه الزوايا دائما في مواقعها بغض النظر عن حجم الشاشة. أما الخيارات الأخرى مثل <span style="font-family:courier new,courier,monospace;">left </span>،<span style="font-family:courier new,courier,monospace;">center </span>،<span style="font-family:courier new,courier,monospace;">right</span> أفقيا أو <span style="font-family:courier new,courier,monospace;">top </span>،<span style="font-family:courier new,courier,monospace;">middle </span>،<span style="font-family:courier new,courier,monospace;">bottom</span> عموديا، فهي تحدد نقطة ارتكاز العنصر بالنسبة للكائن الأب، فإذا حددت مثلا نقطة الارتكاز بأنها<span style="font-family:courier new,courier,monospace;"> middle center</span>، فإن العنصر سيحافظ على مسافة ثابتة من وسط الكائن الأب بغض النظر عن حجم هذا الأخير وحجم الشاشة. سنستخدم هذا الخيار عند إضافة أزرار القائمة الرئيسية كأبناء لكائن اللوح، وبذلك نضمن وجودها دائما في وسط الشاشة.</p><p dir="rtl">بالعودة لخلفية القائمة، قم بسحب إحدى صور الخلفية المتوفرة إلى الخانة <span style="font-family:courier new,courier,monospace;">Source Image</span> لتظهر هذه الصورة في خلفية الشاشة الرئيسية. افتراضيا سيقوم Unity بجعل كائن اللوح شفافا نسبيا مما يظهره بشكل معتم وهذا ما لا نريده. لنقم بإزالة هذه الشفافية عن طريق فتح لوح الألوان بالضغط على المستطيل الأبيض في الخانة Color، ومن ثم تحريك منزلق الشفافية A إلى أقصى اليمين كما ترى هنا:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image03.png.4b09680897bcc6acfa68f197726118a2.png"><img data-fileid="3645" class="ipsImage ipsImage_thumbnailed" alt="image03.thumb.png.e0653f833bfa19a2b6e969" src="https://academy.hsoub.com/uploads/monthly_2015_08/image03.thumb.png.e0653f833bfa19a2b6e96938519b4271.png"></a></p><p dir="rtl">بعد ذلك قم بتغيير اسم الكائن من <span style="font-family:courier new,courier,monospace;">Panel</span> إلى <span style="font-family:courier new,courier,monospace;">MainMenu</span>. سنضيف لهذا اللوح ثلاثة أبناء:</p><ul dir="rtl"><li>الأول هو ظل العنوان <span style="font-family:courier new,courier,monospace;">GameTitleShadow</span>.</li><li>الثاني والثالث هما الزران "ابدأ اللعب" NewGame و "خروج" Exit.</li></ul><p>لنبدأ أولا مع ظل العنوان: لماذا أضفت ظل العنوان قبل العنوان نفسه؟ السبب هو أن ترتيب تصيير عناصر واجهة المستخدم يقدّم تصيير الآباء على الأبناء. لذا سنضيف العنوان نفسه <span style="font-family:courier new,courier,monospace;">GameTitle</span> كابن لظل العنوان <span style="font-family:courier new,courier,monospace;">GameTitleShadow</span>. بعد ذلك قم بكتابة عنوان اللعبة "الحيوانات الغاضبة" داخل الخانة <span style="font-family:courier new,courier,monospace;">Text</span> لكل من الظل والابن، ومن ثم غير ألوانهما للأخضر بحيث يبدو الظل أفتح من العنوان نفسه. وأخيرا قم بتصغير العنوان قليلا حتى يظهر الظل من خلاله. (استخدمت خطا يسمى<strong> HACEN PROMOTER LT</strong> ويمكن تحميله مجانا من الموقع hacen.net). الشكل التالي يوضح الإعدادات الكاملة لنص العنوان وظله:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image04.png.5fb4c22361ed4f4709f1c0cac170ac35.png"><img data-fileid="3646" class="ipsImage ipsImage_thumbnailed" alt="image04.thumb.png.ca7c68bca5b4b49fa37301" src="https://academy.hsoub.com/uploads/monthly_2015_08/image04.thumb.png.ca7c68bca5b4b49fa3730135bd3839c8.png"></a></p><p dir="rtl">بالنسبة للنص العربي الذي يظهر مقطعا ومن اليسار لليمين: لا تقلق حيال هذا الأمر فالحل موجود وسهل وسنطبقه بعد قليل. أخيرا سيظهر شكل العنوان في الشاشة كما يلي:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image05.png.1a3a54efa42bd73cec9a8a5da9656cd5.png"><img data-fileid="3647" class="ipsImage ipsImage_thumbnailed" alt="image05.thumb.png.78b41b950eb530de1f13b0" src="https://academy.hsoub.com/uploads/monthly_2015_08/image05.thumb.png.78b41b950eb530de1f13b0c21626a0ad.png"></a></p><p dir="rtl">علينا بعد ذلك أن نقوم بإضافة كائنين من نوع <span style="font-family:courier new,courier,monospace;">Button</span> أي أزرار، وسنضيفهما بشكل عمودي أحدهما فوق الآخر في منتصف الشاشة. لكن قبل ذلك لنضف بعض المصادر الجديدة ونقوم بإعدادها، وهذه المصادر هي عبارة عن صور ورموز لواجهة المستخدم تم استخراجها من المجموعتين التاليتين:</p><ul dir="rtl"><li><a rel="external nofollow" href="http://www.kenney.nl/assets/ui-pack">http://www.kenney.nl/assets/ui-pack</a></li><li><a rel="external nofollow" href="http://www.kenney.nl/assets/game-icons">http://www.kenney.nl/assets/game-icons</a></li></ul><p dir="rtl">طبعا لن نحتاج لجميع محتويات المجموعتين، لكن سنكتفي بالعناصر الموضحة في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image06.png.0c4ceb6bb65d6ff1b283bd9081137165.png"><img data-fileid="3648" class="ipsImage ipsImage_thumbnailed" alt="image06.thumb.png.401997196225ab79b00a83" src="https://academy.hsoub.com/uploads/monthly_2015_08/image06.thumb.png.401997196225ab79b00a83de390572d1.png"></a></p><p dir="rtl">لنبدأ أولا بإعداد صور الأزرار الستة: الثلاث الزرقاء والثلاث الحمراء. قم باختيار أحد الأزرار من مستعرض المشروع ومن ثم اضغط على الزر <span style="font-family:courier new,courier,monospace;">Sprite Editor</span> في نافذة الخصائص. ستظهر لك نافذة تحرير الصورة <span style="font-family:courier new,courier,monospace;">Sprite Editor</span> والتي تمكنك من تقطيع الصورة مستخدما نظام الأجزاء التسعة. هذا النظام يقوم على تقسيم أي صورة نريد استخدامها في واجهة المستخدم إلى 9 مناطق كما هو موضح في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image07.png.dc64c6abadfc6b0f522c734d7635620f.png"><img data-fileid="3649" class="ipsImage ipsImage_thumbnailed" alt="image07.thumb.png.2714509abf071c110dee71" src="https://academy.hsoub.com/uploads/monthly_2015_08/image07.thumb.png.2714509abf071c110dee7100d22dd147.png"></a></p><p dir="rtl">الهدف من هذا التقسيم هو جعل الصورة قابلة للتمدد أفقيا وعموديا، بحيث تبقى الزوايا دائما بحجمها الأصلي ويتم شد الأجزاء أفقيا وعموديا دون أن يؤثر ذلك سلبا على المظهر. يمكنك من خلال النافذة المذكورة تحريك خطوط التقسيم الخضراء من أجل عزل الزوايا عن بقية الأجزاء التي ستتم عملية شدها أثناء تغيير حجم عنصر الواجهة. ل</p><p dir="rtl">احظ أن لدينا 3 أزرار من كل لون: الأول مرتفع والثاني عادي والثالث مضغوط للأسفل. الأزرار التي سنضيفها ستعمل كالآتي. في الحالة الافتراضية سنعرض صورة الزر العادي، وحين تمرير الفأرة على الزر سنعرض صورة الزر المرتفع، وحين الضغط عليه سنعرض صورة الزر المنخفض. يمكنك تحقيق هذا السلوك عن طريق ضبط إعدادات المكوّنين <span style="font-family:courier new,courier,monospace;">Image</span> و <span style="font-family:courier new,courier,monospace;">Button</span> في كائن الزر وفق القيم التي تراها في الصورة التالية. تذكر أن نقطة الارتكاز للأزرار وللعنوان هي المنتصف أفقيا وعموديا <span style="font-family:courier new,courier,monospace;">middle center</span>.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image08.png.b382c304e29cbec669654b3b64670041.png"><img data-fileid="3650" class="ipsImage ipsImage_thumbnailed" alt="image08.thumb.png.d9c7d281c3d223209f5f7a" src="https://academy.hsoub.com/uploads/monthly_2015_08/image08.thumb.png.d9c7d281c3d223209f5f7a432442be11.png"></a></p><p dir="rtl">لاحظ أننا حددنا الصورة الافتراضية للزر عبر المكوّن <span style="font-family:courier new,courier,monospace;">Image</span>، حيث تلاحظ أن نوع الصورة هو <span style="font-family:courier new,courier,monospace;">Sliced</span> أي صورة مقسمة إلى 9 أجزاء كما سبق ورأينا. بعدها قمنا بتغيير نوع الانتقال في الزر <span style="font-family:courier new,courier,monospace;">Transition</span> إلى <span style="font-family:courier new,courier,monospace;">Sprite Swap</span> بحيث نقوم بتبديل الصورة حين الانتقال بين الحالات. حددنا هنا صورتين أخريين إحداهما لحالة التحديد أو المرور بالفأرة<span style="font-family:courier new,courier,monospace;"> Highlighted Sprite</span> والثانية لحالة الضغط <span style="font-family:courier new,courier,monospace;">Pressed Sprite</span>. أخيرا ستلاحظ وجود كان ابن لكل زر وهو عبارة عن نص يعرض الكتابة التي نرغب بظهورها على الزر. بالتالي يمكننا استخدام هذه الكائنات للكتابة والحصول في النهاية على النتيجة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image09.png.89b018c1197df0b17db0f690c168afdb.png"><img data-fileid="3651" class="ipsImage ipsImage_thumbnailed" alt="image09.thumb.png.057c843ad0427ca989e04f" src="https://academy.hsoub.com/uploads/monthly_2015_08/image09.thumb.png.057c843ad0427ca989e04f0234418b39.png"></a></p><h2>حل مشكلة اللغة العربية</h2><p>مشكلة اللغة العربية في محرك Unity قديمة وقد عانيت معها منذ أول إصدار استخدمته وهو 3.5، وحتى الإصدار الخامس لم تحل هذه المشكلة من قبل الشركة. إلا أن الحل موجود، حيث قمت قبل عدة سنوات بكتابة بريمج يسمى ArabicText، ومبدأ عمله يقوم على عكس ترتيب الأحرف بحيث تصبح من اليمين لليسار كما يفترض، إضافة إلى استبدال رموز الحروف المتقطعة بالمتصلة حسب موقع الحرف في الكلمة. هذا البريمج موجود في المشروع داخل المجلد <span style="font-family:courier new,courier,monospace;">Assets\Scripts\UI</span> وكل ما عليك هو إضافته لكل كائن من نوع <span style="font-family:courier new,courier,monospace;">Text</span> (أي العنوان وظل العنوان وكائنات الأبناء النصيّة للأزرار). عند تشغيل اللعبة سيقوم البريمج بعمله في تصحيح النص كما ترى في الصورة التالية. هذا البريمج مجرد أداة مساعدة لا علاقة لها بموضوع الدرس لذا لن أقوم بشرحه هنا، لكن يمكنك الاطلاع عليه في المجلد المذكور إن كنت ترغب بذلك.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image10.png.39089fb734e52baad8f5b5695ddec408.png"><img data-fileid="3652" class="ipsImage ipsImage_thumbnailed" alt="image10.thumb.png.a378404b4ca8c1c475e0b1" src="https://academy.hsoub.com/uploads/monthly_2015_08/image10.thumb.png.a378404b4ca8c1c475e0b1ada3b6dd1e.png"></a></p><h2 dir="rtl">التفاعل مع عناصر واجهة المستخدم</h2><p dir="rtl">أصبحت القائمة الرئيسية جاهزة الآن، إلا أن ضغطك على الأزرار لن يكون ذا تأثير حيث لا توجد أية أوامر ترتبط بها بعد. ربط الأوامر بالأزرار يتم عن طريق استدعاء داّلة أو أكثر من بريمج محدد عند الضغط على الزر. من أجل ذلك سنقوم بكتابة بريمج لكل أمر من هذه الأوامر.</p><p dir="rtl">البريمج الأول وهو الأسهل هو برنامج الخروج من اللعبة<span style="font-family:courier new,courier,monospace;"> ExitGameCommand</span>. أمر الخروج يمكن تنفيذه في القائمة الرئيسية وفي مشهد اللعبة على حد سواء، حيث يقوم في الحالة الأولى بإغلاق تطبيق اللعبة نهائيا وفي الثانية بالعودة للقائمة الرئيسية. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">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);
       }
   }
}</pre><p dir="rtl">لاحظ أن البريمج يستخدم أوامر مباشرة يتيحها محرك Unity من أجل تحميل المشاهد حسب أرقامها. حيث نعرف المشهد الحالي عن طريق المتغير <span style="font-family:courier new,courier,monospace;">Application.loadedLevel</span> ونقوم بتحميل المشهد الذي نريد عن طريق الدّالة <span style="font-family:courier new,courier,monospace;">()Application.LoadLevel</span>. تذكر أن مشهد القائمة الرئيسية يحمل الرقم 0 ومشهد اللعبة يحمل الرقم 1. أخيرا يمكنك ملاحظة أن الدّالة <span style="font-family:courier new,courier,monospace;">()Application.Quit</span> تستخدم لإغلاق التطبيق.</p><p dir="rtl">الخطوة التالية هي ربط الضغط على الزر "خروج" باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()ExitGame</span>. الخطوة الأولى هي أن نضيف هذا البريمج إلى المشهد على أي كائن، وليكن كائن الزر نفسه. بعدها نعود للمكوّن <span style="font-family:courier new,courier,monospace;">Button</span> حيث سنجد في أسفله قائمة بالأوامر التي نريد استدعاءها حين الضغط على هذا الزر وهي مرتبة في القائمة <span style="font-family:courier new,courier,monospace;">()OnClick</span> كما في ترى في الصورة التالية. يمكنك إضافة أمر جديد بالضغط على الزر <span style="font-family:courier new,courier,monospace;">+</span> في أسفل القائمة:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image11.png.d52124fe738ceb13532f79325295cd41.png"><img data-fileid="3653" class="ipsImage ipsImage_thumbnailed" alt="image11.thumb.png.505097fed512fca7a0245d" src="https://academy.hsoub.com/uploads/monthly_2015_08/image11.thumb.png.505097fed512fca7a0245d011e9511be.png"></a></p><p dir="rtl">عند إضافة أمر جديد للقائمة، عليك تحديد الكائن الذي سينفذ الأمر، ومن ثم تحدد البريمج، وأخيرا تحدد الدّالة داخل هذا البريمج. بما أننا أضفنا البريمج <span style="font-family:courier new,courier,monospace;">ExitGameCommand</span> على كائن الزر نفسه، علينا أن نسحب الزر "خروج" Exit من الهرمية إلى داخل الخانة الخاصّة بالكائن، ومن ثم نفتح قائمة الأوامر والتي تكون قيمتها الافتراضية No Function حيث نختار البريمج <span style="font-family:courier new,courier,monospace;">ExitGameCommand</span> ومن ثم الدّالة <span style="font-family:courier new,courier,monospace;">()ExitGame</span> كما في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image12.png.368784a5216320a6685575db1f12847e.png"><img data-fileid="3654" class="ipsImage ipsImage_thumbnailed" alt="image12.thumb.png.753cdbd1393c5a033126dc" src="https://academy.hsoub.com/uploads/monthly_2015_08/image12.thumb.png.753cdbd1393c5a033126dceeb003f318.png"></a></p><p dir="rtl">بالتالي عند الضغط على الزر "خروج" فإن التطبيق سيتم إيقاف تشغيله (ملاحظة: لا يعمل الأمر <span style="font-family:courier new,courier,monospace;">()Application.Quit</span> من داخل محرر المحرك، عليك بناء التطبيق وتشغيله منفردا لتجربته).</p><p dir="rtl">لننتقل الآن للزر الثاني وهو زر بداية اللعب. عند الضغط عليه سيعرض نافذة جديدة تحتوي على المراحل الموجودة بحيث يتسنى للاعب اختيار مرحلة منها. من أجل ذلك علينا أولا بناء نافذة مستقلة تحتوي على أزرار المراحل. مبدئيا سنكتفي بزرين يحملان الأرقام <span style="font-family:courier new,courier,monospace;">1</span> و <span style="font-family:courier new,courier,monospace;">2</span> حيث سيكون لدينا مرحلتان فقط في هذا المثال. إضافة لذلك سيكون هناك زر ثالث يحمل الرمز<span style="font-family:courier new,courier,monospace;"> X</span> يقوم بإغلاق النافذة والعودة للقائمة الرئيسية مرة أخرى. لعمل النافذة المذكورة قم بإضافة لوح جديد <span style="font-family:courier new,courier,monospace;">Panel</span> واحرص على أن يكون ترتيبه بين أبناء الكائن <span style="font-family:courier new,courier,monospace;">Canvas</span> تحت اللوح الأول الخاص بالقائمة الرئيسية <span style="font-family:courier new,courier,monospace;">MainMenu</span>. هذا الترتيب مهم حيث أن الكائنات في أسفل الهرمية تظهر على الشاشة أمام الكائنات التي في الأعلى، وهذا ما نريده: أن تظهر هذه النافذة حين عرضها أمام القائمة الرئيسية. قم بتغيير لون اللوح للأسود مع الإبقاء على الشفافية، ومن ثم غير اسمه إلى <span style="font-family:courier new,courier,monospace;">LevelSelector</span> وحجمه على المحورين الأفقي والعمودي إلى 0.9. هذا سيجعل شكله يبدو كالآتي (لاحظ أيضا ترتيب العناصر في الهرمية على اليسار).</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image13.png.c0a955b4d393412ed51bac417cd07662.png"><img data-fileid="3655" class="ipsImage ipsImage_thumbnailed" alt="image13.thumb.png.059cc2782b7be5a58f7425" src="https://academy.hsoub.com/uploads/monthly_2015_08/image13.thumb.png.059cc2782b7be5a58f74254a7f2250d4.png"></a></p><p>ما يلزمنا الآن هو ترتيب الأزرار داخل هذه النافذة على شكل جدول مكون من صفوف وأعمدة، بحيث تكون هذه الأزرار متساوية في الحجم وبينها مسافات ثابتة. لحسن الحظ فإن Unity يسهل علينا هذه المهمة عن طريق توفير المكوّن <span style="font-family:courier new,courier,monospace;">GridLayoutGroup</span>. هذا المكوّن يقوم بترتيب العناصر داخل اللوح بالطريقة التي ذكرتها للتو، وهو يحتوي على عدة متغيرات كما ترى في هذه الصورة. انتبه لأن إضافة مكوّن كهذا يلغي تأثير طريقة الارتكاز التي تحدثنا عنها سابقا، حيث يصبح المكوّن هو المسؤول عن المواقع والأحجام الخاصة بالعناصر التي يحتويها.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image14.png.c5cda54fa594c584cde0ff973377ebc2.png"><img data-fileid="3656" class="ipsImage ipsImage_thumbnailed" alt="image14.thumb.png.30be885f3a1357ca34853f" src="https://academy.hsoub.com/uploads/monthly_2015_08/image14.thumb.png.30be885f3a1357ca34853ff3d4cd3372.png"></a></p><p dir="rtl">المتغيرات الأربع تحت البند <span style="font-family:courier new,courier,monospace;">Padding</span> تحدد حجم الهوامش من الجهات الأربعة بالبكسل، وهنا اخترت القيمة 32. بعدها نقوم بتحديد حجم كل عنصر أفقيا وعموديا عن طريق المتغير <span style="font-family:courier new,courier,monospace;">Cell Size</span> وأخيرا نحدد المسافات بين العناصر وهي هنا 16. باقي المتغيرات يمكن تركها على قيمها الافتراضية. بعد هذا علينا أن نصنع قالبا لزر المرحلة بحيث يمكننا إضافته عدة مرات مع تغيير المرحلة التي سيتم تحميلها بتغير الزر. الزر المذكور شبيه بالأزرار التي أضفناها حتى الآن من حيث آلية العرض بتغيير الصور، لكن الذي سيتغير هو النص حيث سيحمل كل زر رقم المرحلة (1، 2، 3، …) إضافة لتغيير البريمج الذي سيستقبل الأمر. بعد صنع قالب الزر حسب الوصف السابق، سنضيف عليه البريمج<span style="font-family:courier new,courier,monospace;"> LevelButton</span>، وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">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);
   }
}
</pre><p dir="rtl">يعمل هذا البريمج عند استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()StartLevel</span> على تحميل مشهد اللعبة (المشهد رقم 1)، لكن قبل ذلك يقوم بتخزين رقم المرحلة التي يجب تحميلها في إعدادات اللاعب. هذه الإعدادات يتم تخزينها على القرص الصلب أي أنها دائمة وليست في الذاكرة. بالتالي فإن القيمة التي تخزن فيها ستبقى محفوظة حين الانتقال بين مشهدي القائمة واللعبة. يمكن الوصول لإعدادات اللاعب عبر <span style="font-family:courier new,courier,monospace;">PlayerPrefs</span> والتي تحتوي على دوالّ لتخزين وقراءة بيانات بأنواع مختلفة. هنا مثلا استخدمنا الدّالة <span style="font-family:courier new,courier,monospace;">()SetInt</span> والتي تقوم بتخزين عدد صحيح، واخترنا اسما للقيمة التي قمنا بتخزينها وهي <span style="font-family:courier new,courier,monospace;">SelectedLevel</span>. سنرى لاحقا كيف يمكننا قراءة هذه القيمة وتحميل المرحلة بناء عليها.</p><p dir="rtl">ما علينا فعله الآن هو إضافة عنصر جديد للقائمة <span style="font-family:courier new,courier,monospace;">()OnClick</span> ومن ثم سحب الزر نفسه لخانة الكائن تماما كما فعلنا مع زر الخروج من اللعبة. بعدها سنختار البريمج <span style="font-family:courier new,courier,monospace;">LevelButton</span> من القائمة ومن ثم نختار الدّالة <span style="font-family:courier new,courier,monospace;">()StartLevel</span>. الشيء الجديد الذي ستلاحظه هذه المرة هو وجود خانة لإدخال قيمة المتغير <span style="font-family:courier new,courier,monospace;">levelIndex</span>، حيث أن هذه الدّالة تأخذ متغيرا بخلاف <span style="font-family:courier new,courier,monospace;">()ExitGame</span> التي تعاملنا معها في زر الخروج من اللعبة. لاحظ الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image15.png.37b7b2f6ffb103a75efa20cae98ff30a.png"><img data-fileid="3657" class="ipsImage ipsImage_thumbnailed" alt="image15.thumb.png.c9e511058ae9b6e70554ad" src="https://academy.hsoub.com/uploads/monthly_2015_08/image15.thumb.png.c9e511058ae9b6e70554adcff4effbb2.png"></a></p><p>سنقوم بعمل زرين من هذا القالب. أحدهما سيحمل النص 1 والقيمة 0 للدّالة <span style="font-family:courier new,courier,monospace;">()StartLevel</span>، والآخر سيحمل النص 2 والقيمة 1 للدّالة <span style="font-family:courier new,courier,monospace;">()StartLevel</span>. هذان الزران سنقوم بإضافتهما كأبناء للكائن <span style="font-family:courier new,courier,monospace;">LevelSelector</span>. بعد إضافة الأزرار بالترتيب الصحيح سيتكفل المكوّن <span style="font-family:courier new,courier,monospace;">Grid Layout Group</span> بوضع كل منهما في الموقع الصحيح وبالحجم الصحيح. قبل الانتقال للحديث عن الزر الثالث وهو زر إغلاق النافذة، لنقم بكتابة البريمج الذي سيحول هذا اللوح إلى نافذة يمكن فتحها وإغلاقها. هذا البريمج هو <span style="font-family:courier new,courier,monospace;">UIDialog</span> وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">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) &lt; 0.01f)
           {
               scale = maxSize;
               expanding = false;
           }
       }
       else if (shrinking)
       {
           scale = Vector2.Lerp(scale, Vector2.zero, Time.deltaTime * 10);
           //تحقق من الوصول للمنطقة الميتة
           if (Vector2.Distance(scale, Vector2.zero) &lt; 0.01f)
           {
               scale = Vector2.zero;
               shrinking = false;
           }
       }

       //قم بتغيير القياس للقيمة الجديدة
       transform.localScale = scale;
       }

   //تقوم بفتح النافذة
   public void Show()
   {
       expanding = true;
       shrinking = false;
   }

   //تقوم بإغلاق النافذة
   public void Hide()
   {
       shrinking = true;
       expanding = false;
   }
}
</pre><p>يعتمد مبدأ عمل هذا البريمج على قيمة المتغيرين <span style="font-family:courier new,courier,monospace;">expanding</span> و <span style="font-family:courier new,courier,monospace;">shrinking</span>، حيث يحددان ما إذا كانت النافذة تتقلص إلى أن تصل لمرحلة الإغلاق أو إن كانت تتمدد حتى تصل لمرحلة الفتح. حين فتح النافذة يتم إيصال قياسها لقيمة الحد الأعلى المحددة في <span style="font-family:courier new,courier,monospace;">maxSize</span>، أما حين الإغلاق يجب أن تصل قيمة القياس لصفر حتى تختفي النافذة تماما. لاحظ أن تمدد وتقلص النافذة يتم بشكل سلس عبر <span style="font-family:courier new,courier,monospace;">()Vector2.Lerp</span> والتي تستخدم الاستيفاء الذي شرحناه سابقا. افتراضيا يتم ضبط قياس النافذة على <span style="font-family:courier new,courier,monospace;">Vector2.zero</span> مما يؤدي لأن تبدأ مختفية (مغلقة)، وسيتم إظهارها (فتحها) حين استدعاء الدّالة<span style="font-family:courier new,courier,monospace;"> ()Show</span>، كما يمكن استدعاء <span style="font-family:courier new,courier,monospace;">()Hide</span> لإخفائها (أو إغلاقها) ثانية. بعد إضافة هذا البريمج للكائن <span style="font-family:courier new,courier,monospace;">LevelSelector</span> ستلاحظ أنه يختفي تلقائيا عند تشغيل اللعبة. بقي علينا أن نظهره حين يضغط اللاعب على "ابدأ اللعب" ونخفيه حين يضغط اللاعب على الزر <strong>X</strong> الذي سنضيفه لهذه النافذة.</p><p dir="rtl">لنبدأ بعمل زر إغلاق النافذة مستخدمين الصور الثلاث للزر الأحمر. بعد إضافة هذا الزر سنقوم بحذف مكوّن النص من الكائن الإبن <span style="font-family:courier new,courier,monospace;">Text</span> ونضيف بدلا منه كائن صورة <span style="font-family:courier new,courier,monospace;">Image</span> كما هو موضح في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image16.png.6023b34bedcbb2d96f345cf1a22823fc.png"><img data-fileid="3658" class="ipsImage ipsImage_thumbnailed" alt="image16.thumb.png.3a95e86a12f7585134e32d" src="https://academy.hsoub.com/uploads/monthly_2015_08/image16.thumb.png.3a95e86a12f7585134e32dc6f9482b0d.png"></a></p><p dir="rtl">بعدها سنقوم بسحب الصورة <span style="font-family:courier new,courier,monospace;">cross</span> والموجودة في مجموعة رسوم واجهة المستخدم في المجلد<span style="font-family:courier new,courier,monospace;"> Assets\Kenney.nl\UI Pack </span>إلى الخانة<span style="font-family:courier new,courier,monospace;"> Source Image</span> مما يجعل الشكل النهائي لنافذة اختيار المرحلة يبدو كالتالي:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image17.png.fc2b63f807780d2bd2a02d2de3b64c1c.png"><img data-fileid="3659" class="ipsImage ipsImage_thumbnailed" alt="image17.thumb.png.553891ee26a2a9c5fe93dc" src="https://academy.hsoub.com/uploads/monthly_2015_08/image17.thumb.png.553891ee26a2a9c5fe93dcd0227a6ad9.png"></a></p><p dir="rtl">بالنسبة لزر الإغلاق الأحمر سيكون الكائن الهدف لتنفيذ الأمر هو النافذة <span style="font-family:courier new,courier,monospace;">LevelSelector</span> بالتالي سنسحبها لعنصر جديد نضيفه للقائمة <span style="font-family:courier new,courier,monospace;">()OnClick</span>، ومن ثم سنقوم بتحديد البريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span> والدّالة <span style="font-family:courier new,courier,monospace;">()Hide</span> كأمر يتم تنفيذه حين الضغط على هذا الزر. بعدها سنعود للزر الأول في القائمة الرئيسية وهو "ابدأ اللعب" ونضيف له النافذة <span style="font-family:courier new,courier,monospace;">LevelSelector</span> كهدف للأمر والبريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span> أيضا، إلا أن الدّالة هذه المرة ستكون<span style="font-family:courier new,courier,monospace;"> ()Show</span> حيث أن الضغط على هذا الزر سيظهر النافذة. الشكل النهائي للقائمة <span style="font-family:courier new,courier,monospace;">()OnClick</span> في هذين الزرين سيبدو كالآتي:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image18.png.b556b54d78fabdcfde99328f25d3ca27.png"><img data-fileid="3660" class="ipsImage ipsImage_thumbnailed" alt="image18.thumb.png.d59076d954016e4551019c" src="https://academy.hsoub.com/uploads/monthly_2015_08/image18.thumb.png.d59076d954016e4551019c75d2162aff.png"></a></p><p dir="rtl">لو قمت بتشغيل اللعبة الآن ستلاحظ أن الضغط على "ابدأ اللعب" سيظهر لك نافذة اختيار المراحل، ومن هناك يمكنك الضغط على الزر 1 أو 2 لتحميل المرحلة التي تريدها. بطبيعة الحال لا توجد أي مراحل حاليا، لذا سيأخذك الضغط على هذه الأزرار إلى مشهد اللعبة الفارغ. ما نريد عمله الآن هو إضافة زر في مشهد اللعبة يمكّن اللاعب من العودة للقائمة الرئيسية.</p><p dir="rtl">كل ما علينا فعله هو إضافة زر صغير في أعلى يمين الشاشة يحمل إشارة X ، وعند الضغط عليه سيظهر للاعب نافذة صغيرة يسأله من خلالها إن كان يريد أن يعود للقائمة الرئيسية. بالنظر لموقع الزر المفترض، علينا مراعاة أن تكون نقطة ارتكازه في أعلى اليمين، وذلك حتى يبقى على مسافة ثابتة من أعلى يمين الشاشة بغض النظر عن حجمها. هذا الزر لا يختلف عن التي أنشأناها سابقا سوى أنه أصغر حجما. سنعود لاحقا لإضافة الأمر الخاص بهذا الزر. الصورة التالية توضح موقعه في الشاشة، ويمكنك ملاحظة نقطة ارتكازه في أعلى اليمين:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image19.png.4b9bc37a282e28c861bc0a5fc25f712f.png"><img data-fileid="3661" class="ipsImage ipsImage_thumbnailed" alt="image19.thumb.png.47ed446e44aea6b5371f18" src="https://academy.hsoub.com/uploads/monthly_2015_08/image19.thumb.png.47ed446e44aea6b5371f181f37ee3066.png"></a></p><p dir="rtl">بعد إضافة هذا الزر سنضيف نافذة حوار جديدة كالتي أضفناها في القائمة الرئيسية لاختيار المراحل، إلا أنها ستكون أصغر حجما وتحتوي على سؤال لتأكيد العودة للقائمة الرئيسية، إضافة لزرين للاختيار بين نعم و لا. الصورة أدناه تمثل الشكل والحجم المفترضين لنافذة كهذه. (لاحظ الهرمية في يسار الصورة لترى مم تتكون هذه النافذة):</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image20.png.5ad6aabf3eb6a2181346ba6c47e526ff.png"><img data-fileid="3662" class="ipsImage ipsImage_thumbnailed" alt="image20.thumb.png.e253d75177abc0a8ffdf10" src="https://academy.hsoub.com/uploads/monthly_2015_08/image20.thumb.png.e253d75177abc0a8ffdf10443fca1ca0.png"></a></p><p dir="rtl">الزر الذي يحمل علامة ✓ سيعود باللاعب للقائمة الرئيسية، بينما الآخر سيقوم بإغلاق نافذة الحوار هذه مع البقاء في مشهد اللعبة• من أجل العودة للقائمة الرئيسية سنحتاج مرة أخرى للبريمج <span style="font-family:courier new,courier,monospace;">ExitGameCommand</span> ولكننا سنضيفه هذه المرة على الكائن الجذري للواجهة <span style="font-family:courier new,courier,monospace;">Canvas</span> حيث سنحتاج لاستدعائه من أكثر من نافذة كما سنرى. بعد إضافة البريمج ستكون الدّالة <span style="font-family:courier new,courier,monospace;">()ExitGame</span>  المعرفة فيه هي الأمر الذي سينفذ حين الضغط على الزر ✓، بينما سيكون <span style="font-family:courier new,courier,monospace;">Canvas</span> هو الكائن الهدف حيث أنه من يحمل هذا البريمج. بالتالي سيكون شكل القائمة <span style="font-family:courier new,courier,monospace;">()OnClick</span> كما يلي:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image21.png.04c4b01690ab1e4c2689629d02d7c5a1.png"><img data-fileid="3663" class="ipsImage ipsImage_thumbnailed" alt="image21.thumb.png.3d373eeb2b96bb380121fc" src="https://academy.hsoub.com/uploads/monthly_2015_08/image21.thumb.png.3d373eeb2b96bb380121fc32acdbc68a.png"></a></p><p dir="rtl">تذكر أن الدّالة <span style="font-family:courier new,courier,monospace;">()ExitGame</span> تعود للقائمة الرئيسية في حال تم استدعاؤها من مشهد اللعبة. بعد ذلك علينا أن نضيف لهذه النافذة الصغيرة البريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span> بحيث تبدأ مختفية وتظهر حين استدعاء <span style="font-family:courier new,courier,monospace;">()Show</span>. بطبيعة الحال سيكون زر الخروج الموجود أعلى يمين الشاشة هو من يستدعي الدّالة<span style="font-family:courier new,courier,monospace;"> ()Show</span> عند الضغط عليه، بينما سيكون زر الإغلاق X الموجود على النافذة نفسها هو من يستدعي لها الدّالة <span style="font-family:courier new,courier,monospace;">()Hide</span>. أعتقد أنه إلى هنا أصبحت فكرة ربط الضغط على الزر بكائن معين واستدعاء دالّة من بريمج عليه واضحة، لذا لن أعاود شرحها بالصور وسأكتفي بذكر الارتباطات اللازمة.</p><p dir="rtl">بهذا تكون القائمة الرئيسية للعبة جاهزة، ويمكننا الانتقال بينها وبين مشهد اللعبة. بقي علينا أن نجهز المراحل وما يتعلق بحالة اللعبة حتى تصبح لعبتنا مكتملة ويمكننا لعبها.</p><h2>إضافة المراحل والتنقل بينها</h2><p dir="rtl">بعد أن أصبحت عناصر بناء المرحلة مكتملة لدينا إضافة للشاشة الرئيسية وبعض عناصر واجهة المستخدم، سنقوم الآن بصنع مرحلتين لتجربة تتابع المراحل إضافة للتنقل بينها وبين الشاشة الرئيسية. يمكنك أن تستخدم أي مقذوفات ترغب بها وأي وحدات بنائية وخصوم. المهم هو أن تتبع بناء هرميا محددا حتى تكون جميع المراحل متوافقة في الشكل. الشكل التالي يوضح مثالا على مرحلة صغيرة ومما تتكون هرمية المرحلة.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image22.png.c7bb9779940ac2381f11b7004ace1f3a.png"><img data-fileid="3664" class="ipsImage ipsImage_thumbnailed" alt="image22.thumb.png.568561d5fd70a9f360a5d1" src="https://academy.hsoub.com/uploads/monthly_2015_08/image22.thumb.png.568561d5fd70a9f360a5d123012002b9.png"></a></p><p dir="rtl">لاحظ أن المرحلة تتكون من 3 عناصر: القاذف، والعناصر البنائية والوحوش والتي تندرج تحت الكائن الفارغ Elements، وأخيرا المقذوفات والتي تندرج تحت الكائن الفارغ Projectiles. لاحظ أيضا أن جميع العناصر على مستوى أفقي واحد وهو المستوى الذي ستظهر فيه الأرضية. عند بناء المرحلة، راعي أن يكون الكائن الفارغ الأب للمرحلة (Level1 في الصورة السابقة) في منتصف المشهد، وأن يكون أسفل المرحلة على مستوى الأرضية التي ستظهر. بعد بناء المرحلة يجب أن نحولها كاملة إلى قالب واحد كبير، لكن قبل ذلك علينا إضافة بريمج بسيط لكائن المرحلة الجذري. هذا البريمج مهمته تحديد رقم الخلفية التي ستظهر حين تحميل المرحلة ويسمى GameLevel وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class GameLevel : MonoBehaviour {

    //صورة الخلفية التي ستظهر عند تحميل المرحلة
    public int backgroundIndex;

       //تستدعى مرة واحدة عند بداية التشغيل
       void Start () {
    
       }
    
       //يتم استدعاؤها مرة عند تصيير كل إطار
       void Update () {
    
       }
}</pre><p dir="rtl">المهم في هذا البريمج هو أن نعرف أي صورة خلفية يجب أن نختار عند تحميل المرحلة، عدا عن ذلك فمحتويات المرحلة كفيلة بالتحكم بحالة اللعبة كما سنرى بعد قليل. بعد تجهيز المراحل على شكل قوالب، سنقوم بعمل بريمج جديد لتخزين هذه القوالب ومن ثم إنشائها حسب الحاجة، أي حسب المرحلة التي يتم تحميلها. هذا البريمج يسمى <span style="font-family:courier new,courier,monospace;">GameLevelLoader</span> وسنقوم بإضافته للكائن الجذري في المشهد. السرد التالي يوضح هذا البريمج:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">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&lt;BackgroundManager&gt;();
       egc = FindObjectOfType&lt;ExitGameCommand&gt;();
       }
    
       //يتم استدعاءها مرة عند تصيير كل إطار لكن في وقت متأخر
       void LateUpdate () {
       if (currentLevel == -1)
       {
           //قم بتحميل المرحلة التي تم اختيارها من القائمة الرئيسية
           //إذا لم تكن هناك أي مرحلة، قم تلقائيا بتحميل المرحلة الأولى
           int selectedLevel = PlayerPrefs.GetInt("SelectedLevel", 0);
           LoadLevel(selectedLevel);
       }
       }

   //تقوم بتحميل المرحلة المحددة
   public void LoadLevel(int index)
   {
       //قم بالتأكد من وجود المرحلة المطلوبة في المصفوفة
       //إن لم تكن موجودة فعد للقائمة الرئيسية
       if (index &lt; 0 || index &gt;= allLevels.Length)
       {
           egc.ExitGame();
           return;
       }

       //قم بالبحث عن المرحلة المحملة حاليا وتدميرها إن وجدت
       GameLevel current = FindObjectOfType&lt;GameLevel&gt;();
       if (current != null)
       {
           Destroy(current.gameObject);
       }

       //قم بإنشاء المرحلة الجديدة مستخدما قالبها
       GameObject newLevelObject = (GameObject)Instantiate(allLevels[index].gameObject);
       GameLevel newLevelScript = newLevelObject.GetComponent&lt;GameLevel&gt;();

       //قم بتحديد الكائن الأب والموقع للقائمة الجديدة
       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);
   }
}</pre><p dir="rtl">هذا البريمج يحتوي على متغير عام واحد فقط وهو المصفوفة<span style="font-family:courier new,courier,monospace;"> allLevels</span> التي تحتوي على قوالب جميع مراحل اللعبة. لاحظ أن تحميل المرحلة يتم تأخيره باستخدام الدّالة <span style="font-family:courier new,courier,monospace;">()LateUpdate</span> وذلك حتى نضمن أن جميع البريمجات الأخرى قد بدأت العمل ويمكننا الاعتماد عليها مثل البريمج <span style="font-family:courier new,courier,monospace;">BackgroundManager</span> والذي سنستخدمه لتغيير صورة الخلفية للصورة المحددة في البريمج <span style="font-family:courier new,courier,monospace;">GameLevel</span> الخاص بالمرحلة الحالية. يبحث البريمج مبدئيا عن متغير مخزن في إعدادات اللاعب ويحمل الاسم <span style="font-family:courier new,courier,monospace;">SelectedLevel</span>. كما تذكر فإن هذا المتغير يفترض أن يتم تخزينه من قبل البريمج<span style="font-family:courier new,courier,monospace;"> LevelButton</span> والخاص بأزرار المراحل في القائمة الرئيسية. إذا لم يوجد هذا المتغير يتم إرجاع القيمة الافتراضية وهي 0 بالتالي يتم تحميل المرحلة الأولى في المصفوفة.</p><p dir="rtl">الدّالة<span style="font-family:courier new,courier,monospace;"> ()LoadLevel</span> هي الأساسية في هذا البريمج حيث نعطيها رقم المرحلة التي نرغب بتحميلها من المصفوفة، فإذا لم يكن رقم المرحلة المحددة صالحا ستعود للقائمة الرئيسية للعبة. أما إذا كان الرقم صحيحا فإنها تتأكد من عدم وجود مرحلة محملة حاليا عن طريق البحث عن بريمج من نوع<span style="font-family:courier new,courier,monospace;"> GameLevel</span>، إذا وجدت هذا البريمج فإنها تقوم بتدمير الكائن الذي يحمله، وبما أن الكائن هو جذر عناصر المرحلة جميعها، سيتم تدمير جميع هذه العناصر أيضا، مما يجعل المشهد فارغا وجاهزا لاستقبال المرحلة الجديدة. هذه المرحلة يتم إنشاؤها عن طريق استخراج القالب الموجود في الموقع المحدد <span style="font-family:courier new,courier,monospace;">index</span> ومن ثم بناء كائن منه. هذا الكائن تتم إضافته كابن للكائن الجذري لمشهد اللعبة كما يتم وضعه في منتصف المشهد. بعدها يتم تحديث قيمة <span style="font-family:courier new,courier,monospace;">currentLevel</span> إلى المرحلة الجديدة وتغيير الخلفية باستخدام المتغير <span style="font-family:courier new,courier,monospace;">backgroundIndex</span> الخاص ببريمج المرحلة الجديدة. أخيرا تقوم الدّالة بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">NewLevelLoaded</span> حتى تخبر البريمجات الأخرى بأن المرحلة الجديدة تم تحميلها.</p><p dir="rtl">إضافة لذلك لدينا الدّالتان <span style="font-family:courier new,courier,monospace;">()RestartCurrentLevel </span>والتي تقوم بإعادة تحميل المرحلة الحالية، و<span style="font-family:courier new,courier,monospace;"> ()LoadNextLevel</span> والتي تقوم بتحميل المرحلة التالية في الترتيب في المصفوفة.</p><h2>حالة اللعبة وشروط الفوز والخسارة</h2><p dir="rtl">بعد أن أصبحت جميع محتويات اللعبة مكتملة بما فيها المراحل، بقي علينا أن نضيف شروط الفوز والخسارة وما يترتب عليها من تغيير على حالة اللعبة. في ألعاب من هذا النوع يفوز اللاعب إذا قام بتدمير جميع الخصوم وهي الوحوش في لعبتنا هذه، ويخسر إذا استنفد جميع ما لديه من مقذوفات دون تدمير الخصوم. تذكر أننا سابقا أضفنا البريمج <span style="font-family:courier new,courier,monospace;">Enemy</span> لكائنات الوحوش والذي يرسل للكائن الجذري الرسالة <span style="font-family:courier new,courier,monospace;">EnemyDestroyed</span> حين يتم تدمير الكائن، كما أن بريمج المقلاع <span style="font-family:courier new,courier,monospace;">Launcher</span> يقوم بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectilesConsumed </span>عندما يتم إطلاق كافة المقذوفات التي كانت بحوزة اللاعب. ما يتوجب علينا هو كتابة بريمج يستقبل هاتين الرسالتين وبناء عليهما يقوم بفحص حالة اللعبة والتأكد من فوز أو خسارة اللاعب. هذا البريمج هو <span style="font-family:courier new,courier,monospace;">GameStateManager</span> وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class GameStateManager : MonoBehaviour {
    //متغير لمعرفة ما إذا فاز اللاعب بالمرحلة
    private bool playerWon;
       //تستدعى مرة واحدة عند بداية التشغيل
       void Start () {
       playerWon = false;
       }
    
       //تستدعى مرة عند تصيير كل إطار
       void Update () {
    
       }

   //والتي ترسلها EnemyDestroyed تستقبل الرسالة
   //كائنات الوحوش عند تدميرها
   void EnemyDestroyed()
   {
       //قم بعد الوحوش المتبقية في المشهد
       Enemy[] enemies = FindObjectsOfType&lt;Enemy&gt;();
       if (enemies.Length &lt;= 1)
       {
           //تم تدمير جميع الوحوش، أي فاز اللاعب بالمرحلة
           SendMessage("PlayerWon");
           playerWon = true;
       }
   }

   //تقوم باستقبال رسالة استنفاد اللاعب
   //لجميع المقذوفات التي كانت بحوزته
   void ProjectilesConsumed()
   {
       if (!playerWon)
       {
           SendMessage("PlayerLost");
       }
   }

   //التي تعني NewLevelLoaded تستقبل الرسالة
   //false إلى  playerWon أنه تم تحميل مرحلة جديدة، وبناء عليها تعيد
   void NewLevelLoaded()
   {
       playerWon = false;
   }
}</pre><p dir="rtl">في كل مرة يتم فيها تدمير أحد الوحوش يستقبل هذا البريمج الرسالة<span style="font-family:courier new,courier,monospace;"> EnemyDestroyed</span> ومن ثم يقوم بعد الوحوش المتبقية في المشهد عن طريق البحث عن البريمج <span style="font-family:courier new,courier,monospace;">Enemy</span>. لاحظ أن وجود بريمج واحد في المشهد يعني أن اللاعب قد فاز فكيف هذا؟ الجواب هو أن تدمير الكائن لا يتم مباشرة عند استدعاء<span style="font-family:courier new,courier,monospace;"> ()Destroy</span>، وإنما يتم تأخيره حتى نهاية الإطار الحالي. لذا فمن المحتمل أن تصل الرسالة ويتم بعدها البحث عن بريمج من نوع Enemy وإيجاده. فإن كان العدد واحدا فهذا يعني أنه الأخير المتبقي في المشهد واستقبال الرسالة يعني أنه تم تدميره. لذا نعرف هنا بأن اللاعب قد فاز في المرحلة ويتم إرسال الرسالة <span style="font-family:courier new,courier,monospace;">PlayerWon</span> وتغيير قيمة <span style="font-family:courier new,courier,monospace;">playerWon</span> إلى true<span style="font-family:courier new,courier,monospace;">.</span></p><p dir="rtl">أما استقبال الرسالة <span style="font-family:courier new,courier,monospace;">ProjectilesConsumed</span> فيعني أن آخر مقذوف أطلقه اللاعب قد انقضت مدة بقائه وتم حذفه من المشهد، وأن القاذف لم يجد أي مقذوفات أخرى. حينها تقوم الدّالة <span style="font-family:courier new,courier,monospace;">()ProjectilesConsumed</span> باستقبال الرسالة ومن ثم التأكد من أن اللاعب لم يفز باللعبة حتى الآن – أي لم يدمر جميع الوحوش – وفي هذه الحالة تحكم بخسارة اللاعب عن طريق إرسال الرسالة <span style="font-family:courier new,courier,monospace;">PlayerLost</span>.</p><p dir="rtl">السؤال الآن هو ماذا سيحدث عندما يتم إرسال <span style="font-family:courier new,courier,monospace;">PlayerWon</span> أو <span style="font-family:courier new,courier,monospace;">PlayerLost</span>؟ الجواب هو أن كل رسالة ستقوم بإظهار نافذة حوار مختلفة. ففي حال فوز اللاعب ستظهر له نافذة تخيره بين إعادة اللعب وبين التقدم للمرحلة التالية واسمها <span style="font-family:courier new,courier,monospace;">WinDialog</span>، وفي حالة الخسارة تظهر نافذة أخرى تخيره بين إعادة المرحلة والخروج للقائمة الرئيسية واسمها <span style="font-family:courier new,courier,monospace;">LoseDialog</span>. هاتان النافذتان ستكونان كالنوافذ السابقة عبارة عن كائنات <span style="font-family:courier new,courier,monospace;">Panel</span> مضاف عليها البريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span> وتحتوي كل منهما على نص وزرين تماما كنافذة تأكيد العودة للقائمة الرئيسية.</p><p dir="rtl">بداية لنقم ببناء هاتين النافذتين وتحديد الوظائف الخاصة بأزرارها. لنبدأ مع نافذة الفوز والتي ستبدو بالشكل التالي:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image23.png.9121c0baf9d55a0277c08ad22c3be357.png"><img data-fileid="3665" class="ipsImage ipsImage_thumbnailed" alt="image23.thumb.png.a5b8ebdc19f205593d6d5d" src="https://academy.hsoub.com/uploads/monthly_2015_08/image23.thumb.png.a5b8ebdc19f205593d6d5d223db40ce0.png"></a></p><p dir="rtl">المشترك في الزرين الموجودين على النافذة هو أن الهدف لأوامرهما هو الكائن الجذري لمشهد اللعبة <span style="font-family:courier new,courier,monospace;">SceneRoot</span> وتحديدا بريمج تحميل المراحل<span style="font-family:courier new,courier,monospace;"> GameLevelLoader</span>. أما الفرق فهو أن الزر الأيمن سيقوم باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()LoadNextLevel</span> عند الضغط عليه مما ينقل اللاعب للمرحلة التالية، بينما الزر الأيسر يستدعي عند الضغط عليه الدّالة <span style="font-family:courier new,courier,monospace;">()RestartCurrentLevel </span>مما يؤدي لإعادة تحميل المرحلة الحالية. علاوة على ذلك، يجب أن يقوم كلا هذين الزرين أيضا بإخفاء النافذة حتى يتمكن اللاعب من متابعة اللعب سواء في المرحلة التالية أو الحالية. من أجل ذلك يجب أن نضيف لكل منهما هدفا آخر وهو النافذة نفسها، حيث سيقوم كلاهما باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()Hide</span> من البريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span>. لاحظ أن<span style="font-family:courier new,courier,monospace;"> ()OnClick</span> هي عبارة عن قائمة كما ذكرنا سابقا، بالتالي يمكنها أن تستدعي أكثر من أمر من أكثر من كائن وبريمج كما هو مبين في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image24.png.48812736cdd41cdd9315359eb26ab333.png"><img data-fileid="3666" class="ipsImage ipsImage_thumbnailed" alt="image24.thumb.png.65d91939874420ba7d637e" src="https://academy.hsoub.com/uploads/monthly_2015_08/image24.thumb.png.65d91939874420ba7d637e245ac1df4e.png"></a></p><p dir="rtl">النافذة الأخرى وهي التي تظهر في حال الخسارة تبدو بهذا الشكل:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image25.png.5e8c2720e49a33449d5f827758622259.png"><img data-fileid="3667" class="ipsImage ipsImage_thumbnailed" alt="image25.thumb.png.02921cb8d9337d75a9cd8e" src="https://academy.hsoub.com/uploads/monthly_2015_08/image25.thumb.png.02921cb8d9337d75a9cd8e73c7dd33d9.png"></a></p><p dir="rtl">الزر الأيمن وهو زر العودة للقائمة الرئيسية سيكون الكائن الهدف بالنسبة له هو الكائن الجذري للواجهة <span style="font-family:courier new,courier,monospace;">Canvas</span> وتحديدا البريمج <span style="font-family:courier new,courier,monospace;">ExitGameCommand</span> والدّالة<span style="font-family:courier new,courier,monospace;"> ()ExitGame</span>. أما الزر الأيسر فتماما كما في نافذة الفوز يستدعي الدّالة <span style="font-family:courier new,courier,monospace;">()RestartCurrentLevel</span> ويقوم أيضا باستدعاء <span style="font-family:courier new,courier,monospace;">()Hide </span>من البريمج <span style="font-family:courier new,courier,monospace;">UIDialog</span> الموجود على كائن نافذة الخسارة <span style="font-family:courier new,courier,monospace;">LoseDialog</span>.</p><p dir="rtl">بقي علينا الآن أن نربط بين الرسائل التي يرسلها <span style="font-family:courier new,courier,monospace;">GameStateManager</span> وبين ظهور هذه النوافذ. المشكلة التي تواجهنا هنا هي أن النوافذ تقع تحت كائن جذري مختلف عن الكائن الجذري للمشهد، وكل منهما ذو وظيفة محددة ولا يجب أن تتداخل هذه الوظائف كثيرا. من أجل ذلك سنقوم بكتابة بريمج يعمل على استقبال الرسائل من<span style="font-family:courier new,courier,monospace;"> GameStateManager</span> ومن ثم استدعاء دوال من بريمج آخر سنضيفه على <span style="font-family:courier new,courier,monospace;">Canvas</span> بحيث يشكل هذان البريمجان معا جسر التواصل بين واجهة المستخدم ومنطق اللعبة. لنبدأ مع البريمج الأول الذي سنضيفه على جذر واجهة المستخدم <span style="font-family:courier new,courier,monospace;">Canvas</span> وهو <span style="font-family:courier new,courier,monospace;">GameStateDialogs</span> الموضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">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();
   }
}
</pre><p>كل ما يفعله هذا البريمج البسيط هو تخزين نافذتي الفوز والخسارة في مراجع ومن ثم عرضها عند استدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()ShowWindDialog</span> أو الدّالة <span style="font-family:courier new,courier,monospace;">()ShowLoseDialog</span>. بعد إضافة هذا البريمج للجذر <span style="font-family:courier new,courier,monospace;">Canvas</span> عليك أن تسحب كلا من نافذة الفوز ونافذة الخسارة لخانة المتغير المناسب لها كما ترى في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/image26.png.aa41c792c5820e1c6244efd23ef403e2.png"><img data-fileid="3668" class="ipsImage ipsImage_thumbnailed" alt="image26.thumb.png.b2bc1383ceaf5c17b1b6c4" src="https://academy.hsoub.com/uploads/monthly_2015_08/image26.thumb.png.b2bc1383ceaf5c17b1b6c4105468c6f1.png"></a></p><p dir="rtl">لننتقل الآن للطرف الآخر وهو جذر المشهد <span style="font-family:courier new,courier,monospace;">SceneRoot</span> والذي سنضيف عليه البريمج <span style="font-family:courier new,courier,monospace;">GameStateReporter</span> الموضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class GameStateReporter : MonoBehaviour {

    //مرجع لبريمج عرض نافذتي الفوز والخسارة
    GameStateDialogs gsDialogs;

       //تستدعى مرة عند بداية التشغيل
       void Start () {
       gsDialogs = FindObjectOfType&lt;GameStateDialogs&gt;();
       }
    
       //تستدعى مرة عند تصيير كل إطار
       void Update () {
    
       }

   //تستقبل رسالة فوز اللاعب
   void PlayerWon()
   {
       gsDialogs.ShowWinDialog();
   }

   //تستقبل رسالة عرض اللاعب
   void PlayerLost()
   {
       gsDialogs.ShowLoseDialog();
   }
}</pre><p dir="rtl">كل ما يفعله هذا البريمج هو استقبال رسائل الفوز والخسارة ومن ثم استدعاء الدّالة التي تعرض النافذة المناسبة من البريمج <span style="font-family:courier new,courier,monospace;">GameStateDialog</span>.</p><p dir="rtl">بهذا تكون لعبتنا قد اكتملت على جهاز الحاسب ويمكن تشغيلها ولعب المراحل والفوز والخسارة بها. بقي علينا أن ننقلها للهواتف الذكية وشاشات اللمس، وهي خطوة بسيطة نظرا للطريقة المنظمة التي اتبعناها في استقبال المدخلات.</p>
]]></description><guid isPermaLink="false">140</guid><pubDate>Thu, 06 Aug 2015 22:20:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x646;&#x627;&#x626;&#x64A;&#x629; &#x648;&#x634;&#x62E;&#x635;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62E;&#x635;&#x648;&#x645; &#x641;&#x64A; Unity3D</title><link>https://academy.hsoub.com/programming/game-development/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%B4%D8%AE%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%B5%D9%88%D9%85-%D9%81%D9%8A-unity3d-r134/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/unity3d3.png.4becd1c004d7f985f2b7c1f6c15264fd.png" /></p>

<p dir="rtl">قمنا في <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D9%85%D8%B4%D9%87%D8%AF-%D9%88%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%8A%D8%B1%D8%A7-%D9%81%D9%8A-unity3d-r131/">الدرس السابق</a> من هذه السلسلة بتجهير مشهد اللعبة و بناء الأرضية والخلفية إضافة إلى إعداد الكاميرا. الآن ننتقل إلى المكونات الرئيسية للعبة وهي الوحدات البنائية كالصخور والحجارة وأيضا الخصوم.</p><p dir="rtl"><strong style="line-height: 22.3999996185303px;">ملاحظة</strong><span style="line-height: 22.3999996185303px;">: يمكن تحميل الملفات المصدرية لكامل هذه السلسلة عبر </span><a style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/tree/master/AngryAnimals%20Game" rel="external nofollow">حساب أكاديمية حسوب على Github</a><span style="line-height: 22.3999996185303px;">، يمكن أيضا تحميل </span><a style="line-height: 22.3999996185303px;" href="https://github.com/HsoubAcademy/Unity3D/releases/tag/v0.1.0" rel="external nofollow">ملف APK لتجريب اللعبة على أجهزة Android</a><span style="line-height: 22.3999996185303px;"></span><span style="line-height: 22.3999996185303px;">.</span></p><h2 dir="rtl">إنشاء الوحدات البنائية للعبة</h2><p dir="rtl">النوع الثاني من الكائنات التي سنقوم بإنشائها هي الوحدات البنائية التي تتكون منها المراحل. هذه الوحدات عبارة عن أشكال هندسية منها مربعات ومثلثات ومستطيلات ودوائر. هذه الأشكال أيضا تتميز بأنها مصنوعة من مواد مختلفة، فيمكن أن تكون من المعدن أو الصخر أو الخشب أو الزجاج أو المواد المتفجرة، وهذه الأنواع كلها متوفرة بكل الأشكال في مجموعة الصور. هذه المواد تتفاوت في الوزن والصلابة، إضافة لأن المواد المتفجرة حين تتحطم تحدث انفجارا يؤثر في الوحدات المجاورة و الخصوم.</p><p dir="rtl">لنبدأ أولا بحصر الأشكال التي سنستخدمها، ومن ثم نرى ما الذي يتوفر لدينا من صور لكل من هذه الأشكال، وبالتالي نتعرف على طريقة صناعة القوالب الخاصة بكل شكل. قوالب الأشكال هذه ستشكل العنصر الرئيسي الذي سنبني منه المراحل المختلفة. إذا استعرضت أحد مجلدات الوحدات البنائية ستجد مجموعة كبيرة من الأشكال المختلفة، مثلا الصورة في الأسفل توضح لنا محتويات المجلد Metal elements والذي يحتوي على صور الوحدات البنائية المعدنية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image00.png.f8e072af84e7b58027eea04dfe5f85d5.png"><img data-fileid="3438" class="ipsImage ipsImage_thumbnailed" alt="image00.thumb.png.11a91dd06e57ee82d218f6" src="https://academy.hsoub.com/uploads/monthly_2015_07/image00.thumb.png.11a91dd06e57ee82d218f6c7bc67c6ab.png"></a></p><p dir="rtl">لاحظ أن هناك مجموعة أشكال رئيسية، وكل واحد منها يأتي مرة فارغا من المنتصف ومرة ممتلئا. إضافة إلى ذلك فإن هناك عدة مراحل لتشقق كل وحدة قبل تحطمها نهائيا. اختصارا للوقت سأختار مجموعة صغيرة من هذه الأشكال وهي الموجودة في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image01.png.14c6016cb333b49121829990642ec224.png"><img data-fileid="3439" class="ipsImage ipsImage_thumbnailed" alt="image01.thumb.png.3889ae2a77a928711401bf" src="https://academy.hsoub.com/uploads/monthly_2015_07/image01.thumb.png.3889ae2a77a928711401bfbf481e4008.png"></a></p><p>سنتعرف الآن على الخطوات اللازمة لتحويل كل صورة من هذه الصور إلى وحدة بنائية ذات خصائص فيزيائية، إضافة لجعلها قابلة للتحطم عبر تلقيها للضربات أو تصادمها مع غيرها أو سقوطها على الأرض أو تأثرها بالانفجارات.</p><p>سأبدأ مع المثلثات لأنها حالة خاصة تحتاج لعناية عند بناء القالب الخاص بها، بينما ستكون الأشكال التالية أسهل. لبناء قالب المثلث متساوي الضلعين والذي تراه أيمن الصورة، علينا أولا أن نضيف كائنا فارغا ونسميه <span style="font-family:courier new,courier,monospace;">Triangle</span> ومن ثم نضيف إليه المكوّن <span style="font-family:courier new,courier,monospace;">Sprite Renderer</span> ومكوّن التصادم المسمى <span style="font-family:courier new,courier,monospace;">Polygon Collider 2D</span> والذي سيظهر مبدئيا على شكل خماسي كما توضح الصورة في الأسفل. بعد إضافة مكوّن التصادم يمكننا سحب صورة المثلث إلى داخل الخانة Sprite في المكوّن<span style="font-family:courier new,courier,monospace;"> Sprite Renderer</span>. أنوه هنا إلى أنه من الضروري إضافة مكوّن التصادم قبل تحديد الصورة، وذلك لأن Unity سيحاول تغيير شكل مكوّن التصادم ليطابق شكل الصورة وهو ما لا يتم بدقة. سنقوم الآن بتغيير شكل مكوّن التصادم يدويا وذلك عبر الضغط على الزر <span style="font-family:courier new,courier,monospace;">Edit Collider</span>.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image02.png.30c04b814eb6b1fe59cd808ebdfb44f1.png"><img data-fileid="3440" class="ipsImage ipsImage_thumbnailed" alt="image02.thumb.png.29f973dd5f34ce82beb516" src="https://academy.hsoub.com/uploads/monthly_2015_07/image02.thumb.png.29f973dd5f34ce82beb5168702701dcb.png"></a></p><p dir="rtl">عند تغيير شكل مكوّن التصادم فإنه يمكننا اختيار أي نقطة من النقاط الخمسة وتحريكها، كما يمكننا اختيار نقطة وحذفها بضغط المفتاح <span style="font-family:courier new,courier,monospace;">Delete</span>. سنحتاج لحذف نقطتين من الخمسة ومن ثم مطابقة النقاط الثلاث المتبقية على زوايا المثلث ليصبح كما ترى في الصورة، وبطبيعة الحال كلما قربت الصورة أثناء مطابقة الزوايا حصلت على نتيجة أدق وأفضل.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image03.png.b2b6b70a42152aac0f8536fe28c77901.png"><img data-fileid="3441" class="ipsImage ipsImage_thumbnailed" alt="image03.thumb.png.684d6f0a7435cbb2acb789" src="https://academy.hsoub.com/uploads/monthly_2015_07/image03.thumb.png.684d6f0a7435cbb2acb78964a6d0041a.png"></a></p><p dir="rtl">بعد أن انتهينا من تجهيز شكل مكوّن التصادم يمكننا تثبيته بالضغط مجددا على <span style="font-family:courier new,courier,monospace;">Edit Collider</span> ليتم حفظ الشكل الجديد. أصبح لدينا الآن مثلث يمكن أن تصطدم به الأجسام الأخرى، إلا أنه نفسه ثابت ولا يتأثر بأي عوامل فيزيائية. لنجعله نشطا فيزيائيا علينا أن نضيف مكوّن الجسم الصلب المسمى <span style="font-family:courier new,courier,monospace;">Rigid Body 2D</span>، وهو المكوّن المسؤول عن وضع الكائن تحت تحكم المحاكي الفيزيائي الخاص بمحرك Unity، مما يجعله يتأثر بالجاذبية وقوى الدفع وغيرها.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image04.png.00b2693cb85b323de57f7b55054a30ca.png"><img data-fileid="3443" class="ipsImage ipsImage_thumbnailed" alt="image04.thumb.png.09e988a8ca6197ae0c0a8c" src="https://academy.hsoub.com/uploads/monthly_2015_07/image04.thumb.png.09e988a8ca6197ae0c0a8ce46301632d.png"></a></p><p dir="rtl">هذا المكوّن يحتوي على مجموعة خصائص أذكر هنا أهمها بالنسبة لنا:</p><ul dir="rtl"><li><strong>الكتلة Mass</strong>: كلما زادت يصبح تحريك الجسم أصعب لأن إزاحته ستحتاج لقوة أكبر، لكن هذا لا يؤثر على سرعة سقوطه.</li><li><strong>مقاومة الهواء لحركة الجسم Linear Drag</strong>: كلما زادت سيصبح توقف الجسم عن الحركة بعد زوال القوى الخارجية عنه أسرع.</li><li><strong>مقاومة الهواء للدوران Angular Drag</strong>: كلما زادت سيصبح توقف الجسم عن الدوران بعد زوال القوى الخارجية عنه أسرع.</li><li><strong>معامل الجاذبية Gravity Scale</strong>: الجاذبية الافتراضية هي 9.8 كما هو الحال مع الجاذبية الأرضية، وسيتم ضرب هذه القيمة بالمعامل لحساب الجاذبية الخاصة بهذا الكائن تحديدا.</li></ul><p dir="rtl">سنقوم بتعديل هذه القيم من أجل تمييز أنواع الوحدات البنائية عن بعضها؛ فمثلا الوحدات المعدنية يجب أن تكون أكبر كتلة من مثيلاتها الخشبية وهكذا. بقي الآن أن نجعل هذه الوحدات تتأثر بالصدمات وتتحطم بعد تلقيها عددا معينا منها؛ وهذه الآلية تتم عبر عدة بريمجات سنتعرف عليها.</p><p dir="rtl">البداية ستكون مع البريمج الذي يحدد مدى قوة تحمل الوحدة البنائية وسنسميه <span style="font-family:courier new,courier,monospace;">Breakable</span>. مهمة هذا البريمج هي تلقي الصدمات وإنقاص صحة الكائن بناء عليها؛ ومن ثم تدميره حين تصل صحته إلى صفر. السرد التالي يوضح البريمج المذكور.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class Breakable : MonoBehaviour {
    
    //مقدار الصحة الأولية للكائن
    public float initialHealth = 100;
    
    //متغير داخلي لمتابعة تغير قيمة صحة الكائن
    private float health;
    
    //تستدعى مرة واحدة عند بداية التشغيل
    void Start () {
        health = initialHealth;
    }

    //تستدعى مرة عند تصيير كل إطار
    void Update (    
    }
    
    //تقوم باستقبال الضربات وإنقاص الصحة بناء عليها
    public void TakeDamage(float amount){
           //الصحة منتهية فلا يمكن تلقي المزيد من الضربات
              if (health &lt;= 0.0f)
           {
                   return;
           }

        if(health &lt;= amount){
            //في هذه الحالة تم تدمير الكائن
                   health = 0.0f;
            SendMessageUpwards("BreakableDestroyed");
            Destroy(gameObject);
            return;
        }
        
        //قم بتقليل قيمة الصحة بمقدار قوة الضربة
        health -= amount;
        
        //أرسل رسالة تخبر بتغير الصحة
        SendMessage("DamageTaken", health);
    }
}
</pre><p>كل ما يفعله هذا البريمج البسيط هو تخزين قيمة الصحة الأولية في متغير خاص داخلي وذلك ليمنع البريمجات الأخرى من تغييرها (تذكر فصل الاهتمامات). يمكن إنقاص الصحة عن طريق إرسال رسالة لهذا البريمج اسمها <span style="font-family:courier new,courier,monospace;">TakeDamage</span> والتي تأتي مرفقة بمقدار قوة الضربة التي تلقاها الكائن. تقوم الدّالة باستقبال هذه الرسالة وإنقاص قوة الضربة من صحة الكائن، فإذا وصلت صفرا أو أقل من ذلك تقوم بتدميره. ترسل هذه الدّالة رسالتين هما <span style="font-family:courier new,courier,monospace;">DamageTaken</span> حين تلقي الضربة وترفق معها قيمة الصحة الجديدة بعد إنقاصها. الرسالة الأخرى هي <span style="font-family:courier new,courier,monospace;">BreakableDestroyed</span> والتي يتم إرسالها عند وصول الصحة إلى صفر أي عند تدمير الكائن.</p><p dir="rtl">بالعودة إلى مجموعة الصور، لنتذكر ما قلناه عن الصور المشققة والتي تمثل مراحل تحطم الوحدة البنائية. مثلا بالنسبة للمثلث الذي نستخدمه حاليا لدينا الصورة الأصلية (السليمة) إضافة لصورتين تمثلان المرحلة الأولى والثانية للتشقق كما هو موضح في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image05.png.b2bf7667d40d0fd33d90742d2ece37c7.png"><img data-fileid="3442" class="ipsImage ipsImage_thumbnailed" alt="image05.thumb.png.8f3a6b5e005471a6ecd105" src="https://academy.hsoub.com/uploads/monthly_2015_07/image05.thumb.png.8f3a6b5e005471a6ecd105a95fc5266d.png"></a></p><p dir="rtl">ما سنقوم به الآن هو كتابة بريمج آخر يقوم بالربط بين مقدار صحة الكائن والصورة المعروضة. بما أن لدينا ثلاث صور فإن كل واحدة منها ستمثل ثلث الصحة. فإذا كانت الصحة الكاملة 60 مثلا، فإن الصورة الأولى ستبقى ظاهرة طالما أن الصحة بين 60 و40، فإذا قلّت عن 40 ستظهر الصورة الثانية، وإذا قلّت عن 20 ستظهر الثالثة. وبهذه الطريقة نعطي اللاعب فكرة عن قرب تحطم هذه الوحدة. البريمج المسؤول عن هذا الأمر هو <span style="font-family:courier new,courier,monospace;">BreakableDislay</span> والموضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class BreakableDislay : MonoBehaviour {
    
    //مصفوفة لتخزين صور جميع مراحل التدمير
    //مرتبة من الحالة الأسوأ للحالة الأفضل
    public Sprite[] destructionStages;
    
    //مرجع لبريمج الوحدة البنائية
    private Breakable brk;
    
    //مرجع لمكوّن تصيير الصورة
    private SpriteRenderer sr;
    
    //متغير لتخزين صحة الكائن الأصلية في البداية
    private float fullHealth;
    
    //يتم استدعاؤها مرة واحدة عند بداية التشغيل
    void Start () {
        brk = GetComponent&lt;Breakable&gt;();
        fullHealth = brk.initialHealth;
        sr = GetComponent&lt;SpriteRenderer&gt;();
        UpdateDisplay (fullHealth);
    }
    
    //يتم استدعاؤها مرة واحدة عند تصيير كل إطار
    void Update () {
    
    }
    
    //تقوم باستقبال رسالة تلقي الضربة وتحديث الصورة بناء على قيمة الصحة الجديدة
    void DamageTaken(float newHealth){
        UpdateDisplay(newHealth);
    }
    
    //تقوم بتغيير الصورة المعروضة بناء على قيمة الصحة المزودة
    void UpdateDisplay(float health){
        //قم بتغيير مرحلة التدمير بناء على
        //قيمة الصحة الجديدة
        float healthRatio = health / fullHealth;
        int maxIndex = destructionStages.Length - 1;
        int matchingIndex = (int)(healthRatio * maxIndex);
        sr.sprite = destructionStages[matchingIndex];
    }
}
</pre><p>الدّالة الأهم في هذا البريمج هي<span style="font-family:courier new,courier,monospace;"> ()UpdateDisplay</span>، والتي تقوم باختيار صورة مرحلة التشقق الملائمة لمقدار الصحة المتبقية. لنفترض أن لدينا 3 مراحل مختلفة كما هو الحال مع المثلث الذي نعمل عليه. عندما تتغير صحة الكائن نتيجة لتلقيه ضربة معينة، سيقوم بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">DamageTaken</span> مرفقا معها قيمة الصحة الجديدة. عند استقبال هذه الرسالة من قبل البريمج <span style="font-family:courier new,courier,monospace;">BreakableDisplay</span> يقوم باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">()UpdateDisplay</span> مباشرة ويزودها بقيمة الصحة الجديدة، عندها تقوم الدّالة بقسمة الصحة الجديدة على الصحة الكاملة التي سبق تخزينها في <span style="font-family:courier new,courier,monospace;">fullHealth</span>. بقسمة الرقمين نحصل على نسبة الصحة الجديدة من الصحة الكاملة، ومن ثم نقوم بتحويل هذه النسبة إلى عدد صحيح يمثل القيمة الأقرب لها إذا ما قسمناه على عدد العناصر الكلي في مصفوفة صور مراحل التشقق.</p><p>مثلا إذا كانت الصحة الكاملة هي 100 والجديدة هي 25 وعدد المراحل 3. فإن 0.25 * 2 = 0.5 وبتحويله إلى عدد صحيح (دون جبر الكسر) سيصبح الناتج صفرا أي صورة آخر مرحلة للتشقق قبل التدمير.</p><p dir="rtl">البريمجان اللذان أضفناهما حتى الآن يعملان على حساب صحة الكائن وعرض صورة درجة التشقق بناء عليها. وكما رأينا فحين تصل صحة الكائن إلى صفر سيتم تدميره وحذفه من المشهد. حذف الكائن من المشهد سيؤدي إلى اختفائه عن الشاشة بشكل فجائي، وهو أمر غير محبذ حيث لا بد أن نعطي اللاعب شعورا أن الوحدة البنائية قد تحطمت إلى قطع صغيرة. لحسن الحظ فإن مجموعة الصور التي استخدمناها تحتوي على صور قطع حطام لجميع أنواع المواد المستخدمة، وما علينا سوى استخدامها بالطريقة الصحيحة. لنبدأ أولا بضبط الخصائص الفيزيائية لهذه القطع ومن ثم نصنع منها قوالب بعد أن تصبح جاهزة للاستخدام. لنبدأ مع القطع الثلاث الخاصة بالمعدن، والتي ستكون أجزاء الحطام لكل من الوحدات المعدنية والمتفجرة. صور هذه الأجزاء موجودة في المجلد <span style="font-family:courier new,courier,monospace;">Explosive elements</span> وهي موضحة في الصورة التالية:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image06.png.88fefb6c737804747b324cc501633835.png"><img data-fileid="3444" class="ipsImage ipsImage_thumbnailed" alt="image06.thumb.png.292b72f6b3130357725c8f" src="https://academy.hsoub.com/uploads/monthly_2015_07/image06.thumb.png.292b72f6b3130357725c8f17ffe514bd.png"></a></p><p dir="rtl">سنصنع قالبا واحدا بحيث يمكننا استخدامه لجميع صور القطع، ومن ثم نقوم بتحديد الصورة التي سنضعها عليه من خلال البريمج الذي سنراه بعد قليل. ما يلزمنا في قالب القطع المتناثرة مكوّنان:</p><ul dir="rtl"><li>الأول هو <span style="font-family:courier new,courier,monospace;">Sprite Renderer</span> والذي سيعرض الصورة كما نعرف،</li><li>والمكوّن الآخر هو الجسم الصلب <span style="font-family:courier new,courier,monospace;">Rigid Body 2D</span> والذي سيمكننا من إضافة قوة دافعة لتحريك القطعة.</li></ul><p>بعد إضافة هذين المكوّنين أصبح القالب المطلوب جاهزا ويمكننا إضافته للمشروع. الصورة التالية توضح القيم المفترضة للجسم الصلب الخاص بهذا القالب (لاحظ أننا لم نضف مكوّن تصادم، وذلك لأننا لا نريد أن تصطدم هذه القطع بأي شيء بل نريدها أن تتناثر وتسقط فحسب).</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image07.png.1373ac1d193464f4e8dde97be7b2662f.png"><img data-fileid="3445" class="ipsImage ipsImage_thumbnailed" alt="image07.thumb.png.cdc273987001e74e75cc1b" src="https://academy.hsoub.com/uploads/monthly_2015_07/image07.thumb.png.cdc273987001e74e75cc1b85aa31d1dc.png"></a></p><p dir="rtl">البريمج الثالث الذي سنضيفه للقالب هو <span style="font-family:courier new,courier,monospace;">BreakablePieces</span>، ومهمته استقبال الرسالة <span style="font-family:courier new,courier,monospace;">BreakableDestroyed</span> والتي تخبر بأن الكائن قد تم تدميره، وبناء عليها يقوم بإضافة مجموعة من قطع الحطام للمشهد وتحريكها في اتجاهات متباعدة. ليس هذا فقط، بل إن هذا البريمج سيكون مسؤولا عن إحداث الانفجار في حالة المواد المتفجرة. لنلق نظرة على البريمج أولا في السرد أدناه، ومن ثم نتناول أهم خطواته ببعض الشرح.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class BreakablePieces : MonoBehaviour {
    
    //قالب كائن قطع الحطام
    public GameObject piecePrefab;
    
    //الصور المستخدمة لقطع الحطام
    public Sprite[] piecesSprites;
    
    //كم عدد القطع التي سيتم إنشاؤها؟
    public int pieceCount;
    
    //مقدار تصغير أو تكبير قطع الحطام الناتجة
    public float scale = 1.0f;
    
    //ما هي قوة الانفجار الناتجة من تناثر القطع؟
    //القيمة صفر تعني عدم وجود انفجار
    public float explosionForce = 0.0f;
    
    //تستدعى مرة واحدة عند بداية التشغيل
    void Start () {
    
    }
    
    //تستدعى مرة واحدة عند تصيير كل إطار
    void Update () {
    
    }
    
    //BreakableDestroyed تقوم باستقبال الرسالة
    public void BreakableDestroyed(){
        //قم بجلب مكوّن التصادم
        Collider2D myCollider;
        myCollider = GetComponent&lt;Collider2D&gt;();
        
        //قم بإيجاد حدود مكوّن التصادم
        Bounds myBounds = myCollider.bounds;
        
        //قم بإنشاء العدد المطلوب من قطع الحطام
        for(int i = 0; i &lt; pieceCount; i++){
            GameObject piece = (GameObject) Instantiate(piecePrefab);
            
            //قم بوضع الصورة التالية على القطعة الجديدة
            int index = i % piecesSprites.Length;
            SpriteRenderer sr = piece.GetComponent&lt;SpriteRenderer&gt;();
            sr.sprite = piecesSprites[index];
            
            //قم بتوليد موقع عشوائي ضمن حدود مكوّن التصادم
            float posX = Random.Range(myBounds.min.x, myBounds.max.x);
            float posY = Random.Range(myBounds.min.y, myBounds.max.y);
            
            //قم بوضع قطعة الحطام في الموقع العشوائي
            piece.transform.position = new Vector2(posX, posY);
            
            //قم بتحديد الكائن الأب لقطعة الحطام بحيث
            //يكون الكائن الأب للوحدة البنائية التي تم تدميرها
            piece.transform.parent = transform.parent;
            
            //قم بتغيير حجم القطعة بالمقدار المطلوب
            piece.transform.localScale *= scale;
            
            //قم بجلب مكوّن الجسم الصلب لقطعة الحطام
            Rigidbody2D rb = piece.GetComponent&lt;Rigidbody2D&gt;();
            
            //قم بإضافة قوة دفع صغيرة
            //لتحريك قطعة الحطام بحيث يكون اتجاه القوة من مركز
            //الجسم الأصلي إلى الموقع العشوائي حيث القطعة
            Vector2 force = piece.transform.position - transform.position;
            if(explosionForce == 0.0f){
                //لا يوجد انفجار
                rb.AddForce (force, ForceMode2D.Impulse);
            } else {
                //يوجد انفجار
                rb.AddForce(force * explosionForce, ForceMode2D.Impulse);
            }

                   //احذف قطعة الحطام من المشهد بعد 5 ثوان
                  Destroy(piece, 5.0f);
        }

               if (explosionForce &gt; 0.0f)
            {
                    //تأثير الانفجار على الأجسام الأخرى
             //قم بحساب نصف قطر مجال تأثير الانفجار
                float radius = myBounds.max.magnitude * 2.0f;
                   //قم بإيجاد جميع الوحدات البنائية والأجسام القابلة للتحطيم
                   Breakable[] breakables = FindObjectsOfType&lt;Breakable&gt;();
                //قم بإرسال قوة الانفجار كمقدار تدمير للأجسام الواقعة في محيط التأثير
                  foreach (Breakable target in breakables)
                {
                       //استثن الكائن نفسه الذي نتج عنه الانفجار
                   if (target.gameObject != gameObject)
                    {
                           //قم بحساب المسافة بين الكائن وموقع الانفجار وقارنها بنصف قطر محيط التأثير
                           float dist= Vector2.Distance(
                        transform.position, target.transform.position);
                          if (dist &lt;= radius)
                      {
                               //قم بإضافة قوة الانفجار كمقدار للتدمير
                              target.TakeDamage(explosionForce / dist);
                             //قم بحساب مقدار واتجاه قوة دفع الانفجار
                           Vector2 expDir = target.transform.position - transform.position;
                           expDir = expDir * (explosionForce / radius);
                           //قم بإضافة قوة الانفجار للكائن
                             Rigidbody2D targetRB = target.GetComponent&lt;Rigidbody2D&gt;();
                            targetRB.AddForce(expDir, ForceMode2D.Impulse);
                       }
                     }
                 }
           }
    }
}
</pre><p>يحتاج هذا البريمج حتى يعمل إلى قالب يستخدمه من أجل إنشاء قطع الحطام المطلوبة، إضافة إلى قائمة بالصور التي يمكنه استخدامها لتمثيل هذه القطع. بطبيعة الحال ستختلف قائمة الصور هذه تبعا لمادة الوحدة البنائية الأصلية؛ فالكائن المعدني سينتج قطعا معدنية والخشبي قطعا خشبية وهكذا. إضافة لذلك يمكننا تحديد عدد القطع التي ستنتج عن تحطيم كل وحدة بنائية وحجم هذه القطع. هذه الأرقام ستمكننا مع ضبط عدد وحجم القطع بما يتناسب مع حجم الشكل الأصلي. أخيرا يمكننا اختيار وجود انفجار من عدمه، ومدى قوة الانفجار إن وجد. هذا يجعل البريمج قابلا للاستخدام مع الوحدات المتفجرة أيضا.</p><p dir="rtl">كل خطوات هذا البريمج مرتبطة باستقبال الرسالة <span style="font-family:courier new,courier,monospace;">BreakableDestroyed</span> التي سبق ذكرها. عند استقبال الرسالة يقوم البريمج باستخراج مكوّن التصادم ومن ثم استخراج حدود هذا المكوّن، وهي نفسها حدود الكائن. بعد ذلك يدخل في حلقة تكرارية لإنتاج العدد المطلوب من القطع، حيث يقوم في كل مرة بإنشاء قطعة جديدة واختيار صورة لها بالتسلسل. لاحظ استخدام باقي ناتج القسمة من أجل ضمان العودة من بداية قائمة الصور في حال كان عدد القطع المطلوبة أكبر من الصور المتوفرة. بعدها يتم توليد موقع عشوائي لوضع قطعة الحطام، شرط أن يكون ضمن الحدود التي سبق استخراجها من مكوّن التصادم. بما أنّ الكائن الأصلي سيتم حذفه في نهاية الإطار الحالي، فإنه لا يصلح ليكون أبا لقطع الحطام لأنها ستحذف معه في هذه الحالة. بالتالي نأخذ أب الكائن الأصلي ونحدده كأب لقطع الحطام. كذلك يتم تغيير حجم القطعة بالمقدار المطلوب scale، حيث نحتاج أحيانا لجعلها أكبر أو أصغر من حجمها في الصورة الأصلية.</p><p dir="rtl">بعد أن تصبح قطعة الحطام جاهزة وفي مكانها الصحيح، سنحتاج لإضافة قوة فيزيائية تحركها بعيدا عن مركز القطعة الأصلية. نقوم أولا باستخراج مكوّن الجسم الصلب <span style="font-family:courier new,courier,monospace;">Rigid Body 2D</span> وهو المسؤول عن الخصائص الفيزيائية لقطعة الحطام، ومن ثم نحسب المتجه المطلوب لهذه القوة وذلك بطرح موقع قطعة الحطام من موقع الكائن الأصلي. إذا كانت قوة الانفجار تساوي صفرا فلن نحتاج سوى لإضافة هذه القوة للجسم الصلب على شكل قوة اندفاع <span style="font-family:courier new,courier,monospace;">Impulse</span>. أما في حالة وجود انفجار فالأمر أكثر تعقيدا، حيث يتوجب علينا أولا ضرب القوة الدافعة بمقدار قوة الانفجار مما ينتج عنه اندفاع الحطام بسرعة أكبر ولمسافة أبعد. إضافة لذلك سيكون علينا إحداث تأثير على القطع المجاورة وهذا الأمر يتم عن طريق حساب نصف قطر محيط تأثير الانفجار، والذي اخترناه هنا ليكون طول متجه الحد الأقصى مضروبا في 2. نقوم بعدها باستخدام الدّالة<span style="font-family:courier new,courier,monospace;"> ()FindObjectsOfType</span> من أجل البحث عن جميع الكائنات التي تحتوي على البريمج <span style="font-family:courier new,courier,monospace;">Breakable</span> (أي الوحدات البنائية)، وأي واحد من هذه الوحدات يقع في محيط التأثير يجب أن تضاف له قوة الانفجار الدافعة متناسبة عكسيا مع المسافة بين مركز الانفجار في الجسم المدمر وبين الوحدة المستهدفة. قوة الانفجار الدافعة ستقوم فقط بتحريك الوحدة البنائية، لكننا نريد أيضا إنقاص صحتها بسبب الانفجار ولذلك نستدعي<span style="font-family:courier new,courier,monospace;"> ()TakeDamage</span>.</p><p dir="rtl">بعد إضافة البريمجات أصبح الكائن جاهزا لنصنع منه قالب المثلث المعدني. لكون عدد قوالب الأشكال كبيرا نسبيا، من الأفضل وضع كل مجموعة في مجلد خاص بها. مثلا مجلد <span style="font-family:courier new,courier,monospace;">Metal</span> للأشكال المعدنية و <span style="font-family:courier new,courier,monospace;">Wood</span> للخشبية وهكذا. بعد صناعة القالب يمكنك أن تغير الكائن نفسه وتغير اسمه ومن ثم تسحبه مرة أخرى إلى مستعرض المشروع لصناعة قالب جديد. مثلا يمكنك استبدال صورة المثلث بالدائرة ومن ثم تغيير الاسم إلى Circle. أيضا سيتوجب عليك تغيير شكل مكوّن التصادم عن طريق إزالة المكوّن <span style="font-family:courier new,courier,monospace;">Polygon Collider 2D</span> وإضافة المكوّن <span style="font-family:courier new,courier,monospace;">Circle Collider 2D</span> لأنه الأنسب للدائرة. وبعد صناعة قالب الدّائرة نضيف واحدا آخر للمستطيل مع تغيير مكوّن التصادم مرة أخرى ليصبح <span style="font-family:courier new,courier,monospace;">Box Collider 2D</span> وهكذا حتى ننجز الأشكال التي نرغب بها. أثناء عملك راعي الأمور التالية:</p><ol dir="rtl"><li>لحذف مكوّن موجود على كائن، قم بالضغط على رمز الترس في أعلى يمين المكوّن في نافذة الخصائص ومن ثم اختر Remove Component.</li><li>هناك بعض الأشكال مثل المثلث القائم تحتوي على صور لمرحلتي تشقق فقط بينما الأشكال الباقية تحتوي على 3 مراحل. هذا يؤثر فقط على عدد عناصر المصفوفة destructionStages ولا يلزمنا تغيير أي شيء في الكود.</li><li>مقدار الكتلة للمواد هي 6 للمعدن والمواد المتفجرة و2.5 للزجاج و5 للصخور و1 للخشب.</li><li>مقدار الصحة الافتراضية هي 100 للمعدن و 45 للمواد المتفجرة و20 للزجاج و 80 للصخور و 35 للخشب.</li></ol><p dir="rtl">بعد الانتهاء من الوحدات البنائية علينا أن نحل مشكلة صغيرة ستطرأ الآن. تذكر أن الكائنات الموجودة في المشهد حاليا هي الخلفية والأرضية والوحدات البنائية، وجميع هذه الكائنات تحتوي على مكوّنات تصادم بغض النظر عن أشكالها. معنى هذا أن Unity سيقوم باكتشاف التصادمات بين هذه الكائنات مع بعضها، وهذا ما نريده بالنسبة للأرضية والوحدات البنائية التي ستوضع فوقها، لكننا لا نريده للخلفية. فإذا تصادمت الوحدات البنائية مع الخلفية سيختل منطق المشهد تماما. لحل هذه المشكلة يوفر لنا Unity نظام الطبقات Layers والذي يمكننا من خلاله فصل الكائنات إلى طبقات بحيث يمكننا لاحقا التحكم بعلاقات هذه الطبقات مع بعضها. فمثلا يمكن أن نحدد للكاميرا ما هي الطبقات التي يمكنها أن تراها، كما يمكننا أن نحدد أي الطبقات تتصادم مع بعضها البعض. إذن لحل هذا الإشكال علينا أن نضيف طبقة جديدة مخصصة للخلفية، ونمنعها من التصادم مع الطبقة الافتراضية التي تنتمي إليها باقي الكائنات.</p><p dir="rtl">لإضافة طبقة جديدة قم باختيار قالب الخلفية <span style="font-family:courier new,courier,monospace;">BGElement</span> ومن ثم افتح القائمة Layer الموجودة في أعلى يمين نافذة الخصائص واختر Add Layer كما ترى في الصورة:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image08.png.bb0295b5b700f032878dc21e307bd03b.png"><img data-fileid="3446" class="ipsImage ipsImage_thumbnailed" alt="image08.thumb.png.fbf0e463646cb8b3641943" src="https://academy.hsoub.com/uploads/monthly_2015_07/image08.thumb.png.fbf0e463646cb8b36419438662d9872a.png"></a></p><p dir="rtl">ستظهر لك نافذة فيها مصفوفة بجميع الطبقات الافتراضية حيث يمكنك من خلالها إضافة طبقات جديدة خاصة بك. لنقم بإضافة طبقة جديدة اسمها <span style="font-family:courier new,courier,monospace;">Background</span>، ومن ثم نقوم بتغيير القالب <span style="font-family:courier new,courier,monospace;">BGElement</span> ليصبح ضمن هذه الطبقة كما ترى في الصورتين التاليتين:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image09.png.44759b057d1c296e69cf6afb1b350f39.png"><img data-fileid="3447" class="ipsImage ipsImage_thumbnailed" alt="image09.thumb.png.f8d2576bb143448b64fda7" src="https://academy.hsoub.com/uploads/monthly_2015_07/image09.thumb.png.f8d2576bb143448b64fda77a545cfe58.png"></a></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image10.png.0c3c59cf2345168c4d06b34b24b4ce1a.png"><img data-fileid="3448" class="ipsImage ipsImage_thumbnailed" alt="image10.thumb.png.73c87b407db47b67dbf2d8" src="https://academy.hsoub.com/uploads/monthly_2015_07/image10.thumb.png.73c87b407db47b67dbf2d816a8456b62.png"></a></p><p dir="rtl">بعدها علينا أن نطلب من محاكي الفيزياء الخاص بالمحرك أن يهمل التصادمات الحاصلة بين الطبقة الافتراضية <span style="font-family:courier new,courier,monospace;">Default</span> وطبقة الخلفية <span style="font-family:courier new,courier,monospace;">Background</span> بحيث لا تتصادم عناصر الأرضية أو الوحدات البنائية مع الخلفية. لتنفيذ هذا الأمر اذهب إلى القائمة:</p><p dir="rtl" style="text-align: center;"><strong>Edit &gt; Project Settings &gt; Physics 2D </strong></p><p dir="rtl">حيث ستجد في أسفل نافذة الخصائص مصفوفة تصادم الطبقات <span style="font-family:courier new,courier,monospace;">Layer Collision Matrix</span> والتي تحتوي على جميع الطبقات الموجودة في المشروع منتظمة في صفوف وأعمدة. في كل نقطة تقاطع بين صف وعمود ستجد مربعا يمكنك تفعيله أو تعطيله. إذا قمت بتعطيل أحد هذه المربعات فإن التصادم الحاصل بين الطبقتين المتقاطعتين فيه سيتم إهماله. بالتالي ما نريده هو تعطيل المربع الذي تتقاطع فيه الطبقة <span style="font-family:courier new,courier,monospace;">Default</span> مع الطبقة <span style="font-family:courier new,courier,monospace;">Background</span> كما ترى في الصورة أدناه:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image11.png.17cdbbbe4384694fade7ee1ce92a0f08.png"><img data-fileid="3449" class="ipsImage ipsImage_thumbnailed" alt="image11.thumb.png.486cc15d44e606b56c934f" src="https://academy.hsoub.com/uploads/monthly_2015_07/image11.thumb.png.486cc15d44e606b56c934f5a62fb137a.png"></a></p><p dir="rtl">بعد تجهيز قوالب الوحدات البنائية يتبقى علينا إضافة قالب قطع الحطام للبريمج <span style="font-family:courier new,courier,monospace;">BreakablePieces</span>، كما أن علينا تحديد صور القطع الخاصة بكل وحدة بنائية وتحديد عددها وأحجامها. لاختصار الوقت سأعتمد قيما ثابتة لجميع الوحدات البنائية، وهو 5 قطع حطام لكل وحدة وتحجيم بمقدار 0.5 (صور قطع الحطام موجودة في مجلد يسمى <span style="font-family:courier new,courier,monospace;">Debris</span>). للوقوف على التقدم في بناء قالب الوحدة البنائية، يفترض أن يكون ما أنشأناه حتى الآن شبيها بما تراه في الصورة أدناه:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image12.png.b1a1bfae2fd208d15f3c0709d8f6a10f.png"><img data-fileid="3450" class="ipsImage ipsImage_thumbnailed" alt="image12.thumb.png.a71957631582976ce87be1" src="https://academy.hsoub.com/uploads/monthly_2015_07/image12.thumb.png.a71957631582976ce87be14452f1018d.png"></a></p><p dir="rtl">السؤال التالي الذي نريد الإجابة عليه هو: كيف تتناقص قيمة صحة هذه الوحدات البنائية عند سقوطها أو اصطدامها ببعضها البعض أو بمقذوفات اللاعب؟</p><p dir="rtl">يساعدنا Unity بالإجابة على هذا السؤال حيث أنه يوفر لنا رسائل إعلام بحدوث أي عمليات تصادم بين الكائنات المختلفة. سنقوم الآن بكتابة بريمج يستقبل رسائل التصادم هذه ويقوم بتحليل محتوياتها وحساب مقدار التدمير الذي يجب أن يتم على كل وحدة بنائية. هذا البريمج هو <span style="font-family:courier new,courier,monospace;">CollisionDamageTaker</span>، وهو موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class CollisionDamageTaker : MonoBehaviour {

   //متغير لتخزين آخر عملية تصادم
   //يساعد هذا على منع تكرار التصادمات
   private float lastCollisionTime = 0.0f;

   //يتم استدعاؤها مرة واحدة عند بداية التشغيل
   void Start () {
    
   }
    
   //يتم استدعاؤها مرة عند تصيير كل إطار
   void Update () {
    
   }

   //يتم استدعاؤها عند حدوث تصادم بين هذا الكائن وكائن آخر
   void OnCollisionEnter2D(Collision2D col)
   {
       if (Time.time - lastCollisionTime &lt; 0.25f)
       {
           //لم يمر وقت كاف منذ آخر تصادم، قم بإهمال هذا التصادم ولا تفعل شيئا
           return;
       }

       //قم بتسجيل وقت حدوث التصادم
       lastCollisionTime = Time.time;

       //قم باستخراج مكوّن الموقع من الكائن الآخر الذي حدث معه التصادم
       Transform otherObject = col.transform;

       //احسب ارتفاع الكائنين المتصادمين
       float myHeight = transform.position.y;
       float otherHeight = otherObject.position.y;

       //ما هو مقدار قوة الإصابة التي تم تلقيها؟
       float damageAmount = 1.0f;

       //قم بحساب قوة الإصابة بناء على موقع
       //الكائن الآخر
       if (myHeight &lt; otherHeight)
       {
           //سقط كائن آخر فوق هذا الكائن

           //كم كانت سرعة الجسم الساقط حين اصطدامه؟
           float fallVelocity = col.relativeVelocity.magnitude;
           //اضرب مقدار الإصابة بسرعة الاصطدام
           damageAmount *= fallVelocity;

           //ما هي كتلة الكائن الذي سقط فوق هذا الكائن؟
           Rigidbody2D otherRB = otherObject.GetComponent&lt;Rigidbody2D&gt;();
           float otherMass = otherRB.mass;
           //اضرب مقدار الإصابة مرة أخرى بالكتلة
           damageAmount *= otherMass;
           //قم أخيرا بمضاعفة مقدار الإصابة لأن الكائن الآخر جاء من مكان أعلى
           damageAmount *= 2.0f;
       }
       else
       {
           //الكائن الحالي هو الذي سقط
           //الكائنات الساقطة بسرعة أكبر ستحصل على إصابة أكبر
           float myFallVelocity = col.relativeVelocity.magnitude;
           //اضرب مقدار الإصابة بسرعة الاصطدام
           damageAmount *= myFallVelocity;
       }
       
       //قم بإرسال رسالة لإنقاص الصحة بمقدار الإصابة المحسوبة
       SendMessage("TakeDamage", damageAmount);
   }
}
</pre><p>كما ذكرت فإنّ هذا البريمج يعمل على تقليل صحة كائن الوحدة البنائية بناء على اصطدامها بالكائنات الأخرى في المشهد. المتغير الوحيد الذي عرفناه هنا هو <span style="font-family:courier new,courier,monospace;">lastCollisionTime</span> والذي يخزن الوقت الذي تم فيه إنقاص الصحة آخر مرة. الهدف من استخدام هذا المتغير هو منع الاصطدامات المتتالية والتي قد تحدث في إطار واحد أو إطارين متتابعين من إنقاص الصحة بسرعة كبيرة، حيث أننا هنا نسمح بإنقاص الصحة مرة كل ربع ثانية فقط.</p><p dir="rtl">عند تصادم كائنين مع بعضهما يقوم محرك Unity بإرسال الرسالة <span style="font-family:courier new,courier,monospace;">OnCollisionEnter</span> إلى هذين الكائنين في نفس الوقت، ويرفق مع هذه الرسالة متغيرا من نوع <span style="font-family:courier new,courier,monospace;">Collision2D</span> والذي يحتوي على معلومات حول التصادم، إضافة لأنه يحتوي على مرجع للكائن الآخر بالتالي يمكن لكل منهما التعرف على الكائن الآخر الذي اصطدم به وخصائصه. الخطوة الأولى للدّالة <span style="font-family:courier new,courier,monospace;">()OnCollisionEnter</span> هي أن تتأكد من مرور ربع ثانية على الأقل منذ آخر مرة تم فيها إنقاص صحة الكائن، فإن لم يتحقق هذا الشرط سيتوقف تنفيذ الدّالة على الفور.</p><p dir="rtl">طريقة حساب مقدار الإصابة (المقدار الذي سيتم إنقاصه من الصحة) يعتمد على عدة عوامل ويبدأ من قيمة افتراضية هي 1. العامل الأول هو ارتفاع كل من الكائنين المتصادمين. لنفترض أن الدّالة اكتشفت أثناء التنفيذ أن الكائن الآخر <span style="font-family:courier new,courier,monospace;">otherObject</span> ذو ارتفاع أعلى من الكائن الحالي. هذا الأمر يفسر على أن الكائن الآخر قد سقط فوق الكائن الحالي واصطدم به، بالتالي يجب أن يكون مقدار الإصابة أعلى. من أهم المعلومات التي تحملها الرسالة هي<span style="font-family:courier new,courier,monospace;"> col.relativeVelocity</span>، والتي تحسب السرعة النسبية بين الكائنين لحظة الاصطدام. منطقيا يجب أن يتناسب مقدار هذه السرعة طرديا مع قوة الإصابة، لذا فإننا نقوم باستخراج هذا المقدار <span style="font-family:courier new,courier,monospace;">relativeVelocity.magnitude</span> (السرعة هنا هي متجه لذلك نستخرج مقدارها) وضربه بقيمة قوة الإصابة. بعد ذلك نقوم باستخراج مكوّن الجسم الصلب <span style="font-family:courier new,courier,monospace;">RigidBody2D</span> من الكائن الآخر وضرب كتلته بمقدار الإصابة، حيث يجب أن تزيد الإصابة كلما كان الكائن الذي سقط ذا كتلة أكبر. أخيرا نقوم بمضاعفة القيمة النهائية التي حسبناها؛ وذلك لجعل سقوط كائن فوق آخر ذا تأثير أكبر من سقوط الكائن نفسه على الأرض أو على جسم آخر.</p><p dir="rtl">الاحتمال الآخر هو أن يكون الكائن الحالي ذا ارتفاع أعلى من الكائن الآخر الذي سقط فوقه، بالتالي لا حاجة لنا بأخذ أية معلومات من هذا الجسم الآخر. كل ما سنفعله في هذه الحالة هو ضرب قيمة الإصابة بسرعة الاصطدام، مما يجعل سقوط الجسم نفسه أقل أذى من سقوط جسم آخر فوقه. بعد المرور على أحد هذين الاحتمالين نحصل على قيمة الإصابة النهائية في المتغير <span style="font-family:courier new,courier,monospace;">damageAmount</span> وبالتالي نرسل الرسالة <span style="font-family:courier new,courier,monospace;">TakeDamage</span> ونرفق معها القيمة المحسوبة. لاحظ أن البريمج المرسل <span style="font-family:courier new,courier,monospace;">CollisionDamageTaker</span> والمستقبل <span style="font-family:courier new,courier,monospace;">Breakable</span> موجودان على نفس الكائن، ولا يوجد أي كائن آخر مهتم باستقبال هذه الرسالة. لهذا السبب استخدمنا الدّالة<span style="font-family:courier new,courier,monospace;">()SendMessage</span> في عملية الإرسال.</p><p dir="rtl">بقي علينا خطوة واحدة لإكمال قالب الوحدة البنائية، وهي الصوت الذي سيصدر من الوحدة البنائية حين تحطمها. هذا الصوت سيختلف باختلاف مادة الوحدة البنائية؛ فصوت تحطم الزجاج ليس كالحجر وليس كالمعدن أو الخشب. هذا الاختلاف سينعكس على ملف الصوت المستخدم، إلا أن التقنية ستكون نفسها وستعمل كلها باستخدام نفس البريمج وهو <span style="font-family:courier new,courier,monospace;">BreakableSounds</span>. سيعمل هذا البريمج على إصدار صوت في حالتين: عند تلقي إصابة بمقدار قوي، وعند تحطم الوحدة البنائية نهائيا. الهدف من حصر الصوت الأول بالإصابات ذات المقدار القوية هو أن عددا كبيرا من التصادمات يمكن أن يحدث في نفس الإطار مما سينتج عنه أصوات كثيرة مزعجة وهي نتيجة ليست مرضية على الإطلاق. هذا البريمج موضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class BreakableSounds : MonoBehaviour {

   //يتم تشغيل هذا الصوت عند تلقي إصابة
   public AudioClip damageSound;

   //يتم تشغيل هذا الصوت عند تحطم الوحدة البنائية
   public AudioClip destructionSound;

   //الحد الأدنى لمقدار الإصابة التي تؤدي لتشغيل الصوت
   public float minDamage = 25.0f;

   //المدة الزمنية التي يمنع خلالها تشغيل أي صوت من قبل هذا الكائن
   private float suspensionTime = 0.0f;

   //الوقت الذي بدأ فيه تشغيل آخر صوت من قبل هذا الكائن
   private float playTime = 0.0f;

   //تستدعى مرة واحدة عند بداية التشغيل
    void Start () {
    
   }
    
    //تستدعى مرة عند تصيير كل إطار
    void Update () {
    
    }

   //DamageTaken تقوم باستقبال رسالة الإصابة
   void DamageTaken(float amount)
   {
       //سيتم تشغيل الصوت فقط للإصابات التي
       //يزيد مقدارها عن الحد الأدنى
       if (amount &gt;= minDamage)
       {
           CheckAndPlay(damageSound);
       }
   }

   //BreakableDestroyed تقوم باستقبال رسالة تدمير الوحدة البنائية
   void BreakableDestroyed()
   {
       AudioSource.PlayClipAtPoint(destructionSound, transform.position);
   }

   //تقوم بحساب الوقت الذي يمنع فيه تشغيل ملف الصوت وتقرر بناء عليه تشغيل الملف مجددا من عدمه
   void CheckAndPlay(AudioClip clip)
   {
       if (Time.time - playTime &gt; suspensionTime)
       {
           AudioSource.PlayClipAtPoint(clip, transform.position, 0.25f);
           playTime = Time.time;
           suspensionTime = clip.length + 0.5f;
       }
   }
}
</pre><p>لعل المهام الرئيسية لهذا البريمج واضحة: فهو يستقبل الرسالتين <span style="font-family:courier new,courier,monospace;">DamageTake</span> و <span style="font-family:courier new,courier,monospace;">BreakableDestroyed</span> من البريمج <span style="font-family:courier new,courier,monospace;">Breakable</span> ويقوم بناء عليها بتشغيل واحد من ملفي الأصوات المحددين وهما من نوع <span style="font-family:courier new,courier,monospace;">AudioClip</span>، واللذين يمكننا اختيارهما من نافذة الخصائص كما سنرى بعد قليل. المتغير <span style="font-family:courier new,courier,monospace;">minDamage</span> يمكننا من اختيار الحد الأدنى للإصابة التي ستؤدي إلى تشغيل ملف الصوت، وهو افتراضيا 25. لاحظ أن تشغيل صوت الإصابة يتم بطريقة تختلف عن تشغيل صوت التدمير؛ ذلك أن الأخير لا يمكن أن يتكرر كما هو الحال في الأول. بطبيعة الحال فإن تلقي عدة إصابات في فترة قصيرة أمر ممكن، لذلك علينا أن نمنع تكرار تشغيل ملف الصوت مرات متتابعة بشكل مزعج. لأجل ذلك نقوم عند تشغيل ملف صوت الإصابة بحساب طول الملف وإضافة نصف ثانية إليه، ومن ثم تخزين الناتج في المتغير <span style="font-family:courier new,courier,monospace;">suspentionTime</span>. عند محاولة تشغيل ملف صوت الإصابة مرة أخرى نقوم بمقارنة الوقت المنقضي منذ آخر تشغيل بوقت منع التشغيل <span style="font-family:courier new,courier,monospace;">suspentionTime</span>. إذا كانت هذه المدة أقل من وقت المنع فلن يتم تشغيل الملف. هذه الخطوات تقوم بها الدّالة <span style="font-family:courier new,courier,monospace;">()CheckAndPlay</span>.</p><p dir="rtl">بعد إضافة هذا البريمج لقالب الوحدة البنائية، سيظهر المتغيران <span style="font-family:courier new,courier,monospace;">damageSound</span> و <span style="font-family:courier new,courier,monospace;">destructionSound</span> في نافذة الخصائص على شكل خانات يمكن أن تضيف إليها ملفات صوتية. لكل نوع من أنواع الوحدات البنائية الخمسة (المعدن والمتفجرات والحجر والخشب والزجاج) سيكون هناك ملفات مختلفة. هذه الملفات تم جلبها من مواقع مختلفة حيث لا يتوفر دائما مكتبة صوتية شاملة يمكن الاعتماد عليها كمصدر لكل المؤثرات الصوتية، أو على الأقل لا تتوفر مجانا. كما ذكرت سابقا تم وضع الملفات في مجلدات تحمل أسماء المواقع التي تم إحضارها منها، مع الإبقاء على اسم الملف الأصلي كما هو في الموقع دون تغيير. الصورة التالية توضح شكل البريمج <span style="font-family:courier new,courier,monospace;">BreakableSounds</span> لكائنين أحدهما وحدة بنائية خشبية والأخرى حجرية. وبهذا نكون قد انتهينا من قوالب الوحدات البنائية بشكل عام. الصورة الأخيرة في الأسفل توضح الشكل العام لقوالب الوحدات البنائية مع كافّة المكوّنات اللازمة، والتي تم إغلاقها اختصارا للمساحة.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image13.png.ab6c0a2e7ff5d254cc6beceea42439a1.png"><img data-fileid="3451" class="ipsImage ipsImage_thumbnailed" alt="image13.thumb.png.18ebdf6f920112788896ad" src="https://academy.hsoub.com/uploads/monthly_2015_07/image13.thumb.png.18ebdf6f920112788896ad1ed5df54b9.png"></a><br><br><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image14.png.b9d1e5fe9bdc45bcd0aeb832f66dc83e.png"><img data-fileid="3452" class="ipsImage ipsImage_thumbnailed" alt="image14.thumb.png.4deeb8e835b778385877bd" src="https://academy.hsoub.com/uploads/monthly_2015_07/image14.thumb.png.4deeb8e835b778385877bd4c6a40f7bc.png"></a></p><p dir="rtl">بقي أمر واحد سنضيفه كلمسة جمالية على لعبتنا، وهي حدوث انفجار مرئي عند تحطم الوحدات البنائية المتفجرة. هذا الانفجار موجود في الحزمة <span style="font-family:courier new,courier,monospace;">Explosion Pack</span> في موقع kenney.nl والذي سبق وضع روابطه، وهو يحمل الاسم <span style="font-family:courier new,courier,monospace;">Regular Explosion</span>. الانفجار عبارة عن 9 صور متتابعة كما ترى في الصورة في الأسفل:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image15.png.1a64b7d501035c296592f6f40232e784.png"><img data-fileid="3453" class="ipsImage ipsImage_thumbnailed" alt="image15.thumb.png.ea158b01dc0529ca85201a" src="https://academy.hsoub.com/uploads/monthly_2015_07/image15.thumb.png.ea158b01dc0529ca85201a685891b781.png"></a></p><p dir="rtl">ما يتوجب فعله الآن هو أن نصنع قالبا خاصا بالانفجار بحيث يعرض هذه الصور التسعة بشكل متتابع، ومن ثم نقوم بكتابة بريمج يعمل على إنشاء كائن من هذا القالب في حال تحطم أحدى الوحدات البنائية المتفجرة. لنبدأ مع قالب الانفجار والذي سيحتوي على مكوّن واحد هو <span style="font-family:courier new,courier,monospace;">SpriteRenderer</span> إضافة للبريمج <span style="font-family:courier new,courier,monospace;">SpriteAnimator</span> الموضح في السرد التالي، والذي سيعمل على عرض الصور بشكل متتابع.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class SpriteAnimator : MonoBehaviour {

   //مصفوفة تحتوي على اللقطات التي تشكل الحركة
   public Sprite[] frames;

   //سرعة التحريك مقدرة بعدد اللقطات في الثانية
   public float framesPerSecond = 16.0f;

   //هل يجب أن يتم تدمير الكائن وحذفه بعد انتهاء التحريك؟
   public bool destroyOnCompletion = true;

   //متغير لتسجيل الوقت الذي تم فيه تغيير اللقطة آخر مرة
   private float lastChange = 0.0f;

   //متغير مرجعي لمكوّن تصيير الصور ثنائية الأبعاد
   private SpriteRenderer renderer;

   //موقع اللقطة المعروضة حاليا في مصفوفة اللقطات
   private int currentFrame = 0;

   //يتم استدعاؤها مرة واحدة عند بداية التشغيل
   void Start () {
       renderer = GetComponent&lt;SpriteRenderer&gt;();
   }
    
   //يتم استدعاؤها مرة عند تصيير كل إطار
   void Update () {
       Animate();
   }

   //تقوم بعملية التحريك عن طريق عرض اللقطات بشكل متتابع
   void Animate()
   {
       //احسب المدة التي يجب أن تقضيها اللقطة الواحدة
       float frameTime = 1.0f / framesPerSecond;
       //قم بالتبديل للإطار التالي في حال انقضى الوقت اللازم للقطة السابقة
       if (Time.time - lastChange &gt; frameTime)
       {
           lastChange = Time.time;
           currentFrame = (currentFrame + 1) % frames.Length;
           renderer.sprite = frames[currentFrame];
           if (currentFrame == 0 &amp;&amp; destroyOnCompletion)
           {
               Destroy(gameObject);
           }
       }
   }
}
</pre><p>ببساطة شديدة يقوم هذا البريمج عند تصيير كل إطار باستدعاء الدّالة <span style="font-family:courier new,courier,monospace;">Animate</span>، والتي تقوم بحساب الوقت اللازم لعرض كل لقطة عن طريق قسمة الرقم 1 على السرعة. بعد ذلك تقارن الوقت المنقضي منذ تم التبديل للقطة الحالية مع الوقت اللازم للقطة الواحدة، فإذا انقضى هذا الوقت تقوم بالتبديل إلى اللقطة التالية في المصفوفة <span style="font-family:courier new,courier,monospace;">frames</span>. من البديهي هنا أن تتم إضافة لقطات الانفجار بشكل مرتب إلى المصفوفة <span style="font-family:courier new,courier,monospace;">frames</span> وذلك حتى تظهر بالتتابع الصحيح كما هو موضح في الصورة التالية. لاحظ أخيرا أننا نقوم بتدمير الكائن بعد انتهاء عرض اللقطات لأننا لا نريد تكرار مشهد الانفجار سوى مرة واحدة.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image16.png.2d97b2399e48a2f112e435a63f933714.png"><img data-fileid="3454" class="ipsImage ipsImage_thumbnailed" alt="image16.thumb.png.ff9a49000ebd7f70fb37bb" src="https://academy.hsoub.com/uploads/monthly_2015_07/image16.thumb.png.ff9a49000ebd7f70fb37bb618f3d86a1.png"></a></p><p dir="rtl">بعد إنشاء قالب الانفجار علينا أن نربط إنشاء الانفجار بتدمير الوحدة البنائية المتفجرة. هذه عملية بسيطة لا تتطلب أكثر من استقبال الرسالة <span style="font-family:courier new,courier,monospace;">BreakableDestroyed</span> ومن ثم إنشاء كائن جديد من قالب الانفجار في نفس موقع الوحدة البنائية التي تم تدميرها. هذه المهمة يقوم بها البريمج <span style="font-family:courier new,courier,monospace;">BreakableSpawn</span> والموضح في السرد التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class BreakableSpawn : MonoBehaviour {

    //قالب الكائن الذي سيتم إنشاؤه بعد التدمير
    public GameObject prefab;

   //يتم استدعاؤها مرة عند بداية التشغيل
   void Start () {
    
   }
    
   //يتم استدعاؤها مرة عند تصيير كل إطار
   void Update () {
    
   }

   //BreakableDestroyed تقوم باستقبال رسالة تدمير الوحدة البنائية
   void BreakableDestroyed()
   {
       //قم بإنشاء كائن جديد كم القالب وضعه في نفس موقع الكائن الحالي الذي تم تدميره
       GameObject newObject = (GameObject)Instantiate(prefab);
       newObject.transform.position = transform.position;
       newObject.transform.parent = transform.parent;
   }
}
</pre><h2 dir="rtl">إنشاء كائنات الخصوم</h2><p dir="rtl">كما تعلم تتكون المرحلة الواحدة في هذه الألعاب من العناصر البنائية والخصوم ومقذوفات اللاعب التي يطلقها على هذه الوحدات والخصوم التي تحتمي بها. بالتالي فالعنصر الثاني الذي يلزمنا بعد تجهيز الوحدات البنائية هو شخصيات الخصوم. بالاطلاع على المجلد <span style="font-family:courier new,courier,monospace;">Aliens</span> في مجموعة الصور، تلاحظ وجود خمسة أنواع من الكائنات بأشكال غريبة، بعضها مربع الشكل والآخر دائري، وبعضها يرتدي ما يشبه الخوذة. من ناحية السلوك الفيزيائي لا تختلف كائنات الخصوم عن الوحدات البنائية؛ حيث أنها تمتلك صحة محددة تنقص بتلقي الضربات، كما أنها تتأثر بالانفجارات والتصادمات وما شابه. هذا يعني – لحسن الحظ – أن المجهود الذي بذلناه في كتابة البريمجات السابقة الخاصة بقوالب الوحدات البنائية سيعطي ثماره في هذه المرحلة، حيث سنعيد استخدام تلك البريمجات من أجل صنع قوالب الخصوم، ولن نحتاج لكتابة أي بريمج جديد باستثناء واحد سنتحدث عنه بعد قليل.</p><p dir="rtl">كل ما علينا هو إضافة البريمجات <span style="font-family:courier new,courier,monospace;">Breakable</span> و <span style="font-family:courier new,courier,monospace;">BreakablePieces</span> و <span style="font-family:courier new,courier,monospace;">CollisionDamageTaker</span> و <span style="font-family:courier new,courier,monospace;">BreakableSounds</span>، ومن ثم تحديد القيم المناسبة لكل نوع من أنواع الوحوش. اختصارا للوقت سأعتبر الأشكال الأربعة ذات نفس الخصائص، إضافة لمنح الوحوش التي تحتوي على خوذة مقدارا أعلى من الصحة. ستكون صحة الوحشين المربع والدائري هي 50، بينما الوحش ذو الخوذة ستكون صحته 100. وهذا سينطبق على الألوان الخمسة للوحوش.</p><p dir="rtl">بطبيعة الحال علينا أيضا إضافة مكوّن الجسم الصلب <span style="font-family:courier new,courier,monospace;">RigidBody2D</span> و أحد مكوّني التصادم <span style="font-family:courier new,courier,monospace;">BoxCollider2D</span> أو <span style="font-family:courier new,courier,monospace;">CircleCollider2D</span> وذلك حسب شكل الوحش. الشكل التالي يوضح القالب الخاص بأحد الوحوش التي ترتدي خوذة. يمكنك الاطلاع على قوالب الوحوش في المجلد <span style="font-family:courier new,courier,monospace;">Prefabs\Enemies:</span></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image17.png.2aa30b29c0e3b96f3a8be8dedbc80622.png"><img data-fileid="3455" class="ipsImage ipsImage_thumbnailed" alt="image17.thumb.png.b280d141f90f198cd6cf10" src="https://academy.hsoub.com/uploads/monthly_2015_07/image17.thumb.png.b280d141f90f198cd6cf105a8d6ca99f.png"></a></p><p dir="rtl">هناك اختلافات أخرى يجب مراعاتها بين الوحدات البنائية والوحوش، فهناك ملفات صوتية مختلفة للإصابة والتدمير، إضافة لأن تدمير الوحوش ينتج عنه نجوم بدلا من قطع الحطام. صور النجوم هذه موجودة في المجلد <span style="font-family:courier new,courier,monospace;">PhysicsPack\Others</span> وهي موضحة في الشكل التالي. لاحظ أيضا أن عدد النجوم الناتجة كبير نسبيا وهو 10:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image18.png.dbee4fe45101981f1c9c332d5068242c.png"><img data-fileid="3456" class="ipsImage ipsImage_thumbnailed" alt="image18.thumb.png.89312181e0a3a71b286afa" src="https://academy.hsoub.com/uploads/monthly_2015_07/image18.thumb.png.89312181e0a3a71b286afa232ffb405a.png"></a></p><p dir="rtl">كل الفروق السابقة بين الوحدات البنائية والوحوش هي فروق شكلية، لكن الفرق الأهم هو أن نكون قادرين على التمييز بينهما برمجيا؛ وذلك لأن تدمير الوحوش يختلف عن تدمير الوحدات البنائية وهو ذو علاقة مباشرة بحالة اللعبة. فتدمير جميع الوحوش في المشهد سيؤدي لفوز اللاعب بالمرحلة وانتقاله للمرحلة التالية، إلا أن هذا ليس هو الحال بالنسبة للوحدات البنائية. ولأن تدمير الوحوش أمر مهم، علينا أن نضيف لقالب كل وحش منها بريمجا يقوم بإرسال رسالة للكائن الجذري حين تدمير كائن الوحش، وسيتكفل بريمج آخر سنأتي عليه بعد حين بمهمة استقبال الرسالة وعمل ما يلزم حيالها. ما يهم الآن هو أن نضيف البريمج <span style="font-family:courier new,courier,monospace;">Enemy</span> والموضح في السرد التالي لكل قوالب الوحوش التي أنشأناها.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

   //يتم استدعاؤها مرة عند بداية التشغيل
   void Start () {
    
   }
    
   //يتم استدعاؤها مرة عند تصيير كل إطار
   void Update () {
    
   }

   //ومن ثم BreakableDestroyed تقوم باستقبال الرسالة
   //ترسل رسالة للأعلى أي للكائن الجذري بأن الوحش تم تدميره
   void BreakableDestroyed()
   {
       SendMessageUpwards("EnemyDestroyed");
   }
}</pre><p dir="ltr" style="text-align: right;">:بهذا أصبح لدينا كل ما يلزم لبناء مشهد، وما عليك سوى رص الوحدات البنائية والوحوش بأي ترتيب ترغب به من أجل صنع مرحلة كما في الصورة التالية</p><p dir="ltr" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_07/image19.png.6c5dad1f6b3b53c303b6cc34ad24cd34.png"><img data-fileid="3457" class="ipsImage ipsImage_thumbnailed" alt="image19.thumb.png.b20f2e31042312d93740e6" src="https://academy.hsoub.com/uploads/monthly_2015_07/image19.thumb.png.b20f2e31042312d93740e68535fa7b20.png"></a></p><p dir="ltr" style="text-align: right;">.وبهذا نكون انتهينا من تجهيز مشهد اللعبة. سنقوم في الدرس القادم ببناء واجهة المستخدم والشاشة الرئيسية للعبة</p>
]]></description><guid isPermaLink="false">134</guid><pubDate>Sun, 02 Aug 2015 10:42:00 +0000</pubDate></item></channel></rss>
