صنعت منذ مدة مكتبة اسمها g4c لبرمجة الالعاب. هذا درس سريع فيها. تحتاج إلى Visual C++ لتجرب ويمكنك تحميل المكتبة نفسها هنا:
سوف نصنع اليوم لعبة happy bird..البعض يحب الطيور الغاضبة لكننا نسمع دائما نصائح على غرار "كن ايجابيا"، "تفاءل" لذلك لن نقلد هؤلاء :)
تجهيز البرنامج
أولاً، خذ نسخة من الdirectory المسمى g4c empty project وسمها بإسم مشروعك. هذه هي الطريقة الرسمية لعمل مشروع جديد.
ثانياً، افتح المشروع (اسمه ينتهي بـ .sln) في الفجوال سي++.
ثالثاً: اذهب إلى مربع solution explorer في يسار الشاشة، أو اختر view -> solution explorer، افتح جزء source files، واختر empty.cpp
سوف تجد دالة main فارغة..سوف تكون هذه برنامجنا بعد قليل.
الرسومات
ارسم طائراً وتفاحة وضعهما في ملفين بإسم bird.bmp و apple.bmp وخزنهما في مكان سهل الوصول اليه مثل c:\img
لاحظ ان الملف يجب ان يكون من نوع BMP وليس أي نوع آخر.لو كانت مواهبك الفنية ضعيفة يمكنك الحصول على الصور من الكود الكاملة الخاصة بهذا المثال.
وضع الشخصيات على الشاشة
يوجد في g4c مفهوم الsprites (الأشكال الطيفية)؛ وهي صور يمكن تحريكها على الشاشة تمثل شخصيات الالعاب (طائرة، كرة، ثائر، ...). يوجد لديك 30 sprite في البرنامج ارقامهم من 0 إلى 29. لتحميل صورة في احدهم تستخدم الدالة load_sprite.
هذه الدالة تأخذ (1) اسم الملف الذي يحتوي الصورة (2) رقم الsprite المطلوب تحميل الصورة فيه.
void main() { load_sprite("c:/img/bird.bmp", 0); load_sprite("c:/img/apple.bmp", 1); }
لكننا لم نرسم هذه الأطياف بعد! لنفعل ذلك نستخدم الدالة put_sprite، وهي تأخذ رقم الشكل الطيفي وقيم x,y الخاصة بالنقطة التي سيوضع فيها. (x من اليسار، y من الأعلى).
void main() { //write your program ;) load_sprite("c:/img/bird.bmp", 0); load_sprite("c:/img/apple.bmp", 1); int x = rand() % 640; int y = rand() % 480; put_sprite(0, x, y); put_sprite(1, 150, 150); }
هنا اخترنا قيمة عشوائية من صفر إلى 633 للمتغير x (عن طريق عملية mod)، ومثلها للy من 0 إلى 479 (لأن الشاشة دائما 640×480). ثم نادينا put_sprite لنضع الطيف رقم صفر (الطائر) في المكان العشوائي، بينما التفاحة دائما في المكان 150، 150.
تحريك الطائر
لكي نحرك الطائر سنصنع حلقة متكررة كالآتي:
استمر في الآتي:
اقرأ المفتاح
لو المفتاح المضغوط يمين، حرك الطائر لليمين
لو المفتاح المضغوط يسار، حرك الطائر لليسار
لكي نقرأ المفتاح نستخدم الدالة inkey، وهي تعيد -1 لو لم يكن هناك مفتاح مضغوطا لحظة ندائها، أو تعيد كود لو كان زر مضغوط. ما هي الأكواد؟ هي ثوابت في الويندوز (رقم لكل مفتاح) تجدها هنا
حسناً إذاً...
void main() { load_sprite("c:/img/bird.bmp", 0); load_sprite("c:/img/apple.bmp", 1); int x = rand() % 640; int y = rand() % 480; put_sprite(0, x, y); put_sprite(1, 150, 150); while(true) { int k = inkey(); switch(k) { case VK_UP: y -= 3; break; case VK_DOWN: y += 3; break; case VK_LEFT: x -= 3; break; case VK_RIGHT: x += 3; break; } put_sprite(0, x, y); } }
الثوابت VK_... هي الأكواد التي حدثتك عنها. لاحظ ان تغيير قيم الx, y لا تكفي! يجب أن آمر البرنامج ان يعيد رسم الطيف في المكان x,y بواسطة الدالة put_sprite
الآن لو قمنا بتشغيل البرنامج يمكننا تحريك الطائر بالأسهم.
التصادم
كيف نعرف ان الطائر وصل للتفاحة؟ هناك دالة في الg4c اسمها register_sprite_proc، هذه تأخذ اسم دالة اخرى (يجب ان تكون موجودة) وتقوم باستدعاها اوتوماتيكيا في حالة تصادم طيفين مع بعضهما.
يعني لو قلت مثلا
register_sprite_proc(myFunc);
فسوف يقوم الg4c - وليس انت - باستدعاء myFunc في حالة أي تلامس لاشكال sprite أثناء تنفيذ البرنامج. لابد لهذه الدالة ان يكون لها مواصفات محددة:
- Can have any name
- Return value always of type int
- Parameters always of types (int, int, void *)
القيمة من نوع * void يمكن تجاهلها، أما الparameters من نوع int, int فهي ارقام الsprites المتصادمة. يعني لو اثناء تشغيل البرنامج تلامس الاطياف 3، 22 فسوف يتم استدعاء هذه الدالة بحيث يكون اول اثنان من الparameters هما [3، 22] أو [22، 3].
لكننا في لعبتنا لن نحتاج لفحص هذه القيم لأنه في حالة تلامس اطياف فليس لدينا اصلا سوى الطائر والتفاحة!
ها هي الكود الجديدة، لاحظ الاجزاء باللون الأحمر!
int myFunc(int s1, int s2, void *) { // حنكتب هنا ايه اللي المفروض يحصل لما الطائر يوصل للتفاحة return 0; } void main() { //write your program ;) load_sprite("c:/img/bird.bmp", 0); load_sprite("c:/img/apple.bmp", 1); register_sprite_proc(myFunc); int x = rand() % 640; int y = rand() % 480; put_sprite(0, x, y); put_sprite(1, 150, 150); while(true) { int k = inkey(); switch(k) { case VK_UP: y -= 3; break; case VK_DOWN: y += 3; break; case VK_LEFT: x -= 3; break; case VK_RIGHT: x += 3; break; } put_sprite(0, x, y); } }
ماذا سيحدث في الدالة myFunc؟ نريد ان نخبر المستخدم انه فاز في اللعبة. لكي نعرض رسالة على الشاشة لابد من استخدام دالة text_out، وهي تأخذ string + مكان x, y الذي سيظهر فيه الكلام. نعدل الدالة myFucn ونترك باقي البرنامج كما هو
int myFunc(int s1, int s2, void *) { text_out("You won!!", 5, 5); return 0; }
ربما تريد أيضاً قراءة دليل الملتمس إلى استخدام الماوس.
هناك 81 تعليقًا:
dr hwa ana yenfa3 a3mel snake game bil g4c
@ahmed alaa
لا يوجد ما يمنع :)
بسم الله ماشاء الله بجد بجد شرح اكثر من رائع شكراً جداً يا دكتور
@Ahmed Atito
سعيد أنه أعجبك :)
لو سمحت يا دكتور .. أنا كنت عايز اعرف ايه اللي مكان الـ goto في الـ g4c .. وشكرا مقدما :)
دكتور هو مافيش حاجه تسرع الحركه شويه
@Abdalla Hazem
G4C was not really designed for speed. Try increasing the velocity or disabling sprite collision for non-essential sprites
ازاي الكتبه ديه تساعدني في مشروع Typisch Schools Application وشكرا
@elsherbini
مكتبة g4c مطروحة كما هي لمن يريد استخدامها، ومش دوري أني أقيم ملاءمتها لمشروع معين :)
لو سمحت يادكتور دلوقتى عرفت ازاى اطلع صورة فى مكان معين طيب لو عايز اطلع الصورة على الشاشة كاملة اعملها ازاى؟
@Ahmed Mohamed
لو قصدك "الشاشة كاملة" بمعنى شاشة الكمبيوتر، فالإجابة أن الإمكانية دي غير موجودة في g4c. البرنامج دائماً بيشتغل في run window له حجم ثابت.
لو قصدك صورة تملأ الrun window بالكامل: اعمل صورة بحجم 640×480 وارسمها في المكان 0، 0.
ملاحظة: لو الصورة معمولة كخلفية ممكن تستخدم disable_sprite_proc(int) معاها وإلا حيحصل collision detection بينها وبين كل الـsprites الثانية على الشاشة، أو ممكن بدل ما ترسمها بـput_sprite تستخدم copy_sprite_image
طيب لو سمحت يادكتور دلوقتى انا معنديش غير من اماكن من 0 الى 29 يعنى معرفش اطلع اكتر من 30 صورة طيب دلوقتى مثلا لو انا محتاج اكتر من 30 صورة اعمل ايه؟
@Ahmed Mohamed
Do you want them as images or as sprites (with motion & collision)? If you just want to draw images use the copy_sprite_image function, if you want sprites you can:
1- Rework your game to use 30 sprites or less
OR
2- Change the maximum by changing the value of the constant maxSprites defined in g4c.h, but note that this may slow down your game.
if i use copy_sprite_image(,,)
to make imge how can i delete thes capy of image or hide it with aut del or hid the sprite?
@Mahmoud Rashad
If you use copy_sprite_image then you're not drawing a sprite, you're drawing an image (similar to drawing a line or a circle), and therefore cannot be moved...etc.
You can erase it by using e.g fill_rect to draw a rectangle over it.
لو سمحت يادكتور ممكن حضرتك تكتبلى مثال يوضح اكتر الفنكشن بتاعت التصادم وخاصة الparamenter بتاع الpointer مش عارف استخدامه ازاى معلش يادكتور بتعب حضرتك؟
@Ahmed Mohamed
Do not use the void pointer, it's not currently used in g4c (but reserved for future use).
The collision callback will be called automatically when two sprites collide. You write the callback the way you want and register it using register_sprite_proc
The arguments passed (by g4c) to the callback will be the numbers of the sprites that collided (in no particular order). You can test those numbers to see if the sprites that collided are the ones you care about.
Did that help?
طيب يا دكتور انا كتبتها وبردك بيطلعلى ايرور register_sprite_proc(onsprite( a,4));
وبرة ال main بخدهم varaible 2عادى
فمعلش يادكتور ممكن حضرتك تكتبلى مثال يوضحها اكتر من كدة
الهدف مش انك تنادي الـcallback. الهدف انك ترسلها لـregister_sprite_proc
You should not call the callback yourself. You should not supply parameters to it. It will be called for you, with the parameters filled in.
Here's a quick example on using the mouse with g4c:
_______________________
// put this code after the #include....statements in you empty.cpp
int myMouseProc(int x, int y, bool left, bool right, void *)
{
char buffer[80];
sprintf(buffer, "position =(%d,%d)|left button=%d|right button=%d", x, y, left, right);
text_out(buffer, 100, 100);
}
void main()
{
register_mouse_proc(myMouseProc);
}
طيب دلوقتى يادكتور حضرتك قولتلك هى اللى هتسدعي ال parameters مش هتحتاج انى انا اللى ابعتهلها .....طيب دلوقتى انا مثلا عندى اكتر من اتنين parameters فى اللعبة ازاى هى هتعرف انا عايز انى اتنين فيهم ؟!!!!
The callback is invoked whenever a mouse action (button press, button release, motion) happens. Try running the example, holding the left button, and moving the mouse.
طيب ده يادكتور الفنكشن اللى انا كتبتها
int onsprite(int a,int k ,void *)
{
return 0;
}
void main
{
register_sprite_proc(onsprite);
}
ودلوقتى انا عايز التصادم بين الصورة رقم 0و 4 يعنى عايز اخلى ال a=0; , وال k=4; او العكس اعملها ازاى
الإجابة موجودة في مثال الطيور السعيدة؛ أرجو أن تقرأه مرّة أخرى.
فى مثال الطيورة السعيدة ما كانش فى غير صورتين بس ما احنجناش ندى قيم للparameters بس دلوقتى انا عندى اكتر من صورتين ومش عارف ابعت رقم الصور ازاى
You do not provide values for parameters to the callback. Read the example carefully.
plz doctor i need to take input in text box can u help me in that ?
g4c Does not support adding text box controls
لو سمحت يا دكتور .. أنا كنت عايز اعرف ايه اللي مكان الـ goto في الـ g4c .
ما المقصود بـgoto؟ لو قصدك طريقة لكتابة نص في مكان معين على الشاشة شوف text_out
طب بالنسبة للعبة الdots يا دكتور نعمل فيها ايه ؟
و يا دكتور ف errors كتير قبل ماكتب اى حاجة فى الملفات.h و كدة اعمل ايه ؟؟؟
@medo gemy
1- عندك فيها سؤال محدد؟
2- بالنسبة للأخطاء؛ هل اتبعت طريقة عمل المشاريع الموصوفة في أول المقال؟
لا ال errors خلاص طلع عيب فى ال visual و صلحته.
الdots: انا عملت sprite على شكل dots 5*5 دلوقتى ارسم الخط ازاى بالماوس ؟؟
واحدد اللون
جرب. جربت؟
انا مش لاقى حاجة شبهها فى g4c explained غير example mouse callback ف غيرت فيه بدل fire...
كتبت void draw_line(int x1,int y1,int x2,int y2,int clr);
بس فيه error
wla void register_mouse_proc(MouseProc);
انا مش فاهمهم
Have you tried reading this
http://iamsamy.blogspot.com/2012/04/g4c_27.html
لا اول مرة اقراها,فهمتها.
بس عندى مشكلة فى اتجاه الخط احدد النقط ازاى داخل الsprite ؟؟ يعنى عايزه بين اى نقطتين انا عايزهم اكتب ايه هنا (draw_line(?,?,x,y
x,y دول مكان المؤشر
و ربنا يخليك لينا :)
عملتها يا دكتور عرفت
a=x-1
b=y-1
draw_line(a,b,x,y)
ممكن تعليقك ؟
خليت player 2 يلعب right button
صح ولا ايه ؟
انا بس عايز الحتة دى D:
completes closed square gains point
ادينى hints
D:
You need to store information about the squares: what edges have already been drawn (top, left,...etc). This will allow you to find what squares have been completed.
how to store these information
could you give me an example plz :D
لو سمحت يادكتور ازاى اعمل المتابعة او المطارده فى لعبة الpacman يعنى ازاى اخلى الاعداء يعرفوا مكان ال pacman ويطاردوه ؟!!!!!!!!!!!
Use what you know (arrays, structs,...etc)
@Ahmed Mohamed
Learn about the A* algorithm
طب ماالsquares دى جوة الsprite ازاى هاشاور عليها بarray مثلا
يعني إيه squares جوة sprites؟ مش انت اللي بترسم كل حاجة؟ يبقى عندك المعلومات المطلوبة، وممكن تخزنها.
انا بعت لحضرتك رسالة على الايميلgmail ممكن تقراها.
شكرا لتعبك معايا
دكتور انا مطلوب منى اعمل dots game وعملت ال dots بطريقة دى
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
fill_ellipse(60+(i*60),60+(j*60) ,10, 10, 0,7);
}
}
تنفع ولا لا
ولو تنفع لوسمحت كنت عايز اعرف اعمل ازاى خطوط مخفية بينهم بحيث ان اليوزر لما يدوس عليه بالماوس يظهر
وياريت يا دكتور ترد عليا علشان دة project عليا ولازم اسلمو قريب
@Ahmed
الإجابة الرسمية لمعظم أسئلة "ينفع كذا" هي "جرب وشوف"
بالنسبة للمكان اللي يرسم فيه دي مشكلة برمجية مش حاجة خاصة بمكتبة g4c، المكتبة بتقدم لك مكان مؤشر الماوس (في الـmouse proc) وبتسمح لك ترسم على الشاشة. تعمل إيه بدول ده دور الكود.
لوسمحت يا دكتور ازاى فى لعبة hang man عايزة ابين صورة واخفيها وبعد كده ابين صورة تانية وهكذا وشكرا يا دكتور
لو الصورة ظهرت بـput_sprite يبقى إخفاؤها بـhide_sprite
ملاحظة: قيم x, y في hide_sprite مش مهمة..أي أرقام تنفع
لو تم إظهارها بـcopy_sprite_image يبقى إخفاؤها برسم مستطيل فوقها
فى حاجة تخلينى اعرف مكان اى نقطة(x,y) فى الwindows application
مكان أي نقطة؟؟
دكتور لما بعمل run للكود بيظهر اللعبه بس لما لعمل click بالmouse فى اى مكان بيوقف الdebug مع ان الكود صح
@Rana Hossam
لا يوجد معلومات كافية في السؤال لأقول رأياً.
أيضاً أرجو النظر إلى هذا المقال ربما تكون مشكلتك أحد المشاكل المذكورة فيه:
http://iamsamy.blogspot.com/2013/05/g4c-common-problems-and-frequently.html
يا دكتور هو بعد ما ينفذ الcollision بيرجع لل main ولا لأ
يا دكتور هو بعد ما ينفذ ال collision بيرجع تا ني لل main ولا لأ
كيفية اعادة التصادم لجسم واحد اكثر من مرة يا دكتور لو سمحت؟
كيفية اعادة التصادم لجسم واحد اكثر من مرة يا دكتور لو سمحت؟
@mohamed omiera
مش فاهم قصدك من السؤال. عموماً الـcallback بتاعة التصادم بتستدعى مادامت الـsprites متلامسة).
الجسم بعد مايخصله تصادم اعمله hide وبعد كدة اظهره فى مكان تانى ينفع بقى بعد كدة لو حصله تصادم تانى اكرر الموضوع ده؟
يعنى فى لعبة snake انا بخلى الطعم بتاع snake يختفى بعد مايحصل تصادم بين snake والطعم وبظهر نفس ال sprite فى احداثيات تانية غير الاولى بس بعد كدة بيجى snake قدام الطعم مش بيعمل تصادم ولا هو لازم لكل مرة اظهر فيها الطعم يكونsprite مختلف عن الى قبله؟
The collision callback is invoked whenever two sprites collide. It doesn't matter if the sprites had collided before.
اعمل callback ازاى طيب معلش يا دكتور؟
You have already done it.
int spriteproc(int a,int b,void *data)
{
hide_sprite(b,0,0);
put_sprite(b,5,5);
return 0;
};
deh alfunction
بس التعبان بياكل الطعم اول مرة ويجى المرة التانية مش بيحصل تصادم
معلش يا دكتور علشان مش فاهم يعنى انا الطعم ده بيبقى اكتر من sprite ولا sprite واحد وانا بعمله hide واظهره فى مكان تانى وهكذا ؟
أعتقد ان عشر دقائق من التجربة حتكون أفضل عشان توضح كل حاجة.
اعمل برنامج وشغله وشوف اللي حيحصل.
#include
#include
using namespace std;
void main()
{
string x;
cout<<"Enter the word"<<endl;
getline(cin,x);
for(int i=0;i<x.length();i++)
{
if( x[i]=='a'|| x[i]=='e'|| x[i]=='i'|| x[i]=='o'|| x[i]=='u')
{
if(x[i]!=x[i]) // y3ny a el line dh?? geh m3aya bl 7z w msh fahm el brnamg esht3'l ezaay :D //
{
cout<<x[i+1];
i++;
}
}
else cout<<x[i];
}
}
dh brnamg besheel el vowels
@medo gemy
Your program is not related to g4c
m5dtsh baly ..srry
fe link tany 3'ir dh ??
@medo gemy
I don't debug programs online on my blog :)
لو سمحت يا دكتور هو فى حاجة اقدر اخلى بيها ال text_out تاخد (int,int,int) بدل ما بتاخد (string,int,int)
إرسال تعليق