آموزش برنامه نویسی بازی اندروید – از صفر تا صد

۳۱۶۳ بازدید
آخرین به‌روزرسانی: ۲۴ اردیبهشت ۱۴۰۲
زمان مطالعه: ۲۶ دقیقه
آموزش برنامه نویسی بازی اندروید – از صفر تا صد

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

فهرست مطالب این نوشته

پیش درآمد برنامه نویسی بازی اندروید

بازی‌های اندرویدی در سال‌های اخیر رشد بسیار چشم‌گیری داشته‌اند و به یکی از محبوب‌ترین راه‌ها برای گذراندن اوقات فراغت تبدیل شده‌اند. شرکت‌های ارائه‌دهنده گوشی‌های موبایل نیز با تمرکز بر روی ارتقا سخت‌افزاری دستگاه‌های خود و ارائه دستگاه‌های قدرتمندتر، تجربه بهتری را برای کاربران رقم زده‌اند. در نتیجه، امروزه گیمر‌ها به عناوین مختلف از ژانرهای متنوع دسترسی دارند.

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

پیش درآمد برنامه نویسی بازی اندروید

امروزه با توجه به وجود منابع مختلف برای آموزش برنامه نویسی بازی اندروید ، ساخت بازی نسبت به گذشته بسیار آسان‌تر شده است. به عنوان مثال، اگر فردی قصد توسعه بازی ساده‌ و محبوبی همچون Super Mario را داشته باشد، اکنون در مقایسه با ۲۰ سال قبل کار واقعاً راحت‌تری خواهد داشت. در زمینه کسب درآمد از بازی‌های موبایلی نیز با توجه به وجود بستر‌های مختلف برای درآمدزایی، کار بسیار آسان‌تر از گذشته است. تنها چالشی که امروزه در زمینه بازی سازی وجود دارد، بحث جذب مخاطب و رقابت با سایر عناوین در این حوزه است، زیرا با وجود عناوین با کیفیت و جذاب و همچنین حضور شرکت‌های معتبر در این حوزه، رقابت بسیار سختی برای جذب مخاطبین شکل گرفته است.

برنامه نویسی اندروید یا برنامه نویسی بازی اندروید کدامیک بهتر است؟

انتخاب بین برنامه نویسی اندروید و برنامه نویسی بازی اندروید ارتباط مستقیمی با مهارت و علاقه فرد دارد. در ادامه، بررسی مختصری در خصوص این دو حوزه ارائه شده است.

برنامه نویسی بازی اندروید

سیستم عامل اندروید پلتفرمی فوق‌العاده برای شروع ساخت بازی است و چالش‌های منحصر به فردی نیز در این حوزه در انتظار برنامه‌نویسان است. یکی از چالش‌های موجود در برنامه نویسی بازی اندروید بحث مقیاس‌بندی «رابط کاربری» (User Interface | UI) بازی‌ها است و باید بسته به اندازه و وضوح دستگاه اندرویدی، راه‌حل هوشمندانه‌ای برای این موضوع پیدا کرد. با این حال، چالش‌های زیاد دیگری نیز در حین توسعه بازی اندروید در انتظار برنامه‌نویسان است.

به طور کلی، اگر از دیدگاه شغلی به برنامه نویسی بازی اندروید نگاه شود، باید گفت نسبت به برنامه نویسی اندروید حرفه چالشی‌تری است و می‌توان از تخیل و مهارت‌ بیشتری نیز در آن استفاده کرد. اساساً در بحث توسعه بازی اندرویدی نیاز به ایجاد سیستمی با «تجربه کاربری» (User Experience | UX) و رابط گرافیکی بهتری وجود دارد و در بحث «پایگاه داده» (Database) نیز باید امکان ارتباط پایدار با سرور وجود داشته باشد. علاوه بر این، از نکات قابل توجه در بحث برنامه نویسی بازی اندروید این است که باید همزمان از چندین زبان برنامه نویسی استفاده کرد. در ادامه، تعدادی از انواع زبان‌های برنامه نویسی مورد استفاده در توسعه بازی اندروید ارائه شده‌اند.

علی‌رغم وجود چالش‌های بسیار در زمینه برنامه نویسی بازی اندروید و نیاز به داشتن مهارت‌های مختلف، باید به این نکته نیز اشاره کرد که میانگین پرداختی برای توسعه‌دهنده بازی اندرویدی تقریباً دو برابر برنامه‌نویس اندروید است.

برنامه نویسی بازی اندروید

برنامه نویسی اندروید

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

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

برنامه نویسی اندروید

برنامه نویسی بازی اندروید را از کجا شروع کنیم؟

همان طور که پیش‌تر نیز بیان شد، توسعه بازی اندروید به عنوان حرفه‌ای تمام وقت شناخته می‌شود. با این وجود، با توجه به فرصت‌های گوناگون موجود در این حوزه بسیاری از افراد تصمیم به ساخت و برنامه نویسی بازی اندروید می‌گیرند. در حال حاضر، فروشگاه‌های اندرویدی نظیر «گوگل پِلی» (Google Play)، مملو از بازی‌های گوناگون هستند. بر اساس آمار سال ۲۰۲۲ میلادی (۱۴۰۱ شمسی)، تقریباً ۴۷۸ هزار بازی اندرویدی در فروشگاه گوگل پلی در دسترس کاربران بوده است. بنابراین، با در نظر گرفتن این آمار می‌توان متوجه سختی کار جذب مخاطب در این حوزه شد.

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

بهترین بازی های اندرویدی

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

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

در ابتدای فرایند ساخت بازی اندرویدی مهم‌ترین مورد، داشتن چشم‌اندازی روشن در خصوص چیزی است که قصد ایجاد آن را دارید. داشتن چشم‌انداز روشن در خصوص ساخت بازی از این جهت اهمیت دارد که انتخاب ابزارها و گردش کار مناسب ارتباط مستقیمی با نوع بازی دارد. در این خصوص، تفاوتی بین ساخت بازی پازل ساده، بازی دو بعدی و حتی یک بازی با استفاده از «واقعیت مجازی» (Virtual Reality) وجود ندارد و برای هر کدام از این موارد باید چشم‌انداز و برنامه ساخت بازی مشخص و روشن باشد.

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

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

تعیین مشخصات اصلی بازی دومین گام در برنامه نویسی بازی اندروید

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

  • ژانر و دسته‌بندی بازی چیست؟
  • مخاطب هدف بازی در چه رده سنی قرار دارد؟
  • سبک گرافیکی بازی به چه شکلی خواهد بود؟
  • تصاویر و جلوه‌های صوتی بازی به چه صورتی انتخاب شوند؟
  • از چه ابزاری برای ساخت جلوه‌های گرافیکی بازی استفاده خواهد شد؟
  • از چه روشی برای درآمدزایی بازی استفاده شود؟
  • نقاط عطف و چالش‌های بازی به چه صورتی طراحی شوند؟

