صفر تا صد ساخت بازی با سی شارپ 11#

صفر تا صد ساخت بازی با سی شارپ 11#
در جلسه قبلی برخورد موشک ها با دشمنان را برنامه نویسی کردید. در این جلسه نحوه محاسبه امتیازات را بررسی می کنیم و نیز ذخیره سازی این امتیازات روی فایل را برنامه نویسی می کنیم.
دارالترجمه رسمی
دارالترجمه رسمی پارسیس شامل خدمات ترجمه رسمی و تخصصی در بیش از 60 زبان زنده دنیا
جای بروشور دیواری
خرید جای بروشور دیواری و رومیزی
افزونه های سئو وردپرس
بهترین افزونه های سئو وردپرس به صورت کاملا فارسی
خودتان را اینجا معرفی کنید

برای محاسبه امتیاز بازیکن لازم نیست که محاسبات پیچیده ای انجام دهیم، فقط کافی است که برای هر شلیک موفق یک امتیاز در نظر بگیرید و اگر دوست دارید که کار بیشتری انجام دهید می توانید برای شلیک های نا موفق هم امتیاز منفی در نظر بگیرید. من برای هر شلیک موفق 5 امتیاز مثبت و برای هر شلیک ناموفق 5 امتیاز منفی در نظر گرفته ام.

برای نمایش امتیاز بازیکن از همان روش قبلی یعنی قرار دادن label روی فرم استفاده می کنیم، منظورم همان کاری است که برای نمایش تعداد موشک های شلیک شده و تعداد موشک های خطا رفته استفاده کردیم. برای انجام این کار باید از روی label های که برای موشک ها قرار داده بودید کپی بگیرید و دقیقا همان کارهایی که برای آنها انجام دادید برای این دو label نیز انجام بدهید. یعنی این دو label نیز در زمان شروع بازی ظاهر می شوند و قبل از آن دیده نمی شوند. من اسم این دو  label را بصورت زیر در نظر گرفته ام.
 
lblScore                        برای نمایش امتیاز
lblScoreText                  متن "امتیاز :" را نمایش می دهد
در پایان صفحه شما باید شبیه به تصویر زیر باشد.
 

اما چه زمانی باید امتیاز کاربر اضافه شود و چه زمانی باید کسر شود. خیلی ساده است زمانی که موشک به دشمن برخورد کرد یعنی شلیک موفق بوده است و باید 5 امتیاز به امتیاز بازیکن افزوده شود و زمانی که موشک از صفحه خارج می شود یعنی شلیک نا موفق بوده است و باید امتیاز از کاربر کسر گردد. با این تعاریف حتما متوجه شده اید که یک متغییر سراسری نیاز داریم تا امتیاز بازیکن را در خود نگهداری کند. پس لطفا یک متغییر سراسری با نام زیر تعریف کنید.
Int playerScore = 0;
حالا باید در قسمت برخورد موشک امتیاز را 5 واحد افزایش دهیم و همچنین نیاز داریم تا امتیاز اضافه شده را به بازیکن نمایش دهیم پس باید متن label را نیز تغییر دهیم و امتیاز کاربر را در آن قرار دهیم. لطفا به قسمت برخورد موشک بروید و کد های زیر را به آن قسمت اضافه کنید.
playerScore += 5;
lblScore.Text = playerScore.ToString();
 

با این قطعه کد پس از هر بار برخورد موشک به یکی از دشمنان 5 امتیاز به کاربر اضافه می شود. اما قسمت کسر امتیاز را باید درست در جایی اضافه کنید که بررسی می کردیم که آیا موشک از صفحه خارج شده است یا خیر؟ مانند تصویر کد زیر را به این قسمت اضافه کنید.
if(playerScore > 0)
{
                playerScore -= 5;
                lblScore.Text = playerScore.ToString();
}
 
 

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

ثبت امتیاز بازیکن

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


مشاهده می کنید که دو سطر در این لیست وجود دارد. اما من این سطر ها را در زمان طراحی به این لیست اضافه نکردم بلکه در زمان اجرای بازی آنها را به برنامه اضافه کردم. برای اینکار کدهای زیر را به برنامه اضافه کرده ام. همانطور که در تصویر زیر مشاهده می کنید این دو سطر زمانی به لیست اضافه می شوند که کاربر روی دکمه شروع بازی کلیک می کند.
 

اما معنی هر یک از این خطوط چیست یا به عبارت دیگر چگونه کار می کند. دوستان هر سطر از یک کنترل listView یک شیی از کلاس ListViewItem است. پس برای ساخت یک سطر برای این کنترل اول باید یک نمونه از این کلاس بسازیم. در اولین خط همین کار را انجام داده ام، یک نمونه از این کلاس ساخته ام. اما مطمعنا همه listView ها به یک شکل نیستند. یعنی چی؟ منظور این است که ما در این listView سه ستون به نام های : نام، امتیاز و تاریخ داریم ولی ممکن است در یک listView ستونهای تاریخ ، ایمیل ، تلفن ، آدرس و ...  غیره وجود داشته باشند، پس نمی توانیم برای همه listView ها به یک شکل ListViewItem بسازیم و باید LsitViewItem مخصوص آن listView را بسازیم. برای حل این مشکل برای ListViewItem یک شکل کلی در نظر می گیریم ولی برای مشخصات درونش از یک آرایه استفاده می کنیم. به تصویر فوق نگاه کنید. درون پرانتز از کلمه []new استفاده شده است به این وسیله یک آرایه ساخته می شود و در داخل {} بخش های مختلف آن نوشته شده است. اولین خانه حاوی نام، دومین حاوی امتیاز و سومین خانه حاوی تاریخ بازی است. پس از ساخت این ListViewItem حالا باید آن را به ListView اضافه کنیم.

در خط دوم همانطور که مشاهده می کنید. با استفاده از متد add این ListViewItem را به لسیت item های lsv_playerListAsc اضافه کرده ام. دو خط بعدی دقیقا کار همین دو خط را انجام می دهند. فقط مقدار درون پرانتز تغییر کرده است.
برای اضافه کردن نام بازیکن جدید در زمان اجرا نیز باید همین کار را انجام دهیم. اما نه در زمان شروع بازی این چهار خط را از برنامه حذف می کنیم تا ListView ما کاملا تمیز شود. سپس به رخداد دکمه خروج بازی بروید و کدهای زیر را به آن اضافه کنید.
ListViewItem item = new ListViewItem(new[] { txt_username.Text, playerScore.ToString() , DateTime.Now.ToShortDateString() });
lsv_playerListAsc.Items.Add(item);
MessageBox.Show("");
برنامه را اجرا کنید و نام خود را وارد کنید و کمی بازی کنید و سپس دکمه خروج از بازی را بزنید، یک کادر پیغام نمایش داده می شود که درون آن چیزی نوشته نشده است. اما اگر به ListView نگاه کنید می بینید که یک سطر به آن اضافه شده است که نام شما ، امتیاز شما و تاریخ بازی را به شما نمایش می دهد.
قسمت اول از خط اول را که در مثال قبلی دید، اما داخل پرانتز و قسمت آرایه، اگر به مثال قبلی نگاه کنید می بینید که این آرایه از نوع string بود و خانه های این آرایه را خودمان بصورت دستی وارد کرده بودیم. در این بخش متنی که درون  txt_username نوشته شده است را بعنوان نام بازیکن در نظر گرفتیم. امتیاز هم که کاملا مشخص است، همان متغییر سراسری است که برای نگهداری امتیاز بازیکن تعریف کرده بودیم، که در اینجا آن را به String تبدیل کردیم. اما بخش آخر تاریخ سیستم شما است. DateTime یک نوع داده ای است که شما با استفاده از آن می توانید متغییرهایی بسازید که زمان را در خود نگه داری می کنند. متد Now کلاس DateTime زمان حال حاضر سیستم را بر می گرداند. یعنی اگر شما از این متد استفاده کنید زمان سیستم را به دست می آورید، اما یک اشکال وجود دارد و آن این است که این متد زمان را بطور کامل نمایش می دهد، یعنی تاریخ بعلاوه ساعت و دقیقه و ثانیه  اما ما فقط تاریخ را لازم داریم از همین رو از تابع ToShortDateString استفاده کردیم که فقط تاریخ را بصورت یک string بر می گرداند. در آخر کادر پیغام را فقط به این خاطر استفاده کرده ام که برنامه بسته نشود و شما بتوانید نتیجه را مشاهده کنید. حالا روی دکمه ok کلیک کنید تا برنامه بسته شود و سپس مجددا برنامه را اجرا کنید و بازی را شروع کنید، همانطور که می بینید اطلاعات سری قبلی وجود ندارند. خب مشخص است که اینطور خواهد شد چون ما آن اطلاعات را ذخیره نکرده ایم. فعلا این سه خط را از برنامه حذف کنید. در ادامه در مورد ذخیره سازی صحبت می کنیم.

ذخیره سازی

بازی ما باید یک بخش داشته باشد که امتیاز بازیکن ها را در خود ذخیره کند در غیر اینصورت با هر بار بسته شدن برنامه تمام اطلاعات بازیکنان از بین می روند. برای ذخیره کردن امتیاز بازیکنان دو راه وجود دارد. راه اول استفاده کردن از فایل ها است، در این روش در زمان بسته شدن برنامه تمام اطلاعات بازیکنان را درون یک فایل متنی می نویسیم و بعد از اجرا مجدد برنامه این فایل را می خوانیم و نمایش می دهیم. اما در روش دوم باید از پایگاه داده استفاده کنیم. در حالت کلی استفاده از روش دوم صحیح است اما در برنامه های مثل بازی ما که امنیت و بعضی فاکتور های دیگر اهمیت چندانی ندارند می توانیم از روش اول استفاده کنیم. چون این روش راحتتر و سریعتر است اما در آینده یاد خواهید گرفت که چگونه از پایگاه داده استفاده کنید. 
 
برای شروع کار اول از همه باید کتابخانه مربوط به File را به برنامه اضافه کنیم. نام این کتابخانه IO به معنی input و output است. قطعه کد زیر را به قسمت کتابخانه ها مطابق تصویر اضافه کنید.
using System.IO;
پس از اضافه کردن این کد، توابع لازم جهت کار با فایل ها در اختیار ما قرار می گیرد. حالا باید مشخص کنیم که این فایل در کدام قسمت از هارد کامپیوتر قرار داشته باشد. برای تعیین این مسیر ذخیره سازی از یک متغییر سراسری از نوع string استفاده می کنیم.
string path = "C:\MajidOnline\TheGuards.txt";
همانطور که مشاهده می کنید از دو برای آدرس دهی استفاده کردیم. دلیل این کار این است که برخی از کارکتر ها مثل همین در متن ها معانی خاصی برای کامپایلر دارند و اگر بخواهیم آنها معنی اصلی خود را بدهند باید از علامت () قبل از آنها استفاده کنیم. از همین رو از دو علامت \ استفاده کردیم اما اگر این کار را دوست ندارید می توانید از روش زیر بجای این روش استفاده کنید.
string path = @"C:MajidOnlineTheGuards.txt";
من روش دوم را پیشنهاد می کنیم. در این روش با گذاشتن علامت @ به کامپایلر می گوییم که این رشته آدرس فایل یا فولدر است.
می توانیم کد مربوط به ذخیره کردن را در همان رخداد خروج از بازی بنویسیم و کدهای مربوط به خواندن اطلاعات ذخیره شده را در رخداد شروع بازی بنویسیم. اما برای ساده تر شدن کار و نیز تمیزتر شدن کد از دو تابع load و save استفاده می کنیم. متد save را در زمان بسته شدن بازی فراخوانی می کنیم و در آن عملیات ذخیره سازی را انجام  می دهیم. متد load هم در زمان شروع بازی فراخوانی می شود و درون آن اطلاعات را از روی فایل می خوانیم و نمایش می دهیم. لطفا این دو متد را بصورت زیر به برنامه اضافه کنید.
 

در داخل متد save کدهای زیر را بنویسید و تابع save را در رخداد دکمه خروج فراخوانی کنید.
File.AppendAllText(path, "MajidOnline");
 حالا به آدرسی که در متغییر path آن را تعریف کردید بروید، می بینید که چنین آدرسی وجود ندارد. حالا برنامه را اجرا کنید و سپس با زدن دکمه خروج از برنامه خارج شوید. دوباره به آن آدرس بر گردید مشاهده می کنید که این آدرس ساخته شده است، اگر شما هم مثل ما آدرس دهی کرده باشید و به آدرس C:majidonline بروید مشاهده می کنید که یک فایل متنی به نام TheGuards در آن ساخته شده است در صورتی که پیش از این فولدر majidonline و فایل متنی TheGuards اصلا وجود نداشتند. حالا فایل متنی را باز کنید مشاهده می کنید که کلمه MajidOnline در آن نوشته شده است. اما این فایل چگونه ساخته شد؟ برای کار با فایل ها ابتدا باید آنها را باز کنیم. برای باز کردن فایل ها چند راه وجود دارد. ساده ترین راه تابعی است که من از آن استفاده کردم. تابع AppendAllText از کلاس File فایل را از مسیری که برای آن مشخص کرده اید باز می کند و متنی که بعنوان پارامتر دوم به آن داده اید را به انتهای آن فایل اضافه می کند. در صورتی که شما آدرس فایلی را داده باشید که قبلا وجود نداشته است، این تابع آن فایل را می سازد و متن داده شده را در آن می نویسد. توجه داشته باشید که همه توابع کار با فایل ها اینکار را انجام نمی دهند یعنی اگر از تابع دیگری استفاده کنید که در صورت وجود نداشتن فایل آن را نسازد برنامه شما در اولین اجرای خود دچار مشکل می شود و اجرا نمی شود، مگر اینکه این فایل را بصورت دستی بسازید. پس بهترین روش برای باز کردن یک فایل استفاده از همین متد است. همانطور که گفتم اولین پارامتر این متد مسیری است که فایل باید در آن نوشته شود و پارامتر دوم متنی است که باید در آن فایل نوشته شود.

خب حالا توانستیم که بخشی از اطلاعات را ذخیره کنیم. اما هنوز راه زیادی تا پایان باقیمانده است. حالا نوبت آن رسیده است که اطلاعات کاربر را ذخیره کنید. برای اینکار کافی است تا بجای ورودی دوم این تابع مشخصات کاربر را قرار دهیم، یعنی درست مثل کد زیر:
File.AppendAllText(path, txt_username.Text + playerScore.ToString() + DateTime.Now.ToShortDateString());
یک بار فایل ساخته شده را پاک کنید تا از اول ساخته شود. برنامه را اجرا کنید و نام خود را بعنوان بازیکن وارد کنید و بازی را شروع کنید سپس دکمه خروج را بزنید. حالا بسراغ فایل ذخیره شده بروید، می بینید که تمام اطلاعات شما در آنجا بصورت پشت سر هم ذخیره شده است. در این مثال دقیقا مثل قبل در پارامتر اول محل ذخیره سازی را مشخص کردیم و در پارامتر دوم متنی که باید ذخیره شود. مطمعنا می دانید که می توانیم از علامت + برای پیوستن متن ها به هم استفاده کنیم.

اما در این روشی که ما مشخصات کاربر را ذخیره کردیم دو مشکل وجود دارد. اول اینکه اگر برنامه را یکبار دیگر اجرا کنید و دوباره ببندید مشاهده می کنید که مشخصات دومین بار نیز دقیقا در ادامه همین خط نوشته می شود در صورتی که ما در زمان بازخوانی اطلاعات ما هر خط از این فایل به منزله مشخصات یک بازیکن در نظر می گیریم. به تصاویر زیر نگاه کنید تا متوجه این موضوع شوید در تصویر اول این حالت نمایش داده شده است و در تصویر دوم نحوه صحیح نمایش داده شده است.
 




برای حل این مشکل یک راه حل خیلی ساده وجود دارد و آن راه این است که در انتهای هر از سطر از این اطلاعات یکبار دکمه enter کیبورد را بزنید، اما زمانی که کاربر این بازی را روی سیستم خود نصب کند دیگر شما دسترسی به این فایل ندارید که بصورت دستی آن را تغییر دهید و از طرفی به کاربر هم که نمی شود بگویید خودش اینکار را انجام دهد پس باید چاره ی دیگه پیدا کرد. اگر به یاد داشته باشید قبلا گفته بودم که کاراکتر n را که در یک متن بزنید ادامه آن متن در خط بعدی چاپ می شود. اما شما در زمان کار با فایل ها نمی توانید از این سیستم استفاده کنید و اگر این کارکتر را به انتهای متن خود اضافه کنید هیچ اتفاق خاصی رخ نمی دهد و متن در ادامه خط قبلی نوشته می شود. برای حل این مشکل باید به روش زیر عمل کنید.
File.AppendAllText(path, txt_username.Text + playerScore.ToString() + DateTime.Now.ToShortDateString() + Environment.NewLine);
می بینید که به انتهای کد قبلی یک قسمت اضافه شده است با استفاده از کلاس Environment می توانیم بعضی کارها را انجام دهیم که یکی از آنها رفتن به خط بعدی در یک فایل متنی است. NewLine یک ویژگی از این کلاس است که باعث می شود که اشاره گر موس در خط بعدی قرار گیرد. حالا دوباره فایل ذخیره بازی را پاک کنید و مجددا چند بار بازی را اجرا کنید و ببندید مشاهده می کنید که اطلاعات در سطرهای جدا از هم ذخیره می شوند.

و اما مشکل دوم دوستان به اطلاعاتی که ذخیره شده اند نگاه کنید، حتما متوجه شدید که تشخیص اینکه کدام بخش نام بازیکن و کدام بخش امتیاز و کدام بخش تاریخ بازی است کار راحتی نیست. شما که یک انسان هستید اینکار برایتان سخت است حالا فرض کنید که کامپیوتر بخواهد این اطلاعات را بخواند و در هر بخش را درست در سر جای خودش قرار دهد. مطمعنا چنین کاری امکان پذیر نیست و کامپیوتر همه آن را بصورت یک متن واحد در نظر می گیرد. جهت حل این مشکل ما باید یک کاراکتر را بعنوان جدا کننده در نظر بگیریم و به برنامه بگوییم که هر بخش با این جدا کننده از دیگری جدا شده است. اما این جدا کننده نمی تواند هر کاراکتری باشد. چرا؟ شما فرض کنید که کاراکتر فضای خالی را بعنوان جدا کننده در نظر گرفته اید، حالا یک بازیکن می آید و نام Majid Online را وارد می کند اینجاست که برنامه شما به مشکل بر می خورد پس نمی توانید از این کاراکتر استفاده کنید. کاراکتر جدا کننده را باید به نحوی انتخاب کنیم که مطمعا باشیم کاربر هیچ وقت از آن در نام خود استفاده نمی کند، در ضمن هر کاراکتری که انتخاب کردیم باید در زمان شروع بازی چک کنیم اگر نام بازیکن حاوی این کاراکتر بود از بازیکن بخواهیم که آن را از نام خود حذف کند سپس بازی را ادامه دهد. من کاراکتر برای جدا کننده در نظر گرفتم چون احتمال استفاده آن در نام بازیکن بسیار کم است درضمن در تاریخ نیز از آن استفاده نمی شود.
پس باید کاراکتر را بین هر بخش از متن ذخیره سازی اضافه کنیم این کار بسیار ساده است به کد زیر نگاه کنید.
File.AppendAllText(path, txt_username.Text + "\" + playerScore.ToString() + "\" + DateTime.Now.ToShortDateString() + Environment.NewLine);
در قسمت های قبلی گفتم که کاراکتر یک کاراکتر کنترلی در متن ها است و برای چاپ یکی از آن باید دو عدد از آن را بنویسیم تا یکی چاپ شود. البته این کاراکتر کارهای دیگری هم انجام می دهد که ما فعلا کاری به آنها نداریم. حالا برنامه را باز کنید و چند بار ببندید. تمام مشکلات حل شدند و حالا زمانی که بخواهیم قسمت load را بنویسیم به مشکلی بر نمی خوریم. اما پیش از خروج از بازی باید مشخصات بازیکن و امتیاز را به بازیکن نمایش دهیم، برای اینکار هم می توانید یک فرم برای خود بسازید و هم می توانید از MessageBox استفاده کنید، من برای ساده تر شدن کار از MessageBox استفاده می کنم. اما یک نکته دیگر این است که زمانی که کاربر بازی را تمام می کند باید همه چیز از کار بیافتد و حرکت نکند پس باید تایمر را نیز stop کنیم. پس قطعه کد زیر را در متد save برناه خودتان بنویسید و متد save را در هر قسمت از برنامه که باعث می شود بازی تمام شود فراخوانی کنید.
 

 خب دوستان برای این جلسه به اندازه کافی کار انجام داده اید به امید خدا در جلسه بعد تابع load را برنامه نویسی می کنیم و تقریبا کار را تمام می کنیم. بعد از تابع load نحوه اضافه کردن تصاویر دشمنان و موشک و کلا تم بازی را توضیح خواهم داد.
سورس کد بازی تا این قسمت را می توانید از اینجا دانلود کنید.
 

مصطفی مدرک کارشناسی نرم افزار دارد و از برنامه نویسان شرکت آرتیمان استودیو است. از سال 86 برنامه نویسی با زبان سی شارپ را آغاز کرده و در حوزه توسعه وب با تکنولوژی دات نت بسیار مسلط است. وی هم اکنون در حال توسعه اپلیکیشن های موبایل از طریق پلتفرم زامارین است.

نظرات و سوالات کاربران

هنوز دیدگاه و یا سوالی ارسال نشده است.
هم اکنون شما اولین دیدگاه را ارسال کنید.