CodeGym /وبلاگ جاوا /Random-FA /بخش بازی در CodeGym: نظریه مفید
John Squirrels
مرحله
San Francisco

بخش بازی در CodeGym: نظریه مفید

در گروه منتشر شد
در بخش «بازی‌ها» در CodeGym، پروژه‌های هیجان‌انگیزی را خواهید دید که شامل نوشتن بازی‌های رایانه‌ای محبوب هستند. آیا می خواهید نسخه خود را از بازی های محبوب 2048، Minesweeper، Snake و بازی های دیگر ایجاد کنید؟ ساده است. ما نوشتن بازی را به یک فرآیند گام به گام تبدیل کرده ایم. بخش "بازی ها" در CodeGym: نظریه مفید - 1برای آزمایش توانایی های خود به عنوان یک توسعه دهنده بازی، لازم نیست یک برنامه نویس پیشرفته باشید، اما مجموعه خاصی از دانش جاوا لازم است. در اینجا اطلاعاتی را خواهید یافت که در نوشتن بازی مفید خواهد بود .

1. ارث

کار با موتور بازی CodeGym شامل استفاده از وراثت است. اما اگر ندانید که چیست؟ از یک طرف، شما باید این موضوع را درک کنید: در سطح 11 مطالعه می شود . از طرف دیگر، موتور به طور ویژه بسیار ساده طراحی شده بود، بنابراین می توانید از دانش سطحی وراثت دور شوید. پس ارث چیست؟ به زبان ساده، وراثت یک رابطه بین دو طبقه است. یکی از آنها پدر و مادر می شود و دیگری فرزند (فرزند). علاوه بر این، کلاس والد ممکن است حتی نداند که دارای فرزندان است. به عبارت دیگر با داشتن اولاد مزیت خاصی به دست نمی آورد. اما وراثت به نسل مزایای بسیاری می دهد. و مهمترین آنها این است که همه متغیرها و متدهای کلاس والد به گونه ای در نزول ظاهر می شوند که گویی کد کلاس والد در کلاس نزول کپی شده است. این توصیف کاملاً دقیق نیست، اما برای درک ساده وراثت کافی است. در اینجا چند مثال برای درک بهتر وراثت آورده شده است. مثال 1: ساده ترین ارث.
public class Parent {

}
کلاس Child کلاس Parent را با استفاده از کلمه کلیدی extends به ارث می برد .
public class Child extends Parent {

}
مثال 2: استفاده از متغیرهای کلاس والد.
public class Parent {

   public int age;
   public String name;
}
کلاس Child می تواند از متغیرهای سن و نام کلاس والد استفاده کند که انگار در کلاس Parent اعلام شده اند .
public class Child extends Parent {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
مثال 3: استفاده از متدهای کلاس والد.
public class Parent {

   public int age;
   public String name;

   public getName() {
      return name;
  }
}
کلاس Child می تواند از متغیرها و متدهای کلاس Parent به گونه ای استفاده کند که گویی در کلاس Child اعلام شده اند. در این مثال از متد getName() استفاده می کنیم .
public class Child extends Parent {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
این چیزی است که کلاس Child برای کامپایلر به نظر می رسد:
public class Child extends Parent{

   public int age;  // Inherited variable
   public String name;  // Inherited variable

   public getName() {  // Inherited method.
      return name;
  }
   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}

2. روش های غلبه بر

گاهی اوقات موقعیت‌هایی پیش می‌آید که کلاس Child خود را وادار می‌کنیم تا کلاس Parent بسیار مفید را همراه با همه متغیرها و متدهای آن به ارث ببرد، اما برخی از متدها آنطور که ما می‌خواهیم کار نمی‌کنند. یا اصلاً آنطور که ما می خواهیم نیست. در این شرایط چه کنیم؟ ما می توانیم روشی را که دوست نداریم لغو کنیم. انجام این کار بسیار آسان است: در کلاس Child ما به سادگی متدی را با امضای مشابه متد در کلاس Parent اعلام می کنیم و سپس کد خود را در آن می نویسیم. مثال 1: لغو یک روش.
public class Parent {

   public String name;

   public void setName(String nameNew) {
       name = nameNew;
  }

   public getName() {
      return name;
  }
}
متد printInfo() "Luke, No!!!" را نمایش می دهد.
public class Child extends Parent{

   public void setName(String nameNew) {
       name = nameNew + ", No!!!";
  }

   public void printInfo() {
      setName("Luke");
      System.out.println(getName());
   }
}
این چیزی است که کلاس Child برای کامپایلر به نظر می رسد:
public Child extends Parent {

   public String name;  // Inherited variable

   public void setName(String nameNew)  // Overridden method instead of the inherited method {

       name = nameNew + ", No!!!";
   }
   public getName() {  // Inherited method.

      return name;
   }
   public void printInfo() {

     setName("Luke");
     System.out.println( getName());
   }
}
مثال 2: مقداری جادوی وراثت (و غلبه بر روش).
public class Parent {

   public getName() {
      return "Luke";
  }
   public void printInfo() {

     System.out.println(getName());
   }
}
public class Child extends Parent {

   public getName() {
      return "Luke, I am your father";
  }
}
در این مثال، اگر printInfoمتد (از کلاس Parent) در کلاس Child بازخوانی نشود، وقتی این متد روی یک شی Child فراخوانی می شود، getName()متد آن به جای متد کلاس Parent فراخوانی می شود getName().
Parent parent = new Parent ();
parent.printnInfo();
این کد "Luke" را روی صفحه نمایش می دهد.
Child child = new Child ();
child.printnInfo();
این کد "لوک، من پدرت هستم" را روی صفحه نمایش می دهد.
این چیزی است که کلاس Child برای کامپایلر به نظر می رسد:
public class Child extends Parent {

   public getName() {
      return "Luke, I am your father";
   }
   public void printInfo() {

     System.out.println(getName());
   }
}

3. فهرست ها

اگر هنوز لیست‌ها (فهرست) را ملاقات نکرده‌اید، در اینجا یک مرور مختصر وجود دارد. اطلاعات کامل را می توانید در سطوح 6-7 دوره CodeGym بیابید . لیست ها با آرایه ها اشتراکات زیادی دارند:
  • شما می توانید تعداد زیادی داده از یک نوع خاص را ذخیره کنید.
  • آنها به شما اجازه می دهند آیتم ها را با شاخص آنها دریافت کنید.
  • شاخص های عنصر از 0 شروع می شود.
مزایای لیست ها: بر خلاف آرایه ها، لیست ها می توانند به صورت پویا اندازه تغییر کنند. هنگامی که یک لیست ایجاد می شود، اندازه آن 0 است. با اضافه کردن موارد به یک لیست، اندازه آن افزایش می یابد. در اینجا مثالی از ایجاد یک لیست آورده شده است:
ArrayList<String> myList = new ArrayList<String>(); // Create a new ArrayList
مقدار موجود در براکت های زاویه نشان دهنده نوع داده ای است که لیست می تواند ذخیره کند. در اینجا چند روش برای کار با لیست آورده شده است:
کد شرح مختصری از کاری که کد انجام می دهد
ArrayList<String> list = new ArrayList<String>(); لیست جدیدی از رشته ها ایجاد کنید
list.add("name"); یک عنصر را به انتهای لیست اضافه کنید
list.add(0, "name"); یک عنصر را به ابتدای لیست اضافه کنید
String name = list.get(5); یک عنصر را با شاخص آن دریافت کنید
list.set(5, "new name"); یک عنصر را با شاخص آن تغییر دهید
int count = list.size(); تعداد عناصر موجود در لیست را بدست آورید
list.remove(4); حذف یک عنصر از لیست
از مقالات زیر می‌توانید درباره فهرست‌ها اطلاعات بیشتری کسب کنید:
  1. کلاس ArrayList
  2. ArrayList در تصاویر
  3. حذف یک عنصر از ArrayList

4. آرایه ها

ماتریس چیست؟ ماتریس چیزی نیست جز یک جدول مستطیلی که می تواند با داده ها پر شود. به عبارت دیگر، این یک آرایه دو بعدی است. همانطور که احتمالا می دانید، آرایه ها در جاوا شی هستند. یک آرایه استاندارد یک بعدی intبه شکل زیر است:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
ما می توانیم آن را به این صورت تجسم کنیم:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
ردیف بالا نشان دهنده آدرس سلول ها است. به عبارت دیگر، برای به دست آوردن عدد 67، باید به عنصر آرایه با شاخص 6 دسترسی داشته باشید:
int number = array[6];
همه چیز خیلی ساده است. آرایه دو بعدی آرایه ای از آرایه های یک بعدی است. اگر برای اولین بار است که در مورد این موضوع می شنوید، توقف کنید و آن را در ذهن خود تصور کنید. یک آرایه دو بعدی به شکل زیر است:
0 آرایه یک بعدی آرایه تک بعدی
1 آرایه تک بعدی
2 آرایه تک بعدی
3 آرایه تک بعدی
4 آرایه تک بعدی
5 آرایه تک بعدی
6 آرایه تک بعدی
7 آرایه تک بعدی
در کد:
int [][] matrix = {
{65, 99, 87, 90, 156, 75, 98, 78}, {76, 15, 76, 91, 66, 90, 15, 77}, {65, 96, 17, 25, 36, 75, 54, 78}, {59, 45, 68, 14, 57, 1, 9, 63}, {81, 74, 47, 52, 42, 785, 56, 96}, {66, 74, 58, 16, 98, 140, 55, 77}, {120, 99, 13, 90, 78, 98, 14, 78}, {20, 18, 74, 91, 96, 104, 105, 77} }
0 0 1 2 3 4 5 6 7
65 99 87 90 156 75 98 78
1 0 1 2 3 4 5 6 7
76 15 76 91 66 90 15 77
2 0 1 2 3 4 5 6 7
65 96 17 25 36 75 54 78
3 0 1 2 3 4 5 6 7
59 45 68 14 57 1 9 63
4 0 1 2 3 4 5 6 7
81 74 47 52 42 785 56 96
5 0 1 2 3 4 5 6 7
66 74 58 16 98 140 55 77
6 0 1 2 3 4 5 6 7
120 99 13 90 78 98 14 78
7 0 1 2 3 4 5 6 7
20 18 74 91 96 104 105 77
برای بدست آوردن مقدار 47، باید به عنصر ماتریس در [4][2] مراجعه کنید.
int number = matrix[4][2];
شاید متوجه شده باشید که مختصات ماتریس با سیستم مختصات مستطیلی کلاسیک (سیستم مختصات دکارتی) متفاوت است. هنگامی که به ماتریس دسترسی پیدا می کنید، ابتدا مختصات y و سپس مختصات x را مشخص می کنید. در ریاضیات مرسوم است که ابتدا مختصات x یعنی (x,y) مشخص شود. ممکن است تعجب کنید: "خب، چرا نمایش ماتریس را نمی چرخانیم و سپس با استفاده از (x, y) به عناصر به روش معمول دسترسی پیدا نمی کنیم؟ انجام این کار باعث تغییر محتوای ماتریس نمی شود." بله، هیچ چیز تغییر نخواهد کرد. اما در دنیای برنامه نویسی، روش پذیرفته شده دسترسی به ماتریس ها "اول توسط y، سپس توسط x" است. شما باید این را به عنوان راه مناسب بپذیرید. حالا بیایید در مورد طرح ماتریس به موتور ( Gameکلاس) خود صحبت کنیم. همانطور که می دانید موتور روش های زیادی دارد که سلول های زمین بازی را در مختصات خاصی تغییر می دهد. مثلا setCellValue(int x, int y, String value)روش. یک سلول خاص با مختصات (x, y) برابر با پارامتر مقدار تنظیم می کند. شاید متوجه شده باشید که این روش مانند سیستم مختصات کلاسیک ابتدا x را می گیرد. روش های دیگر موتور نیز به همین شکل عمل می کنند. هنگام توسعه بازی ها، اغلب لازم است وضعیت یک ماتریس روی صفحه نمایش داده شود. چگونه ما آن را انجام دهیم؟ ابتدا باید تمام عناصر ماتریس را در یک حلقه تکرار کنید. دوم، روش نمایش را برای هر یک از آنها با استفاده از مختصات معکوس فراخوانی کنید. مثلا:
private void drawScene() {
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            setCellValue(j, i, String.valueOf(matrix[i][j]));
        }
    }
}
به طور طبیعی، معکوس در هر دو جهت کار می کند. می توانید (i, j) را به setCellValueمتد ارسال کنید و همزمان عنصر [j][i] را از ماتریس بگیرید. معکوس کردن مختصات ممکن است کمی دشوار به نظر برسد، اما باید آن را به خاطر بسپارید. و همیشه، اگر با مشکلی مواجه شدید، باید یک تکه کاغذ و یک قلم بگیرید، ماتریس را بکشید و فرآیندهای مربوط به ماتریس را بازتولید کنید.

5. اعداد تصادفی

چگونه با یک مولد اعداد تصادفی کار می کنید؟ کلاس متد را Gameتعریف می کند getRandomNumber(int). در زیر هود، Randomاز کلاس بسته java.util استفاده می کند، اما نحوه کار شما با مولد اعداد تصادفی تغییر نمی کند. getRandomNumber(int)یک عدد صحیح را به عنوان آرگومان می گیرد. این عدد حد بالایی برای آنچه که ژنراتور می تواند برگرداند خواهد بود. حد پایین 0 است. مهم! ژنراتور هرگز عدد حد بالایی را برنمی‌گرداند. به عنوان مثال، اگر شما تماس بگیرید getRandomNumber(3)، به طور تصادفی 0، 1 یا 2 را برمی گرداند. همانطور که می بینید، نمی تواند 3 را برگرداند. استفاده از ژنراتور به این روش بسیار ساده است، اما در بسیاری از موارد بسیار موثر است. فرض کنید باید یک عدد تصادفی در محدوده ای بدست آورید: تصور کنید به یک عدد سه رقمی در محدوده [100..999] نیاز دارید. همانطور که می دانید، حداقل عدد بازگشتی 0 است. بنابراین باید 100 اضافه کنید. اما در این مورد، باید مراقب باشید که از حد بالایی تجاوز نکنید. برای بدست آوردن 999 به عنوان حداکثر مقدار تصادفی، getRandomNumber(int)متد را با آرگومان 1000 فراخوانی کنید. اما اکنون به یاد داریم که 100 را به نتیجه اضافه می کنیم: این بدان معنی است که کران بالایی باید 100 کاهش یابد. به عبارت دیگر، کد به دریافت عدد سه رقمی تصادفی ما به شکل زیر خواهد بود:
int number = 100 + getRandomNumber(900);
اما برای ساده‌تر کردن این روش، موتور روشی را ارائه می‌کند getRandomNumber(int, int)که اولین پارامتر آن حداقل عدد برای بازگشت است. با استفاده از این روش، مثال قبلی را می توان به صورت زیر بازنویسی کرد:
int number = getRandomNumber(100, 1000);
برای بدست آوردن یک عنصر آرایه تصادفی می توان از اعداد تصادفی استفاده کرد:
String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
ایجاد رویدادهای خاص با احتمال کمی. برای انسان‌ها، صبح‌ها با چند سناریو ممکن آغاز می‌شوند: بیش‌خوابی – 50% احتمال. به موقع از خواب بیدار شد - احتمال 40٪؛ یک ساعت زودتر از خواب بیدار شوید - احتمال 10٪. تصور کنید که در حال نوشتن یک مولد نتیجه صبح هستید. شما باید رویدادهایی را با احتمال خاصی تولید کنید. برای انجام این کار، دوباره باید از یک مولد اعداد تصادفی استفاده کنید. پیاده سازی های مختلفی ممکن است، اما ساده ترین آنها باید بر اساس الگوریتم زیر باشد:
  1. محدودیت های مورد استفاده برای تولید یک عدد را تنظیم کنید.
  2. تولید یک عدد تصادفی؛
  3. عدد به دست آمده را پردازش کنید.
در این صورت حداکثر 10 خواهد بود. getRandomNumber(10)متد را فراخوانی کرده و آنالیز کنید که می توانیم آن را برگردانیم. می تواند 10 عدد (از 0 تا 9) را برگرداند که هر کدام با احتمال یکسان - 10٪. اکنون باید همه نتایج ممکن را ترکیب کنیم و آنها را با رویدادهای احتمالی خود ترسیم کنیم. تصور شما ممکن است ترکیب‌های ممکن زیادی را به ذهن متبادر کند، اما واضح‌ترین آنها این است: "اگر عدد تصادفی در محدوده [0..4] باشد، رویداد "Overslept" را داریم؛ اگر عدد در محدوده [5] باشد. ..8]، ما رویداد "به موقع بیدار شدم" را داریم؛ و اگر عدد 9 باشد، رویداد "یک ساعت زودتر از خواب بیدار شدم" را داریم. همه اینها بسیار ساده است. 5 عدد در محدوده [0] وجود دارد. ..4]، که هر کدام ممکن است با احتمال 10% برگردانده شوند، در مجموع 50%؛ 4 عدد در محدوده [5..8] وجود دارد، خوب، و 9 فقط یک عدد است که با احتمال 10% این طراحی نرم و صاف در کد حتی ساده تر به نظر می رسد:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Overslept");
} else if (randomNumber < 9) {
    System.out.println("Woke up on time");
} else {
    System.out.println("Woke up an hour early");
}
به طور کلی، روش های زیادی برای استفاده از اعداد تصادفی وجود دارد. شما فقط توسط تخیل خود محدود شده اید. اما اگر بخواهید مکرراً به نتیجه برسید از آنها به طور مؤثر استفاده می شود. سپس نتیجه جدید با نتیجه قبلی متفاوت خواهد بود. البته با کمی احتمال فعلاً همین است! اگر می‌خواهید درباره بخش «بازی‌ها» اطلاعات بیشتری کسب کنید، در اینجا چند سند مفید وجود دارد که می‌تواند کمک کند:
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION