Game Programming بخش اول

دانلود سورس کد – 8.77 KB

معرفی

هدف این خود آموز این است که به شما نشان دهد چطور یک بازی ساده بدون کمک API های سطح بالا مثل XNA یا DirectX که نیمی از فرایند ها را اتوماتیک برای شما انجام می دهند ، بسازید . تمام چیزی که ما استفاده می کنیم یک فرم ویندوز و توابع GDI+ است برای ترسیمات پایه ای و تعدادی از Event های فرم .

پیش زمینه

چند نکته در مورد loop بازی وجود دارد ، چون فرم های ویندوز رویدار گرا هستند در حالی که بازی ها عموماً این طور نیستند . من روی تفاوتهایی که بین کدهایی که به طور ‹regular› استفاده میشوند و کدهایی که در Windows Form باید استفاده شود تاکید می کنم .

قدم اول : تنظیم کردن بازی

حلقه ی اصلی

به خاطر اینکه بازی ها معمولاً رویداد گرا نیستند ، ما از یک loop استفاده می کنیم تا تمام logic  و ترسیمات را در آن انجام دهیم . پس در هر حلقه ما منطق بازی ، چک کردن ورودی ها و کشیدن گرافیک روی صفحه نمایش را انجام می دهیم . به کدهای زیر نگاه کنید . آیا می توانید مشکل را پیدا کنید؟


 bool runGame = true;
  while(runGame)
  {
   GetInput();
   PerformLogic();
   DrawGraphics();
  } 

اگر متوجه شده باشید بازی با حد اکثر سرعت ممکن اجرا میشود . در این حلقه بازی با تمام سرعتی که می تواند اجرا می شود از 1fps گرفته تا 1000fps . سرعت بازی ممکن است برای دشمنان و یا اشیایی که به بازی اضافه میشوند تفاوت داشته باشد و بازی آنقدر به سرعت اجرا میشود که بازیکن نمیتواند به موقع واکنش نشان دهد .

همه چیز راجع به زمان بندی

ما باید سرعت بازی را کنترول کنیم. برای این کار از یک timer استفاده می کنیم . timer یک flag را set می کند و ما متوجه میشویم که چه موقع باید logic در حلقه ی اصلی اجرا شود ؛ با این روش بازی با سرعت کنترول شده تری اجرا می شود .


 Timer MainTimer;
 //The timer’s interval is in milliseconds, so we need to work out  
 //how long each interval should be
  MainTimer.Interaval = 1000/60;
  bool runGame = true;
  volatile bool doStuff = false;
  Main()
  {
    while(runGame)
    {
    if(doStuff)
    {
  GetInput();
  PerformLogic();
   DrawGraphics();
  doStuff = false;
   }
  } 
 }
  Timer()
  {
   doStuff = true;
  } 

ما میتوانیم یک کار بهتر انجام بدهیم

اگر چه این روش سرعت بازی را تا سطحی قابل قبولی محدود می کند ، اما هنوز اصلاحات بیشتری میتوان انجام داد . ترسیمات گرافیکی معمولاً کند ترین قسمت در بازی هستند ، پس اگر نمایش صحنه بیش از حد طول بکشد ، میتواند باعث شود logic کند اجرا شود در نتیجه تمام بازی کند میشود . برای جلوگیری از این مشکل ما نیاز داریم ترسیمات گرافیکی را از logic جدا کنیم و مطمئن شویم که logic اولویت بیشتری نسبت به رندر کردن صحنه دارد . به این معنا که اگر logic کند شد ، ما نباید در طول حلقه گرافیک را آپدیت کنیم پس ما فریم جاری را رها می کنیم .

این تنظیماتی است که برای مدیریت بازی بکار می بریم :


 Timer MainTimer;
 //The timer’s interval is in milliseconds, so we need to work out
 //how long each interval should be
 MainTimer.Interaval = 1000/60;
 bool runGame = true;
 volatile uint speedCounter = 0;
 Main()
 {
  while(runGame)
  {
  if(speedCounter >0)
  {
  GetInput();
   PerformLogic();
  speedCounter--;
  if(speedCounter == 0)
  DrawGraphics();
  }
  }
 }
 Timer()
 {
  speedCounter++;
 } 

در این حلقه logic تنها زمانی اجرا می شود که counter بزرگتر از صفر باشد . بعد از اینکه تمام logic اجرا شد ، Counter کاهش پیدا میکند و اگر دوباره صفر بود ما صحنه را آپدیت می کنیم . اگر تمام حلقه بیش از یک فریم طول بکشد ( بیش از timer interval ) ، سپس زمانی که ما counter را کاهش می دهیم ، هنوز بزرگتر از صفر می ماند ، پس ما فریم را رها می کنیم و دوباره زمان بدست می آوریم .

تغییرات برای یک فرم

اگر از یک حلقه while در فرم ویندوز مان استفاده کنیم ، آن وقت نمی توانیم هیچگاه صفحه را آپدیت کنیم و application هنگ خواهد کرد . به همین دلیل ما منطق را در یک تابع callback در timer قرار می دهیم و آنرا در یک thread مخصوص خودش اجرا می کنیم . به غیر از این همه چیر به همان صورت باقی می ماند . کد نهایی چیزی شبیه این است :


 bool drawGraphics = false;
 void TimerElapsed()
 {
  //Increase the counter
  speedCounter++;
  GetInput();
  PerformLogic();
  speedCounter--;
  //If the counter is 0, then the logic is not running slow 
 //we can therefore get on with drawing the graphics
  if(speedCounter == 0)
  drawGraphics = true;
 } 

ما همچنین باید متدهای OnPaint و OnPaintBackground را که windows هیچ ترسیمی را انجام نمی دهد را override کنیم و خودمان آنرا مدیریت کنیم . به یاد داشته باشید که نباید            base. OnPaint یا base.OnPaintBackground را فراخوانی کنید .


 protected override void OnPaint(PaintEventArgs e)
 {
  //We do our drawing here
 }
 protected override void OnPaintBackground(PaintEventArgs e)
 {
  //Do nothing
  //base.OnPaintBackground(e);
 } 

 

به خاطر اینکه ما از آن برای ترسیمات گرافیکی استفاده می کنیم ، فکر می کنم بحث در مورد چگونگی استفاده از آن بسیار مفید باشد . برای شروع ترسیم به چند چیز نیاز داریم :

  1. یک graphic object ( این شی کار ترسیم را انجام می دهد )
  2. یک سطح برای ترسیم روی آن
  3. یک pen یا brush برای ترسیم با آن

اگر ما متد OnPaint فرم مان را override کرده باشیم می توانیم از شی Graphics در PaintEventArgs که قبلاً فرم را به عنوان سطحش دارد استفاده کنیم  . شما میتوانید از متد های شی Graphics برای ترسیم روی صفحه استفاده کنید :


 override void OnPaint(PaintEventArgs e)
 {
  //We can draw with e.Graphics
  //Brushes are used to fill areas
  Brush myBrush = new SolidBrush(Color.Red);
  e.Graphics.FillRectangle(myBrush,0,0,100,100);
  //Pens are used to draw lines
  Pen myPen = new Pen(Color.Green);
  e.Graphics.DrawLine(myPen, 50, 250, 65, 15);
 } 

Demo

این demo شامل game  loop که در موردش صحبت کردیم است ، به علاوه کمی کد های ترسیم که میتوانیم چیزهایی را روی صفحه ببینیم .

چی شد ؟ تمرین !

قبل از اینکه من مقاله ی بعدی رو بنویسم ( یا قبل از اینکه بروید و آنرا بخوانید ) ، چرا سعی نمی کنید که demo را ویرایش کنید و دایره را حرکت دهید ؟ زود باشید ، زیاد سخت نیست ، من میدانم شما میتوانید آنرا انجام دهید اگر تلاش کنید .

مباحث بعدی

حالا که ما کدهای پایه ی game را داریم می توانیم کارهایی را با آن انجام دهیم . در مقاله بعدی این موارد بحث خواهند شد :

  • Double Buffering
  • گرفتن ورودی
  • ایجاد یک شمارنده ی FPS
  • ترسیم یک Sprite متحرک

شما چه می خواهید ؟

در مورد چیز هایی که می خواهید در این مقالات بحث شود راحت باشید و آنها را در Comment ها مطرح کنید .من این جا هستم که به شما کمک کنم پس اگر بدانم چه می خواهید می توانم آنها را در مقالاتم بیاورم . این مقالات در مورد بازی های 2D است .

منبع :

Game-Programming-One

Advertisements

دربارهٔ DeltaCode

Somewhere near the sky Far away from people Far away from noise Somewhere near yourself

Posted on فوریه 8, 2012, in بازی and tagged , . Bookmark the permalink. 2 دیدگاه.

  1. مرسی. کاش در مورد کلید واژه volatile هم یه توضیحی میدادی.

  2. این صفت از C به جا مونده و به این معناست که کامپایلر نباید متغییری که با این صفت معرفی میشود را بهینه سازی کند حتی اگر از آن استفاده نشود یا کامپایلر نباید ترتیب انتسابها را به هم بزند و یا آنها را حذف کند و نباید مقادیر متغییرهای volatile را در رجیسترها ذخیره کند حتی اگر در دستور قبلی مقدار آن خوانده شده باشد چون هر لحظه ممکن است مقدار آن تغییر کند . این صفت باعث میشود تا کامپایلر دقیقاً همون چیزی که برنامه نویس نوشته را بدون optimize کردن کامپایل کند . کلاً مطلب در مورد این کلمه کم پیدا میشه و اکثر برنامه نویسا هم باهاش آشنا نیستند و یه کم تجربه لازم داره . موارد استفادش در سیستم عاملهای multi thread و ارتباط با سخت افزار هستش .

    با تشکر از شما

پاسخی بگذارید

در پایین مشخصات خود را پر کنید یا برای ورود روی شمایل‌ها کلیک نمایید:

نشان‌وارهٔ وردپرس.کام

شما در حال بیان دیدگاه با حساب کاربری WordPress.com خود هستید. بیرون رفتن / تغییر دادن )

تصویر توییتر

شما در حال بیان دیدگاه با حساب کاربری Twitter خود هستید. بیرون رفتن / تغییر دادن )

عکس فیسبوک

شما در حال بیان دیدگاه با حساب کاربری Facebook خود هستید. بیرون رفتن / تغییر دادن )

عکس گوگل+

شما در حال بیان دیدگاه با حساب کاربری Google+ خود هستید. بیرون رفتن / تغییر دادن )

درحال اتصال به %s

%d وب‌نوشت‌نویس این را دوست دارند: