الثلاثاء، 17 أغسطس 2010

سلسلة تطوير الألعاب للبلاليص | الجزء الخامس : الدبابات #2

تمهيد : أولاً أحب أن أهنّئ المسلمين بمناسبة شهر رمضان ..... ثانياً أعتذر عن التأخير مرة أخرى ... كما يبدو الآن فالسلسلة مواعيدها غير منتظمة ... سأحاول في الفترة المقبلة أن أنتظم أكثر أو أن أصدر جزئين معاً مثلا حين بتوفر لي بعض الوقت .... حسناً ... فلنعود للعمل ... لقد تركنا اللعبة على هذه الحال :-







الكاميرا وحركة الدبابة : هناك تعديل بسيط على حركة الدبابة ...... فالأزرار المعينة لاتجاهات الحركة ليست مناسبة .... فالأزرار الرأسية تجعل الدبابة تتحرك في مستوى أفقي .... وهذا قد يسبب ارتباك للاعب ... ولهذا فسنقوم بتعديل بسيط على حركة الدبابة وهو تغير الأزرة التي نتحقق من الضغط عليها إلى Horizontal ولكن عندها سنلاحظ ان الحركة معكوسة ... وحلّها بسيط وهو إبدال الـ (+) بـ (-) ...... الآن الحركة منطقية بعض الشئ ... والآن فلنترك الدبابة ولنتحدّث عن حركة الكاميرا قليلاً .... اللعبة من النوع التنقّل الجانبي (side-scroller) ... ولهذا فيجب على الكاميرا أن تتحرك مع الدبابة في المستوي المسطح وفي نفس اتجاه الدبابة .... ولهذا أرفنقنا نفس السكريبت الخاص بالدبابة للكاميرا ... ولكن لايبدو أنه يعمل كما يبدو .... فلو نظرت إلى المشهد خلال اللعب ستجد أن الكاميرا تتحرك في الاتجاه المعاكس ... ولهذا يجب أن ننشئ نسخة خاصة بالكاميراً من السكريبت ونعدّل عليها لتوافق خصائص الكاميرا ..... حسنا ... فلننشئ سكريبت جديد ولنسمّيه cameraController .... في الحقيقة هو نفس السكريبت الخاص بحركة الدبابة ولكن مع تعديل بسيط .... وهو عكسّ اتجاه الحركة .... أي إبدال الـ (-) بالـ (+) مرّة أخرى وطبعا تخصيص المتغيرات .... ها هو السكريبت بعد التعديل :

//Camera Controller
var cameraSpeed : int = 2.0 ;

function Update () {
if(Input.GetButton("Horizontal"))
{
transform.position += Input.GetAxis("Horizontal") * transform.right * cameraSpeed * Time.deltaTime;
}
}

والآن عند تطبيق السكريبت الجديد على الكاميرا وحذف السكريبت القديم وتجربة اللعبة سيبدو لك أن الدبابة لا تتحرك .... ولكن في الحقيقة هي تتحرك والكاميرا معا فلا يبدو التغير النسبيي بين موقعيهما ظاهراً لأنهما يتحركان في نفس الاتجاه وبنفس السرعة .... وهذا هو المطلوب ... أيضا ربما علينا أن نسرّع الحركة قليلاً للدبابة والكاميرا .... فلنعيّن سرعة الدبابة والكاميرا لـ 3 بدلاً من 2 من خلال خصائص مكوّن السكريبت لكل واحدة .... ولنضع دليلاً ثابتا أيضاً كمكعب مثلا حتى نستطيع قياس إذا كانت السرعة مناسبة  .... كما في الصورة هنا :-

أيضاً الخلفية لونها لا يعجبني ... ولهذا سأقوم بتغيرها للون آخر إلى أن نتطرق إلى كيفية إضافة صناديق السماء (SkyBoxes) ...فلنحدد الكاميرا وفي مكوّن Camera سنجد خصيصة بعنوان Back Ground Color ... همممم ... فلنرى .... فليكن هذا اللون :-

لايهم اللون الآن ... فكلّه سيتغير على أي حال بعد أن نضيف صندوق سماء للعبة ..... والآن بعد أن أصبّح تنقّل الدبابة والكاميرا مضبوطاً .... فلننتقل لموضوع آخر وهو الخامات والإكساء ....

الخامات والإكساء (Materials & Textures) :- لو تذكّر فقد تكلّمنا قليلاً عن الخامة أو الـMaterial في الجزء الثالث من السلسلة .... وقد حان الوقت لنطبّق هذا عملياً .... ولكن أولاً علينا أن نوضّح الفرق بين الخامة (Material) والإكساء (Texture) ..... فلنفكّر في الخامة على أنها كل شئ يصفّ "منظر" السطح المطبّق عليه ... بينما الإكساء هو جزء من الخامة وهو عبارة عن صورة ... لها وظيفة معينه في الخامة .... قد تكون اللون/الصورة الأولية (Diffuse) ... أو خريطة لوصف الإضاءة على السطح (Light Map) ... إلخ إلخ .... على العموم ... لاتشغل بالك بهذا ... يمكنك البحث بتعمّق عن الموضوع إذا أردت .... ولكن مايهمن الآن هو أننا سننشئ خامة جديدة للأرضية في اللعبة .... ولكن أولاً علينا إنشاء إكساء لها ... سيكون الصورة الأولية (Diffuse) لها ... وبعدها سنطبّقه في الخامة ..... قمت بعمل خامة بسيطة جداَ عن طريق دمج صورتين إحداهما لأعشاب والأخرى لتراب لينتج الآتي (اضغط على الصورة لتحميل النسخة بامتداد .TGA) :-

أعد تسمية الصورة لـ textureGround .... وانقلها إلى مجلد Materials الموجود في Objects .... والآن لم يتبقى غير إنشاء الخامة .... في تبويب Project في اليونتي , اختر Create ومنها Material ... وأعد تسمية الخامة الجديدة إلى matGround ....واضغط عليها ... ستجد التالي :-

ستلاحظ في الأعلى في خصيصة Shader (المظلّل) أنه معيّن على Diffuse وهذا ما نريدة ولهذا لنّ نعدّل فيه ..... كل ماعلينا فعله هو تعين الإكساء الذي صنعناه مسبقا بهذه الخامة ... ولهذا سنضغط على المربع الذي به (None -Texture2D) وسنختار textureGround ..... وبعدها نطبّق الخامة على الأرض بسحب الخامة على العنصر لتظهّر كمكون في تتبويب (Inspector) .... هممم ... ستحتاج الأرضية لبعض التغييرات في الحجم لتتوافق مع الخامة وكذلك ستحتاج الخامة لبعض التعديدل في خصائص الـ Tiling والتي أحبّ أن أطلق عليها أن التبلّيط ... وستفهم لماذا أطلق عليها هذا إذا عبثّت قليلا بالقيم لتعرف وظيفتها .... سأترك تظبيط الخامة والأرضية عليك .... فقط قم بتغير عرض الأرضية قليلاً باستخدام أداة التحجيم الموجودة في شريط الأدوات الصغير الموجود في أعلى اليسار ..... أيضاً أعتقد ان الدبابة مغروسة قليلاً في الأرضية لذا لسننزل الأرضية قليلاً ايضاً .... يمكن أن تقضي بعض الوقت في تظبيّط بعض الأجزاء في اللعبة ... مثلاً يمكن تعديل خصيصة الـ Far clip plane في مكوّن Camera لعنصر الـ Main Camera ليكون 50 بدلا من 1000 ... فلا حاجة لكل هذا البعد .... وكذلك فلنطبق خامة أخرى على المكعب الكبير الذي وضعناه في البداية ليكون مقياس للسرعة ..... ولنعتبره مثلا جدار ونطبق عليه خامة بهذا الإكساء الذي وجدته على الانترنت :-

لا حاجة لتكرار الشرح هنا أيضاّ ..... مع ملاحظة أننا سنقوم بتغير اللون الرئيسي Main Color ليكون رمادي قليلاً هنا بسبب الإضاءة ...... والآن لننتقل لإنشاء الطلقة للدبابة .....

الطلقة للدبابة : سنقوم بإنشاء كرة (Sphere) جديدة كعنصر من GameObject > Create Other > Sphere ..... سنصغّر حجمها قليلاً لتناسب حجم القذيفة ...... والآن سنقوم بإنشاء "كائن مستبق الصنع" أو Prefab (اختصار لـ Prefabricated) ... ببساطة فلنعتبره كأي عنصر آخر ولكن مع إمكانية تكراره في المشهد أكثر من مرة بنفس الخصائص .... وسنتطرق أكثر بالتفصيل لها فيما بعد ..... والآن نريد أن نجعل الذخيرة Prefab ... لأن الطلقة بالتأكيد ستخلق أكثر من مرّة واحدة في المشهد .... للقيام بهذا ... سننشئ Prefab جديد ... من تبويب Project اضغط على Create ومنها Prefab .... وأعد تسميته إلى pfProjectile .... وقم بسحب الكرة التي أنشأتها مسبقاً وأدرجها عال الـ Prefab الجديد ... والآن احذف الكرة من المشهد ..... ولنتجّه الآن لبعض البرمجة ..... انشئ سكريبت جديد و أعد تسميته لـ tankShoot .... وافتحه ..... أولاً سنقوم بتعريف المتغيرات .... سنحتاج إلى متغيّرين في هذه الحالة .... أحدهم سنستخدمه لنصل به إلى الـ  Prefab الذي صنعناه مسبقاً ... والآخر للتحديد قوة/سرعة الطلقة ... كالآتي :-
var prefabProjectile:Transform;
var power:float;

هنا نتعرف على نوعين آخرين من المتغيرات ... أولهم Transform .... وهو متغيّر مميز ... ببساطة فلنعتبره يشير إلى مكوّن Transform في العنصر العائد عليه .... وبهذا سنستطيع التعامل مع هذا المكون مباشرة من خلال السكريبت ... وهذا مانحتاجه الآن .... النوع الآخر من المتغيرات هو float ..... هو للأرقام بالضبط كـ int ولكن الفرق أن int هو للأرقام الصحيحة ... بينما float يستطيع تخزين الكسور .... (لن أوجع دماغك بسعة كل متغير كالمعتاد) .... والآن وكما فعلنا في المرة السابقة عند كتابة السكريبت الخاص بحركة الدبابة ... هنا سنتأكد من أن اللاعب ضغط على زر الإطلاق مثلا وليكن المسطرة- Space .... هذا الزرّ معرّف في اليونتي بـ jump ولهذا سنكتب الكود التالي داخل دله Update ....:-

function Update()
{
if(Input.GetButtonDown("Jump"))
{
 //فارغة إلى حين
}
}
والآن المطلوب هو أنه كلّما ضغط اللاعب على زر المسطرة فستخلق طلقة عند الإحداثيات كذا وكذا وسنضيف إلها سرعة/قوة في إتجاه الأمام .... فلنبدأ أولا بخلق العنصر بوضع هذا الكود بين علامات الـ{} للدالة الشرطية :-
Instantiate(prefabProjectile, transform.position, Quaternion.identity);
ما قام به هذا الكود هو ببساطة خلق العنصر الذي يعود عليه متغير prefabProjectile ووضعه في الموضع الذي ننادي منه هذا الكود وهو الدبابة وبهذا فإن transform.position تعود على موقع الدبابة وبهذا ستخلق الطلقة في نفس موضع الدبابة وكذلك بنفس الزاوية والتي نطلق عليها Quaternion.identity ..... يمكنك خلق أي عنصر في أي وقت بهذه الدالة إذا (Instantiate) فقط بتحديد العنصر الذي تريد خلقة والموضع والاتجاه الذي ترغب في أن تخلق فيه ..... والآن فلنجرّب هذا الكود ... لكن أولاً علينا التأكد من أننا حددنا العائد على prefabProjectile من خلال تبويب الـ Inspector في مكوّن السكريبت طبعاً بعد إضافته للدبابة ... وذلك عن طريق سحب الـPrefab من تبويب Project وإسقاطة في الخانة المقابلة لـ Pf Projectile والتي بها (none)transfom .... همممم ... لا يبدو أن شيئا تغيّر ... ولكن لو دققت النظر فعند ضغطك على زر المسطرة ستلاحظ أن عنصراً باسم pfProjectile(Clone) ظهر في الـ Hierarchy ... والآن إذا حرّكت الدبابة من مكانها ستجد أن الطلقة موجودة ولكن ثابتة في مكنها (طبعاً فنحن لم نضيف لها قوّة لتحركها) .... للقيام بهذا علينا أولاً أن نُخضع (بضم النون) الكرة لقوانين الفيزياء .... وببساطة عن طريق إضافة مكوّن Rigid Body للكرة .... حدد الـ Prefab الخاص بالكرة ومن قائمة Component اختر Rigidbody من قائمة Physics ... والآن ستلاحظ أن عنصر Rigidbody تم إضافته للـ Prefab  .... والآن سنعود مرّة أخرى للسكريبت .... سنحتاج إلى أن نصل إلى مكوّن الـ Rigidbody الذي أضفناه مؤخرا من خلال السكريبت .... هناك عدّة طرق للقيام بذلك ..... سنكتفي بطريقة واحدة الآن على أن نشرح الباقي في الأجزاء القديمة .... والطريقة هي وببساطة أن نستغل العائد من دالة Instantiate والتي هي من نوع GameObject أي وببساطة نستطيع تخزين العائد من دالة Instantiate لنتتحكم في خصائص العنصر الذي خلقناه .... ليصبح السطر السابق كالآتي :-

var instanceProjectile = Instantiate(pfProjectile, transform.position, Quaternion.identity);

والآن يمكننا التعديل في خصائص العنصر ببساطة عن طريق متغير instanceProjectile .... وبما اننا نريد أن نصل إلى مكوّن Rigidbody في هذا العنصر من الطبيعي أن نكتب instanceProjectile.rigidbody ... الآن ... مالذي نريدة ياترى من مكوّن الـ Rigidbody ؟! .... نريد إضافة قوة للعنصر في اتجاه الأمام ليتحرك طبعاّ .... وهذا بالضبط مايفعله الكود التالي :-

instanceProjectile.rigidbody.AddForce(Vector3(1,1,0)*power);
فلنحلل هذا الكود .... أولا AddForce كما هو واضح من اسمها لإضافة قوة .... ومابداخ الأقواس هو ببساطة متجّه .... وكما وضّحنا مسبقاً فالمتجّه يتكون من قيمة واتجاه .... والإتجاه هنا هو Vector3(1,1,0) .... هو كزاوية 45 في مسطّح رأسي  ..... والقيمة وهي power وهي مقدار القوة التي ستضاف في هذا الاتجاه .... وطبعاً القوة الآن بـ 0 لأننا لم نعيّنها ... فلنجرّب اللعبة الآن بقيم power مختلفة ونري الأنسب .... بعد التجرب وجدت أن 500 هي الأنسب .... يمكنك أن تغيّرها لأي قيمة ترغب ... ستلاحظ أيضا أن الكرة تخرج من جسم الدبابة وليس من الفوّه ... هذه المشكلة ... بالإضافة إلى تأثيرات الجزيئات (Particle Effects) هو ما سنناقشة في الجزء القادم  ..... ولكن أولاً فلنرى الكود الخاص بسكريبت tankShoot مجمّعا:-
var pfProjectile:Transform;
var power:float;

function Update () {
if(Input.GetButtonDown("Jump"))
{
var instanceProjectile = Instantiate(pfProjectile, transform.position, Quaternion.identity);
instanceProjectile.rigidbody.AddForce(Vector3(1,1,0)*power);
}
}

وستكون النتيجة كالآتي :-


يمكنك تحميل ملف المشروع والتعديلات التي تمّت حتى الآن من هنا : http://dl.dropbox.com/u/9047337/TankGame/TankGame02.rar

هناك تعليق واحد: