JavaRush /وبلاگ جاوا /Random-FA /بخش "بازی ها" در JavaRush: نظریه مفید

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

در گروه منتشر شد
در بخش "بازی ها" JavaRush پروژه های هیجان انگیزی برای نوشتن بازی های رایانه ای محبوب خواهید یافت. آیا می خواهید نسخه خود را از بازی های محبوب "2048"، "Sapper"، "Snake" و سایر بازی ها ایجاد کنید؟ ساده است. ما نوشتن بازی را به یک فرآیند گام به گام تبدیل کرده ایم. فصلبرای اینکه خود را به عنوان یک توسعه دهنده بازی امتحان کنید، لازم نیست یک برنامه نویس پیشرفته باشید، اما مجموعه خاصی از دانش جاوا هنوز مورد نیاز است. در اینجا اطلاعاتی را خواهید یافت که هنگام نوشتن بازی ها مفید خواهد بود .

1. ارث

کار با موتور بازی JavaRush شامل استفاده از وراثت است. اما اگر ندانید چیست؟ از یک طرف، شما باید این موضوع را درک کنید: در سطح 11 مطالعه می شود . از طرف دیگر، موتور به عمد بسیار ساده طراحی شده است، بنابراین می توانید با دانش سطحی از وراثت از پس آن برآیید. بنابراین، ارث چیست؟ به بیان خیلی ساده، وراثت رابطه بین دو کلاس است. یکی از آنها والد می شود و دومی فرزند (کلاس جانشین). در این حالت، کلاس والد ممکن است حتی نداند که دارای کلاس‌های نسل است. آن ها هیچ سود خاصی از حضور کلاس های وارث دریافت نمی کند. اما وراثت مزایای بسیاری را برای یک طبقه از نسل فراهم می کند. و نکته اصلی این است که همه متغیرها و متدهای کلاس والد در کلاس فرزند ظاهر می شوند، گویی کد کلاس والد در کلاس فرزند کپی شده است. این کاملاً درست نیست، اما برای درک ساده وراثت، این کار انجام خواهد شد. در اینجا چند مثال برای درک بهتر وراثت آورده شده است. مثال 1: ساده ترین ارث.
public class Родитель {

}
کلاس Child با استفاده از کلمه کلیدی extends از کلاس Parent ارث می برد .
public class Потомок extends Родитель {

}
مثال 2: استفاده از متغیرهای کلاس والد.
public class Родитель {

   public int age;
   public String name;
}
کلاس Child می تواند از متغیرهای سن و نام کلاس Parent به گونه ای استفاده کند که گویی در آن تعریف شده اند.
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
مثال 3: استفاده از متدهای کلاس والد.
public class Родитель {

   public int age;
   public String name;

   public getName() {
      return name;
   }
}
کلاس Child می تواند از متغیرها و متدهای کلاس Parent طوری استفاده کند که انگار در آن اعلان شده اند. در این مثال از متد getName () استفاده می کنیم .
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
کلاس Descendant از نظر کامپایلر به این صورت است :
public class Потомок extends Родитель {

   public int age; //  унаследованная переменная
   public String name; //  унаследованная переменная

   public getName() { //  унаследованный метод.
      return name;
  }
   public void printInfo() {

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

2. نادیده گرفتن روش

گاهی اوقات موقعیت‌هایی پیش می‌آید که کلاس Descendant خود را از یک کلاس Parent بسیار مفید به همراه همه متغیرها و متدها به ارث برده‌ایم، اما برخی از متدها دقیقاً آنطور که می‌خواهیم کار نمی‌کنند. یا اصلاً آنطور که ما نمی خواهیم نیست. در این شرایط چه باید کرد؟ ما می توانیم روشی را که دوست نداریم لغو کنیم. این کار بسیار ساده انجام می شود: در کلاس Descendant ما به سادگی متدی را با همان امضا (هدر) متد کلاس Parent اعلام می کنیم و کد خود را در آن می نویسیم. مثال 1: غلبه بر روش.
public class Родитель {

   public String name;

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

   public getName() {
      return name;
  }
}
متد printInfo() عبارت "Luke, No!!!" را چاپ می کند.
public class Потомок extends Родитель {

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

   public void printInfo() {

      setName("Luke");
      System.out.println( getName());
   }
}
کلاس Descendant از نظر کامپایلر به این صورت است :
public Потомок extends Родитель {

   public String name; //  унаследованная переменная

   public void setName (String nameNew) { //  Переопределенный метод взамен унаследованного

       name = nameNew + ", No!!!";
   }
   public getName() { //  унаследованный метод.

      return name;
   }
   public void printInfo() {

     setName("Luke");
     System.out.println(getName());
   }
}
مثال 2: کمی جادوی وراثت (و روش نادیده گرفتن).
public class Родитель {

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

     System.out.println(getName());
   }
}
public class Потомок extends Родитель {

   public getName() {
      return "I'm your father, Luke";
  }
}
در این مثال: اگر متدی printInfo(از کلاس Parent) در کلاس Descendant بازخوانی نشود، وقتی این متد بر روی یک شی از کلاس Descendant فراخوانی شود، متد آن فراخوانی می شود getName()و نه getName()کلاس Parent.
Родитель parent = new Родитель ();
parent.printnInfo();
این کد کتیبه "Luke" را روی صفحه نمایش می دهد .
Потомок child = new Потомок ();
child.printnInfo();
این کد کتیبه "من پدرت هستم، لوک" را نمایش می دهد. .
کلاس Descendant از نظر کامپایلر به این صورت است :
public class Потомок extends Родитель {

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

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

3. فهرست ها

اگر هنوز لیست ها را ملاقات نکرده اید، در اینجا یک آغازگر سریع وجود دارد. می توانید اطلاعات کاملی در مورد سطوح 6-7 دوره JavaRush پیدا کنید . لیست ها با آرایه ها اشتراکات زیادی دارند:
  • می تواند داده های زیادی از نوع خاصی را ذخیره کند.
  • به شما امکان می دهد عناصر را بر اساس شاخص/تعداد آنها بازیابی کنید.
  • شاخص های عنصر از 0 شروع می شود.
مزایای لیست ها: بر خلاف آرایه ها، لیست ها می توانند به صورت پویا اندازه تغییر کنند. بلافاصله پس از ایجاد، اندازه لیست 0 است. با اضافه کردن عناصر به لیست، اندازه آن افزایش می یابد. نمونه ای از ایجاد لیست:
ArrayList<String> myList = new ArrayList<String>(); // создание нового списка типа 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) را به مقدار تنظیم می کند value. همانطور که متوجه شدید، این روش ابتدا دقیقاً x را می گیرد، مانند سیستم مختصات کلاسیک. بقیه روش های موتور به روشی مشابه کار می کنند. هنگام توسعه بازی ها، اغلب نیاز به بازتولید وضعیت ماتریس روی صفحه وجود دارد. چطور این کار را بکنیم؟ ابتدا در یک حلقه باید تمام عناصر ماتریس را تکرار کنید. دوم، برای هر یک از آنها، متدی را فراخوانی کنید تا با مختصات INVERTED نمایش داده شود. مثال:
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]));
        }
    }
}
طبیعتاً وارونگی در دو جهت کار می کند. setCellValueمی توانید (i، j) را به متد ارسال کنید، اما در همان زمان عنصر [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 = {"Andrey", "Валентин", "Сергей"};
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 باشد، "من یک ساعت زودتر از حد انتظار بیدار شدم." همه چیز بسیار ساده است: در داخل [0..4] 5 عدد وجود دارد که هر کدام می توانند با احتمال 10٪ برگردند که در مجموع 50٪ خواهد بود. در [5..8] 4 عدد وجود دارد و 9 تنها عددی است که با احتمال 10% ظاهر می شود. در کد، کل این طراحی هوشمندانه ساده تر به نظر می رسد:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Проспал ");
} else if (randomNumber < 9) {
    System.out.println("Встал вовремя ");
} else {
    System.out.println("Встал на час раньше положенного ");
}
به طور کلی، گزینه های زیادی برای استفاده از اعداد تصادفی وجود دارد. همه چیز فقط به تخیل شما بستگی دارد. اما اگر بخواهید مکرراً به نتیجه برسید از آنها به طور مؤثر استفاده می شود. سپس این نتیجه با نتیجه قبلی متفاوت خواهد بود. البته با کمی احتمال همین! اگر می‌خواهید درباره بخش بازی‌ها اطلاعات بیشتری کسب کنید، در اینجا چند سند مفید وجود دارد که می‌تواند کمک کند:
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION