Ballspiel mit Gyrosensor (open source :-)

Hallo liebe Leute!

Hier ist ein kleines Spiel, bei dem man per Neigung des Geräts einen grünen Ball bewegt, um andere grüne Bälle einzusammeln und dabei sich ständig vermehrenden roten Punkten aus dem Weg gehen muss.
Es gibt ein Zeitlimit, es gibt Punkte, und es gibt eine Highscore.

Mit letzterer gibt es allerdings Probleme.
Bei der Highscore wird immer nur der erste Buchstabe des Spielerkürzels (drei Buchstaben sollten möglich sein) gespeichert

Achso... fast vergessen: Hardware:
Arduino Uno Rev.3
Waveshare 4inch TFT-Touch-Shield mit SD-Slot

GY61 ADXL335 Gyrosensor (an Pins 3,4,5)
Akku aus ehemaliger Powerbank inkl. elektronischem Schnickschnack (an Vin und GND)
Externen Resetknopf wegen Zugänglichkeit in Gehäuse drangelötet

[ der Quellcode ist zu lang zum posten, ich schick ihn hinterher. ]

...wie gesagt, die ganze Klamotte mit der Highscore ist inzwischen etwas aus dem Ruder gelaufen.
Warum nur speichert er die letzten beiden Buchstaben nicht?! >:(

Die Highscore-Datei hat das Format

ACB 123
DEF 456
...
BLA 200

und das Ganze in 11 Zeilen.
Zehn Zeilen Highscore, eine elfte wird mit der aktuellen Punktezahl und dem Namen hinzugefügt, alles wird sortiert und neu geschrieben. Theorie ist einfach...
Aber...
Beispiel: Name sollte MJK sein, Punkte 333.
In die Datei kommt

M[\0][\0] 333

...Sortierung funktioniert, nur Name nicht.
"[\0]" steht natürlich nicht so in der Datei, mein Editor zeigt mir diese schwarz hinterlegte "0" an...

Liebe, verzweifelte Grüße :wink:

// CODE TEIL EINS (ZU LANG FÜR POST) //

#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Waveshare4InchTftShield.h>

#define error(s) sd.errorHalt(F(s))  // store error strings in flash to save RAM
#define BLACK   0x0000  // Farben zum leichteren Zugriff
#define BLUE    0x001F
#define GREEN   0x07E0
#define MAX_ENEMIES 30  // maximale Anzahl roter Punkte

Waveshare4InchTftShield Waveshield; // Waveshield-TFT erstellen
Adafruit_GFX &tft = Waveshield;     // und mit Adafruit-Lib koppeln

bool SDCard=true;  // Kann die Highscore gespeichert werden?
int timeLeft = 90,             // verbleibende Spielzeit
    timeLeftOld = 0;           // testet, ob sich was getan hat
int ax, ay, az,                // Achsen des Gyrosensors
    calibX, calibY, calibZ;    // Kalibrierung 
int bkColor = BLUE;            // Hintergrundfarbe des Spielfelds festlegen

// Ja, man könnte das Ganze wirklich objektorientierter gestalten...
// Mach ich vielleicht auch irgendwann.

// Spielerdaten
int playerX = 20, playerY = 20, playerRadius = 10,
    playerSpeedX = 1, playerSpeedY = 1, playerSpeedZ = 1, 
    playerColor = GREEN,
    playerXold, playerYold,
    playerHealth = 100,
    playerScore = 0, playerScoreOld = 1;
// Bonusdaten
int bonusX, bonusY, 
    bonusXold, bonusYold,
    bonusRadius = 10, bonusColor = GREEN;
int numEnemies=-1; // aktuelle Anzahl der roten Punkte
int enemyX[MAX_ENEMIES], enemyY[MAX_ENEMIES],
    enemyXold[MAX_ENEMIES], enemyYold[MAX_ENEMIES],
    enemyRadius[MAX_ENEMIES], enemyColor[MAX_ENEMIES];
char highscoreName[10][4],      // Top-Ten für I/O
     highscorePoints[10][4];
File fHighscore;                // Datei für die Highscore
char charName[4] = {'M','J','K','\0'}; // aktuell eingegebener Highscore-Name
unsigned int timeToInit;        //Zeit, die für die Initialisierung benötigt wird


uint16_t rgb2int(uint8_t r, uint8_t g, uint8_t b) // Umwandlung von GRB-Wert in Interger
{ 
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}

int addEnemy()
{
  numEnemies++;
  newEnemy(numEnemies);
}

int removeEnemy()
{
  tft.fillCircle(enemyX[numEnemies], enemyY[numEnemies], enemyRadius[numEnemies], bkColor);
  numEnemies--;
  for (int i = 0; i < numEnemies - 1; i++) drawEnemy(i, 1);
}

int newBonus()
{
  bool bonusCollides = false; 
  bonusRadius = 10;
   
  do {
    bonusX = random(tft.width() - bonusRadius) + bonusRadius;
    bonusY = random(tft.height() - bonusRadius - 20) + bonusRadius + 20;
    bonusCollides = false;
    for (int i=0; i < numEnemies + 1; i++)
    {  
      bonusCollides = (((bonusX > playerX - playerRadius - 10) && (bonusX < playerX + playerRadius + 10) && (bonusY > playerY - playerRadius - 10) && (bonusY < playerX + playerRadius + 10)) ||
                       ((enemyX[i] > bonusX - bonusRadius - 10) && (enemyX[i] < bonusX + bonusRadius + 10) && (enemyY[i] > bonusY - bonusRadius - 10) && (enemyY[i] < bonusY + bonusRadius + 10)));
      if (bonusCollides) break;
    }
  } 
  while (bonusCollides == true);
  
  drawBonus(1);
}

int newEnemy(int num)
{
  enemyRadius[num]=5;
  enemyColor[num]=GREEN;
  // der rote Punkt soll nicht beim Bonus und nicht beim Spieler landen. Das wäre echt unfair ;-)
  do 
  {     
    enemyX[num] = random(tft.width() - enemyRadius[num]) + enemyRadius[num];
    enemyY[num] = random(tft.height() - enemyRadius[num] - 20) + enemyRadius[num] + 20;
  }
  while (((enemyX[num] > playerX - playerRadius - 10) && (enemyX[num] < playerX + playerRadius + 10) && (enemyY[num] > playerY - playerRadius - 10) && (enemyY[num] < playerY + playerRadius + 10)) ||
         ((enemyX[num] > bonusX - bonusRadius - 10) && (enemyX[num] < bonusX + bonusRadius + 10) && (enemyY[num] > bonusY - bonusRadius - 10) && (enemyY[num] < bonusY + bonusRadius + 10)));
 
  drawEnemy(num, 0);
}

int bonusCollision()
{
  if ((playerX + playerRadius > bonusX - bonusRadius) &&
      (playerY + playerRadius > bonusY - bonusRadius) &&
      (playerX - playerRadius < bonusX + bonusRadius) &&
      (playerY - playerRadius < bonusY + bonusRadius)) {
    newBonus();
    drawPlayer(1);
    for (int i = 0; i < numEnemies + 1; i++) drawEnemy(i, 0);
    playerScore += 10;
    addEnemy();
  }
}

int enemyCollision(int num)
{
  if ((playerX + playerRadius > enemyX[num] - enemyRadius[num]) &&
      (playerY + playerRadius > enemyY[num] - enemyRadius[num]) &&
      (playerX - playerRadius < enemyX[num] + enemyRadius[num]) &&
      (playerY - playerRadius < enemyY[num] + enemyRadius[num])) {
    newEnemy(num);
    removeEnemy();
    for (int i = 0; i < numEnemies + 1; i++) drawEnemy(i, 0);
    playerScore -= 20;
    if (playerScore < 0) playerScore = 0;
  }
}

int drawPlayer(int force)
{
  if ((playerX != playerXold) || (playerY != playerYold) || (force == 1))
  {
    tft.fillCircle(playerXold, playerYold, playerRadius, bkColor);
    tft.fillCircle(playerX, playerY, playerRadius, playerColor);
    playerXold = playerX; playerYold = playerY;
  }
}

int drawBonus(int force)
{
  if ((force == 1) || (bonusX != bonusXold) || (bonusY != bonusYold)) {
    tft.fillCircle(bonusXold, bonusYold, bonusRadius, bkColor);
    tft.fillCircle(bonusX, bonusY, bonusRadius, bonusColor);
    bonusXold = bonusX; bonusYold = bonusY;
  }
}

int drawEnemy(int num, int force)
{
  if ((enemyX[num] != enemyXold[num]) || (enemyY[num] != enemyYold[num]) || (force == 1)) {
    tft.fillCircle(enemyXold[num], enemyYold[num], enemyRadius[num], bkColor);
    tft.fillCircle(enemyX[num], enemyY[num], enemyRadius[num], rgb2int(255, 0, 0));
    enemyXold[num] = enemyX[num]; enemyYold[num] = enemyY[num];
  }
}
// CODE TEIL ZWEI                        //
// ab hier wird's (für mich) spannend... //

int readHighscoreFromFile()
{
  char linebuf[11]; // eingelesene Zeile zwischenspeichern
  int counter=0;

  fHighscore=SD.open("score.txt", FILE_READ); // Datei öffnen

  for (int i=0; i<10; i++) {
    memset(linebuf,'0',sizeof(linebuf)); // ausnullen des Zeilenspeichers
    counter=0;
    while (fHighscore.available()) {
      linebuf[counter]=fHighscore.read();
      if (linebuf[counter]=='\n') break; // Zeilenende, Schleife verlassen
      if (counter<sizeof(linebuf)-1) counter++;
    }
    highscoreName[i][0]=linebuf[0];
    highscoreName[i][1]=linebuf[1];
    highscoreName[i][2]=linebuf[2];
    highscorePoints[i][0]=linebuf[4];
    highscorePoints[i][1]=linebuf[5];
    highscorePoints[i][2]=linebuf[6];
  }
  
  // Einen elften Highscore-Eintrag mit den aktuellen Punkten erstellen
  char savePoints[4];
  char* sP;
  highscoreName[10][0] = charName[0];  
  highscoreName[10][1] = charName[1];
  highscoreName[10][2] = charName[2];
  highscoreName[10][3] = '\0';
  sP = itoa(playerScore, savePoints, 10);
  highscorePoints[10][0] = savePoints[0];
  highscorePoints[10][1] = savePoints[1];
  highscorePoints[10][2] = savePoints[2];
  highscorePoints[10][3] = '\0';
 
  fHighscore.close();
}

int writeHighscoreToFile()
{
  fHighscore=SD.open("score.txt", FILE_WRITE);  // Datei öffnen
 
  // Jetzt wird sortiert!
  for(unsigned int i = 0; i < 10; i++)  // Alle Elemente durchgehen (letztes ausgenommen)
  {
    unsigned int min_pos = i;  // Position des zurzeit kleinstes Elementes
   
    // unsortierten Teil des Feldes durchlaufen
    // und nach kleinstem Element suchen
    for (unsigned int j = i + 1; j < 11; j++)
      if (atoi(highscorePoints[j]) > atoi(highscorePoints[min_pos])) min_pos = j;
    
    // Elemente vertauschen:
    // Das kleinste Element kommt an das Ende
    // bereits sortierten Teils des Feldes
    char temp[4];   //Punkte zwischenspeichern
    char temp2[4];  // Namen zwischenspeichern
    temp[0] = highscorePoints[i][0];
    temp[1] = highscorePoints[i][1];
    temp[2] = highscorePoints[i][2];
    temp[3] = '\0';
    temp2[0] = highscoreName[i][0];    
    temp2[1] = highscoreName[i][1];    
    temp2[2] = highscoreName[i][2];    
    temp2[3] = '\0';    
    highscorePoints[i][0] = highscorePoints[min_pos][0]; // Punkte tauschen
    highscorePoints[i][1] = highscorePoints[min_pos][1]; 
    highscorePoints[i][2] = highscorePoints[min_pos][2]; 
    highscorePoints[min_pos][0] = temp[0];
    highscorePoints[min_pos][1] = temp[1];
    highscorePoints[min_pos][2] = temp[2];
    highscoreName[i][0] = highscoreName[min_pos][0];  // auch den Namen tauschen, sonst werden NUR die Punkte vertauscht ...
    highscoreName[i][1] = highscoreName[min_pos][1];  // ... und das führt zu falschen Lorbeeren ;-)
    highscoreName[i][2] = highscoreName[min_pos][2];  
    highscoreName[min_pos][0] = temp2[0];             
    highscoreName[min_pos][1] = temp2[1];            
    highscoreName[min_pos][2] = temp2[2];            
  }

  // alles (sortiert) wieder in die Datei schreiben
  for (unsigned int i = 0; i < 11; i++)
  {
    fHighscore.print(highscoreName[i][0]);
    fHighscore.print(highscoreName[i][1]);
    fHighscore.print(highscoreName[i][2]);
    fHighscore.print(" ");
    fHighscore.print(highscorePoints[i][0]);
    fHighscore.print(highscorePoints[i][1]);
    fHighscore.println(highscorePoints[i][2]);
  }
  fHighscore.close();  // Datei wieder schließen
}

int processHighscore()  // Namen eingeben, Highscore laden, aktualisieren und anzeigen
{
  TSPoint p;

  if (!SDCard) { // keine SD-Karte?
    tft.fillRect(0, 0, 480, 320, BLACK);
    tft.setTextColor(rgb2int(255, 0, 0));
    tft.print("Keine SD-Karte gefunden, Highscore nicht möglich :-(");
    do { /*nix*/ } while (333==333);
  }

  tft.fillRect(0,0,480,320,BLUE);
  tft.fillRoundRect(40, 160,40,80,10,rgb2int(0,255,0));
  tft.fillRoundRect(160,160,40,80,10,rgb2int(0,255,0));
  tft.fillRoundRect(280,160,40,80,10,rgb2int(0,255,0));
  tft.fillRoundRect(380,180,80,40,10,rgb2int(0,255,0));
  tft.fillTriangle(60, 100,40, 140,80, 140,rgb2int(0,255,0));
  tft.fillTriangle(180,100,160,140,200,140,rgb2int(0,255,0));
  tft.fillTriangle(300,100,280,140,320,140,rgb2int(0,255,0));
  tft.fillTriangle(60, 300,80, 260,40, 260,rgb2int(0,255,0));
  tft.fillTriangle(180,300,200,260,160,260,rgb2int(0,255,0));
  tft.fillTriangle(300,300,280,260,320,260,rgb2int(0,255,0));
  tft.setTextSize(2); tft.setTextColor(BLACK); tft.setCursor(385,190); tft.print(F("fertig"));
  tft.setTextColor(rgb2int(0,255,0));tft.setCursor(120,40); tft.print(F("Deine Punktzahl: ")); tft.print(playerScore);
  tft.setTextSize(3); tft.setTextColor(BLACK);
  tft.setCursor(50, 190); tft.print(charName[0]);
  tft.setCursor(170,190); tft.print(charName[1]);
  tft.setCursor(290,190); tft.print(charName[2]);
  
  do
  {
    p = Waveshield.getPoint();      // Rohdaten vom Touchscreen holen ...
    Waveshield.normalizeTsPoint(p); // ... und in Bildschirmkoordinaten umwandeln

    if (p.z>10) {   // Wurde der Touchscreen gedrückt?
      // Die ganzen Eingabefelder abfragen
      // (Ja, ja... mit Objekten wäre besser ;-)
      if (p.x>20 && p.x<100 && p.y>80 && p.y<180) charName[0]--;
      if (p.x>140 && p.x<220 && p.y>80 && p.y<180) charName[1]--;
      if (p.x>260 && p.x<340 && p.y>80 && p.y<180) charName[2]--;
      if (p.x>20 && p.x<100 && p.y>220 && p.y<320) charName[0]++;
      if (p.x>140 && p.x<220 && p.y>220 && p.y<320) charName[1]++;
      if (p.x>260 && p.x<340 && p.y>220 && p.y<320) charName[2]++;

      // Die Buchstaben in "menschlichem Rahmen" halten
      for (int i=0; i<3; i++) {
        if (charName[i]<65) charName[i]=90;
        if (charName[i]>90) charName[i]=65;
      }

      // wunderschön zeichnen
      tft.fillRoundRect(40, 160,40,80,10,rgb2int(0,255,0));
      tft.fillRoundRect(160,160,40,80,10,rgb2int(0,255,0));
      tft.fillRoundRect(280,160,40,80,10,rgb2int(0,255,0));
      tft.setCursor(50, 190); tft.print(charName[0]);
      tft.setCursor(170,190); tft.print(charName[1]);
      tft.setCursor(290,190); tft.print(charName[2]);
      // die nächste Zeile würde dafür sorgen, dass gar nichts mehr passiert
      //while (p.z>10) {} // solange nix machen, bis der "Touch" aufgehört hat
      delay(100); // ...stattdessen einfach kurz warten, damit die Buchstabenauswahl nicht durchdreht
    }
  } while (!(p.x>380 && p.y>180 && p.x<480 && p.y<220));  // das Ganze solange wiederholen, bis auf "fertig" gedrückt wurde

  readHighscoreFromFile();  // die Highscore in den Speicher laden
  SD.remove("score.txt");   // und von der SD-Karte löschen! Sonst werden alle Daten angehängt und die Datei wird riesig. Ich brauche doch nur eine "Top-Ten"
  writeHighscoreToFile();   // Werte sortieren (inkl. aktuellen Punkten) und in die Datei schreiben

  // Highscore anzeigen
  tft.fillRect(0, 0, 480, 320, BLACK);
  tft.setTextColor(rgb2int(0, 255, 0)); tft.setCursor(0, 0);
  tft.print(F("\n  \tBESTENLISTE:\t\n\n")); tft.setTextSize(2);
  for (unsigned int i = 0; i < 10; i++) {
    tft.print(F("     \t ")); tft.print(highscoreName[i]); tft.print(F("\t  ")); tft.println(highscorePoints[i]);  
  }
  tft.setTextSize(3); tft.print(F("\n  druecke RESET fuer ein\nneues Spiel,wenn du magst!"));
  do { /*nichts*/ } while (333 == 333); // Für immer und ewig warten (Bei meinem Spiel ist der Resetknopf für "neues Spiel" zuständig!)
}
// ...UND DER LETZTE TEIL... //

void setup()
{
  randomSeed(analogRead(A1)); // dem Zufall etwas auf die Sprünge helfen
  // LCD-Display initialisieren
  SPI.begin();
  Waveshield.begin();
  tft.setRotation(1);
  
  //analogReference(EXTERNAL); // seitdem ich den tollen Akku meiner aufgebohrten Ex-Powerbank benutze, hab ich keine Spannungsschwankungen mehr!

  tft.print(F("Bitte das Spiel gerade halten, ich kalibriere...\n"));
  delay(1000);
    calibY = analogRead(A3); // Werte der Achsen auslesen, während das Board gerade gehalten wird,
    calibX = analogRead(A4); // um so eine Kallibrierung durchzuführen
    calibZ = analogRead(A5);
  tft.print(F("fertig.\n"));
  

  if (!  /*card.init(SPI_HALF_SPEED, 5)*/ SD.begin(5)) // SD-Karte initialisieren
  {
    tft.print(F("SD-Karte nicht erkannt. Keine Highscore :-(\n"));
    SDCard=false;
    delay(2000);
  } else {
    tft.print(F("SD-Karte in Ordnung :-)\n"));
    SDCard=true;
  }
  
  tft.fillRect(0, 0, tft.width(), tft.height(), bkColor);   //Spielfeld zeichenen
  tft.drawFastHLine(0, 19, tft.width(), rgb2int(0, 255, 0));  // obere Spielfeldbegrenzung zeichnen
  // Beschriftung
  tft.setTextSize(2); tft.setTextColor(rgb2int(0, 255, 255)); 
  tft.setCursor(200, 3); tft.print(F("deine Punkte: "));
  tft.setCursor(0, 3); tft.print(F("Zeit:"));

  playerY = tft.height() / 2; // Spieler vertikal ausrichten

  newBonus();    // ersten Bonus erstellen...
  drawBonus(1);  // ...und zeichnen
  playerColor=rgb2int(0, 255, 0); // Spielerfarbe einstellen
  drawPlayer(1); // Spieler zeichnen

  timeToInit=millis(); // Initialisierung fertig; Zeit nehmen, damit später nicht zu wenig Spielzeit bleibt
  
  //zum Testen der Highscore:
  //playerScore=333;
  //processHighscore();
}

void loop()
{
  ay = analogRead(A3) - calibY;  // Daten der drei Achsen auslesen und die Werte abziehen, die entstanden, als das Teil gerade gehalten wurde
  ax = analogRead(A4) - calibX;
  az = analogRead(A5) - calibZ;  // Z könnte man irgendwann zum "hüpfen" benutzen...
    
  playerSpeedX = (ay / 3);        // Geschwindigkeit spielbar machen
  playerSpeedY = (ax / 3);
  playerSpeedZ = az / 3;
    
    
  drawPlayer(0);     //Spielball zeichnen
  bonusCollision();  //Kollision mit Bonus abfragen
  
  //Kollision für jeden roten Ball abfragen
  for (int i = 0; i < numEnemies + 1; i++)
    enemyCollision(i); 
 
  playerXold = playerX; playerYold = playerY; //alte Spielerposition speichern für neuzeichnen

  // Spieler je nach Neigung des Sensors bewegen und innerhalb der Spielfeldgrenzen festhalten
  playerX += playerSpeedX;
  if (playerX < playerRadius) playerX = playerRadius;
  if (playerX > tft.width() - playerRadius) playerX = tft.width() - playerRadius;
  playerY += playerSpeedY;
  if (playerY < playerRadius + 20) playerY = playerRadius + 20;  //+20 wegen Leiste oben
  if (playerY > tft.height() - playerRadius) playerY = tft.height() - playerRadius;
    
    
  timeLeft = 60 - (millis()- timeToInit) / 1000;  // Die Zeit läuft!
    
  if (timeLeft != timeLeftOld) // Zeug nur anzeigen bei veränderten Werten 
  {            
    tft.fillRect(60, 0, 71 ,18, bkColor);
    if (timeLeft > 10) tft.setTextColor(rgb2int(0, 255, 0), bkColor);
      else tft.setTextColor(rgb2int(255, 0, 0), bkColor);
    tft.setCursor(60, 3);
    tft.print(timeLeft);
    timeLeftOld = timeLeft;
  }

  if (playerScore != playerScoreOld) // Zeug nur anzeigen bei veränderten Werten
  {                                  // to do: auslagern in drawScore(), alte Funktion weg
    tft.fillRect(360, 0, 400 ,18, bkColor);
    tft.setCursor(360, 3);
    tft.print(playerScore);
    playerScoreOld = playerScore;
  }

  delay(10); // to do: steuern der Geschwindigkeit mit Millis() und eigener Delay-Funktion
             // aber in diesem Fall egal, der Prozessor wird auf ewig der gleiche sein!
    
  if (timeLeft <= 0) processHighscore(); // Highscore: Namen eingeben, lesen, schreiben, anzeigen
}

Sorry, aber ich denke, es ist immer besser, das ganze Programm zu posten. Der Fehler versteckt sich meist in einem unbeachteten, weit von meiner Fehlersuche entfernten Teil des Codes...

Nochmal Danke :wink:

SCORE.TXT (99 Bytes)

pixelfreak:
Beispiel: Name sollte MJK sein, Punkte 333.
In die Datei kommt

M[\0][\0] 333

...Sortierung funktioniert, nur Name nicht.
"[\0]" steht natürlich nicht so in der Datei, mein Editor zeigt mir diese schwarz hinterlegte "0" an...

Naja, dann wäre es jetzt entweder an der Zeit einen HEX-Editor zu nehmen, oder wenigstens sinnvoller Weise die Datei mit anzuhängen, damit man da mal draufsehen kann.

Wenn da eine fette 0 in irgendeinem unbekannten Editor steht, könnte es sich ebenso um ein notPrintableChar handeln. Wer soll das jetzt erraten?

Hab sie drangehängt (oben).
Nein, ist definitiv nicht druckbar.
Allerdings ist jetzt noch ein nicht druckbares Zeichen dazugekommen: SOH.
Ich hab also
NUL (oder 0x00) (oder "\0") (Zeichenketten-Terminierung) und
SOH (oder 0x01) ("Markiert den Anfang der maschinen-lesbaren Zieladresse oder Routing Information" - Wikipedia*),*
wo eigentlich die letzten beiden Zeichen des Namens stehen sollten :frowning:
Dort, wo das in der Datei noch nicht passiert ist, besteht noch der von mir per Hand geschriebene Eintrag.
Alles, was vom Programm dazukommt, wird zerhackt...

Mein Zwischendurch-Editor unter Windows ist übrigens Notepad++.

pixelfreak:
Hab sie drangehängt (oben).

DANKE!

Allerdings ist jetzt noch ein nicht druckbares Zeichen dazugekommen: SOH.

Alles, was vom Programm dazukommt, wird zerhackt...

Mein Zwischendurch-Editor unter Windows ist übrigens Notepad++.

Na das ist ja mal was.
Unten angefangen:
Das ist gut so. Solche Infos gehören beim nächsten Mal mit dazu, dann spart es Nachfragen. :wink:

Zerhackt ist vielleicht übertrieben. Ich schau nochmal auf den Code, aber... Was hast Du an Debug-Versuchen unternommen?
Mir fehlt derzeit:
a) Ausgaben auf dem seriellen Monitor
b) Die Angabe was passiert, wenn mit externen Editor geschaffene Datei auf der Karte bearbeitet wird

Bei SOH fällt mir als erstes ein, das irgendwas mit der Herkunft nicht passt. Dazu muss ich aber über den Code schauen, den auch verstehen und dann ggfls. analysieren. Da mag ggfls. jemand anderes schneller sein.

a) Ausgaben auf dem seriellen Monitor
b) Die Angabe was passiert, wenn mit externen Editor geschaffene korrekte Datei auf der Karte bearbeitet wird

Bei (a) wäre insbesondere die Ausgabe der gelesenen highscoreName spannend.
(b) wäre wirklich gut zu wissen - dann siehst Du schnell, ob es beim Lesen schon kaputt geht oder dann beim Schreiben.

Ansonsten ist mir nur aufgefallen, dass Du beim Lesen vom File das abschließende '\0' nicht in highscoreName[ i ][3] und highScorePoints[ i ][3] schreibst - nur beim zusätzlich angelegten Element.

Hat das einen bestimmten Grund?

Danke!
Serieller Output, Debugging...
Muss ich wohl :wink:
Das passiert, wenn man so'n Spiel "mal eben" on-the-fly schreibt. Ohne Plan...
Ich glaube inzwischen, dass es ein Speicherproblem ist.
Ich habe zu Testzwecken mir vor Spielbeginn die Highscoretabelle anzeigen lassen.
Im anschließenden Spiel stimmte gegen Ende was mit dem Radius der roten Punkte nicht mehr und bei der Buchstabenauswahl ist der arme Arduino dann komplett ausgefallen :frowning:
Habe 69% Speicher verbraucht, bei Kompilierung. Habe noch mal ein paar Interger ge-unsigned, noch ein paar nicht ge F("")-te Strings gefunden, bringt aber nicht mehr viel.

Wenn das Pogramm mit längerer Laufzeit an allen möglichen Stellen durchdreht ist irgendwas im Speicher daneben...

Ich werde an bestimmten Punkten mal den Speicherzustand "messen", die Variablen prüfen usw,usf...
Aber nicht mehr heute :wink:

Schon doof, wenn alles an der letzten Aufgabe hakt. Das Spiel läuft wie gehofft - "noch eben" Highscore dazu...
Jaja.
Melde mich mit weiteren Erkenntnissen!

Zusatz:
Die Ausgabe der Score ist perfekt! Nix mehr kaputt, er macht auch keine merkwürdigen Sachen mehr mit den Namen!
DANKE!
Das mit den "\0" muss ich jetzt noch eben schnell checken :smiley:

@wno185

Ansonsten ist mir nur aufgefallen, dass Du beim Lesen vom File das abschließende '\0' nicht in highscoreName[ i ][3] und highScorePoints[ i ][3] schreibst - nur beim zusätzlich angelegten Element.

...heftig, dass du das so schnell gesehen hast!

'\0' hinzugefügt. Aber da läuft trotzdem einiges durcheinander...

Ausgabe Datei UND Display:

133 197
MJK 190
MJK 190
MJK 190
KHH 185
KGY 182
ICH 172
Wfd 133
Cfd 133
Jfd 133
Jdf 133

Unterscheidet sich jetzt nicht mehr...
Aber: Die Punkte kennen eigentlich nur 10er-Schritte und ich hatte immer mehr als 200 Punkte! :-
Also nix gewonnen... Ich mach' morgen weiter, ich kann heute nicht mehr denken :wink:

Ah ja - es geht voran :slight_smile:

Dann wäre es hilfreich, wenn Du den aktuellen Sketch nochmal anhängst, damit wir nicht in veraltetem Code suchen. Das sollte als txt-Datei getarntes Attachment eigentlich funktionieren.

Ich kann leider wieder mal nicht mit der Forensoftware und den (skript)Servern....
Nur um das Ganze noch abzurunden - ich hab meinen Text schon runtergekürzt; wno158 war bei der Analyse sowieso schneller.

Sooo...
Also nur um mal wieder zu beweisen, das es sinnvoll ist ALLES was man hat herzugeben...
Du schreibst:

Bei der Highscore wird immer nur der erste Buchstabe des Spielerkürzels (drei Buchstaben sollten möglich sein) gespeichert

Das stimmt schon mal nicht; denn: im nachgereichten File fällt auf: in Zeile 1 und 2 ist noch alles ok.
Auch in Zeile 10 ist wieder alles i.O.
Nur ab Z:3 bis Z:9 stimmt was nicht. Ebenso gilt das für Z:11 - wobei das eventl. noch einen anderen Hintergrund haben könnte.
Also gilt es aufzulösen, wer/was ab Z:3 der Auslöser ist.

Für mich erster Ansatz: Wenn nicht sortiert wird, bleibt es wie ist - wenn sortiert wird, kommt ein \0 an Stelle 2 und 3.

Na schaun wa mal - Du hast Dir ja auch ne Aufgabe gestellt :wink:

char highscoreName[10][4],
     highscorePoints[10][4];

Für die Highscore:
10 Namen mit Punkten PLUS der jeweils neu hinzugefügte!

mit

char highscoreName[11][4],
     highscorePoints[11][4];

funktioniert alles!

...ist mir jetzt echt peinlich... Aber wenigstens kann ich jetzt ruhig schlafen.
Morgen nochmal den Code aufräumen (Debugging-Schnipsel überall, "static"-Statements usw.)

Anmerkung: Ich glaube, ich brauche die Stringterminierung nicht.
Und alle Chars einzeln?
Und alles ziemlich unsauber :wink:

Und wenn man das Spiel durch hat könnte man ein neues Level erreichen, in dem sich die roten Punkte bewegen. und.. und...
Ganz zum Schluß alles nach Android portieren (eine meiner Baustellen, ausßerdem hat ja - bedauerlicherweise - nicht jeder einen Arduino :slight_smile: )

pixelfreak:
funktioniert alles!

Glückwunsch!

...ist mir jetzt echt peinlich...

Peinlich? Nein, nein und nochmal nein!
Erstens hätte der eine oder andere das hier auch gefunden (also das Problem war lösbar), aber Du hast es selbst entdeckt.
Zweitens - viel wichtiger! - jeder von uns hat (in C-artigem Code) schon mal so einen Bock geschossen.
Drittens meinen Respekt dafür, dass Du das so klar kommunizierst. Das kann auch nicht jeder.

Anmerkung: Ich glaube, ich brauche die Stringterminierung nicht.

Ich glaube doch, mindestens für die Points. Beim Sortieren greifst Du mit atoi() auf diese "Strings" zu.

Und alle Chars einzeln?
Und alles ziemlich unsauber :wink:

Nun ja, da ist m.E. wirklich noch Luft nach oben.

Viel Spaß beim weiter lernen und vorankommen!

Das hört so schnell nicht auf. Ich z.B. habe gerade meinen ersten ESP8266 Accesspoint hinbekommen. der sinnvolle Sensordaten (SCD30) bereitstellt - kann also auch ruhig schlafen.

Gute Nacht!