یکی از بهترین روش‌ها برای بدست آوردن دیدی روشن در خصوص بازی و نکات پیرامون آن، بررسی سایر بازی‌های موجود در فروشگاه‌های اندرویدی است. در هر بازه زمانی بازی‌‌هایی با ایده‌های خلاقانه توانسته‌اند توجه کاربران زیادی را به سمت خود جلب کنند. در نتیجه، می‌توان با گشت و گذار در فروشگاه‌های اندرویدی از این سبک بازی‌ها و ایده‌هایشان برای ساخت بازی الهام گرفت.

انتخاب ابزار مناسب برای توسعه سومین گام در مسیر یادگیری برنامه نویسی بازی اندروید

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

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

انتخاب ابزار مناسب برای توسعه سومین گام در برنامه نویسی بازی اندروید

اندروید استودیو

انتخاب «اندروید استودیو» (Android Studio) برای برنامه نویسی بازی اندروید در واقع گام برداشتن در مسیر سنتی ساخت بازی اندروید است.

IDE یا همان محیط توسعه اندروید استودیو، توسط گوگل به عنوان محیط رسمی برنامه نویسی اندروید معرفی شده است. برای برنامه نویسی بازی اندروید به کمک محیط توسعه اندروید استودیو، باید یکی از دو زبان رسمی اندروید یعنی «جاوا» (Java) یا «کاتلین» (Kotlin) را فرا گرفت. علاوه بر این، برای راه‌اندازی اندروید استودیو باید ابزار‌هایی همچون «کیت توسعه جاوا» (Java Development Kit | JDK) و «بسته توسعه نرم‌افزاری اندروید» (Android SDK) را دانلود کرد و کمی نیز با زبان XML آشنایی داشت.

برنامه نویسی بازی اندروید با اندروید استودیو

در واقع SDK شامل مجموعه‌ای از کتابخانه‌ها و ابزارهای گوگل می‌شود که به جاوا اجازه برقراری ارتباط با سیستم عامل اندروید را می‌دهد. علاوه بر این، به اندروید استودیو کمک می‌کند تا کد نوشته شده را به فایل APK تبدیل کند. در مجموع می‌توان گفت اندروید استودیو تمام موارد لازم برای توسعه بازی اندروید را در اختیار توسعه‌دهنده قرار می‌دهد و برای همین از آن به عنوان «محیط یکپارچه توسعه» (Integrated Development Environment | IDE) یاد می‌شود.

اندروید استودیو برای ساخت بازی‌های ساده دو بعدی نظیر بازی پازل ساده گزینه مناسبی است. به لحاظ نظری، امکان ساخت بازی‌های سه بعدی با اندروید استودیو وجود دارد و برای این مورد باید از کتابخانه‌های گرافیکی OpenGL و Vulkan API استفاده کرد. برای ساخت بازی‌های پیچیده، استفاده از اندروید استودیو توصیه نمی‌شود و گزینه‌های بسیار بهتری برای این مورد وجود دارد.

 

موتور بازی سازی یونیتی و Unreal

توسعه‌دهندگان حرفه‌ای در زمینه برنامه نویسی بازی اندروید به دلایلی که در بالا اشاره شد، یکی از دو موتور بازی‌سازی «یونیتی» (Unity) یا «آنریل انجین» (Unreal Engine) را برای توسعه بازی انتخاب می‌کنند.

این ابزارها محیط یکپارچه توسعه را با موتور بازی‌سازی ترکیب می‌کنند. به عبارت دیگر، این موتور‌های بازی‌سازی رابطی را برای مدیریت کدها فراهم می‌کنند و همچنین، بسیاری از جنبه‌های فیزیکی و رفتار‌های آماده قابل استفاده در بازی را ارائه می‌دهند. به عنوان مثال، در محیط‌های یونیتی و Unreal Engine، مثلاً برای مشخص کردن چگونگی سقوط چیزی از هوا نیازی به کدنویسی نیست و تنها با علامت زدن کادری با عنوان «گرانش» (Gravity) می‌توان این مورد را مدیریت کرد.

موتور بازی سازی یونیتی و انریل

یونیتی یا Unreal کدامیک برای ساخت بازی بهتر است؟

برای اکثر پروژه‌های بازی‌سازی می‌توان از یونیتی استفاده کرد. علاوه بر این، افزودن ویژگی‌های گرافیکی به این ابزارها تنها با «کشیدن و رها کردن» (Drag & Drop) آن‌ها در محیط برنامه امکان‌پذیر است. این ابزارها کار را برای ساخت بازی بسیار آسان می‌کنند. به عنوان مثال، می‌توان یک بازی اندرویدی ساده را در زمانی بسیار کوتاه (حتی ۷ دقیقه) ساخت.

البته در هر حال برای کار کردن با هر کدام از این دو محیط بازی‌سازی، نیاز به کدنویسی مختصری وجود دارد. یونیتی از زبان برنامه نویسی سی شارپ استفاده می‌کند که بسیار شبیه جاوا است. از سوی دیگر، Unreal نیز از زبان ++C برای بخش اسکریپت خود استفاده می‌کند. برای کار با این ابزارها، همچنان نیاز به استفاده از Android SDK وجود دارد. در ادامه، بارزترین ویژگی‌های این دو ابزار برنامه نویسی بازی اندروید ارائه شده است.

  • هر دو ابزار کاملاً رایگان هستند.
  • محدودیتی در ساخت بازی با آن‌ها وجود ندارد.
  • توسط توسعه‌دهندگان حرفه‌ای استفاده می‌شوند.
  • «چند پلتفرمی» (Cross-Platform) هستند و می‌توان خروجی را به سایر پلتفرم‌ها انتقال داد.

البته این دو موتور بازی‌سازی قدرتمند در برخی زمینه‌ها با یکدیگر تفاوت‌هایی نیز دارند. در مجموع، استفاده از یونیتی کمی ساده‌تر است و برای ساخت بازی‌های موبایلی و دو بعدی گزینه مناسب‌تری به حساب می‌آید. از Unreal نیز با توجه به برتری آن در بحث گرافیک سه بعدی می‌توان برای توسعه بازی‌های بزرگ‌تر و پیچیده‌تر استفاده کرد.

ساخت بازی با انریل

استفاده از بازی سازها

یکی از آسان‌ترین روش‌ها برای ساخت بازی اندرویدی استفاده از نرم‌افزار‌های «بازی‌ساز» (Game Builder) است. استفاده از این ابزارها در واقع مفهوم برنامه نویسی بازی اندروید را کم رنگ می‌کند، زیرا دیگر نیازی به کد نویسی زیاد برای ساخت بازی نیست. بیشتر این نرم‌افزارهای بازی‌سازی از قابلیت «کشیدن و رها کردن» (Drag & Drop) استفاده و فرایند ساخت بازی را بسیار آسان می‌کنند.

نرم‌افزار GameMaker Studio یکی از ابزارهای بازی‌سازی محسوب می‌شود که توسط شرکت Yoyo Games معرفی شده است. کار با این ابزار بسیار ساده‌تر از یونیتی و انریل است و حتی در صورت آشنایی با اصول برنامه نویسی نیز می‌توان با زبان مخصوص آن، تحت عنوان GML اسکریپت‌های اولیه را نوشت. زبان برنامه نویسی GML در واقع ترکیبی از زبان‌های C++‎، جاوا و C است و قابلیت برنامه نویسی شی‌گرا را نیز دارد. در حالی که برخی از بازی‌های موفق به کمک GameMaker توسعه داده شده‌اند، اما این ابزار در برخی از عملکردها برنامه‌نویس را با محدودیت‌هایی روبرو می‌کند. تمرکز نرم‌افزار GameMaker بر استفاده از الگوها و گرافیک‌های از پیش‌تعریف شده است.

استفاده از بازی سازها در برنامه نویسی بازی اندروید

شروع ساخت پروژه گام چهارم در برنامه نویسی بازی اندروید

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

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

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

آموزش برنامه نویسی بازی اندروید در اندروید استودیو

در این بخش از نوشته به آموزش برنامه نویسی بازی اندروید در اندروید استودیو به صورت پروژه محور و در قالب ساخت بازی دو بعدی ساده پرداخته می‌شود.

هدف از ارائه این بخش، آشنایی با چند تکنیک ساده در برنامه نویسی بازی اندروید است. در ادامه، تکنیک‌های ارائه شده در این بخش معرفی شده‌اند.

آموزش برنامه نویسی بازی اندروید با اندروید استودیو

  • کاربرد SurfacView در ساخت بازی
  • طراحی بر روی Canvas
  • ایجاد جلوه حرکتی برای شخصیت‌های بازی
  • استفاده از جلوه‌های صوتی در بازی
  • تعامل بازیکنان با بازی
  • طراحی مراحل مختلف بازی

در این بخش به صورت گام به گام بخش‌های مختلف بازی از ابتدا تا انتها پیاده‌سازی می‌شوند.

ساخت پروژه اولین گام در آموزش برنامه نویسی بازی اندروید

برای شروع نیاز است تا پروژه جدیدی در اندروید استودیو ایجاد شود. برای این منظور همانند تصویر زیر، قالب پروژه جدید را از نوع No Activity  انتخاب کنید.

ساخت پروژه جدید در اندروید استودیو

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

وارد نمودن مشخصات پروژه

در نهایت پروژه جدید ایجاد می‌شود. سپس، باید Activity جدیدی را در محیط اندروید استودیو ایجاد کرد. برای این منظور از مسیر File > New > Activity > Empty Activity  باید گزینه Empty Activity  را انتخاب کنیم.

ساخت اکتیویتی جدید

سپس، در پنجره مربوط به تنظیمات اکتیویتی باید نامی دلخواه را برای اکتیویتی مربوطه انتخاب کرد.

تنظیمات اکتیویتی جدید

نکته‌ای که باید به آن توجه داشت این است که دیگر نیازی به فایل activity_main.xml  برای این پروژه وجود ندارد و رابط کاربری بازی از طریق کدنویسی در محیط اندروید استودیو ایجاد خواهد شد.

آماده سازی تصاویر و صداها دومین گام در آموزش برنامه نویسی بازی اندروید

فایل‌های صوتی و تصویری یکی از موارد تاثیرگذار و جدا نشدنی از هر بازی اندرویدی هستند. در گام بعدی باید تصاویر و صداهای مورد نیاز برای بازی را در پروژه قرار دهیم.

برای این منظور تصاویر و فایل‌های صوتی مورد استفاده در بازی ارائه شده است.

  • تصاویر بازی (+)
  • فایل صوتی انفجار (+)
  • فایل صوتی پس‌زمینه (+)

در ادامه، با کلیک راست بر روی پوشه res  و انتخاب مسیر New > Folder > Raw Resource Folder  پوشه جدیدی برای قرار دادن فایل‌های صوتی و تصویری بازی ایجاد کنید.

ایجاد پوشه res

در نتیجه، در زیر مجموعه پوشه res  ، پوشه جدیدی با نام raw  ایجاد می‌شود.

ساخت پوشه raw

در انتها نیز تصاویر قرار داده شده در بالا را در پوشه drawable  قرار دهید و فایل‌های صوتی انفجار و پس‌زمینه را هم در پوشه raw  کپی کنید.

قرار دادن فایل های صوتی و تصویری

تنظیم تمام صفحه بازی گام سوم در آموزش برنامه نویسی بازی اندروید

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

نکته‌ای که باید به آن توجه داشت این است که کلاس MainActivity  از کلاس Activity  ارث‌بری کند.

1package org.o7planning.android2dgame;
2 
3import android.app.Activity;
4import android.os.Bundle;
5import android.view.Window;
6import android.view.WindowManager;
7
8public class MainActivity extends Activity {
9
10    @Override
11    protected void onCreate(Bundle savedInstanceState) {
12        super.onCreate(savedInstanceState);
13
14        // Set fullscreen
15        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
16                WindowManager.LayoutParams.FLAG_FULLSCREEN);
17
18        // Set No Title
19        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
20
21    }
22
23}

سپس، در فایل AndroidManifest.xml  باید تنظیمات مربوط به تمام صفحه شدن اکتیویتی مورد نظر انجام شود. برای این منظور باید مشخصه screenOrientation  را برابر با مقدار landscape  قرار داد.

1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3    package="org.o7planning.android2dgame">
4
5    <application
6        android:screenOrientation="landscape"
7        ... >
8
9       ...
10
11    </application>
12
13</manifest>

برای مشاهده تغییرات مورد نظر باید برنامه را اجرا کرد.

تنظیم تمام صفحه بازی

ادامه آموزش برنامه نویسی بازی اندروید با نمایش شخصیت های بازی

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

نکته‌ای که در خصوص تصویر مورد نظر برای شخصیت بازی باید به آن توجه داشت این است که تنها یک تصویر برای شخصیت بازی در اختیار دارید. در نتیجه، با توجه به این که وضعیت شخصیت بازی در حالت‌های مختلف تغییر می‌کند، این فایل تصویری به چند بخش تقسیم می‌شود. در تصویر زیر این مورد به وضوح مشخص شده است.

تصویر شخصیت بازی در حالات مختلف

با توجه به در اختیار داشتن تنها یک تصویر کلی از شخصیت اصلی بازی در حالت‌های مختلف، می‌توان از مختصات x  و y  برای جداسازی هر بخش استفاده کرد. در نهایت با استفاده از ساختار حلقه در برنامه نویسی اندروید می‌توان به طور متناوب تصاویر مختلف را نمایش داد و حرکت شخصیت اصلی بازی را شبیه‌سازی کرد.

جداسازی بخش های مختلف تصویر شخصیت اصلی

در تصویر زیر نحوه مقیاس‌بندی فایل اصلی مربوط به شخصیت اصلی بازی نمایش داده شده است.

مقیاس‌بندی تصویر شخصیت اصلی بازی

علاوه بر این، در بحث متحرک‌سازی شخصیت‌های بازی باید به جهت حرکت و سرعت آن‌ها نیز توجه شود. در ادامه، برای برنامه نویسی این بخش از بازی باید کلاسی با عنوان Gameobject  ایجاد کرد که شخصیت‌ها و موجودیت‌های بازی از این کلاس ارث‌بری می‌کنند. در نمونه کد زیر کلاس Gameobject  ایجاد شده است.

1package org.o7planning.android2dgame;
2
3import android.graphics.Bitmap;
4
5public abstract class GameObject {
6
7    protected Bitmap image;
8
9    protected final int rowCount;
10    protected final int colCount;
11
12    protected final int WIDTH;
13    protected final int HEIGHT;
14
15    protected final int width;
16
17
18    protected final int height;
19    protected int x;
20    protected int y;
21
22    public GameObject(Bitmap image, int rowCount, int colCount, int x, int y)  {
23
24        this.image = image;
25        this.rowCount= rowCount;
26        this.colCount= colCount;
27
28        this.x= x;
29        this.y= y;
30
31        this.WIDTH = image.getWidth();
32        this.HEIGHT = image.getHeight();
33
34        this.width = this.WIDTH/ colCount;
35        this.height= this.HEIGHT/ rowCount;
36    }
37
38    protected Bitmap createSubImageAt(int row, int col)  {
39        // createBitmap(bitmap, x, y, width, height).
40        Bitmap subImage = Bitmap.createBitmap(image, col* width, row* height ,width,height);
41        return subImage;
42    }
43
44    public int getX()  {
45        return this.x;
46    }
47
48    public int getY()  {
49        return this.y;
50    }
51
52
53    public int getHeight() {
54        return height;
55    }
56
57    public int getWidth() {
58        return width;
59    }
60
61}

در ادامه، برای شخصیت اصلی بازی کلاسی جداگانه با نام ChibiCharacter  ایجاد کنید که این کلاس از کلاس GameObject  ارث‌بری کند.

1package org.o7planning.android2dgame;
2
3import android.graphics.Bitmap;
4import android.graphics.Canvas;
5
6public class ChibiCharacter extends GameObject {
7
8    private static final int ROW_TOP_TO_BOTTOM = 0;
9    private static final int ROW_RIGHT_TO_LEFT = 1;
10    private static final int ROW_LEFT_TO_RIGHT = 2;
11    private static final int ROW_BOTTOM_TO_TOP = 3;
12
13    // Row index of Image are being used.
14    private int rowUsing = ROW_LEFT_TO_RIGHT;
15
16    private int colUsing;
17
18    private Bitmap[] leftToRights;
19    private Bitmap[] rightToLefts;
20    private Bitmap[] topToBottoms;
21    private Bitmap[] bottomToTops;
22
23    // Velocity of game character (pixel/millisecond)
24    public static final float VELOCITY = 0.1f;
25
26    private int movingVectorX = 10;
27    private int movingVectorY = 5;
28
29    private long lastDrawNanoTime =-1;
30
31    private GameSurface gameSurface;
32
33    public ChibiCharacter(GameSurface gameSurface, Bitmap image, int x, int y) {
34        super(image, 4, 3, x, y);
35
36        this.gameSurface= gameSurface;
37
38        this.topToBottoms = new Bitmap[colCount]; // 3
39        this.rightToLefts = new Bitmap[colCount]; // 3
40        this.leftToRights = new Bitmap[colCount]; // 3
41        this.bottomToTops = new Bitmap[colCount]; // 3
42
43        for(int col = 0; col< this.colCount; col++ ) {
44            this.topToBottoms[col] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, col);
45            this.rightToLefts[col]  = this.createSubImageAt(ROW_RIGHT_TO_LEFT, col);
46            this.leftToRights[col] = this.createSubImageAt(ROW_LEFT_TO_RIGHT, col);
47            this.bottomToTops[col]  = this.createSubImageAt(ROW_BOTTOM_TO_TOP, col);
48        }
49    }
50
51    public Bitmap[] getMoveBitmaps()  {
52        switch (rowUsing)  {
53            case ROW_BOTTOM_TO_TOP:
54                return  this.bottomToTops;
55            case ROW_LEFT_TO_RIGHT:
56                return this.leftToRights;
57            case ROW_RIGHT_TO_LEFT:
58                return this.rightToLefts;
59            case ROW_TOP_TO_BOTTOM:
60                return this.topToBottoms;
61            default:
62                return null;
63        }
64    }
65
66    public Bitmap getCurrentMoveBitmap()  {
67        Bitmap[] bitmaps = this.getMoveBitmaps();
68        return bitmaps[this.colUsing];
69    }
70
71
72    public void update()  {
73        this.colUsing++;
74        if(colUsing >= this.colCount)  {
75            this.colUsing =0;
76        }
77        // Current time in nanoseconds
78        long now = System.nanoTime();
79
80        // Never once did draw.
81        if(lastDrawNanoTime==-1) {
82            lastDrawNanoTime= now;
83        }
84        // Change nanoseconds to milliseconds (1 nanosecond = 1000000 milliseconds).
85        int deltaTime = (int) ((now - lastDrawNanoTime)/ 1000000 );
86
87        // Distance moves
88        float distance = VELOCITY * deltaTime;
89
90        double movingVectorLength = Math.sqrt(movingVectorX* movingVectorX + movingVectorY*movingVectorY);
91
92        // Calculate the new position of the game character.
93        this.x = x +  (int)(distance* movingVectorX / movingVectorLength);
94        this.y = y +  (int)(distance* movingVectorY / movingVectorLength);
95
96        // When the game's character touches the edge of the screen, then change direction
97
98        if(this.x < 0 )  {
99            this.x = 0;
100            this.movingVectorX = - this.movingVectorX;
101        } else if(this.x > this.gameSurface.getWidth() -width)  {
102            this.x= this.gameSurface.getWidth()-width;
103            this.movingVectorX = - this.movingVectorX;
104        }
105
106        if(this.y < 0 )  {
107            this.y = 0;
108            this.movingVectorY = - this.movingVectorY;
109        } else if(this.y > this.gameSurface.getHeight()- height)  {
110            this.y= this.gameSurface.getHeight()- height;
111            this.movingVectorY = - this.movingVectorY ;
112        }
113
114        // rowUsing
115        if( movingVectorX > 0 )  {
116            if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
117                this.rowUsing = ROW_TOP_TO_BOTTOM;
118            }else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
119                this.rowUsing = ROW_BOTTOM_TO_TOP;
120            }else  {
121                this.rowUsing = ROW_LEFT_TO_RIGHT;
122            }
123        } else {
124            if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
125                this.rowUsing = ROW_TOP_TO_BOTTOM;
126            }else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
127                this.rowUsing = ROW_BOTTOM_TO_TOP;
128            }else  {
129                this.rowUsing = ROW_RIGHT_TO_LEFT;
130            }
131        }
132    }
133
134    public void draw(Canvas canvas)  {
135        Bitmap bitmap = this.getCurrentMoveBitmap();
136        canvas.drawBitmap(bitmap,x, y, null);
137        // Last draw time.
138        this.lastDrawNanoTime= System.nanoTime();
139    }
140
141    public void setMovingVector(int movingVectorX, int movingVectorY)  {
142        this.movingVectorX= movingVectorX;
143        this.movingVectorY = movingVectorY;
144    }
145}

برای بروزرسانی پیوسته رابط کاربری باید از قابلیت «نخ‌بندی» (Threading) در اندروید استفاده کرد. برای این منظور کلاسی با نام GameThread  بسازید که از کلاس Thread اصلی در اندروید ارث‌بری کند. نمونه کد مورد نظر برای کلاس GameThread  در ادامه ارائه شده است.

1package org.o7planning.android2dgame;
2
3import android.graphics.Canvas;
4import android.view.SurfaceHolder;
5
6public class GameThread extends Thread {
7
8    private boolean running;
9    private GameSurface gameSurface;
10    private SurfaceHolder surfaceHolder;
11
12    public GameThread(GameSurface gameSurface, SurfaceHolder surfaceHolder)  {
13        this.gameSurface= gameSurface;
14        this.surfaceHolder= surfaceHolder;
15    }
16
17    @Override
18    public void run()  {
19        long startTime = System.nanoTime();
20
21        while(running)  {
22            Canvas canvas= null;
23            try {
24                // Get Canvas from Holder and lock it.
25                canvas = this.surfaceHolder.lockCanvas();
26
27                // Synchronized
28                synchronized (canvas)  {
29                    this.gameSurface.update();
30                    this.gameSurface.draw(canvas);
31                }
32            }catch(Exception e)  {
33                // Do nothing.
34            } finally {
35                if(canvas!= null)  {
36                    // Unlock Canvas.
37                    this.surfaceHolder.unlockCanvasAndPost(canvas);
38                }
39            }
40            long now = System.nanoTime() ;
41            // Interval to redraw game
42            // (Change nanoseconds to milliseconds)
43            long waitTime = (now - startTime)/1000000;
44            if(waitTime < 10)  {
45                waitTime= 10; // Millisecond.
46            }
47            System.out.print(" Wait Time="+ waitTime);
48
49            try {
50                // Sleep.
51                this.sleep(waitTime);
52            } catch(InterruptedException e)  {
53
54            }
55            startTime = System.nanoTime();
56            System.out.print(".");
57        }
58    }
59
60    public void setRunning(boolean running)  {
61        this.running= running;
62    }
63}

در ادامه آموزش برنامه نویسی بازی اندروید باید کلاسی برای شبیه‌سازی کل سطح بازی نیز در نظر گرفته شود. برای این منظور کلاس GameSurface  را ایجاد کنید که این کلاس از SurfaceView  ارث‌بری می‌کند و شامل یک شی از نوع Canvas  است که تمام اشیاd بازی بر روی آن ترسیم ‌می‌شوند. در ادامه، نمونه کد مربوط به این کلاس ارائه شده است.

1package org.o7planning.android2dgame;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Canvas;
7import android.view.SurfaceHolder;
8import android.view.SurfaceView;
9
10public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
11
12    private GameThread gameThread;
13    private ChibiCharacter chibi1;
14
15    public GameSurface(Context context)  {
16        super(context);
17
18        // Make Game Surface focusable so it can handle events. .
19        this.setFocusable(true);
20
21        // Sét callback.
22        this.getHolder().addCallback(this);
23    }
24
25    public void update()  {
26        this.chibi1.update();
27    }
28
29    @Override
30    public void draw(Canvas canvas)  {
31        super.draw(canvas);
32
33        this.chibi1.draw(canvas);
34    }
35
36    // Implements method of SurfaceHolder.Callback
37    @Override
38    public void surfaceCreated(SurfaceHolder holder) {
39        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
40        this.chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
41
42        this.gameThread = new GameThread(this,holder);
43        this.gameThread.setRunning(true);
44        this.gameThread.start();
45    }
46
47    // Implements method of SurfaceHolder.Callback
48    @Override
49    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
50
51    }
52
53    // Implements method of SurfaceHolder.Callback
54    @Override
55    public void surfaceDestroyed(SurfaceHolder holder) {
56        boolean retry= true;
57        while(retry) {
58            try {
59                this.gameThread.setRunning(false);
60
61                // Parent thread must wait until the end of GameThread.
62                this.gameThread.join();
63            }catch(InterruptedException e)  {
64                e.printStackTrace();
65            }
66            retry= true;
67        }
68    }
69
70}

در انتها نیز تغییرات زیر را باید در کلاس اصلی بازی یعنی MainActivity  ایجاد کرد.

1package org.o7planning.android2dgame;
2
3import android.app.Activity;
4import android.os.Bundle;
5import android.view.Window;
6import android.view.WindowManager;
7
8public class MainActivity extends Activity {
9
10    @Override
11    protected void onCreate(Bundle savedInstanceState) {
12        super.onCreate(savedInstanceState);
13
14        // Set fullscreen
15        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
16                WindowManager.LayoutParams.FLAG_FULLSCREEN);
17
18        // Set No Title
19        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
20
21        this.setContentView(new GameSurface(this));
22    }
23
24}

با اتمام این بخش، نسخه اولیه بازی قابل مشاهده خواهد بود. در تصویر زیر، صفحه اصلی بازی با نمایش حرکات شخصیت اصلی بازی نشان داده می‌شود.

نسخه اولیه بازی

تعامل کاربر با بازی بخش بعدی در آموزش برنامه نویسی بازی اندروید

تعامل کاربر با بازی یکی از مواردی است که در برنامه نویسی بازی اندروید باید لحاظ شود. به طور معمول نیز میزان تعامل کاربران با یک بازی اندرویدی در مقایسه با سایر اپلیکیشن‌ها بسیار بالاتر است.

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

1@Override
2public boolean onTouchEvent(MotionEvent event) {
3    if (event.getAction() == MotionEvent.ACTION_DOWN) {
4        int x=  (int)event.getX();
5        int y = (int)event.getY();
6
7        int movingVectorX =x-  this.chibi1.getX() ;
8        int movingVectorY =y-  this.chibi1.getY() ;
9
10        this.chibi1.setMovingVector(movingVectorX,movingVectorY);
11        return true;
12    }
13    return false;
14}

در ادامه، کد کامل مربوط به این بخش از بازی ارائه شده است.

1package org.o7planning.android2dgame;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Canvas;
7import android.view.MotionEvent;
8import android.view.SurfaceHolder;
9import android.view.SurfaceView;
10
11public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
12
13    private GameThread gameThread;
14
15    private ChibiCharacter chibi1;
16
17    public GameSurface(Context context)  {
18        super(context);
19
20        // Make Game Surface focusable so it can handle events.
21        this.setFocusable(true);
22
23        // Set callback.
24        this.getHolder().addCallback(this);
25    }
26
27    public void update()  {
28        this.chibi1.update();
29    }
30
31    @Override
32    public boolean onTouchEvent(MotionEvent event) {
33        if (event.getAction() == MotionEvent.ACTION_DOWN) {
34            int x=  (int)event.getX();
35            int y = (int)event.getY();
36
37            int movingVectorX =x-  this.chibi1.getX() ;
38            int movingVectorY =y-  this.chibi1.getY() ;
39
40            this.chibi1.setMovingVector(movingVectorX,movingVectorY);
41            return true;
42        }
43        return false;
44    }
45
46    @Override
47    public void draw(Canvas canvas)  {
48        super.draw(canvas);
49
50        this.chibi1.draw(canvas);
51    }
52
53    // Implements method of SurfaceHolder.Callback
54    @Override
55    public void surfaceCreated(SurfaceHolder holder) {
56        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
57        this.chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
58
59        this.gameThread = new GameThread(this,holder);
60        this.gameThread.setRunning(true);
61        this.gameThread.start();
62    }
63
64    // Implements method of SurfaceHolder.Callback
65    @Override
66    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
67
68    }
69
70    // Implements method of SurfaceHolder.Callback
71    @Override
72    public void surfaceDestroyed(SurfaceHolder holder) {
73        boolean retry= true;
74        while(retry) {
75            try {
76                this.gameThread.setRunning(false);
77
78                // Parent thread must wait until the end of GameThread.
79                this.gameThread.join();
80            }catch(InterruptedException e)  {
81                e.printStackTrace();
82            }
83            retry= true;
84        }
85    }
86
87}

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

تعامل کاربر با بازی

استفاده از شخصیت‌های متعدد ششمین گام در آموزش برنامه نویسی بازی اندروید

امکان افزودن شخصیت‌های جدید به بازی وجود دارد. در این بخش از آموزش برنامه نویسی بازی اندروید یک شخصیت دیگر به بازی اضافه خواهیم کرد.

برای این منظور باید کدهای مربوط به کلاس GameSurface  را ویرایش کرد.

1package org.o7planning.android2dgame;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Canvas;
7import android.view.MotionEvent;
8import android.view.SurfaceHolder;
9import android.view.SurfaceView;
10
11import java.util.ArrayList;
12import java.util.List;
13
14public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
15
16    private GameThread gameThread;
17
18    private final List<ChibiCharacter> chibiList = new ArrayList<ChibiCharacter>();
19
20    public GameSurface(Context context)  {
21        super(context);
22
23        // Make Game Surface focusable so it can handle events.
24        this.setFocusable(true);
25
26        // Set callback.
27        this.getHolder().addCallback(this);
28    }
29
30    public void update()  {
31        for(ChibiCharacter chibi: chibiList) {
32            chibi.update();
33        }
34    }
35
36    @Override
37    public boolean onTouchEvent(MotionEvent event) {
38        if (event.getAction() == MotionEvent.ACTION_DOWN) {
39            int x=  (int)event.getX();
40            int y = (int)event.getY();
41
42            for(ChibiCharacter chibi: chibiList) {
43                int movingVectorX =x-  chibi.getX() ;
44                int movingVectorY =y-  chibi.getY() ;
45                chibi.setMovingVector(movingVectorX, movingVectorY);
46            }
47            return true;
48        }
49        return false;
50    }
51
52    @Override
53    public void draw(Canvas canvas)  {
54        super.draw(canvas);
55
56        for(ChibiCharacter chibi: chibiList)  {
57            chibi.draw(canvas);
58        }
59
60    }
61
62    // Implements method of SurfaceHolder.Callback
63    @Override
64    public void surfaceCreated(SurfaceHolder holder) {
65        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
66        ChibiCharacter chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
67
68        Bitmap chibiBitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi2);
69        ChibiCharacter chibi2 = new ChibiCharacter(this,chibiBitmap2,300,150);
70
71        this.chibiList.add(chibi1);
72        this.chibiList.add(chibi2);
73
74        this.gameThread = new GameThread(this,holder);
75        this.gameThread.setRunning(true);
76        this.gameThread.start();
77    }
78
79    // Implements method of SurfaceHolder.Callback
80    @Override
81    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
82
83    }
84
85    // Implements method of SurfaceHolder.Callback
86    @Override
87    public void surfaceDestroyed(SurfaceHolder holder) {
88        boolean retry= true;
89        while(retry) {
90            try {
91                this.gameThread.setRunning(false);
92
93                // Parent thread must wait until the end of GameThread.
94                this.gameThread.join();
95            }catch(InterruptedException e)  {
96                e.printStackTrace();
97            }
98            retry= true;
99        }
100    }
101
102}

در نهایت، خروجی بازی در این مرحله با افزودن شخصیت جدید به صورت زیر خواهد بود.

استفاده از شخصیت‌های متعدد در برنامه نویسی بازی اندروید

ادامه آموزش برنامه نویسی بازی اندروید با استفاده از جلوه ها در بازی

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

در این بخش از بازی با کلیک بر روی شخصیت اصلی بازی باید انفجار صورت گیرد. در نتیجه، این شخصیت از بازی حذف شده و در همان موقعیت، تصویر انفجار باید نشان داده شود. برای این منظور کلاس Explosion  باید ایجاد شود که از کلاس GameObject  ارث‌بری می‌کند.

1package org.o7planning.android2dgame;  
2
3import android.graphics.Bitmap;
4import android.graphics.Canvas;
5
6public class Explosion extends GameObject {
7
8    private int rowIndex = 0 ;
9    private int colIndex = -1 ;
10
11    private boolean finish= false;
12    private GameSurface gameSurface;
13
14    public Explosion(GameSurface GameSurface, Bitmap image, int x, int y) {
15        super(image, 5, 5, x, y);
16
17        this.gameSurface= GameSurface;
18    }
19
20    public void update()  {
21        this.colIndex++;
22
23        if(this.colIndex >= this.colCount)  {
24            this.colIndex =0;
25            this.rowIndex++;
26
27            if(this.rowIndex>= this.rowCount)  {
28                this.finish= true;
29            }
30        }
31    }
32
33    public void draw(Canvas canvas)  {
34        if(!finish)  {
35            Bitmap bitmap= this.createSubImageAt(rowIndex,colIndex);
36            canvas.drawBitmap(bitmap, this.x, this.y,null);
37        }
38    }
39
40    public boolean isFinish() {
41        return finish;
42    }
43
44}

علاوه بر این، باید کدهای مربوط به کلاس GameSurface  را به صورت زیر تغییر داد.

1package org.o7planning.android2dgame;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Canvas;
7import android.view.MotionEvent;
8import android.view.SurfaceHolder;
9import android.view.SurfaceView;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
16
17    private GameThread gameThread;
18
19    private final List<ChibiCharacter> chibiList = new ArrayList<ChibiCharacter>();
20    private final List<Explosion> explosionList = new ArrayList<Explosion>();
21
22    public GameSurface(Context context)  {
23        super(context);
24
25        // Make Game Surface focusable so it can handle events.
26        this.setFocusable(true);
27
28        // Sét callback.
29        this.getHolder().addCallback(this);
30    }
31
32
33    @Override
34    public boolean onTouchEvent(MotionEvent event) {
35        if (event.getAction() == MotionEvent.ACTION_DOWN) {
36
37            int x=  (int)event.getX();
38            int y = (int)event.getY();
39
40            Iterator<ChibiCharacter> iterator= this.chibiList.iterator();
41
42            while(iterator.hasNext()) {
43                ChibiCharacter chibi = iterator.next();
44                if( chibi.getX() < x && x < chibi.getX() + chibi.getWidth()
45                        && chibi.getY() < y && y < chibi.getY()+ chibi.getHeight())  {
46                    // Remove the current element from the iterator and the list.
47                    iterator.remove();
48
49                    // Create Explosion object.
50                    Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),R.drawable.explosion);
51                    Explosion explosion = new Explosion(this, bitmap,chibi.getX(),chibi.getY());
52
53                    this.explosionList.add(explosion);
54                }
55            }
56
57
58            for(ChibiCharacter chibi: chibiList) {
59                int movingVectorX =x-  chibi.getX() ;
60                int movingVectorY =y-  chibi.getY() ;
61                chibi.setMovingVector(movingVectorX, movingVectorY);
62            }
63            return true;
64        }
65        return false;
66    }
67
68    public void update()  {
69        for(ChibiCharacter chibi: chibiList) {
70            chibi.update();
71        }
72        for(Explosion explosion: this.explosionList)  {
73            explosion.update();
74        }
75
76        Iterator<Explosion> iterator= this.explosionList.iterator();
77        while(iterator.hasNext())  {
78            Explosion explosion = iterator.next();
79
80            if(explosion.isFinish()) {
81                // If explosion finish, Remove the current element from the iterator & list.
82                iterator.remove();
83                continue;
84            }
85        }
86    }
87
88    @Override
89    public void draw(Canvas canvas)  {
90        super.draw(canvas);
91
92        for(ChibiCharacter chibi: chibiList)  {
93            chibi.draw(canvas);
94        }
95
96        for(Explosion explosion: this.explosionList)  {
97            explosion.draw(canvas);
98        }
99
100    }
101
102    // Implements method of SurfaceHolder.Callback
103    @Override
104    public void surfaceCreated(SurfaceHolder holder) {
105        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
106        ChibiCharacter chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
107
108        Bitmap chibiBitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi2);
109        ChibiCharacter chibi2 = new ChibiCharacter(this,chibiBitmap2,300,150);
110
111        this.chibiList.add(chibi1);
112        this.chibiList.add(chibi2);
113
114        this.gameThread = new GameThread(this,holder);
115        this.gameThread.setRunning(true);
116        this.gameThread.start();
117    }
118
119    // Implements method of SurfaceHolder.Callback
120    @Override
121    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
122
123    }
124
125    // Implements method of SurfaceHolder.Callback
126    @Override
127    public void surfaceDestroyed(SurfaceHolder holder) {
128        boolean retry= true;
129        while(retry) {
130            try {
131                this.gameThread.setRunning(false);
132
133                // Parent thread must wait until the end of GameThread.
134                this.gameThread.join();
135            }catch(InterruptedException e)  {
136                e.printStackTrace();
137            }
138            retry= true;
139        }
140    }
141
142}

در نهایت، خروجی حاصل از بازی در این مرحله بعد از افزودن جلوه انفجار به صورت زیر خواهد بود.

افزودن جلوه انفجار به بازی

افزودن جلوه های صوتی به بازی آخرین گام در آموزش برنامه نویسی بازی اندروید

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

برای افزودن صدا به بازی باید تغییراتی را به صورت زیر در کلاس Explosion  ایجاد کرد.

1package org.o7planning.android2dgame;
2
3import android.graphics.Bitmap;
4import android.graphics.Canvas;
5
6public class Explosion extends GameObject {
7
8    private int rowIndex = 0 ;
9    private int colIndex = -1 ;
10
11    private boolean finish= false;
12    private GameSurface gameSurface;
13
14    public Explosion(GameSurface GameSurface, Bitmap image, int x, int y) {
15        super(image, 5, 5, x, y);
16
17        this.gameSurface= GameSurface;
18    }
19
20    public void update()  {
21        this.colIndex++;
22
23        // Play sound explosion.wav.
24        if(this.colIndex==0 && this.rowIndex==0) {
25            this.gameSurface.playSoundExplosion();
26        }
27
28        if(this.colIndex >= this.colCount)  {
29            this.colIndex =0;
30            this.rowIndex++;
31
32            if(this.rowIndex>= this.rowCount)  {
33                this.finish= true;
34            }
35        }
36    }
37
38    public void draw(Canvas canvas)  {
39        if(!finish)  {
40            Bitmap bitmap= this.createSubImageAt(rowIndex,colIndex);
41            canvas.drawBitmap(bitmap, this.x, this.y,null);
42        }
43    }
44
45    public boolean isFinish() {
46        return finish;
47    }
48
49}

در ادامه تغییرات دیگری نیز در کلاس GameSurface  به صورت زیر باید انجام شود.

1package org.o7planning.android2dgame;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Canvas;
7import android.media.AudioAttributes;
8import android.media.AudioManager;
9import android.media.SoundPool;
10import android.os.Build;
11import android.view.MotionEvent;
12import android.view.SurfaceHolder;
13import android.view.SurfaceView;
14
15import java.util.ArrayList;
16import java.util.Iterator;
17import java.util.List;
18
19public class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
20
21    private GameThread gameThread;
22
23    private final List<ChibiCharacter> chibiList = new ArrayList<ChibiCharacter>();
24    private final List<Explosion> explosionList = new ArrayList<Explosion>();
25
26    private static final int MAX_STREAMS=100;
27    private int soundIdExplosion;
28    private int soundIdBackground;
29
30    private boolean soundPoolLoaded;
31    private SoundPool soundPool;
32
33
34
35    public GameSurface(Context context)  {
36        super(context);
37
38        // Make Game Surface focusable so it can handle events.
39        this.setFocusable(true);
40
41        // Sét callback.
42        this.getHolder().addCallback(this);
43
44        this.initSoundPool();
45    }
46
47    private void initSoundPool()  {
48        // With Android API >= 21.
49        if (Build.VERSION.SDK_INT >= 21 ) {
50
51            AudioAttributes audioAttrib = new AudioAttributes.Builder()
52                    .setUsage(AudioAttributes.USAGE_GAME)
53                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
54                    .build();
55
56            SoundPool.Builder builder= new SoundPool.Builder();
57            builder.setAudioAttributes(audioAttrib).setMaxStreams(MAX_STREAMS);
58
59            this.soundPool = builder.build();
60        }
61        // With Android API < 21
62        else {
63            // SoundPool(int maxStreams, int streamType, int srcQuality)
64            this.soundPool = new SoundPool(MAX_STREAMS, AudioManager.STREAM_MUSIC, 0);
65        }
66
67        // When SoundPool load complete.
68        this.soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
69            @Override
70            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
71                soundPoolLoaded = true;
72
73                // Playing background sound.
74                playSoundBackground();
75            }
76        });
77
78        // Load the sound background.mp3 into SoundPool
79        this.soundIdBackground= this.soundPool.load(this.getContext(), R.raw.background,1);
80
81        // Load the sound explosion.wav into SoundPool
82        this.soundIdExplosion = this.soundPool.load(this.getContext(), R.raw.explosion,1);
83
84
85    }
86
87    public void playSoundExplosion()  {
88        if(this.soundPoolLoaded) {
89            float leftVolumn = 0.8f;
90            float rightVolumn =  0.8f;
91            // Play sound explosion.wav
92            int streamId = this.soundPool.play(this.soundIdExplosion,leftVolumn, rightVolumn, 1, 0, 1f);
93        }
94    }
95
96    public void playSoundBackground()  {
97        if(this.soundPoolLoaded) {
98            float leftVolumn = 0.8f;
99            float rightVolumn =  0.8f;
100            // Play sound background.mp3
101            int streamId = this.soundPool.play(this.soundIdBackground,leftVolumn, rightVolumn, 1, -1, 1f);
102        }
103    }
104
105    @Override
106    public boolean onTouchEvent(MotionEvent event) {
107        if (event.getAction() == MotionEvent.ACTION_DOWN) {
108
109            int x=  (int)event.getX();
110            int y = (int)event.getY();
111
112            Iterator<ChibiCharacter> iterator= this.chibiList.iterator();
113
114
115            while(iterator.hasNext()) {
116                ChibiCharacter chibi = iterator.next();
117                if( chibi.getX() < x && x < chibi.getX() + chibi.getWidth()
118                        && chibi.getY() < y && y < chibi.getY()+ chibi.getHeight())  {
119                    // Remove the current element from the iterator and the list.
120                    iterator.remove();
121
122                    // Create Explosion object.
123                    Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(),R.drawable.explosion);
124                    Explosion explosion = new Explosion(this, bitmap,chibi.getX(),chibi.getY());
125
126                    this.explosionList.add(explosion);
127                }
128            }
129
130
131            for(ChibiCharacter chibi: chibiList) {
132                int movingVectorX =x-  chibi.getX() ;
133                int movingVectorY =y-  chibi.getY() ;
134                chibi.setMovingVector(movingVectorX, movingVectorY);
135            }
136            return true;
137        }
138        return false;
139    }
140
141    public void update()  {
142        for(ChibiCharacter chibi: chibiList) {
143            chibi.update();
144        }
145        for(Explosion explosion: this.explosionList)  {
146            explosion.update();
147        }
148
149        Iterator<Explosion> iterator= this.explosionList.iterator();
150        while(iterator.hasNext())  {
151            Explosion explosion = iterator.next();
152
153            if(explosion.isFinish()) {
154                // If explosion finish, Remove the current element from the iterator & list.
155                iterator.remove();
156                continue;
157            }
158        }
159    }
160
161    @Override
162    public void draw(Canvas canvas)  {
163        super.draw(canvas);
164
165        for(ChibiCharacter chibi: chibiList)  {
166            chibi.draw(canvas);
167        }
168
169        for(Explosion explosion: this.explosionList)  {
170            explosion.draw(canvas);
171        }
172
173    }
174
175    // Implements method of SurfaceHolder.Callback
176    @Override
177    public void surfaceCreated(SurfaceHolder holder) {
178        Bitmap chibiBitmap1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi1);
179        ChibiCharacter chibi1 = new ChibiCharacter(this,chibiBitmap1,100,50);
180
181        Bitmap chibiBitmap2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.chibi2);
182        ChibiCharacter chibi2 = new ChibiCharacter(this,chibiBitmap2,300,150);
183
184        this.chibiList.add(chibi1);
185        this.chibiList.add(chibi2);
186
187        this.gameThread = new GameThread(this,holder);
188        this.gameThread.setRunning(true);
189        this.gameThread.start();
190    }
191
192    // Implements method of SurfaceHolder.Callback
193    @Override
194    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
195
196    }
197
198    // Implements method of SurfaceHolder.Callback
199    @Override
200    public void surfaceDestroyed(SurfaceHolder holder) {
201        boolean retry= true;
202        while(retry) {
203            try {
204                this.gameThread.setRunning(false);
205
206                // Parent thread must wait until the end of GameThread.
207                this.gameThread.join();
208            }catch(InterruptedException e)  {
209                e.printStackTrace();
210            }
211            retry= true;
212        }
213    }
214
215}

بعد از انجام تغییرات بالا، بازی برای اجرا آماده است و می‌توان جلوه‌های صوتی استفاده شده در بازی را شنید.

سوالات متداول در برنامه نویسی بازی اندروید

تا این قسمت از نوشته با معرفی نقشه راه و مسیر یادگیری برنامه نویسی اندروید دید روشنی در خصوص این حوزه جذاب ایجاد شد. علاوه بر این، ابزار مناسب برای توسعه بازی اندروید از Android Studio گرفته تا موتور‌های مختلف بازی سازی مورد بررسی قرار گرفتند. در ادامه نیز به آموزش برنامه نویسی بازی اندروید در قالب ساخت بازی ساده دو بُعدی در اندروید استودیو پرداخته شد.

در این بخش از نوشته سعی شده است تا به برخی از رایج‌ترین سوالات پیرامون برنامه نویسی بازی اندروید پاسخ داده شود.

بهترین زبان برنامه نویسی بازی اندروید چیست؟

زبان برنامه نویسی ++C به دلیل همه منظوره بودن و پشتیبانی از شی‌گرایی گزینه بسیار مناسبی برای شروع ساخت بازی به حساب می‌آید. ++C انعطاف‌پذیری بسیار بالایی دارد که در سایر زبان‌های برنامه نویسی بازی‌سازی کمتر دیده شده است.

علاوه بر ++C زبان‌های دیگری نیز برای بازی‌سازی وجود دارند که در ادامه فهرست شده‌اند.

 

روش های کسب درآمد از بازی سازی چیست؟

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

استفاده از این روش بیشتر برای بازی‌هایی با نصب بالا توصیه می‌شود. از سایر روش‌های کسب درآمد از بازی‌سازی می‌توان به پرداخت درون برنامه‌ای، فروش بازی، حق اشتراک و فروش محصولات مرتبط با بازی اشاره کرد.

 

آیا امکان ساخت بازی اندروید بدون کدنویسی وجود دارد؟

استودیو‌های بازی همچون Flowlab، گیم میکر (GameMaker)، Google Game Builder و Quick App Ninja تنها چند نمونه از ابتدایی‌ترین موتور‌های بازی‌سازی هستند.

این ابزارها به توسعه‌دهندگان تازه‌کار کمک می‌کنند تا تنها با «کشیدن و رها کردن» (Drag & Drop) و بدون نیاز به کدنویسی بازی مورد نظر خود را طراحی کنند.

آیا برنامه نویسی بازی اندروید حوزه پردرآمدی است؟

بازار بازی‌های موبایلی با سرعت فوق‌العاده‌ای در حال پیشرفت است. هر ساله شاهد عناوین قدرتمندی هستیم که در کنار جذب کاربران بسیار زیاد، سود بسیار خوبی را نیز برای سازندگان به همراه دارند.

از سوی دیگر نیز بسیاری از بازی‌ها در جذب کاربر ناکام می‌مانند. در نتیجه، برای ساخت یک بازی سودآور و موفق کار بسیار سختی پیش‌روی توسعه‌دهندگان بازی است.

کسب درآمد از برنامه نویسی بازی اندروید

آیا در برنامه نویسی بازی اندروید به محاسبات ریاضی نیاز است؟

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

جمع‌بندی

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

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

بر اساس رای ۱۴ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
ANDROID AUTHORITYANDROID AUTHORITYo7planning
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *