المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : درس في صناعة الألعاب : استخدام الجتا / الجا(Cos/Sin)



modyKun
14-07-2010, 04:36 PM
السلام عليكم ^^

(الدرس كتبته في منتدى ثاني ونقلته هنا ^_^)

أدري إني كسلان في كتابة الدروس >_>" بس سامحوني



الدرس عشان صديق اسمه كلاود عندي في المسن ^^ ..طلب مني أشرح كونسبت الـCos/Sin (جتا/جا) وعلاقتهم بصناعة الالعاب ..لما شفت الدرس بيطول قلته بكتب موضوع عشان يكون موجود للي يبي يتعلم ^^..



الموضوع ببسطه بكونسبت أخف بإذن الله عشان يكون واضح للجميع وما يحتاج عصر دماغ XD



هذا الكونسبت من استنتاجي لصناعة الالعاب بس n_n يعني يا ريت محد يروح يحطه في ورقة الاختبار في الثانوية / الجامعة ويفشلنا ! .. أخلي مسئوليتي من الحين XD



أعتذر مقدماً عن كمية الفلسفة في الموضوع التالي ^_^ رجاءاً تناول حبتين بنادول و اثنين ريفو عشان ما يجيك صداع xD



أولاً نبدأ بإيش ممكن تفيدنا الجتا/الجا (Cos/Sin) في صناعة الالعاب

الموضوع متعلق بشكل بحتي بالزوايا/ الدوائر / المنحنيات ، وبرياضات الألعاب المعقدة(مع إنها من جد مب معقدة لما تفهمها)



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

الدرس بسيط وسهل ، وأتمنى يبين كيف الموضوع سهل ومب معقد مثل ما البعض معتقد ^^

مع العلم الـCos/Sin لها استخدامات أخرى ، وهذي أبسط استخداماتها



ندخل في الدرس xP



تقدرون تشرحون لي الشكل التالي؟

http://www.freeimagehosting.net/uploads/a12b051dbb.png



هاه؟ مين يعرف ؟ لا الشكل ما يشير لحمامة xD هذي زاوية (ما توقعتوا هاه XD )



ندخل في الجد ^^

الزاوية تتكون من ضلعين و"فتحة" بينهم

لاحظوا الضلع الثابت (الأسود) والضلع الآخر المتحرك ( اللي لونته باللون الاحمر xP بتعرفون ليه الحين)



تخيلوا الحين النقطة البنفسجية في الصورة "نقطة تلاقي الضلعين" هي كائن ما ، تصوروا لو نقدر نخليها تتحرك تجاه النقطة الزرقاء في الصورة "نقطة على الضلع المتحرك" ، هذا اللي بإذن الله بنحاول نعمله اليوم

وهذا بيفيدنا في إننا نحرك هذي الشخصية على حسب زاويتها ^^



بالمناسبة ، الضلع الثابت عادة يرسم بس عشان يحدد مقدار فتحة الزاوية



أحس إن شرحي معقد الأمور X"D على أي حال نكمل



ناتج جتا الزاوية في الصورة هو احداثي (س/X ) النقطة الزرقاء ، وناتج جا الزاوية في الصورة هو احداثي (ص/Y ) النقطة الزرقاء في الصورة ، بإعتبار إن احداثي النقطة البنفسجية هو (0 ، 0)

وبإعتبار إن المسافة بين النقطة الزرقاء هي 1 بكسل

فهمتوا شئ؟ XD أنا نفسي مب فاهم اللي أكتبه

عشان نوضح أكثر ، شوفوا الصورة التالية :

http://www.freeimagehosting.net/uploads/349af9ae55.png



هذا يشرح الجتا/جا بالطريقة التقليدية ^^ ..

تخيلوا النقطة البنفسجية في إحداثي (0،0) يعني مكان نقطة الأصل

في دائرة طول نصف قطرها 1 ، وهنا النقطة البنفسجية هي مركزها

بالمناسبة ، هذا معناه إن المسافة بين مركز الدائرة ( النقطة البنفسجية) و أي نقطة على الدائرة ( أي نقطة زرقاء) هو 1 لكن هذا مب معناه إن لازم أي من الاحداثيين يكون 1 ، بس البعد بين المركز وأي نقطة على الدائرة = 1

هنا ^^ لو قلنا جتا(Cos) الزاوية بيطلع احداثي X للنقطة الزرقاء اللي بيتلاقى فيها الضلع المتحرك مع الدائرة

ولو قلنا جا (Sin ) الزاوية بيطلع احداثي Y للنقطة الزرقاء اللي بيتلاقى فيها الضلع المتحرك مع الدائرة

يعني بإختصار ^^ بيكون إحداثي أي نقطة تقع "على" الدائرة هو (جتا الزاوية ، جا الزاوية )

طيب نفترض الزاوية 90 ، يعني الخط طالع من المركز مباشرة على فوق xP .. من دون ما تستخدمون الآلة الحاسبة ، تقدرون تقولون كم جتا 90 وجا 90 في هاي الحالة (النقطة الزرقاء) ؟ ^^

ببساطة بما إننا تحركنا لفوق ومب يمين ولا يسار بتكون جتا( 90 ) = 0 ،، جا ( 90 ) = 1 بما إنه خط طالع لفوق مباشرة ! ..يعني تحركنا 1 على الإحداثي الصادي (Y ) وما تحركنا شئ على الإحداثي السيني (X )

طيب لو 0 ؟ ^^ بنكون تحركنا لليمين وما تحركنا شئ على إحداثي Y يعني جتا(0) = 1 و جا (0) =0



طيب لو زاوية 45 ؟

XD

هذي بإذن الله (0.707 ، 0.707) ..بس طبعاً إحنا مالنا دخل =P بنسيب اللعبة تحسب الزوايا !



في شئ نقدر نستنتجه ^^ .. دام الدائرة نصف قطرها =1 ..فهذا معناه إن الجا/الجتا بين الـ-1 والـ1 !

يعني مستحيل دائرة نصف قطرها 1 وموجودة في نقطة الأصل وتكون نقطة تقاطع الضلع المتحرك معاها 2 مثلاً XD



طيب كيف بنقدر نستفيد من هذا؟ ^^



http://www.freeimagehosting.net/uploads/a12b051dbb.png

نرجع مرة ثانية لصورة الحمامة..أقصد الزاوية xD

على اعتبار إن النقطة الزرقاء هنا تبعد عن النقطة البنفسجية 1 .. كيف نقدر نخلي النقطة البنفسجية تتحرك نحوها؟



ببساطة نفس فكرة الدائرة اللي فوق ^^

الاحداثي السيني للنقطة الزرقاء = الاحداثي السيني للنقطة البنفسجية + جتا(الزاوية)

الاحداثي الصادي للنقطة الزرقاء = الاحداثي الصادي للنقطة البنفسجية + جا(الزاوية)



في البرمجة بيصير الامر كالتالي ^^ :

(على إعتبار إن blueX , blueY احداثيات النقطة الزرقاء..

و purpleX , purpleY إحداثيات النقطة البنفسجية ...
و angle الزاوية بين النقطتين)


blueX = purpleX+cos(angle);

blueY = purpleY + sin(angle);
ممتاز جداً ! >ن< الحين نقدر نحرك النقطة على حسب زاويتها ^_^ !!



طيب بس ما تلاحظون إن السرعة بتكون بطيئة >_>" كيف نقدر نعدلها؟

ببساطة ^^ .. بنقوم بضرب الجتا/الجا في السرعة اللي نبيها ^__^

لو نبي ضعف السرعة(2) بنقوم بضربها في 2 ..لو نبي 3 بنقوم بضربها في 3 وهكذا..

مثال :




Speed = 5;

blueX = purpleX+cos(angle)*Speed;

blueY=purpleY+sing(angle)*Speed;

ببساطة بيتم مضاعفة المسافة ^^

http://www.freeimagehosting.net/uploads/88a3a7f1ea.png





مثال أكثر استخداماً / تنظيماً للتحرك على حسب الزاوية :

(في هذا المثال dX هي المسافة التي سيتم اضافتها على الاحداثي السيني ، و dY هي المسافة التي سيتم اضافتها على الاحداثي الصادي )




dX = cos(angle)*Speed;

dY= sin(angle)*Speed;

x=x+dX;

y=y+dY;



أتمنى يكون كل شئ واضح الحين ^_^ !

بكتب مثال بسيط في النهاية XD ..بالأليغرو لإني بحط الدرس في مكان ثاني بعد ^^ .. بس أتمنى برنس أو أي أحد يقرأ الدرس ويفهمه يعمل مثال بالجيم ميكر بعد عشان يكون واضح لمستخدمي الجيم ميكر ^_^



--

اعمل مشروع جديد ، وبعدها اعمل ملف هيدر جديد ..سميه اللي تبي xD بسميه gameBullet.h ، بما إن اللي ناوي أسويه قريب جداً من اللي يستخدموه في ألعاب الشوتر ^-^

ببساطة بنحط فيه كلاس ، سميه اللي تبي xP بسميه gameBullet بعد عشان يكون على اسم الملف ^^ بس براحتك !






#include <allegro.h>

class gameBullet

{

public:

fixed x , y;

fixed angle;

gameBullet(fixed newX,fixed newY,fixed newAngle);

void update();



};



الكلاس بيخزن معلومات عن احداثيات كل رصاصة ^^ وزاوية تحركها ، ايضاً بيحتوي كونستركتور (يتم استدعاؤه حينما يتم الإعلان عن الكائن) وفنكشن بسيطة بنسميها update بتتكفل بتحديث الرصاصة ^^ وإضافة الموقع الجديد عليها



المهم ، لاحظوا هنا إننا استخدمنا نوع fixed ! نوع غريب للمتغيرات صح؟ متعودين عادة نستخدم انتيغر / فلوت (أعداد صحيحة / أعداد نسبية) .. السبب الرئيسي إن في الواقع في احداثيات على الشاشة مثلاً 2.5 ما لها معنى حقيقة xD رغم إن محركات ثانية تسمح بيها وتقرب لأقرب عدد صحيح لما تطلب منها الرسم في موقع غير صحيح ^^ ..لإن لما يكون عندنا شاشة مثلاً بعرض 850 بكسل ..فمعناها عندنا 850 بكسل صحيحة ومن المستحيل الرسم بينها لأنها أصغر وحدة !



فهنا نوع fixed جاء مع الاليغرو عشان يهتم بالموضوع ^_^ .. بالإضافة لبعض الدوال الثانية للتحويل !





نرجع لملف الـmain.cpp (لو ما غيرت اسمه xP ) فيه الكود المبدأي للأليغرو مثل وضع الـcolor depth و فتح الشاشة ، الخ



المهم لا تنسى تضيف فوق جملة إنكلود لملف الهيدر ^^


#include "gameBullet.h"




انزل تحت ، بنعرف الكونستركتور اللي كتبنا الـprototype حقه في ملف الهيدر ^^ بيتم استدعائه في بداية تكوين الأوبجكت




gameBullet::gameBullet(fixed newX, fixed newY , fixed newAngle)

{

x = newX;

y = newY;

angle = newAngle;

}



ببساطة يتيح لك إنك تدخل القيم ، وبيقوم بمساواة القيم داخل الاوبجكت بالقيم اللي أدخلتها ^^



بعدها عرف فنكشن الـupdate اللي كتبنا البروتوتايب حقها في الهيدر بعد ^_^


void gameBullet::update()

{

x += fcos(angle);

y += fsin(angle);

}
ببساطة بيزود على الاحداثيات الحالية الجتا والجا للزاوية ^^



لاحظ إننا استخدمنا fcos و fsin ، الدالتين بيتم استخدامهم مع نوع fixed ^^ وبيقوموا بإرجاع قيمة من نوع fixed




#include <vector>

using namespace std;

vector<gameBullet*> bullets;



اطلع فوق مرة ثانية XD

قوم بعمل إنكلود لهيدر الفيكتور

اللي ما يعرف ايش هو الفيكتور ^^ فهو جزء من الـSTL ، ببساطة هو array او لائحة تقدر تضيف ليها كائنات من النوع اللي تختاره ^_^ وهذا بيسهل علينا كثير تطبيق نفس الشئ على عدد من الكائنات بوقت واحد !

شئ ثاني ، مثل معظم مكتبات الـSTL لازم تستخدم using namespace std

وفي السطر الثالث بنعمل فيكتور من نوع الكلاس اللي عملناه ..ونسمي الفيكتور بإسم bullets




BITMAP* buffer;



وقوم بعمل بوينتر عشان بفر الشاشة ^^ ( بنقوم برسم كل شئ على هذا البفر ، بعدين في النهاية بنقوم برسم البفر على الشاشة ، وهذا أفضل للجرافكس كارد)



إنزل تحت في بداية الـمين ^^ ..

وضيف هذا السطر :




buffer = create_bitmap(screen->w , screen->h);



ببساطة بنقوم بشغل مساحة البفر بصورة فارغة ^_^ .. عرضها عرض الشاشة وطولها طول الشاشة


for (int i=0; i != 10 ;i++)

{

bullets.push_back(new gameBullet(itofix(screen->w/2) , itofix(screen->h/2) ,itofix( i*30)));

}
بدأنا اللعب XDD

بنستخدم جملة for عشان نكرر الكود 10 مرات ^_^ ..

ببساطة بيقوم بإضافة 10 كائنات للفيكتور (بما إن شرط الخروج إن العداد I يساوي 10 xP )

كل مرة في وسط الشاشة ^^ (العرض مقسوم على 2 ، والطول مقسوم على 2) ..

وهنا دالة ثانية itofix لتحويل الرقم الناتج لـfixed ^^

بالنسبة للقيمة الثالثة (الزاوية ) بتساوي قيمة العداد (0 إلى 10 ) * 30 .. عشان نتأكد إن الزاوية كبيرة بس ^^ وتكبر أكثر مع كل أوبجكت ^^



اعثر على :


while (!key[KEY_ESC])

{

}
وضع بداخلها ^^ :


for ( int i =0; i < bullets.size() ; i++ )

{

bullets[i]->update();

textout_ex(buffer, font, "@",fixtoi( bullets[i]->x), fixtoi(bullets[i]->y)

, makecol(255, 0, 0), -1);

}



ببساطة سنمر داخل كل عنصر في الفيكتور ونقوم باستدعاء فنكشن update

ومن ثم سنقوم برسم حرف "@" مكانه XD يعني بدل السبرايت ^^ >>بما إن المثال ما فيه سبرايت



draw_sprite(screen,buffer,0,0);

clear(buffer);




قم برسم البفر على الشاشة ثم محوه للتجهيز للرسم عليه مجدداً ^^



وأول ما تعمل كومبايل بإذن الله بتشوف هذي النتيجة ^^ :



http://www.freeimagehosting.net/uploads/b6315113fa.png



10 علامات "@" يتحركوا على شكل دائرة XD

هذا ملف exe مع السورس ^^

http://www.mediafire.com/?omkyuj3wm5jdjnw



وبهكذا ينتهي درسنا اللي مدري وش أبي منه ه1



الواجب

في محرككم المفضل اعملوا شخصية لما تضغط سهم أيمن أو أيسر تدور ولما تضغط للأمام أو للوراء تتحرك في إتجاه الزاوية أو عكسه ^_^

CalmKiller
14-07-2010, 06:06 PM
و الله شرح موفق

و بأذن الله يكون واضح للأعضاء

nbrase
14-07-2010, 07:02 PM
طلعت مدرس رياضيات والله شرح ممتاز مرة

CalmKiller
20-07-2010, 02:12 AM
ههههههههههههههه
آخر لعبة عملتها كنت مستخدم فيها الجا و الجتا
عشان السفينة تدور و تدور و ... تدور :]
هع

PrinceOfSorrow
20-07-2010, 02:42 AM
السلام عليكم ورحمة الله وبركاته
تم تطبيق وتصبحون على خير ZzZzZzZz

تم رفع نسخة GMK, و نسخة exe في المرفقات

أستخدمت سكربت المرفق في عمل دوران للكورة حول مسار ثابت وهذا هو السكربت من درس مودي:

Speed = 5;

blueX = purpleX+cos(angle)*Speed;

blueY=purpleY+sing(angle)*Speed;
}


كود مستخدم:

dx = cos(direction)*speed;
dy= sin(direction)*speed;



direction+=2
speed=10
x+=dx
y+=dy

(سيتم تحرير وتحديث الرد غدا)

شكرا مودي كون على الدرس ^___^

hamacka2
18-08-2010, 01:01 AM
مشكووور الدرس يستحق