JavaRush /Java Blogu /Random-AZ /JavaRush-da "Oyunlar" bölməsi: Faydalı nəzəriyyə

JavaRush-da "Oyunlar" bölməsi: Faydalı nəzəriyyə

Qrupda dərc edilmişdir
JavaRush-un “Oyunlar” bölməsində siz məşhur kompüter oyunlarının yazılması üçün maraqlı layihələr tapa bilərsiniz. Məşhur “2048”, “Sapper”, “Snake” və digər oyunların öz versiyasını yaratmaq istəyirsiniz? Bu sadədir. Biz oyun yazmağı addım-addım prosesə çevirdik. FəsilÖzünüzü bir oyun tərtibatçısı kimi sınamaq üçün qabaqcıl proqramçı olmaq lazım deyil, lakin müəyyən Java biliyi hələ də tələb olunur. Burada oyun yazarkən faydalı olacaq məlumatları tapa bilərsiniz .

1. Vərəsəlik

JavaRush oyun mühərriki ilə işləmək mirasdan istifadəni nəzərdə tutur. Bəs bunun nə olduğunu bilmirsinizsə nə etməli? Bir tərəfdən, bu mövzunu başa düşməlisiniz: 11-ci səviyyədə öyrənilir . Digər tərəfdən, mühərrik qəsdən çox sadə olması üçün nəzərdə tutulmuşdur, ona görə də siz miras haqqında səthi biliklərlə əldə edə bilərsiniz. Beləliklə, miras nədir? Çox sadə desək, miras iki sinif arasındakı əlaqədir. Onlardan biri valideyn, ikincisi isə övlad (varis sinfi) olur. Bu halda, valideyn sinifi nəsil siniflərinin olduğunu belə bilməyə bilər. Bunlar. varis siniflərinin olmasından heç bir xüsusi fayda almır. Lakin miras nəsil sinfinə bir çox üstünlüklər verir. Əsas odur ki, ana sinifin bütün dəyişənləri və metodları uşaq sinifdə görünür, sanki ana sinifin kodu uşaq sinifə köçürülür. Bu, tamamilə doğru deyil, lakin mirasın sadələşdirilmiş başa düşülməsi üçün bunu edəcək. Mirası daha yaxşı başa düşmək üçün bəzi nümunələr var. Nümunə 1: ən sadə miras.
public class Родитель {

}
Child sinfi extensions açar sözündən istifadə edərək Ana sinifdən miras alır .
public class Потомок extends Родитель {

}
Misal 2: Ana sinif dəyişənlərindən istifadə.
public class Родитель {

   public int age;
   public String name;
}
Child sinfi Parent sinfinin yaşad dəyişənlərindən , sanki orada elan edilmiş kimi istifadə edə bilər .
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Misal 3: Ana sinif metodlarından istifadə.
public class Родитель {

   public int age;
   public String name;

   public getName() {
      return name;
   }
}
Child sinfi Parent sinfinin dəyişənlərindən və metodlarından sanki orada elan edilmiş kimi istifadə edə bilər. Bu nümunədə getName () metodundan istifadə edirik .
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
Descendant sinfi tərtibçinin nöqteyi-nəzərindən belə görünür:
public class Потомок extends Родитель {

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

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

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

2. Metodun üstünlüyü

Bəzən elə vəziyyətlər olur ki, biz nəsil sinfimizi bütün dəyişənlər və metodlarla birlikdə çox faydalı Valideyn sinfindən miras almışıq, lakin bəzi üsullar tam istədiyimiz kimi işləmir. Ya da heç istəmədiyimiz şəkildə deyil. Bu vəziyyətdə nə etməli? Biz bəyənmədiyimiz metodu ləğv edə bilərik. Bu, çox sadə şəkildə edilir: Descendant sinifimizdə biz sadəcə olaraq Ana sinif metodu ilə eyni imzaya (başlığa) malik metodu elan edirik və kodumuzu ona yazırıq. Nümunə 1: Metodun ləğvi.
public class Родитель {

   public String name;

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

   public getName() {
      return name;
  }
}
printInfo() metodu "Luke, No!!!" ifadəsini çap edəcək.
public class Потомок extends Родитель {

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

   public void printInfo() {

      setName("Luke");
      System.out.println( getName());
   }
}
Descendant sinfi tərtibçinin nöqteyi-nəzərindən belə görünür:
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());
   }
}
Nümunə 2: mirasın bir az sehri (və metodun üstünlüyü).
public class Родитель {

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

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

   public getName() {
      return "I'm your father, Luke";
  }
}
Bu misalda: əgər metod (Valideyn sinfindən olan) Descendant sinfində ləğv edilməyibsə, bu metod Descendant sinfinin obyektində çağırıldıqda, onun metodu Ana sinif deyil, , printInfoadlandırılacaq .getName()getName()
Родитель parent = new Родитель ();
parent.printnInfo();
Bu kod ekranda "Luka" yazısını göstərir .
Потомок child = new Потомок ();
child.printnInfo();
Bu kodda "Mən sənin atanam, Luka;" yazısını əks etdirir. .
Descendant sinfi tərtibçinin nöqteyi-nəzərindən belə görünür:
public class Потомок extends Родитель {

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

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

3. Siyahılar

Əgər siz hələ də Lists ilə tanış olmamısınızsa, burada sürətli bir primer var. Siz JavaRush kursunun 6-7 səviyyələri haqqında tam məlumat tapa bilərsiniz . Siyahıların massivlərlə çox ortaq cəhətləri var:
  • müəyyən tipli çoxlu məlumat saxlaya bilir;
  • elementləri indeksinə/nömrəsinə görə əldə etməyə imkan verir;
  • element indeksləri 0-dan başlayır.
Siyahıların üstünlükləri: Massivlərdən fərqli olaraq siyahılar ölçüsünü dinamik şəkildə dəyişə bilər. Yaradılandan dərhal sonra siyahının ölçüsü 0 olur. Siyahıya elementlər əlavə etdikcə onun ölçüsü artır. Siyahı yaratmaq nümunəsi:
ArrayList<String> myList = new ArrayList<String>(); // создание нового списка типа ArrayList
Bucaq mötərizəsindəki dəyər siyahının saxlaya biləcəyi məlumat növüdür. Siyahı ilə işləməyin bəzi üsulları bunlardır:
Kod Kodun nə etdiyinin qısa təsviri
ArrayList<String> list = new ArrayList<String>(); Yeni sətirlər siyahısının yaradılması
list.add("name"); Siyahının sonuna bir element əlavə edin
list.add(0, "name"); Siyahının əvvəlinə bir element əlavə edin
String name = list.get(5); Elementi indeksinə görə əldə edin
list.set(5, "new name"); Elementi indeksinə görə dəyişdirin
int count = list.size(); Siyahıdakı elementlərin sayını əldə edin
list.remove(4); Siyahıdan elementi silin
Bu məqalələrdən siyahılar haqqında daha çox məlumat əldə edə bilərsiniz:
  1. ArrayList sinfi
  2. Şəkillərdə işləyən ArrayList
  3. ArrayList-dən elementin çıxarılması

4. Massivlər

Matris nədir? Matris verilənlərlə doldurula bilən düzbucaqlı cədvəldən başqa bir şey deyil. Başqa sözlə, iki ölçülü massivdir. Yəqin ki, bildiyiniz kimi, Java-da massivlər obyektlərdir. Standart bir ölçülü massiv tipi intbelə görünür:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Bunu vizual olaraq təsəvvür edək:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
Üst sətir hüceyrə ünvanlarını göstərir. Yəni 67 nömrəsini əldə etmək üçün 6 indeksli massiv elementinə daxil olmaq lazımdır:
int number = array[6];
Burada hər şey çox sadədir. İkiölçülü massiv birölçülü massivlərdən ibarət massivdir. Əgər bu haqda ilk dəfə eşidirsənsə, dayan və bunu beynində təsəvvür et. İki ölçülü massiv belə görünür:
0 Birölçülü massiv Birölçülü massiv
1 Birölçülü massiv
2 Birölçülü massiv
3 Birölçülü massiv
4 Birölçülü massiv
5 Birölçülü massiv
6 Birölçülü massiv
7 Birölçülü massiv
Kodda:
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 dəyərini əldə etmək üçün siz [4][2] ünvanındakı matris elementinə daxil olmalısınız.
int number = matrix[4][2];
Diqqət etsəniz, matrisin koordinatları klassik düzbucaqlı koordinat sistemindən (Kartezian koordinat sistemi) fərqlidir. Matrisə daxil olarkən əvvəlcə y, sonra isə x-i təyin edirsiniz , halbuki riyaziyyatda əvvəlcə x(x, y)-ni təyin etmək adi haldır. Siz özünüzdən soruşa bilərsiniz: “Niyə təsəvvürünüzdəki matrisi tərsinə çevirməyəsiniz və elementlərə adi şəkildə (x, y) daxil olmağasiniz? Bu, matrisin məzmununu dəyişməyəcək”. Bəli, heç nə dəyişməyəcək. Lakin proqramlaşdırma dünyasında matrislərə “əvvəlcə y, sonra x” şəklində müraciət etmək adətdir. Bunu təbii qəbul etmək lazımdır. İndi matrisin mühərrikimizə (sinif Game) proyeksiyası haqqında danışaq. Bildiyiniz kimi, mühərrikdə verilmiş koordinatlarda oyun sahəsinin hüceyrələrini dəyişdirən bir çox üsul var. Məsələn, setCellValue(int x, int y, String value). Koordinatları (x, y) olan müəyyən bir xananı dəyərinə təyin edir value. Diqqət etdiyiniz kimi, bu üsul əvvəlcə klassik koordinat sistemində olduğu kimi, tam olaraq x götürür. Qalan mühərrik üsulları oxşar şəkildə işləyir. Oyunları inkişaf etdirərkən, tez-tez ekranda matrisin vəziyyətini təkrarlamaq ehtiyacı olacaq. Bunu necə etmək olar? Birincisi, bir döngədə matrisin bütün elementlərini təkrarlamaq lazımdır. İkincisi, onların hər biri üçün İNVERTED koordinatları ilə göstərmək üçün bir metod çağırın. Misal:
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]));
        }
    }
}
Təbii ki, inversiya iki istiqamətdə işləyir. Siz (i, j) metoduna setCellValuekeçə bilərsiniz , lakin eyni zamanda matrisdən [j][i] elementini götürə bilərsiniz. İnversiya bir az çətin görünə bilər, amma bunu nəzərə almaq lazımdır. Həmişə, hər hansı bir problem yaranarsa, qələmlə bir kağız parçası götürməyə, bir matris çəkməyə və onunla hansı proseslərin baş verdiyini təkrarlamağa dəyər.

5. Təsadüfi nömrələr

Təsadüfi ədəd generatoru ilə necə işləmək olar? Sinif Gamemetodu müəyyən edir getRandomNumber(int). Başlıq altında Randomjava.util paketindən bir sinifdən istifadə edir, lakin bu, təsadüfi ədədlər generatoru ilə işləmə prinsipini dəyişmir. Arqument kimi getRandomNumber(int)tam ədəd götürür . Bu rəqəm generatorun qaytara biləcəyi yuxarı hədd olacaqdır. Aşağı hədd 0-dır. Vacibdir! Generator heç vaxt yuxarı həddi qaytarmayacaq. Məsələn, təsadüfi çağırıldıqda getRandomNumber(3)0, 1, 2 qaytara bilər. Gördüyünüz kimi, 3-ü qaytara bilməz. Generatorun bu şəkildə istifadəsi olduqca sadədir, lakin bir çox hallarda çox təsirlidir. Bəzi məhdudiyyətlər daxilində təsadüfi bir ədəd əldə etməlisiniz: Təsəvvür edin ki, sizə hansısa üç rəqəmli rəqəm lazımdır (100..999). Artıq bildiyiniz kimi, qaytarılan minimum rəqəm 0-dır.Deməli, ona 100 əlavə etməli olacaqsınız.Lakin bu halda yuxarı həddi keçməməyə diqqət etməlisiniz. Maksimum təsadüfi dəyər kimi 999 almaq üçün 1000 arqumenti olan metodu çağırmalısınız. getRandomNumber(int)Amma biz 100-ün sonrakı əlavəsini xatırlayırıq: bu o deməkdir ki, yuxarı həddi 100-ə endirmək lazımdır. təsadüfi üç rəqəmli nömrə belə görünür:
int number = 100 + getRandomNumber(900);
Ancaq belə bir proseduru sadələşdirmək üçün mühərrik getRandomNumber(int, int)ilk arqument kimi geri dönmək üçün minimum sayı götürən bir üsul təqdim edir. Bu metoddan istifadə edərək, əvvəlki nümunə yenidən yazıla bilər:
int number = getRandomNumber(100, 1000);
Təsadüfi nömrələr təsadüfi massiv elementini əldə etmək üçün istifadə edilə bilər:
String [] names = {"Andrey", "Валентин", "Сергей"};
String randomName = names[getRandomNumber(names.length)]
Müəyyən bir ehtimalla müəyyən hadisələrin tetiklenmesi. Bir insanın səhəri mümkün ssenarilərə görə başlayır: Çox yatdı – 50%; vaxtında qalxmaq - 40%; Gözləniləndən bir saat əvvəl qalxdı - 10%. Təsəvvür edin ki, bir insan səhər emulyatoru yazırsınız. Müəyyən bir ehtimalla hadisələri tetiklemek lazımdır. Bunu etmək üçün yenə də təsadüfi ədəd generatorundan istifadə etməlisiniz. Tətbiqlər fərqli ola bilər, lakin ən sadəsi aşağıdakı alqoritmə əməl etməlidir:
  1. nömrənin yaradılması üçün lazım olan məhdudiyyətləri təyin edirik;
  2. təsadüfi nömrə yaratmaq;
  3. Yaranan nömrəni emal edirik.
Beləliklə, bu halda limit 10 olacaq. Gəlin metodu çağıraq getRandomNumber(10)və onun bizə nə qaytara biləcəyini təhlil edək. 10 rəqəmi (0-dan 9-a qədər) və hər biri eyni ehtimalla - 10% qaytara bilər. İndi biz bütün mümkün nəticələri birləşdirməliyik və onları mümkün hadisələrlə uyğunlaşdırmalıyıq. Təsəvvürünüzdən asılı olaraq bir çox kombinasiya ola bilər, lakin ən bariz səslər: “Əgər təsadüfi bir ədəd [0..4] daxilindədirsə - “Uydurma” hadisəsini çağırın, əgər nömrə [5..8] daxilindədirsə. ] - "Vaxtında oyan" və yalnız rəqəm 9 olarsa, "gözləniləndən bir saat tez durdum". Hər şey çox sadədir: [0..4] daxilində 5 ədəd var, onların hər biri 10% ehtimalla qayıda bilər ki, bu da ümumilikdə 50% olacaq; [5..8] daxilində 4 ədəd var və 9 10% ehtimalı ilə görünən yeganə rəqəmdir. Kodda bütün bu ağıllı dizayn daha sadə görünür:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Проспал ");
} else if (randomNumber < 9) {
    System.out.println("Встал вовремя ");
} else {
    System.out.println("Встал на час раньше положенного ");
}
Ümumiyyətlə, təsadüfi ədədlərdən istifadə etmək üçün bir çox variant ola bilər. Hamısı yalnız təsəvvürünüzdən asılıdır. Ancaq təkrar-təkrar bəzi nəticə əldə etmək lazımdırsa, onlar ən effektiv şəkildə istifadə olunur. Onda bu nəticə əvvəlkindən fərqli olacaq. Təbii ki, müəyyən ehtimalla. Hamısı budur! Oyunlar bölməsi haqqında daha çox öyrənmək istəyirsinizsə, burada kömək edə biləcək bəzi faydalı sənədlər var:
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION