ใน
ส่วน "เกม"บน CodeGym คุณจะพบโปรเจ็กต์ที่น่าตื่นเต้นที่เกี่ยวข้องกับการเขียนเกมคอมพิวเตอร์ยอดนิยม ต้องการสร้างเกมยอดนิยม 2048, Minesweeper, Snake และเกมอื่นๆ ในเวอร์ชั่นของคุณเองหรือไม่? มันง่าย เราได้เปลี่ยนการเขียนเกมให้เป็นกระบวนการทีละขั้นตอน
![ส่วน "เกม" ใน CodeGym: ทฤษฎีที่เป็นประโยชน์ - 1]()
เพื่อทดสอบความสามารถของคุณในฐานะนักพัฒนาเกม คุณไม่จำเป็นต้องเป็นโปรแกรมเมอร์ขั้นสูง แต่จำเป็นต้องมีชุดความรู้เฉพาะของจาวา ที่นี่ คุณจะพบ
ข้อมูลที่เป็นประโยชน์ในการเขียนเกม
1. มรดก
การทำงานกับเอ็นจิ้นเกม CodeGym เกี่ยวข้องกับการใช้การสืบทอด แต่ถ้าคุณไม่รู้ว่ามันคืออะไร? ในแง่หนึ่ง คุณต้องเข้าใจหัวข้อนี้: ศึกษาใน
ระดับ 11. ในทางกลับกัน เครื่องยนต์ได้รับการออกแบบมาเป็นพิเศษให้มีความเรียบง่าย ดังนั้นคุณจึงสามารถหลีกเลี่ยงความรู้เพียงผิวเผินเกี่ยวกับการสืบทอดได้ ดังนั้นมรดกคืออะไร? พูดง่ายๆ ก็คือ การสืบทอดคือความสัมพันธ์ระหว่างสองคลาส คนหนึ่งกลายเป็นพ่อแม่และอีกคนกลายเป็นลูก (ผู้สืบสกุล) ยิ่งกว่านั้น ชนชั้นผู้ปกครองอาจไม่รู้ด้วยซ้ำว่ามีลูกหลาน กล่าวอีกนัยหนึ่งมันไม่ได้มีข้อได้เปรียบพิเศษใด ๆ จากการมีลูกหลาน แต่มรดกให้ประโยชน์มากมายแก่ลูกหลาน และที่สำคัญที่สุดก็คือตัวแปรและเมธอดของคลาสพาเรนต์ทั้งหมดจะปรากฏในคลาสลูกหลานราวกับว่ารหัสของคลาสพาเรนต์ถูกคัดลอกไปยังคลาสลูกหลาน นี่ไม่ใช่คำอธิบายที่ถูกต้องทั้งหมด แต่จะเพียงพอสำหรับการทำความเข้าใจเรื่องมรดกให้ง่ายขึ้น
ตัวอย่างที่ 1:การสืบทอดที่ง่ายที่สุด
public class Parent {
}
|
คลาสลูกสืบทอด คลาส พาเรนต์โดยใช้คีย์เวิร์ดขยาย |
public class Child extends Parent {
}
|
ตัวอย่างที่ 2:การใช้ตัวแปรของคลาสพาเรนต์
public class Parent {
public int age;
public String name;
}
|
คลาสลูก สามารถใช้ตัวแปร อายุและชื่อของคลาสพาเรนต์ได้เหมือนกับที่ประกาศในคลาสพาเรนต์ |
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;
}
}
|
คลาสลูกสามารถใช้ ตัวแปรและเมธอดของคลาส พาเรนต์ได้เหมือนกับที่ประกาศไว้ในคลาสลูก ในตัวอย่างนี้ เราใช้เมธอด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
เมธอด (จากคลาสพาเรนต์) ไม่ถูกแทนที่ในคลาสลูก เมื่อเมธอดนี้ถูกเรียกใช้บนวัตถุลูก เมธอด
getName()
จะถูกเรียกแทนเมธอดของคลาสพาเร
getName()
นต์
Parent parent = new Parent ();
parent.printnInfo();
|
รหัสนี้แสดง"ลุค"บนหน้าจอ |
Child child = new Child ();
child.printnInfo();
|
รหัสนี้แสดง"Luke ฉันคือพ่อของคุณ"บนหน้าจอ |
นี่คือ ลักษณะของคลาส
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); |
ลบองค์ประกอบออกจากรายการ |
คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับรายการได้จากบทความต่อไปนี้:
- คลาส ArrayList
- ArrayList ในรูปภาพ
- การลบองค์ประกอบออกจาก 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) เท่ากับพารามิเตอร์ค่า คุณอาจสังเกตเห็นว่าวิธีนี้ใช้ 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)
วิธีการที่มีอาร์กิวเมนต์ 1,000 แต่ตอนนี้เราจำได้ว่าเรากำลังเพิ่ม 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%; ตื่นเช้า 1 ชั่วโมง - โอกาส 10% ลองนึกภาพว่าคุณกำลังเขียนโปรแกรมสร้างผลลัพธ์ในตอนเช้า คุณต้องสร้างเหตุการณ์ที่มีความน่าจะเป็น ในการทำเช่นนี้ คุณต้องใช้ตัวสร้างตัวเลขสุ่มอีกครั้ง การใช้งานที่แตกต่างกันเป็นไปได้ แต่วิธีที่ง่ายที่สุดควรขึ้นอยู่กับอัลกอริทึมต่อไปนี้:
- กำหนดขีด จำกัด ที่ใช้ในการสร้างตัวเลข
- สร้างตัวเลขสุ่ม
- ประมวลผลหมายเลขที่ได้รับ
ในกรณีนี้ สูงสุดจะเป็น 10 โทร
getRandomNumber(10)
วิธีการและวิเคราะห์ว่าเราสามารถกลับมาได้ สามารถส่งคืนตัวเลข 10 ตัว (ตั้งแต่ 0 ถึง 9) โดยแต่ละตัวมีความน่าจะเป็นเท่ากัน — 10% ตอนนี้เราต้องรวมผลลัพธ์ที่เป็นไปได้ทั้งหมดและจับคู่กับเหตุการณ์ที่เป็นไปได้ของเรา จินตนาการของคุณอาจนึกถึงชุดค่าผสมต่างๆ ที่เป็นไปได้มากมาย แต่ที่เห็นชัดเจนที่สุดคือ "หากตัวเลขสุ่มอยู่ในช่วง [0..4] เราจะมีเหตุการณ์ "นอนเกิน" หากตัวเลขอยู่ในช่วง [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");
}
โดยทั่วไป มีวิธีมากมายในการใช้ตัวเลขสุ่ม คุณถูกจำกัดด้วยจินตนาการของคุณเท่านั้น แต่จะใช้อย่างมีประสิทธิภาพมากที่สุดหากคุณต้องการผลลัพธ์ซ้ำ ๆ จากนั้นผลลัพธ์ใหม่จะแตกต่างจากผลลัพธ์ก่อนหน้า ด้วยความน่าจะเป็นแน่นอน นั่นคือทั้งหมดที่สำหรับตอนนี้! หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับส่วน "เกม" ต่อไปนี้เป็นเอกสารที่มีประโยชน์ซึ่งสามารถช่วยได้:
GO TO FULL VERSION