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

صفر تا صد ساخت بازی با سی شارپ 12#
در جلسه قبلی قسمت امتیازات را برنامه نویسی کردیم و امتیازات بدست آمده کاربر را بر روی فایل ذخیره کردیم. در این جلسه قصد داریم تا نحوه بازگردانی اطلاعات ذخیره شده کاربر را برنامه نویسی کنیم و کمی در مورد مدیریت استثناها صحبت کنیم.
دارالترجمه رسمی
دارالترجمه رسمی پارسیس شامل خدمات ترجمه رسمی و تخصصی در بیش از 60 زبان زنده دنیا
جای بروشور دیواری
خرید جای بروشور دیواری و رومیزی
افزونه های سئو وردپرس
بهترین افزونه های سئو وردپرس به صورت کاملا فارسی
تعمیر لوازم خانگی
تعمیر جاروبرقی، مایکروفر، بخارشوی، ظرفشویی، لباسشویی، سولاردام، کولرگازی
خودتان را اینجا معرفی کنید

همانطور که در جلسه قبل دید ما هر سطر از فایل ذخیره شده را به اطلاعات یک کاربر اختصاص دادیم. با این حساب کار برای ما راحت ترشده است چرا که دیگر لازم نیست کار زیادی برای جداسازی اطلاعات انجام دهیم. اگر بخاطر داشته باشید در جلسه قبل یک متد به نام load ساختیم تا کدهای مربوط به load شدن اطلاعات قبلی را در آن بنویسیم. در زمان load کردن اطلاعات درست مانند زمان save کردن اطلاعات نیاز داریم تا فایلی که اطلاعات در آن ذخیره شده اند را باز کنیم، اینکار در اصل ایجاد یک ارتباط بین برنامه و فایل ذخیره سازی است. اما خواندن از روی فایل هم دقیقا مثل نوشتن بر روی فایل یکسری متدهای آماده دارد که کتابخانه IO در اختیار ما قرار می دهد و دقیقا مثل نوشتن روی فایل خواندن از روی فایل هم متدهای تقریبا مشابه زیادی دارد که هر کدام در جای خاصی کاربرد دارند. در ادامه بیشتر در این رابطه صحبت خواهیم کرد.
 اما پیش از استفاده از متد خواندن باید چند نکته را در نظر داشته باشید:

1 – برای اولین باری که بازی اجرا می شود هیچ فایلی برای ذخیره سازی وجود ندارد و اگر ما سعی کنیم که بازی را اجرا کنیم دچار خطا می شویم.
2 – حتی اگر بازی قبلا باز شده باشد و شما آن را برای چندمین بار اجرا کنید باز هم امکان خطا وجود دارد، بعنوان مثال ممکن است ویروس به فایل شما آسیب زده باشد و یا حتی کسی قصد خراب کردن بازی شما را داشته باشد و در این فایل متنی که هیچگونه امنیتی ندارد، تغییراتی ایجاد کند که برنامه شما دچار خطا شود.

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

 این راه حل یکی از امکانات فوق العاده سی شارپ است یعنی استفاده از ساختار کنترل خطا، همانطور که گفتم در زمان اجرای برنامه ممکن است خطاهای زیادی رخ دهد که حتی به ذهن شما خطور نمی کند اما این خطاها رخ می دهند و شما خودتان قادربه مدیریت تک تک این خطاها نیستید چون هیچ اطلاعی از وجود آن ندارید، اگر این خطاها رخ دهند برنامه شما قطع می شود و این برای شمای برنامه نویس صورت خوشی ندارد. برای جلوگیری از این اتفاقات پیش بینی نشده یک ساختار وجود دارد. عبارت try-catch با استفاده از این عبارت شما بدون هیچ مشکلی کد خودتان را آری از خطا می کنید البته نه اینکه برنامه شما دیگر خطا نداشته باشد، اما دست کم دیگر اجرای آن متوقف نمی شود یا به قول معروف هنگ نمی کند. این عبارت در صورت بروز خطا آن را مدیریت می کند، خطاهای رایج در این عبارت کدهای از پیش تعریف شده ای دارند درست مثل متدهای click و غیره که ما از آنها استفاده کردیم. بعنوان مثال فرض کنید شما یک برنامه ماشین حساب نوشته اید که عمل تقسیم را نیز انجام می دهد.

حالا یک کاربر از روی عمد و یا اشتباه این تقسیم را انجام می دهد 0/5 همانطور که می دانید اگر عددی بر صفر تقسیم شود جواب نامعلوم است یا تعریف نشده است. این کار باعث می شود تا برنامه شما دچار خطا شود، اما اگر از try-catch استفاده کرده باشید و از پیغام خطای آن استفاده کنید بصورت اتوماتیک وار این خطا تشخیص داده می شود و برنامه خراب نمی شود. به خطاهای این تیپی استثنا نیز می گوییم، try-catchخودش این خطا را تشخیص می دهد و شما کافی است که برای آن یک پیغام بسازید.

اما نحوه استفاده از این عبارت به چه صورت است، این عبارت به دو قسمت تقسیم می شود. قسمت اول try که در این قسمت شما کد برنامه را می نویسید بعنوان مثال کد مربوط به قسمت تقسیم در ماشین حساب و قسمت دوم C
catch که خطا را مدیریت می کند. جلوتر می بینید که استفاده از آن چقدر آسان است.
اما نحوه نوشتن این عبارت :
try
{
            int a;عددی اول که کاربر وارد می کند//
                int b;//عدد دوم که کاربر وارد می کند
                int c = a / b;//نتیجه تقسیم در این متغییر ریخته می شود
                MessageBox.Show(c);
}
catch
{
                MessageBox.Show("یک خطا رخ داده است");
}
با استفاده از این روش در صورتی که هر مشکلی برای برنامه پیش بیاید برنامه هنگ نمی کند و فقط پیغام درون catch را نمایش می دهد. اما همیشه یک خطا رخ نمی دهد و استثناهای زیادی وجود دارد که ممکن است اتفاق بیافتند. برای اینکار catch می تواند یک ورودی بگیرد و براساس آن تشخیص دهد که چه خطایی رخ داده است برای مثال اگر یک عدد بر صفر تقسیم شود می توانید با استفاده از catch زیر آن را مدیریت کنید.
catch(DivideByZeroException e)
{
                MessageBox.Show(e.Message);
}
اگر برنامه ای به این صورت بنویسید و اجرا کنید مشاهده می کنید که یک پیغام نمایش داده می شود که به کاربر می گوید نمی تواند مخرج کسر را صفر در نظر بگیرد.
حالا برگردیم سر کار اصلی خودمان حالا که فهمیدیم به همین سادگی می توانیم جلوی بروز مشکلات را بگیریم. اولین کاری که می کنیم این است که در تابع load کدهای زیر را اضافه می کنیم.
try
{
    if (File.Exists(path))
    {
        string[] list = File.ReadAllLines(path);
        foreach (string data in list)
        {
            string[] part = data.Split('\\');
            ListViewItem item = new ListViewItem(new[] { part[0], part[1], part[2] });
            lsv_playerListAsc.Items.Add(item);
        }
    }
}
catch
{
     MessageBox.Show("یک مشکل در برقراری ارتباط با فایل ذخیره سازی بوجود آمده است");
}
خب می دانیم که برای مدیریت کردن موقعیت های استثنا درون catch یک پیغام قرار می دهیم که ما هم اینکار را انجام دادیم. اما در قسمت try یک شرط قرار دادیم. در داخل پرانتز این شرط متد Exists کلاس File را صدا زدیم و مسیر فایل را به آن دادیم. متد Exists بعنوان ورودی مسیر یک فایل را می گیرد و بررسی می کند که آیا این فایل وجود دارد یا خیر؟ مسلم است که اگر فایل هنوز وجود نداشته باشد نباید عملیات load کردن صورت بگیرد پس با استفاده از این شرط جلوی اینکار را گرفتیم.

در خط دوم یک آرایه از نوع string تعریف کردیم، یعنی هر خانه از این آرایه یک رشته را در خود نگاه می دارد. اما در جلوی مساوی متد ReadAllLines را از کلاس File فراخوانی کردیم و مسیر فایل را بعنوان ورودی به آن دادیم. این متد کل خط های موجود در یک فایل را می خواند و آن را بصورت یک رشته بر می گرداند، پس ما تمام خطوط فایل ذخیره سازی را خواندیم و درون آرایه list قرار دادیم. اما یک نکته وجود دارد اگر به خاطر داشته باشید ما گفتیم که مشخصات هر بار بازی را در یک سطر ذخیره می کنیم در تابع save اینکار را انجام دادیم، حالا اینجا آن کار به کمک ما آمده است. یعنی متد ReadAllLines هر سطر را می خواند و آن را در یک خانه از آرایه list قرار می دهد به این ترتیب هر خانه از آرایه list یک سطر از فایل را در خود نگاه می دارد. اما هنوز کار تمام نشده است زیرا هر خانه از این آرایه یک سطر از اطلاعات است ولی هنوز هر سطر را به بخش های اسم، امتیاز و تاریخ تقسیم نکردیم. مجددا اگر بخاطر بیاورید ما از کاراکتر \ برای جدا سازی این بخش ها از هم استفاده کردیم. حالا باید به نحوی با استفاده از این کاراکتر این بخش ها را از هم جدا کنیم. اما همانطور که گفتم list یک آرایه است، پس باید هر خانه آن را تک تک بگردیم و بخش های مختلف را از هم جدا کنیم و در listview قرار دهیم.

برای گشتن تک تک خانه های آرایه از حلقه foreach استفاده می کنیم، همانطور که مشاهده می کنید در این حلقه یک متغییر string به نام data تعریف کردیم. این حلقه به تعداد خانه های list اجرا می شود و در هر بار اجرای حلقه data بصورت خودکار محتویات آن خانه را در خود نگاه می دارد.

در خط بعد مشاهده می کنید که یک آرایه از نوع string به نام part تعریف شده است، این آرایه سه خانه دارد یک خانه برای نام یک خانه برای امتیاز و یک خانه برای تاریخ اما رشته ما بصورت پشت سرهم این اطلاعات را ذخیره کرده است. برای رفع این مشکل از متد split استفاده می کنیم. هر متغییری از نوع رشته ای این متد را دارد. این متد یک کاراکتر را بعنوان کارکتر جدا کننده می گیرد و آن متغییر string را بر اساس آن تقسیم می کند در این برنامه چون هر سطر حاوی دو عدد از این کاراکتر است، به سه قسمت تقسیم می شود به شکل زیر:
 
نام\امتیاز\تاریخ بازی
اما چرا دو عدد از این کاراکتر را در ورودی split قرار دادیم همانطور که قبلا هم گفتم کاراکتر \ یک کاراکتر کنترلی در رشته ها است و برای اینکه یکی از این کاراکتر چاپ شود باید دوبار آن را بنویسیم.

حالا که تقسیمات را انجام دادیم باید listViewItem را بسازیم، این کار را قبلا انجام داده ایم اینجا فقط یک تفاوت کوچک وجود دارد و آن این است که باید از قسمت های مختلف part در آن استفاده کنیم. می دانیم که اگر رشته را بر اساس کاراکتر تقسیم کنیم خانه صفرم part حاوی نام است و همینطور به ترتیب ادامه پیدا می کند. سپس باید listViewItem ساخته شده را به listView اضافه کنیم.

خب کار متد load نیز تمام شد، برای تست این متد می توانید برنامه را اجرا کنید و ببینید که بعد از شروع بازی اطلاعاتی که قبلا ذخیره کرده اید در این listView نمایش داده می شوند.

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

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

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

ارسال پاسخ alirza
alirza
شنبه ۱۴ مرداد ۱۳۹۶ ۰۱:۱۱
سلام
خسته نباشید
ببخشید این آموزش ها ادامه پیدا نمیکنه ؟
شدیدا مشتاقیم ادامه داشته باشه
ممنون
ارسال پاسخ علی عزیزی
علی عزیزی
پنج شنبه ۰۴ آذر ۱۳۹۵ ۱۳:۴۹
سلام خسته نباشید میشه بگید چطوری عکس دشمنان رو تغییر بدیم خیلی زحمت کشیدم تا کدرو نوشتم ممنون میشم توضیح بدید یا برای ایمیلم ارسال کنید
ارسال پاسخ قاسم
قاسم
یکشنبه ۰۹ اسفند ۱۳۹۴ ۰۱:۲۸
با سلام و تشکر از زحمات شما
میخواستم بدونم ادامه جلسات تم و شکلک ها رو هم امکان داره بیان کنید؟
به نظرتون برای ادامه بازی سازی با سی شارپ بهترین راهکار چیه؟
اگر امکان داره میخواستم برای تبادل اطلاعات و ثبت یک نرم افزار با شما مشورت کنم.در صورت تمایل لطفا برام میل بزارید.
با سپاس
ارسال پاسخ محمد
محمد
پنج شنبه ۰۸ بهمن ۱۳۹۴ ۱۶:۰۴
سلام. ایا اموزش بازی انلاین هم توی سرفصل ها هست؟ نحوه ارتباط با سرور و ...؟