JavaRush /จาวาบล็อก /Random-TH /ส่วน "เกม" บน JavaRush: ทฤษฎีที่มีประโยชน์

ส่วน "เกม" บน JavaRush: ทฤษฎีที่มีประโยชน์

เผยแพร่ในกลุ่ม
ในส่วน "เกม"ของ JavaRush คุณจะพบกับโปรเจ็กต์ที่น่าตื่นเต้นสำหรับการเขียนเกมคอมพิวเตอร์ยอดนิยม คุณต้องการสร้างเกมยอดนิยม "2048", "Sapper", "Snake" และเกมอื่น ๆ ในเวอร์ชันของคุณเองหรือไม่? มันง่ายมาก เราได้เปลี่ยนการเขียนเกมให้เป็นกระบวนการทีละขั้นตอน บทหากต้องการลองตัวเองในฐานะนักพัฒนาเกม คุณไม่จำเป็นต้องเป็นโปรแกรมเมอร์ขั้นสูง แต่ยังจำเป็นต้องมีความรู้ Java บางชุด ที่นี่คุณจะพบข้อมูลที่เป็นประโยชน์ในการเขียนเกม

1. มรดก

การทำงานกับเอ็นจิ้นเกม JavaRush เกี่ยวข้องกับการใช้การสืบทอด แต่ถ้าคุณไม่รู้ว่ามันคืออะไร? ในอีกด้านหนึ่ง คุณต้องเข้าใจหัวข้อนี้: มีการศึกษาที่ระดับ 11 . ในทางกลับกัน เครื่องยนต์ได้รับการออกแบบอย่างจงใจให้เรียบง่ายมาก ดังนั้นคุณจึงสามารถเรียนรู้เกี่ยวกับมรดกได้อย่างผิวเผิน แล้วมรดกคืออะไร? พูดง่ายๆ ก็คือ มรดกคือความสัมพันธ์ระหว่างสองคลาส หนึ่งในนั้นกลายเป็นพ่อแม่ และคนที่สองกลายเป็นลูก (ชั้นสืบทอด) ในกรณีนี้ คลาสแม่อาจไม่รู้ด้วยซ้ำว่ามีคลาสที่สืบทอดมา เหล่านั้น. มันไม่ได้รับผลประโยชน์ใด ๆ เป็นพิเศษจากการมีคลาสผู้สืบทอด แต่การสืบทอดนั้นให้ข้อดีหลายประการแก่คลาสผู้สืบทอด และสิ่งสำคัญคือตัวแปรและวิธีการทั้งหมดของคลาสพาเรนต์จะปรากฏในคลาสลูก ราวกับว่าโค้ดของคลาสพาเรนต์ถูกคัดลอกไปยังคลาสลูก สิ่งนี้ไม่เป็นความจริงทั้งหมด แต่เพื่อให้เข้าใจถึงมรดกได้ง่ายขึ้น ต่อไปนี้เป็นตัวอย่างบางส่วนเพื่อให้เข้าใจถึงมรดกได้ดียิ่งขึ้น ตัวอย่างที่ 1:มรดกที่ง่ายที่สุด
public class Родитель {

}
คลาสChildสืบทอดมาจากคลาส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();
รหัสนี้แสดงข้อความ"ลุค"บน หน้าจอ
Потомок child = new Потомок ();
child.printnInfo();
รหัสนี้แสดงข้อความว่า"ฉันเป็นพ่อของคุณ ลุค" .
นี่คือลักษณะของ คลาส Descendantจากมุมมองของคอมไพเลอร์:
public class Потомок extends Родитель {

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

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

3. รายการ

หากคุณยังไม่เคยพบกับ Lists นี่เป็นข้อมูลเบื้องต้นสั้นๆ คุณสามารถค้นหาข้อมูลที่สมบูรณ์เกี่ยวกับ ระดับ 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. อาร์เรย์

เมทริกซ์คืออะไร? เมทริกซ์ไม่มีอะไรมากไปกว่าตารางสี่เหลี่ยมที่สามารถเติมข้อมูลได้ กล่าวอีกนัยหนึ่ง มันคืออาร์เรย์สองมิติ ดังที่คุณคงทราบแล้วว่าอาร์เรย์ใน Java เป็นวัตถุ ประเภทอาร์เรย์หนึ่งมิติมาตรฐาน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)ด้วยอาร์กิวเมนต์ 1,000 แต่เราจำได้เกี่ยวกับการบวก 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