در سه قسمت گذشته، در مورد مفاهیم اولیه بازیسازی با جاوا؛ انیمیشن ، و اسپرایت ها بحث شد.

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

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

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

” برخورد سفینه با دشمن ” و ” برخورد دشمن با گلوله”.
طبق روال گذشته یک پروژه ی جدید در NetBeans ایجاد میکنیم. پکیجی در آن ایجاد کرده و یک به یک کلاسهای مورد نیاز را در آن ایجاد میکنیم.

مطابق توضیحاتی که ارائه شد ،در این برنامه سه sprite خواهیم داشت: سفینه، گلوله وکاراکتر دشمن.
پس ابتدا کلاسی با عنوان sprite ایجاد میکنیم که متدهای مشترک سه کاراکتر فوق را در آن پیاده سازی میکنیم.
سپس کلاسهایی جداگانه برای  هر یک از این  sprite  ها ایجاد میکنیم و متدهایی که خاص انها باشد را ، در آن کلاسها تعریف خواهیم کرد.
در واقع کلاس sprite  نقش کلاس والد را برای sprite  ها خواهد داشت و هر سه sprite  از این کلاس مشتق خواهند شد.
(توجه داشته باشید که تصویر هر سه sprite بایستی مطابق روند همیشگی در محل ذخیره ی پروژه ، کپی شود.)

 

کلاس sprite به این شکل خواهد بود:

 

متغییرها و متد های تعریف شده در این کلاس، کاملا واضح هستند. (در مقاله ی قبل به توضیح مفصل در مورد هر یک از آنها پرداختیم)
تنها نکته ای که وجود دارد این است که، ما برای اینکه در نهایت بتوانیم تشخیص دهیم اشیا مد نظر، به یکدیگر برخورد کرده اند یا خیر، بایدمرزهای تصویر را بشناسیم.
تابع getBounds برای برگرداندن مرزهای تصویر، تعریف شده است.
ابتداتوسط متد getImageDimensions، طول و عرض تصویر را دریافت میکنیم :

سپس در تابع getBounds ، با دستور

 

بسته به مقدار x,y  که نشان دهنده ی مکان فعلی sprite است، یک چند ضلعی برگردانده میشود که این چندضلعی، همان مرز تصویر sprite میباشد.
بعد از ایجاد این کلاس ، به سراغ اولین sprite (سفینه) میرویم و کلاس مربوط به آن را ایجاد میکنیم :

 

همانطور که گفته شد، کلاس فوق، از کلاس sprite  ارث میبرد.
تابع move موجود، مختصات  x,y  سفینه را به ازای هربار حرکت به میزان dx,dy  تغییر میدهد.

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

عملکرد توابع keyPressed ،  fire و keyReleased را نیز از آموزش قبل ، به یاد دارید.

بعد از این کلاس، کلاسی برای گلوله تعریف میکنیم :

سرعت ثابتی را در نظر میگیریم، تا گلوله متناسب با آن حرکت کند:

و در تابع move ،که تابع پیاده سازی حرکت گلوله است، این مقدار را به مختصه ی x گلوله،در زمان حرکت، نسبت میدهیم.

زمانیکه گلوله به حاشیه ی سمت راست پنجره ی خروجی برخورد میکند، باید ناپدید شود. یعنی وقتی مختصه ی x گلوله، بیشتر از طول پنجره شود (که این مقدار را برابر  ; private final int BOARD_WIDTH = 380 قرار دادیم)، باید گلوله را از لیست گلوله هایی که در ArrayList تعریف کردیم حذف کنیم.

حال به سراغ کلاس enemy  میرویم که کلاس تعریف کاراکتر دشمن میباشد:

 

از آنجایی که میخواهیم کاراکتر دشمن در صورت اصابت نکردن با گلوله، با خروج از برد، بار دیگر وارد شود، پس تابع move، به شکل زیر خواهد بود:

به این معنی که اگر کاراکتر دشمن از برد خارج شد، با مقدار دهی دوباره ی مولفه ی x (متغیر INITIAL_X، را نیز ابتدای کلاس، تعریف و  400 مقدار دهی کردیم) از سمت راست برد وارد شده و با دستور x=x-1، به سمت چپ برد حرکت کند.

حال کلاس Board  را ایجاد میکنیم:

 

 

در ابتدای این کلاس متغیر های مورد نیاز را تعریف کردیم. یکی از مهمترین آنها، موقعیت آغازین هر کدام از کاراکترهای دشمن است، که آنها را به کمک یک آرایه دو بعدی، که بعد اول نشان دهنده ی موقعیت x  و بعد دوم نشان دهنده ی موقعیت y هر کاراکتر است، تعریف کردیم:

سپس توسط متد initAliens() یک آرایه از کاراکترهای دشمن ایجاد میکنیم که موقعیت اولیه شان را از آرایه pos دریافت میکنند:

 

در متد paintComponent، بسته به مقدار متغیر ingame، عمل خواهیم کرد. به این شکل که اگر این متغیر مقدار true داشت، اسپرایت های بازی را به کمک متد drawObjects رسم میکنیم و در غیر اینصورت، متد drawGameOver را فراخوانی میکنیم، که این متد عبارت”Game Over” را وسط پنجره ی خروجی نمایش میدهد و به معنای پایان بازی است.

(در واقع این تصویر وقتی ظاهر میشود که کاراکتر سفینه با یکی از کاراکترهای دشمن برخوررد کرده باشد و یا اینکه همه ی کاراکترهای دشمن را از بین برده باشیم)

GameOver

game over برخورد

متد drawObjects هم، همانطور که ذکر شد برای به نمایش در آوردن اسپرایتهاست:

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

 

سپس در حلقه ی تکرار زیر ، گلوله ها را:

 

و در حلقه ی تکرار زیر ، کاراکترهای دشمن را رسم میکنیم: (دقت کنید که هر کاراکتر دشمن فقط در صورتی باید دوباره وارد برد شود که کشته نشده باشد ، ما این را توسط متد  isVisible بررسی کردیم)

 

در پایان متد drawObjects نیز، برای اینکه تعداد کاراکترهای دشمن باقیمانده (کشته نشده) در هر لحظه را بدانیم،
در گوشه ی سمت چپ بالای پنجره، این تعداد را به کمک دستورات زیر، نمایش میدهیم:

در متد actionPerformed، هر یک از اعمال لازم برای اجرا در هر چرخه ی بازی،توسط یک متد خاصی فراخوانی شده است:

 

در متد updateAliens، ابتدا چک میکنیم که آیا کاراکتر دشمنی در لیست ارایه ها ی دشمن هست یا خیر! اگر این لیست خالی بود ، به این معنی است که بازی به پایان رسیده است و در غیر اینصورت ،کاراکترهای دشمن را درون برد به نمایش در می آوریم ، و انها را از لیست خارج میکنیم:

و اما متد checkCollisions:
در این متد  برخوردهایی که ممکن بود اتفاق بیفتند را بررسی میکنیم. در ابتدا بررسی میکنیم که ایا سفینه با هر یک از کاراکترهای دشمن برخورد کرده است یا خیر:

 

 

در ادامه برخورد کاراکتر دشمن با گلوله را بررسی میکنیم:

 

 

بعد از کلاس Board،کلاس اصلی برنامه، که حاوی متد main  میباشد (کلاس collision )  را نیز به پکیج  اضافه میکنیم، تا به برنامه قابلیت اجرا دهیم :

 

main

کلاس main برخورد

 

تصویری از خروجی را در شکل زیر میبینید:

 

finaal

نتیجه نهایی برخورد

 

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

 

ozviiiiiiiat

 

دانلود فایل پروژه