Highscore

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

Eksemplet her er baseret på en udvidelse af koden med muse-interface i Spilleplade.

For at kunne lave en highscore, så er der lavet et lille spil ud af det.

Program med highscore

Spil-ide

Det eksempel der udvides kan tælle elementer op i en spilleplade ved at der klikkes med musen på dem.

Ideen i dette lille "spil" er at man skal se hvor hurtigt man kan få alle spillepladens elementer til at være ens.

Highscore-elementet

For at kunne omdanne tiden det tager til en highscore, så skal der foretages en omregning, så en hurtig tid giver en stor score, og en langsom tid giver en lav score.

Tiden blive målt i millisekunder, så scoren udregnes ved at dividere et store tal (10.000.000) med spilletiden i millisekunder. Dette beregnes på følgende måde:

int newScore = 10000000 / (millis() - startTid);

Registrering af spilletiden

For at give en reel registrering af hvor lang tid der er gået fra den første brik er talt op, til alle brikker igen er ens, så etableres der en variabel started, som registrerer om spillet er i gang, og når det sættes i gang bliver tidspunktet i millis() registreret i variablen startTid.

Variablerne der registreres i og koden der foretager registreringen ser ud som følger:

boolean started = false;
int startTid;

  if (! started) {
    started = true;
    startTid = millis();
  }

Når spillet afsluttes tages tidsregistretingen af sluttidspunktet, ved at variablen newScore beregnes som beskrevet i highscore-elementet. Samtidigt sættes started til false igen, så man kan starte en nyt spil.

Spil Opbygning

Det aktive i spillet sker når der klikkes på et af felterne, som det er gennemgået i spilleplade, hvor det der skete i originalen blot var at elementet blev talt op - det sker stadigvæk, men her skal der også tjekkes om man har afsluttet spillet.

Tjek af om alle elementer er ens

Som omtalt ved spilletiden, så startes tiden ved klik på det første element.

Afslutningen sker ved at alle elementer er ens - det markeres med variablen finished, der startes med at blive sat true. Det første element på banen (0,0) bliver gemt i variablen comp, som man sammenligner alle de andre elementer med, ved at hele banen løbes igennem. Hvis man finder et element der er forskelligt fra, så sættes finished til false, for at sige at spillet ikke er færdigt.

  boolean finished = true;
  boolean ramt = false;
  int comp = bane[0][0];  // Første baneelement for sammenligning

      if (comp != bane[n][i]) { // Hvis ikke alle er ens
        finished = false;
      }

For at man ikke kan stå med at alle elementer er ens i banen (som ved starten af spillet), og man så klikker uden for elementerne, så skal man registrere om man har ramt et felt - det gøres ved at sætte variablen ramt til false, og når man så rammer det aktuelle element sættes ramt til true.

Hvis det er det første element der rammes, så tælles det element op, men for at sammenligningen skal fungere så er man nødt til også at tælle comp en op.

      if (dist < 15) {  // Klikket inden for aktuelt element
        bane[n][i]++;
        ramt = true;
        if (n == 0 && i == 0) {
          comp++;
        }
      }

Highscore

Selve highscoren håndteres i et array score med 10 elementer, og ved hjælp af håndteringen af størrelserne sikres at det altid er det største element der ligger i starten af arrayet, og at de er sorteret efter størrelse. Første gang programmet startes sættes alle score-værdierne til 0, som det omtales under filhåndtering af highscoren.

Arrayet er erklæret som vist her.

int [] score = new int [10];

Visningen af highscoren på skærmen laves som det er vist her, hvor der angives nummeret på pladsen og den score der er opnået.

  // Udskriv highscore-listen
  text("Score", 165, 30);
  for (int n = 0; n < 10; n++) {
    text((n+1) + ".", 140, 30 * n + 60);
    text(score[n], 180, 30 * n + 60);
  }

Håndtering i data-modellen

For at der skal registreres en score, så skal både finished og ramt være true.

Ud fra en tilpasset formel beregnes den aktuelle score, og der indikeres i started, at spillet ikke er i gang længere.

  if (finished && ramt) {  // Alle elementer ens og der er ramt et element
    int newScore = 10000000 / (millis() - startTid);
    started = false;

  }

Når man har fundet den nye score, så finder man først placeringen af hvor den skal lægges ind i arrayet. Hvis den nye score ikke skal ind på listen, så vil ptr blive stående på 10, og skal den stå først, så vil ptr ende med at stå på 0 efter gennemløb af while-løkken, ellers vil ptr komme til at stå på den placering den nye score skal have.

    int ptr = 10;
    // Find ny placering af score
    while (ptr > 0 && score[ptr-1] < newScore) {
      ptr--;
    }

Når positionen i arrayet er fundet, så skal der gives plads til den nye score.

Det gøres ved at løbe igennem fra de laveste scorer og op til der hvor den nye score skal sættes ind. I det område kopieres alle værdier en længere hen i arrayet, så den der ligger lige under den nye score ligger på to pladser. For-løkken sørger for at der ikke flyttes noget hvis det er sidste plads den nye score skal ind på og der flyttes ikke noget, hvis ptr er blevet stående på 10.

    // Ryk de underliggende ned, for at give plads
    for (int n = 8; n >= ptr; n--) {
      score[n+1] = score[n];
    }

Hvis ptr peger ind i arrayet, så skal scoren bare skrives ind i arrayet, som det vises her. I den samme if-betingelse skrives også til en .txt fil som beskrevet. Dette gennemgås i næste afsnit.

    // Indsæt scoren
    if (ptr < 10) {
      score[ptr] = newScore;
    }

Filhåndtering af highscoren

For kunne skrive til harddisken, så skal der være et filnavn. Da det kun er et filnavn "score.txt", der angives, så vil filen komme til at ligge samme sted som koden.

String fileName = "score.txt";

Inde i setup() forsøger programmet at læse i filen med highscore ved hjælp af loadStrings()[1], og hvis filen er der, så forudsættes det at der er 10 linjer i den der kan læses.

Hvis filen ikke eksisterer, så vil der ikke være noget indhold i reader, så den kan testes som null. Hvis det er tilfældet, så skives der 0 i alle 10 scorefelter, så det er klar til at sætte en ny score ind i.

  String[] reader = loadStrings(fileName);
  if (reader == null) {
    println("Ingen fil");
    for (int n = 0; n < 10; n++) {
      score[n] = 0;
    }

Hvis der derimod er en fil, så ligger der 10 linjer med hver sin tekst-udgave af den score der skal være på den aktuelle plads. Dette kan så konverteres med parseInt()[2], linje for lilnje, så arrayet fyldes med den sidste status på score.

  } else {
    println("Der er fil");
    for (int n = 0; n < 10; n++) {
      score[n] = parseInt(reader[n]);
    }
  }

Nede i keyPressed() hvor man lige har sat den nye score ind i score-arrayet sørger man for at opdatere indholdet i score.txt filen. Det gøres ved følgende kode, hvor man nulstiller filen og skaber skriveadgang til den med createWriter()[3], hvorefter alle 10 værdier skrives til filen med output.println(). Efter dette sikres skrivningen til filen og den lukkes igen, så man kan være klar til næste skrivning, når der kommer ny hisghscore.

      PrintWriter output;
      output = createWriter(fileName);
      for (int n = 0; n < 10; n++) {
        output.println(score[n]);
      }
      output.flush(); // Writes the remaining data to the file
      output.close(); // Finishes the file

Hele koden

Herunder ses hele den samlede kode

int xWidth = 3;
int yHeight = 3;
int [][] bane = new int [xWidth][yHeight];
boolean started = false;
int startTid;
int [] score = new int [10];
String fileName = "score.txt";

void setup() {
  for (int n = 0; n < xWidth; n++) {
    for (int i = 0; i < yHeight; i++) {
      bane[n][i] = 0;
    }
  }
  String[] reader = loadStrings(fileName);
  if (reader == null) {
    println("Ingen fil");
    for (int n = 0; n < 10; n++) {
      score[n] = 0;
    }
  } else {
    println("Der er fil");
    for (int n = 0; n < 10; n++) {
      score[n] = parseInt(reader[n]);
    }
  }
  size(260, 360);
  strokeWeight(2);
  textSize(20);
}

void draw() {
  background(255);
  // Tegn banen op
  for (int n = 0; n < xWidth; n++) {
    for (int i = 0; i < yHeight; i++) {
      fill(240);
      ellipse(n*40 + 30, i*40 + 30, 30, 30);
      fill(0);
      text(bane[n][i], n*40 + 23, i*40 + 38);
    }
  }
  // Udskriv highscore-listen
  text("Score", 165, 30);
  for (int n = 0; n < 10; n++) {
    text((n+1) + ".", 140, 30 * n + 60);
    text(score[n], 180, 30 * n + 60);
  }
}

void mousePressed() {
  if (! started) {
    started = true;
    startTid = millis();
  }
  boolean finished = true;
  boolean ramt = false;
  int comp = bane[0][0];  // Første baneelement for sammenligning
  for (int n = 0; n < xWidth; n++) {
    for (int i = 0; i < yHeight; i++) {
      float dist = sqrt(sq(n*40 + 30 - mouseX) + sq(i*40 + 30 - mouseY));
      if (dist < 15) {  // Klikket inden for aktuelt element
        bane[n][i]++;
        ramt = true;
        if (n == 0 && i == 0) {
          comp++;
        }
      }
      if (comp != bane[n][i]) { // Hvis ikke alle er ens
        finished = false;
      }
    }
  }
  if (finished && ramt) {  // Alle elementer ens og der er ramt et element
    int newScore = 10000000 / (millis() - startTid);
    started = false;
    int ptr = 10;
    // Find ny placering af score
    while (ptr > 0 && score[ptr-1] < newScore) {
      ptr--;
    }
    // Ryk de underliggende ned, for at give plads
    for (int n = 8; n >= ptr; n--) {
      score[n+1] = score[n];
    }
    // Indsæt scoren
    if (ptr < 10) {
      score[ptr] = newScore;
      PrintWriter output;
      output = createWriter(fileName);
      for (int n = 0; n < 10; n++) {
        output.println(score[n]);
      }
      output.flush(); // Writes the remaining data to the file
      output.close(); // Finishes the file
    }
  }
}

Referencer

  1. loadStrings() på Processing.org
  2. Converting string to Int
  3. createWriter() på Processing.org