CodeGym /Java blogg /Slumpmässig /Spelsektion på CodeGym: Användbar teori
John Squirrels
Nivå
San Francisco

Spelsektion på CodeGym: Användbar teori

Publicerad i gruppen
I avsnittet "Spel" på CodeGym hittar du spännande projekt som går ut på att skriva populära datorspel. Vill du skapa din egen version av de populära spelen 2048, Minesweeper, Snake och andra spel? Det är enkelt. Vi har gjort spelskrivning till en steg-för-steg-process. Avsnittet "Spel" på CodeGym: Användbar teori - 1För att testa dina förmågor som spelutvecklare behöver du inte vara en avancerad programmerare, men en specifik uppsättning Java-kunskaper är nödvändig. Här hittar du information som kommer att vara användbar när du skriver spel .

1. Arv

Att arbeta med spelmotorn CodeGym innebär att man använder arv. Men vad händer om du inte vet vad det är? Å ena sidan måste du förstå detta ämne: det studeras på nivå 11. Däremot var motorn specialdesignad för att vara väldigt enkel, så man kan komma undan med ytlig kunskap om arv. Så vad är arv? Enkelt uttryckt är arv ett förhållande mellan två klasser. En av dem blir förälder och den andra blir ett barn (ättling). Dessutom kanske föräldraklassen inte ens vet att den har ättlingar. Det får med andra ord ingen speciell fördel genom att ha ättlingar. Men arv ger en ättling många fördelar. Och den viktigaste är att alla överordnade klassens variabler och metoder visas i den understigande klassen som om koden för den överordnade klassen kopierats till den underliggande klassen. Detta är inte en helt korrekt beskrivning, men det räcker för en förenklad förståelse av arv. Exempel 1: Det enklaste arvet.

public class Parent {

}
Klassen Child ärver klassen Parent med hjälp av nyckelordet extends .

public class Child extends Parent {

}
Exempel 2: Använda föräldraklassens variabler.

public class Parent {

   public int age;
   public String name;
}
Klassen Child kan använda förälderklassens ålders- och namnvariabler som om de deklarerades i förälderklassen .

public class Child extends Parent {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
Exempel 3: Använda föräldraklassens metoder.

public class Parent {

   public int age;
   public String name;

   public getName() {
      return name;
  }
}
Klassen Child kan använda Parent- klassens variabler och metoder som om de deklarerades i klassen Child. I det här exemplet använder vi metoden getName() .

public class Child extends Parent {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
Så här ser Child -klassen ut för kompilatorn:

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. Överordnade metoder

Ibland finns det situationer där vi får vår Child-klass att ärva någon mycket användbar förälderklass, tillsammans med alla dess variabler och metoder, men vissa av metoderna fungerar inte riktigt som vi vill att de ska. Eller inte alls som vi vill att de ska. Vad kan vi göra i den här situationen? Vi kan åsidosätta metoden vi inte gillar. Detta är väldigt enkelt att göra: i vår Child-klass deklarerar vi helt enkelt en metod med samma signatur som metoden i Parent-klassen, och sedan skriver vi vår egen kod i den. Exempel 1: Åsidosättande av en metod.

public class Parent {

   public String name;

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

   public getName() {
      return name;
  }
}
Metoden printInfo() visar "Luke, Nej!!!"

public class Child extends Parent{

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

   public void printInfo() {
      setName("Luke");
      System.out.println(getName());
   }
}
Så här ser Child -klassen ut för kompilatorn:

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());
   }
}
Exempel 2: Viss arvsmagi (och överordnad metod).

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";
  }
}
I det här exemplet, om printInfometoden (från klassen Parent) inte åsidosätts i klassen Child, när denna metod anropas på ett Child-objekt, getName()kommer dess metod att anropas istället för Parent-klassens getName()metod.

Parent parent = new Parent ();
parent.printnInfo();
Denna kod visar "Luke" på skärmen.

Child child = new Child ();
child.printnInfo();
Den här koden visar "Luke, jag är din far" på skärmen.
Så här ser Child -klassen ut för kompilatorn:

public class Child extends Parent {

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

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

3. Listor

Om du ännu inte har träffat listor (List), här är en kort översikt. Du hittar fullständig information på nivåerna 6-7 i CodeGym-kursen . Listor har mycket gemensamt med arrayer:
  • du kan lagra mycket data av en specifik typ;
  • de låter dig få föremål efter deras index;
  • elementindex börjar från 0.
Fördelar med listor: Till skillnad från arrayer kan listor ändra storlek dynamiskt. När en lista skapas är dess storlek 0. När du lägger till objekt i en lista ökar dess storlek. Här är ett exempel på hur du skapar en lista:

ArrayList<String> myList = new ArrayList<String>(); // Create a new ArrayList
Värdet inom vinkelparenteserna anger vilken datatyp som listan kan lagra. Här är några metoder för att arbeta med listan:
Koda Kort beskrivning av vad koden gör
ArrayList<String> list = new ArrayList<String>(); Skapa en ny lista med strängar
list.add("name"); Lägg till ett element i slutet av listan
list.add(0, "name"); Lägg till ett element i början av listan
String name = list.get(5); Få ett element genom dess index
list.set(5, "new name"); Ändra ett element med dess index
int count = list.size(); Få antalet element i listan
list.remove(4); Ta bort ett element från listan
Du kan lära dig mer om listor i följande artiklar:
  1. ArrayList klass
  2. ArrayList i bilder
  3. Ta bort ett element från en ArrayList

4. Matriser

Vad är en matris? En matris är inget annat än en rektangulär tabell som kan fyllas med data. Det är med andra ord en tvådimensionell array. Som du säkert vet är arrayer i Java objekt. En standard endimensionell intarray ser ut så här:

int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Vi kan visualisera det så här:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
Den översta raden anger adresserna till cellerna. Med andra ord, för att få siffran 67 måste du komma åt arrayelementet med index 6:

int number = array[6];
Det hela är väldigt enkelt. En tvådimensionell array är en array av endimensionella arrayer. Om du hör om detta för första gången, stanna upp och föreställ dig det i ditt huvud. En tvådimensionell array ser ut så här:
0 Endimensionell array Endimensionell array
1 Endimensionell array
2 Endimensionell array
3 Endimensionell array
4 Endimensionell array
5 Endimensionell array
6 Endimensionell array
7 Endimensionell array
I koden:

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
För att få värdet 47 måste du hänvisa till matriselementet vid [4][2].

int number = matrix[4][2];
Du kanske har märkt att matriskoordinaterna skiljer sig från det klassiska rektangulära koordinatsystemet (kartesiska koordinatsystemet). När du kommer åt matrisen anger du först y-koordinaten och sedan x-koordinaten. Inom matematiken är det vanligt att ange x-koordinaten först, dvs (x, y). Du kanske undrar: "Tja, varför inte rotera din representation av matrisen och sedan komma åt elementen på vanligt sätt med (x, y)? Att göra detta skulle inte ändra innehållet i matrisen". Ja, ingenting skulle förändras. Men i programmeringsvärlden är den accepterade praxis att komma åt matriser "först av y, sedan av x". Du bör acceptera detta som det rätta sättet. Låt oss nu prata om att projicera matrisen till vår motor (Gameklass). Som ni vet har motorn många metoder som ändrar spelplanens celler vid specifika koordinater. Till exempel setCellValue(int x, int y, String value)metoden. Den ställer in en specifik cell med koordinater (x, y) lika med värdeparametern. Du kanske har märkt att den här metoden tar x först, precis som i det klassiska koordinatsystemet. Motorns övriga metoder fungerar på liknande sätt. När man utvecklar spel är det ofta nödvändigt att återge tillståndet för en matris på skärmen. Hur gör vi det? Först måste du iterera genom alla matriselement i en loop. För det andra, anropa visningsmetoden för var och en av dem, med hjälp av REVERSED koordinater. Till exempel:

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]));
        }
    }
}
Naturligtvis fungerar vändningen i båda riktningarna. Du kan passera (i, j) till setCellValuemetoden och samtidigt ta element [j][i] från matrisen. Att vända om koordinaterna kan verka lite svårt, men du måste komma ihåg det. Och alltid, om du stöter på några problem, ska du ta ett papper och en penna, rita matrisen och återskapa processerna som involverar matrisen.

5. Slumptal

Hur arbetar man med en slumptalsgenerator? Klassen Gamedefinierar getRandomNumber(int)metoden. Under huven använder den Randomklassen från java.util-paketet, men sättet du arbetar med slumptalsgeneratorn förändras inte. getRandomNumber(int)tar ett heltal som argument. Detta nummer kommer att vara den övre gränsen för vad generatorn kan returnera. Den nedre gränsen är 0. Viktig! Generatorn kommer ALDRIG att returnera det övre gränstalet. Till exempel, om du anropar getRandomNumber(3), kommer den slumpmässigt att returnera 0, 1 eller 2. Som du kan se kan den inte returnera 3. Att använda generatorn på detta sätt är ganska enkelt, men mycket effektivt i många fall. Anta att du behöver få ett slumptal i något intervall: Föreställ dig att du behöver ett tresiffrigt tal i intervallet [100..999]. Som du redan vet är det minsta antalet returnerade 0. Så du måste lägga till 100. Men i det här fallet måste du se till att inte överskrida den övre gränsen. För att få 999 som det maximala slumpmässiga värdet, ringgetRandomNumber(int)metod med argumentet 1000. Men nu kommer vi ihåg att vi adderar 100 till resultatet: det betyder att den övre gränsen ska reduceras med 100. Med andra ord kommer koden för att få vårt slumpmässiga tresiffriga tal se ut så här :

int number = 100 + getRandomNumber(900);
Men för att förenkla denna procedur tillhandahåller motorn metoden getRandomNumber(int, int)vars första parameter är det minsta antalet att returnera. Med den här metoden kan det föregående exemplet skrivas om enligt följande:

int number = getRandomNumber(100, 1000);
Slumptal kan användas för att få ett slumpmässigt matriselement:

String [] names = {"Sarah", "Val", "Sergey"};
String randomName = names[getRandomNumber(names.length)]
Genererar vissa händelser med viss sannolikhet. För människor börjar morgnarna med några möjliga scenarier: Försov – 50 % chans; Vaknade i tid – 40% chans; Vaknade en timme för tidigt - 10% chans. Föreställ dig att du skriver en morgonresultatgenerator. Du måste generera händelser med en viss sannolikhet. För att göra detta måste du återigen använda en slumptalsgenerator. Olika implementeringar är möjliga, men den enklaste bör baseras på följande algoritm:
  1. ställ in gränserna som används för att generera ett nummer;
  2. generera ett slumptal;
  3. bearbeta det erhållna numret.
I det här fallet blir det maximala 10. RinggetRandomNumber(10)metod och analysera att det kan vi återvända. Den kan returnera 10 nummer (från 0 till 9), var och en med samma sannolikhet - 10%. Nu behöver vi kombinera alla möjliga resultat och mappa dem till våra möjliga evenemang. Din fantasi kanske kommer på många möjliga kombinationer, men här är den mest uppenbara: "Om det slumpmässiga talet är i intervallet [0..4], har vi händelsen "Overslept"; om talet är inom intervallet [5] ..8], har vi händelsen "Vaknade i tid"; och om siffran är 9, så har vi händelsen "Vaknade en timme för tidigt". Det hela är väldigt enkelt. Det finns 5 siffror i intervallet [0] ..4], som var och en kan returneras med en sannolikhet på 10 %, för totalt 50 %; det finns 4 siffror i intervallet [5..8], ja, och 9 är bara ett tal som visas med en sannolikhet på 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");
}
I allmänhet finns det massor av sätt att använda slumptal. Du begränsas bara av din fantasi. Men de används mest effektivt om du upprepade gånger behöver få ett resultat. Då kommer det nya resultatet att skilja sig från det föregående. Med viss sannolikhet förstås. Det var allt tills vidare! Om du vill lära dig mer om avsnittet "Spel", här är lite användbar dokumentation som kan hjälpa:
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION