شروع ساخت بازی دوبعدی سفینه بازیسازی با جاوا

1395/10/12 لیلا کشاورز 1320

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

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

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

 در این بازی  ، چند sprite  خواهیم داشت، که یک به یک ایجادشون میکنیم.
اولین sprite ، خود سفینه هست.
پس ابتدا یک سفینه فضایی میسازیم  و سپس  به کمک کلیدهای صفحه کلید ،بون رو  به حرکت در می یاریم. (یعنی  sprite  را  به چپ ، راست ، بالا یا پایین حرکت میدیم.)

طبق روال گذشته پروژه ای ایجاد میکنیم و پیکیجی برای پروژه میسازیم  و به بررسی کلاسهای مورد نیازی که باید در این پکیج ایجاد بشن ،میپردازیم.

اولین کلاس، کلاسی به نام craft  است که قرار است سفینه و چگونگی حرکت  سفینه را در آن پیاده سازی کنیم:

package sprite;

import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;


public class craft {

    private Image image;
    private int x;
    private int y;
    private int dx;
    private int dy;
    private String craft = "craft.png";

    public craft(){

    ImageIcon im =new ImageIcon(this.getClass().getResource(craft));
    image =im.getImage();
    x=40;
    y=40;
}
  public void  move() {
  x+=dx;
  y+=dy;
if (x < 1) {
            x = 1;
        }
 
        if (y < 1) {
            y = 1;
        }
}


  public int getx(){
  return x;
  }
    
  public int gety(){
  return y;
  }

  public Image getimage(){
  return image;
  }
 
public void keyPressed(KeyEvent e) {

        int key=e.getKeyCode();

        if (key == KeyEvent.VK_LEFT) {
            dx = -1;
        }
        if (key== KeyEvent.VK_RIGHT) {
             dx = +1;
        }
         if (key== KeyEvent.VK_DOWN) {
             dy = +1;
        }
         if (key== KeyEvent.VK_UP) {
             dy = -1;
         }
            }

      public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();

        if (key == KeyEvent.VK_LEFT) {
            dx = 0;
        }
      if (key == KeyEvent.VK_RIGHT) {
            dx = 0;
        }

       if (key == KeyEvent.VK_DOWN) {
            dy = 0;
        }
     if (key == KeyEvent.VK_UP) {
            dy = 0;
        }
      }
}

در ابتدای این کلاس متغییر های مورد نیاز رو تعریف کردیم:
متغییرهای x,y  ، مولفه هایی هستند که  میزان فاصله تصویر از board  رو مشخص خواهند کردو متغییر های dx ,dy  میزان تغییر مولفه  های  x,y  رو مشخص میکنند.

متغییری از نوع image  تعریف کردیم برای  دریافت تصویر مورد نظر،و رشته ای  که نام این تصویر را در خود دارد.

در تابع craft  ، تصویر رو مطابق گذشته، دریافت و همچنین در یک مختصات مشخصی قرار میدیم.( فاصله ی اولیه ی تصویر از گوشه ی بالای سمت چپ Board  رو 40 ,40  قرار دادیم. )
(توجه  داشته باشید که در محل ذخیره ی پروژه و در کنار کلاسهای ساخته شده ، تصویرسفینه رو کپی کردیم.)

تابع move مختصات  x,y   سفینه رو به میزان dx,dy  تغییر می ده .
مقادیر x , y تابع move ،در تابع paint (که  جلوتر بررسی اش میکنیم) برای ترسیم تصویر سفینه استفاده میشن .
دو شرط لحاظ شده در تابع  move نیز به این منظور ه که سفینه هنگام خارج شدن از سمت چپ پنجره یا بالای پنجره،با مقداردهی دوباره ی x یا y  دوباره وارد پنجره بشه.
توابع get  تعریف شده برای  هر یک ازمتغییرهای  x,y,image  هم، مقدار جدید هر کدام رو هر بار بر میگردونه.


دو متد بعدی ، keyPressed و keyReleased ،بررسی میکنند که سفینه  در حالت حرکت قرار داره و یا در حالت ایستاده.
متد keyPressed برای لحظه ای که sprite  در حال حرکت است ، پیاده سازی شده .
در این تابع ، مشخص میکنیم که  حرکت sprite  با فشردن هر یک از کلیدهای جهت نمای صفحه کلید، چه تغییری کنه.
پس باید برای  ورودی این تابع، کلیدی که فشرده میشه رو درنظر بگیریم(یعنی شی ای از نوع keyEvent). سپس با دستور getKeyCode() ،  کد اسکی مربوط به کلیدی که فشرده شده را دریافت میکنیم و اون رو  با کداسکی کلیدهای جهت نما مقایسه میکنیم و بسته به اینکه کدومیک از چهار کلید جهت نما فشرده شده اند، دستوری رو برای افزایش مولفه ی مربوطه ، قرار میدیم.

if (key == KeyEvent.VK_LEFT) {
            dx = -1;
        }


مطابق این دستور ،اگر کلید فشرده شده ،فلش سمت چپ باشه ، مختصه ی x  رو یک واحد کم کن .(به این معنی که sprite  رو یک واحد به سمت چپ حرکت بده.)

if (key== KeyEvent.VK_RIGHT){
             dx = +1;
 
    }


مطابق این دستور، اگر کلید فشرده شده ،فلش سمت چپ باشه ، مختصه ی x  تصویر یک واحد کم میشه .(به این معنی که sprite  یک واحد به سمت راست حرکت میکنه.)

if (key== KeyEvent.VK_DOWN){
             dy = +1;
}

        if (key== KeyEvent.VK_UP){
           dy = -1;
      }

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

اما این تغییرات با یکبار فشردن هر کدام از این کلیدها ، بدون توقف انجام میشه  و سفینه  مدام حرکت میکنه.
مثلا با یکبار فشردن کلید جهت نمای راست، سفینه بطور مداوم به سمت راست حرکت میکنه تا از board خارج بشه.

برای حل این مشکل ، متد keyReleased رو پیاده سازی کردیم . این متد برای ایستادن sprite  ، پیاده سازی شده.
به این معنی که وقتی دستمون از کلیدبرداشته شد ، میزان تغییر در اون جهت، 0 بشه.(یعنی سفینه از حرکت بایسته.):

public void keyReleased(KeyEvent e){
      int key = e.getKeyCode();

       if (key == KeyEvent.VK_LEFT);
           dx = 0;
        }
 if (key == KeyEvent.VK_RIGHT){
          dx = 0;
}

  if (key == KeyEvent.VK_DOWN){
            dy = 0;
}
    if (key == KeyEvent.VK_UP){
           dy = 0;
        }
  }

بعد از پیاده سازی این کلاس ،کلاس Board  را ایجاد میکنیم:

package sprite;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.Timer;

public class Board extends javax.swing.JPanel implements ActionListener{

  private Timer timer ;
  private craft craft ;

  public Board (){

       addKeyListener(new TAdapter ());
     setFocusable(true  );
       setBackground(Color.BLACK)  );
     setDoubleBuffered(true  );
        craft=new craft();

       timer=new Timer(10,this );
      timer.start ();

}

 public void paint(Graphics g  ){
      super.paint(g  );

        Graphics2D g2d = (Graphics2D)g;
       g2d.drawImage(craft.getimage(), craft.getx(), craft.gety(), this );

   Toolkit.getDefaultToolkit().sync   ();
      g.dispose  ();
    }
       
   public void actionPerformed(ActionEvente){  
    craft.move; ()
      repaint; ()
    }
    
     private class TAdapter extends KeyAdapter  {

       public void keyReleased(KeyEvent e ){
            craft.keyReleased(e );
        }

       public void keyPressed(KeyEvent e );
           craft.keyPressed(e);
        }
 }
    }

در این کلاس، داخل تابع paint سفینه فضایی را که قبلا تصویرش رو دریافت کرده بودیم، ترسیم کردیم .
در تابع رسم سفینه هم ،تصویر سفینه و مختصاتش رو بعنوان پارامتر به تابع دادیم:

g2d.drawImage(craft.getimage(), craft.getx(), craft.gety(), this);

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

Toolkit.getDefaultToolkit().sync();
 g.dispose ();

تابع actionPerformed رو هم  هر 10 میلی ثانیه یکبار فراخوانی می کنیم . در این متد ، هم sprite رو حرکت می دیم و هم متد repaint رو فراخوانی می کنیم  .

بعد از پیاده سازی این دو کلاس ،   کلاس حای متد  main  رو هم  ایجاد میکنیم تا به برنامه ، قابلیت اجرا بدیم:

آموزش ساخت بازی با جاوا

خب ، اگر برنامه رو اجرا کنید ،خروجی زیر رو مشاهده خواهید کرد:

(سفینه ی ایجاد شده در board ،با فشردن کلیدهای جهت نما حرکت میکند.)

آموزش بازیسازی با جاوا

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

کلمات کلیدی