In het
gedeelte "Games" op CodeGym vind je spannende projecten waarbij je populaire computerspellen moet schrijven. Wil je je eigen versie maken van de populaire games 2048, Minesweeper, Snake en andere games? Het is makkelijk. We hebben het schrijven van games omgezet in een stapsgewijs proces.
Om je vaardigheden als game-ontwikkelaar te testen, hoef je geen gevorderde programmeur te zijn, maar een specifieke set Java-kennis is noodzakelijk. Hier vind je
informatie die nuttig zal zijn bij het schrijven van games .
1. Overerving
Werken met de CodeGym-game-engine omvat het gebruik van overerving. Maar wat als je niet weet wat dat is? Aan de ene kant moet je dit onderwerp begrijpen: het wordt bestudeerd in
niveau 11. Aan de andere kant is de motor speciaal ontworpen om heel eenvoudig te zijn, zodat je weg kunt komen met oppervlakkige kennis van overerving. Dus wat is erfrecht? Simpel gezegd, overerving is een relatie tussen twee klassen. Een van hen wordt de ouder en de ander wordt een kind (afstammeling). Bovendien weet de ouderklasse misschien niet eens dat het afstammelingen heeft. Met andere woorden, het krijgt geen bepaald voordeel door nakomelingen te hebben. Maar overerving geeft een nakomeling veel voordelen. En de belangrijkste is dat alle variabelen en methoden van de ouderklasse in de afstammeling verschijnen alsof de code van de bovenliggende klasse is gekopieerd naar de afstammelingklasse. Dit is niet een geheel nauwkeurige beschrijving, maar het is voldoende voor een vereenvoudigd begrip van overerving.
Voorbeeld 1: De eenvoudigste erfenis.
public class Parent {
}
|
De klasse Child erft de klasse Parent met behulp van het sleutelwoord extends . |
public class Child extends Parent {
}
|
Voorbeeld 2: variabelen van de bovenliggende klasse gebruiken.
public class Parent {
public int age;
public String name;
}
|
De klasse Child kan de leeftijds- en naamvariabelen van de klasse Parent gebruiken alsof ze in de klasse Parent zijn gedeclareerd. |
public class Child extends Parent {
public void printInfo() {
System.out.println(name+" "+age);
}
}
|
Voorbeeld 3: de methoden van de bovenliggende klasse gebruiken.
public class Parent {
public int age;
public String name;
public getName() {
return name;
}
}
|
De klasse Child kan de variabelen en methoden van de klasse Parent gebruiken alsof ze in de klasse Child zijn gedeclareerd. In dit voorbeeld gebruiken we de getName() methode. |
public class Child extends Parent {
public void printInfo() {
System.out.println(getName()+" "+age);
}
}
|
Zo ziet de klasse
Child eruit voor de compiler:
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. Overschrijvende methoden
Soms zijn er situaties waarin we onze Child-klasse een zeer nuttige Parent-klasse laten erven, samen met al zijn variabelen en methoden, maar sommige methoden werken niet helemaal zoals we willen. Of helemaal niet zoals we willen. Wat kunnen we doen in deze situatie? We kunnen de methode die ons niet aanstaat overschrijven. Dit is heel eenvoudig: in onze Child-klasse declareren we gewoon een methode met dezelfde handtekening als de methode in de Parent-klasse, en dan schrijven we onze eigen code erin.
Voorbeeld 1: een methode overschrijven.
public class Parent {
public String name;
public void setName(String nameNew) {
name = nameNew;
}
public getName() {
return name;
}
}
|
De methode printInfo() geeft "Luke, No!!!" weer. |
public class Child extends Parent{
public void setName(String nameNew) {
name = nameNew + ", No!!!";
}
public void printInfo() {
setName("Luke");
System.out.println(getName());
}
}
|
Zo ziet de klasse
Child eruit voor de compiler:
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());
}
}
Voorbeeld 2: enige overervingsmagie (en methodeoverheersing).
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";
}
}
|
Als in dit voorbeeld de methode (van de Parent-klasse) niet wordt overschreven in de Child-klasse en deze methode wordt aangeroepen voor een Child-object, wordt
printInfo
zijn methode aangeroepen in plaats van de methode van de Parent-klasse.
getName()
getName()
Parent parent = new Parent ();
parent.printnInfo();
|
Deze code toont "Luke" op het scherm. |
Child child = new Child ();
child.printnInfo();
|
Deze code toont "Luke, ik ben je vader" op het scherm. |
Zo ziet de klasse
Child eruit voor de compiler:
public class Child extends Parent {
public getName() {
return "Luke, I am your father";
}
public void printInfo() {
System.out.println(getName());
}
}
3. Lijsten
Als je nog geen lijsten (List) hebt ontmoet, volgt hier een kort overzicht. U vindt de volledige informatie in niveau
6-7 van de CodeGym-cursus .
Lijsten hebben veel gemeen met arrays:
- u kunt veel gegevens van een bepaald type opslaan;
- ze laten je items op hun index krijgen;
- elementindexen beginnen vanaf 0.
Voordelen van lijsten: in tegenstelling tot arrays kunnen lijsten dynamisch van grootte veranderen. Wanneer een lijst wordt gemaakt, is de grootte 0. Naarmate u items aan een lijst toevoegt, neemt de grootte toe. Hier is een voorbeeld van het maken van een lijst:
ArrayList<String> myList = new ArrayList<String>(); // Create a new ArrayList
De waarde tussen punthaken geeft het gegevenstype aan dat de lijst kan opslaan. Hier volgen enkele methoden om met de lijst te werken:
Code |
Korte beschrijving van wat de code doet |
ArrayList<String> list = new ArrayList<String>(); |
Maak een nieuwe lijst met tekenreeksen |
list.add("name"); |
Voeg een element toe aan het einde van de lijst |
list.add(0, "name"); |
Voeg een element toe aan het begin van de lijst |
String name = list.get(5); |
Krijg een element door zijn index |
list.set(5, "new name"); |
Verander een element door zijn index |
int count = list.size(); |
Verkrijg het aantal elementen in de lijst |
list.remove(4); |
Verwijder een element uit de lijst |
In de volgende artikelen vindt u meer informatie over lijsten:
- ArrayList-klasse
- ArrayLijst in afbeeldingen
- Een element verwijderen uit een ArrayList
4. Arrays
Wat is een matrix? Een matrix is niets anders dan een rechthoekige tabel die gevuld kan worden met gegevens. Met andere woorden, het is een tweedimensionale array. Zoals u waarschijnlijk weet, zijn arrays in Java objecten. Een standaard eendimensionale
int
array ziet er als volgt uit:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
We kunnen het als volgt visualiseren:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
32 |
43 |
54 |
15 |
36 |
67 |
28 |
De bovenste rij geeft de adressen van cellen aan. Met andere woorden, om het getal 67 te krijgen, moet u toegang hebben tot het array-element met index 6:
int number = array[6];
Het is allemaal heel eenvoudig. Een tweedimensionale array is een array van eendimensionale arrays. Als je hier voor het eerst over hoort, stop dan en stel je het voor in je hoofd. Een tweedimensionale array ziet er als volgt uit:
0 |
Eendimensionale array |
Eendimensionale array |
1 |
Eendimensionale array |
2 |
Eendimensionale array |
3 |
Eendimensionale array |
4 |
Eendimensionale array |
5 |
Eendimensionale array |
6 |
Eendimensionale array |
7 |
Eendimensionale array |
In code:
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 |
Om de waarde 47 te krijgen, moet u verwijzen naar het matrixelement op [4][2].
int number = matrix[4][2];
Het is je misschien opgevallen dat de matrixcoördinaten verschillen van het klassieke rechthoekige coördinatensysteem (Cartesiaans coördinatensysteem).
Wanneer u de matrix opent, specificeert u eerst de y-coördinaat en vervolgens de x-coördinaat. In de wiskunde is het gebruikelijk om eerst de x-coördinaat op te geven, dwz (x, y). U vraagt zich misschien af: "Waarom draait u uw representatie van de matrix niet en krijgt u dan op de gebruikelijke manier toegang tot de elementen met behulp van (x, y)? Als u dit doet, verandert er niets aan de inhoud van de matrix". Ja, er zou niets veranderen. Maar in de programmeerwereld is de geaccepteerde praktijk om toegang te krijgen tot matrices "eerst door y, dan door x". U dient dit als de juiste manier te accepteren. Laten we het nu hebben over het projecteren van de matrix op onze motor (
Game
klas). Zoals je weet, heeft de engine veel methoden die de cellen van het speelveld op specifieke coördinaten veranderen. De methode bijvoorbeeld
setCellValue(int x, int y, String value)
. Het stelt een specifieke cel in met coördinaten (x, y) gelijk aan de waardeparameter. Het is je misschien opgevallen dat deze methode eerst x neemt, net als in het klassieke coördinatensysteem. De andere methoden van de engine werken op een vergelijkbare manier. Bij het ontwikkelen van games zal het vaak nodig zijn om de toestand van een matrix op het scherm weer te geven. Hoe doen we dat? Eerst moet u alle matrixelementen in een lus herhalen. Ten tweede, roep de weergavemethode voor elk van hen aan, met behulp van OMGEKEERDE coördinaten. Bijvoorbeeld:
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]));
}
}
}
De omkering werkt natuurlijk in beide richtingen. Je kunt (i, j) doorgeven aan de
setCellValue
methode en tegelijkertijd element [j][i] uit de matrix halen. Het omkeren van de coördinaten lijkt misschien een beetje moeilijk, maar je moet het onthouden. En als je problemen tegenkomt, pak dan altijd een stuk papier en een pen, teken de matrix en reproduceer de processen waarbij de matrix betrokken is.
5. Willekeurige getallen
Hoe werk je met een random number generator? De
Game
klasse definieert de
getRandomNumber(int)
methode. Onder de motorkap gebruikt het de
Random
klasse van het java.util-pakket, maar de manier waarop u met de generator voor willekeurige getallen werkt, verandert niet.
getRandomNumber(int)
neemt een geheel getal als argument. Dit aantal is de bovengrens van wat de generator kan retourneren. De ondergrens is 0.
Belangrijk! De generator zal NOOIT het bovenste limietnummer retourneren. Als u bijvoorbeeld aanroept
getRandomNumber(3)
, zal het willekeurig 0, 1 of 2 retourneren. Zoals u kunt zien, kan het geen 3 retourneren. Het op deze manier gebruiken van de generator is vrij eenvoudig, maar in veel gevallen zeer effectief.
Stel dat u een willekeurig getal in een bepaald bereik nodig heeft: Stel u voor dat u een driecijferig getal in het bereik [100..999] nodig hebt. Zoals u al weet, is het minimum geretourneerde aantal 0. U moet dus 100 optellen. Maar in dit geval moet u ervoor zorgen dat u de bovengrens niet overschrijdt. Om 999 als maximale willekeurige waarde te krijgen, bel je de
getRandomNumber(int)
methode met het argument 1000. Maar nu onthouden we dat we 100 optellen bij het resultaat: dit betekent dat de bovengrens met 100 moet worden verminderd. Met andere woorden, de code om ons willekeurige driecijferige getal te krijgen, ziet er als volgt uit :
int number = 100 + getRandomNumber(900);
Maar om deze procedure te vereenvoudigen, biedt de engine de
getRandomNumber(int, int)
methode waarvan de eerste parameter het minimum aantal is dat moet worden geretourneerd. Met deze methode kan het vorige voorbeeld als volgt worden herschreven:
int number = getRandomNumber(100, 1000);
Willekeurige getallen kunnen worden gebruikt om een willekeurig array-element te krijgen:
String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
Het genereren van bepaalde gebeurtenissen met enige waarschijnlijkheid. Voor mensen beginnen de ochtenden met een paar mogelijke scenario's: Verslapen – 50% kans; Op tijd wakker – 40% kans; Een uur te vroeg wakker - 10% kans. Stel je voor dat je een generator voor de ochtenduitkomst schrijft. U moet gebeurtenissen genereren met een bepaalde waarschijnlijkheid. Om dit te doen, moet u opnieuw een generator voor willekeurige getallen gebruiken. Er zijn verschillende implementaties mogelijk, maar de eenvoudigste moet gebaseerd zijn op het volgende algoritme:
- stel de limieten in die worden gebruikt om een getal te genereren;
- genereer een willekeurig getal;
- verwerk het verkregen nummer.
In dit geval is het maximum 10. Bel de
getRandomNumber(10)
methode en analyseer dat we het kunnen retourneren. Het kan 10 getallen retourneren (van 0 tot 9), elk met dezelfde waarschijnlijkheid - 10%. Nu moeten we alle mogelijke resultaten combineren en toewijzen aan onze mogelijke gebeurtenissen. Je fantasie kan veel mogelijke combinaties bedenken, maar hier is de meest voor de hand liggende: "Als het willekeurige getal in het bereik [0..4] ligt, hebben we de gebeurtenis "Overslapen", als het getal in het bereik [5 ..8], hebben we de gebeurtenis "Wordt op tijd wakker"; en als het nummer 9 is, hebben we de gebeurtenis "Wordt een uur te vroeg wakker". Het is allemaal heel eenvoudig. Er zijn 5 getallen in het bereik [0 ..4], die elk kunnen worden geretourneerd met een waarschijnlijkheid van 10%, voor een totaal van 50%; er zijn 4 getallen in het bereik [5..8], nou ja, en 9 is slechts één getal dat verschijnt met een kans van 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");
}
Over het algemeen zijn er tal van manieren om willekeurige getallen te gebruiken. Je wordt alleen beperkt door je verbeeldingskracht. Maar ze worden het meest effectief gebruikt als u herhaaldelijk resultaat moet behalen. Dan zal het nieuwe resultaat anders zijn dan het vorige. Met enige waarschijnlijkheid natuurlijk. Dat is het voor nu! Als u meer wilt weten over het gedeelte "Games", vindt u hier wat nuttige documentatie die kan helpen:
GO TO FULL VERSION