الشبكة العربية لمطوري الألعاب

مبتدئ  أحمد عبد العظيم مشاركة 1

السلام عليكم


هذه هي مشاركتي الأولى في هذا المنتدى الرائع الذي أشعر بالحزن انني اكتشفته متأخراً جداً (للأسف)


احتاج إلى مساعدة بخصوص لعبة أبرمجها بإستخدام Allegro Game Library  على
Dev-C++


اللعبة
شبيهة بلعبة  الشهيرة Space Invaders: لدينا مركبة فضائية تسبح في الفضاء وتقابل مراكب
العدو وتقتلها بإطلاق النار عليها أو يقتلوها هم بالإصطدام بها (فيمابعد
اخطط في جعل الأعداء يتلقون نارا أيضاً).


المشكلة هي: طريقة توليد وتحريك الأعداء حيث اني فكرت أن تكون كالأتي :
توليد  من الأعداء لهم خصائص x و y في أماكن عشوائية من الشاشة
تحريك الأعداء إلى الأسفل باستخدام for loop
عمل check على مكان الأعداء الحالي و قتلهم (بإرجاعهم إلى مكان خارج الشاشة)
توليد عدد جديد من الأعداء


وهذا هو Algothirm الذي فكرت فيه




void update_enemies(){
   for (i=0; i<max_enemies;i++)>      if (enemy[i].isalive) {
                             if (enemy[i].y>SCREEN_H) {enemy[i].kill;}
                             else {enemy[i].y += enemy[i].speed;}
                            }
      else {
            enemy[i].revive(randx,randy);
            }

                                }
                     }





قمت بتجربة هذا الجزء من الكود و لكن لا يظهر أي أعداء :🙁


حاولت أن أفهم المشكلة طول اليوم والأن أنا متأكد من حاجتي للمساعدة


أنا في إنتظار ردودكم الكريمة


شكراً

محترف مشرف عبد اللطيف حاجي علي مشاركة 2

الخوارزمية تبدو صحيحة. باستثناء أنك لا تريد أن تجعل الإحداثي y عشوائياً، حيث يجب أن يبدأ الأعداء من الأسفل (أو اﻷعلى حسب احداثياتك) أي من (y=0)، إليس كذلك؟
ماذا عن كود الرسم؟ وماذا عن الحلقة الأساسية للبرنامج؟

عبد اللطيف حاجي علي
مبرمج
In|Framez

مبتدئ  Ali Amin مشاركة 3

كما قال الاخ عبد اللطيف 
و هذه بعض الاشياء قد تكون ما سببت الخطأ :
تأكد ان isalive يكون true عندما تقوم بوضع العدو ( الحالة الافتراضية له)
تأكد من ان القيمة speed ليست عالية جدا فيختفي العدو عند وضعه
تأكد انك تستدعي الدالة update_enemies
و اعتقد ايضا انك تقصد enemy[i].kill();
جرب وضع عدو واحد في مكان ثابت لكي تتأكد من ان كود الرسم نفسه يعمل جيدا
تأكد من قيم المتغيرات randx و randy و لو تقدر ان تطبعهم على الشاشة سيكون هذا جيد او ان تستخدم فيجوال استوديو و تستخدم الbreak points للتأكد من قيم كل المتغيرات اثناء العمل
بالتوفيق لك إن شاء الله .

مبتدئ  أحمد عبد العظيم مشاركة 4

الأخ عبداللطيف والأخ علي شكراً لردودكم


بالنسبة لملاحظات الأخ عبداللطيف

أنت محق الإحداثي y يجب أن يكون 0 أو عشوائياً أقل من 0 (خارج الشاشة)

كود الرسم و الحلقة الأساسية للبرنامج تعملان جيداً  (سوف ألحق الكود لاحقاً)


اما بالنسبة لملاحظات الأخ علي

ما أفهمه هو عن انشئ الأعداء في حالة isdead ثم اجعلهم alive عن طريق update_enemies() لأن لو أنشأتهم في حالة isalive سوف يتحركون لأسفل خارج الشاشة. لا أعلم سوف أجرب رأيك غداً إن شاء الله.


قمت بكتابة الكود و تجربته فأعطى نتيجة غريبة حيث يظهر عدو واحد عشوائياً عند أعلى الشاشة ثم يختفي ثم يظهر في مكان عشوائي أخر أعلى الشاشة ثم يختفي وهكذا. مع ملاحظة أن الكود يكتشف collision بشكل متكرر

ها هو الكود



void update_enemies() {
     for (int j=0;j<max_enemies-1;j++)>         if (!enemy[j].isdead()) {
            draw_sprite(back_buffer, spaceenemy, enemy[j].getx(), enemy[j].gety());
            if (!(enemy[j].gety()>scrn_h)) {
               if (collide_detect(ship.getx(),ship.gety(),shipframe[ship.currentframe],enemy[j].getx(),enemy[j].gety(),spaceenemy)) {
                  textprintf_ex(back_buffer, font, 10, 150, makecol(255, 100, 200),-1, "SHIP AND ENEMY COLLISION!");
                  enemy[j].kill(true);
                  enemies_present--;
                  }
               else { 
                    enemy[j].sety(enemy[j].gety()+enemy[j].speed);
                    draw_sprite(back_buffer, spaceenemy, enemy[j].getx(), enemy[j].gety());
                    }
                                         }
            else {
                 enemy[j].kill(true);
                 enemies_present--;
                 }
                                 }
         else {
              enemy[j].kill(false);
              enemy[j].setx(rand()% scrn_w);
              enemy[j].sety(0);
              enemies_present++;
              }
            }
     }




قمت بطباعة احداثيات الأعدا







ء وحالتهم isalive أو لا


الصور مرفقة

محترف مشرف عبد اللطيف حاجي علي مشاركة 5

مرة أخرى أرى أن الكود صحيح، عدا أنك تقوم برسم العدو مرتين: قبل وبعد تغيير موقعه
أمور لتتأكد منها:
١. ما هو إتجاه محور y في لعبتك؟ للأسفل أم للأعلى؟
٢. لماذا احداثيات الأعداء سالبة في الصور؟
٣. ما هي قيمة speed للأعداء؟
٤. لماذا لا يتم رسم الأعداء في الصورة الثانية مع أنهم أحياء بينما يرسم الأعداء في الصورة الأولى مع أنهم غير أحياء (حسب الرسالة أسفل الشاشة) ؟
٥. قم بفصل كود الاصطدام. جرب الخوارزمية الأساسية أولاً.
٦. قم بعمل التالي: أنشئ عدواً واحداً باحداثيات محددة وثابتة ثم جرب كود الرسم.

ملاحظة خارجة عن الموضوع: لا أفضل الكود الذي يدمج بين الرسم وتحديث الحالة. أفضل فصل الاثنين وتجريبهما بشكل منفصل

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 6

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

void update()
{
Enemy.Update();
Player.Update();
}


void Draw()
{
Enemy.Draw();
Player.Draw();
}

 الان وقد توضح الكود اكثر :
كود التحديث : 



Class Enemy
{


//يجب ملئ المتغيرات بالقيم المناسبة في الدالة البانية
// 





//دالة تحدد نقطة الانطلاق
  void StartPoint()
{
//تعمل هذه الدالة على اعطاء قية عشوائية لكنها تبقى ضمن مساحة الشاشة، 
X = (rand()%  Screen.width);
Y = (rand()%  Screen.Height);
}
 
  void Update()
  {


     // عند مدخل الدالة لاول مرة نحدد النقطة التي نريد الانطلاق منها
if ( IsCreatedNow == true )
{
StartPoint();
// هذا المتغير يسمح لنا بعدم تغير نقطة البداية عند كل تحديثة
IsCreatedNow = false;
}


     // نتحقق من ان الكائن في الشاشة
     if( 
(Y > 0 && (Y + MySprite.h)< Screen.Height) 
&&
(X > 0 && (X + MySprite.w)< Screen.width) 
)
{
IsDisplayed = true;
}

    else
{
  IsDisplayed = false; 

}



     //نقوم بالتحديث اذا كان الكائن حيا
     if( IsDead == false )
     {
      //  التحقق من التصادم فقط اذا كان حيا او ظاهرا على الشاشة
if ( (collidAgainst( Player.Fire)) == true &&  IsDisplayed == true )
{
IsDead = true;
}
// (Y)القيام بعمليات اخرى كتغير قيم 
//  كي يبدو ان اجسم يتحرك نحو الاسفل
Y+= Speed.Y;//من الافضل استعمال معادلة الحركة هنا و ذلك لتنقل بصفة منتظمة على جميع الاجهزة
     }
  }
}




Class Enemy
{
  void Draw()
  {
     if( IsDisplayed == true )
     {
       //كمثال فقط و ليست الدالة بحد ذاتها
       al_draw(screenbf, X,Y);
     }
  }
}


اذا كانت لديك اسئلة، أو لم تفهم جزءا من الكود أو انني لم افهم قصدك، ارجوا ان تخبرني بذلك.شكراملاحظة : الصورة التي لم يظهر بها العدو هي عادية اذ ان العدو يتواجد عند X = 698
سلام
 
-----

مبتدئ  Islam Merabtene مشاركة 7

إجابة الاخ أنس كاملة, و لكن أريد ان أقوم ببعض التعديلات
لننضر إلى هذا الكود :


  void StartPoint()
{
//تعمل هذه الدالة على اعطاء قية عشوائية لكنها تبقى ضمن مساحة الشاشة، 
X = (rand()%  Screen.width);
Y = (rand()%  Screen.Height);
}

أولا, أضن أنه من الأفضل :


X = rand() %  (Screen.width - MySprite.w);

ثم أفكر في جعل Y سالب بحيث يكون الأعداء خارج الشاشة ثم ينزلون تدريجيا. المشكل في كود الأخ أنس هو إحتمال أن تكون نقطة بداية العدو فوق اللاعب اي ان سفينة العدو تمس سفينة اللاعب وبذلك يخسر اللاعب, هذا ما أقترحه :


void StartPoint()
{
//تعمل هذه الدالة على اعطاء قية عشوائية لكنها تبقى ضمن مساحة الشاشة، 
X = rand() %  (Screen.width - MySprite.h);
Y = -(rand() %  Screen.Height);
}

سلام