Bei erstellung zweiter Klasse lässt sich mein Oled display nicht mehr Initiallisieren

Hallo,
Ich habe ein Programm für ein Spiel geschrieben (Space Invaders), welches man auf einem Oled Display(SSD1360) Spielen kann, ich benutze dazu den Arduino Uno und die Arduino IDE 2.2.1, nun habe ich habe das Problem, wenn ich eine Zweites Objekt meiner Klasse SpaceInvaders erstelle sich das Oled Display nicht mehr Initialisieren lässt.
Danke im vorhinein, für die Hilfe


//Oled
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

//SpaceInvaders

class SpaceInvaders {
  public:
    class SpaceShip {
      public:
        class Bullet {
          public:
            int x, y;
            int speed = 7;
            bool is_Fired = false;
            char Bullet_Char = '|';

            Bullet(int x, int y) {
              this->x = x;
              this->y = y;
            }

            void update() {
              if(this->y >= 0 && this->is_Fired == true) {
                this->y -= this->speed;
                display.setCursor(this->x, this->y);
                display.println(this->Bullet_Char);
              } else {
                this->is_Fired = false;
              }
            }
        };

      public:
        int x;
        int y;
        char SpaceShip_char = 'A';
        int Bullet_Counter = 0;
        Bullet Bullets[10] = {
          Bullet(this->x, 53), Bullet(this->x, 53), Bullet(this->x, 53),
          Bullet(this->x, 53), Bullet(this->x, 53), Bullet(this->x, 53),
          Bullet(this->x, 53), Bullet(this->x, 53), Bullet(this->x, 53), Bullet(this->x, 53)      
        };

        SpaceShip(int x, int y) {
          this->x = x;
          this->y = y;
        }

        void fire() {
          if(Bullet_Counter <= 10) {
            if(this->Bullets[this->Bullet_Counter].is_Fired == false) {
            this->Bullets[this->Bullet_Counter].is_Fired = true;
            this->Bullets[this->Bullet_Counter].y = this->y;
            this->Bullets[this->Bullet_Counter].x = this->x;
            }
          } else {
            Bullet_Counter = 0;
            if(this->Bullets[this->Bullet_Counter].is_Fired == false) {
            this->Bullets[this->Bullet_Counter].is_Fired = true;
            this->Bullets[this->Bullet_Counter].y = this->y;
            this->Bullets[this->Bullet_Counter].x = this->x;
            }
          }
        }

        void update() {
          if (this->x > 116) {
            this->x = 116;
          } else if (this->x < 0) {
            this->x = 0;
          }
          display.setCursor(this->x, this->y);
          display.println(this->SpaceShip_char);

          //Bullets
          for(int i = 0; i <= Bullet_Counter; i++) {
            if(Bullets[i].is_Fired == true) {
              Bullets[i].update();
            }
          }
        }
    };
    class Alien {
      public:
        float x, y;
        float x_speed = 1;
        float y_speed = 8;
        char Alien_char = 'V';
        bool hit = false;

        Alien(int x, int y) {
          this->x = x;
          this->y = y;
        }

        void update() {
          if(!this->hit) {
            this->x += this->x_speed;
            if(this->x < 0 || this->x > 114) {
              this->x <= 0 ? this->x = 1 : this->x = 112; 
              this->x_speed *= -1; 
              this->x_speed *= 1.1;
              
              this->y += this->y_speed;
            }

            display.setCursor(this->x, this->y);
            display.println(this->Alien_char);
          }  
        }

        void revive() {
          if(this->hit == true) {
              this->x = random(5, 114);
              this->x *= -1;
              this->x_speed = 1;
              this->y = random(1, 21);
              this->hit = false;
            }
        }
    };

  private:
    int Button1, Button2, Button3, Button4;
    unsigned long millis1, millis2, millis3, millis4, millis5, millis6;
    bool running = true;
    unsigned int Time_Between_Shots = 25;
    int Score = 0;
    SpaceShip Spaceship = SpaceShip(60, 53);
    Alien aliens[3] = {
      Alien(1, -10), Alien(10, -10), Alien(20, -10)
    };

  public:
    SpaceInvaders(int Button1, int Button2, int Button3, int Button4) {
      this->Button1 = Button1;
      this->Button2 = Button2;
      this->Button3 = Button3;
      this->Button4 = Button4;     
    }

    bool getButton(String Button) {
      if (Button == "B1") {
        if (digitalRead(Button1) == 1) {
          return false;
        } else {
          return true;
        }
      }
      if (Button == "B2") {
        if (digitalRead(Button2) == 1) {
          return false;
        } else {
          return true;
        }
      }
      if (Button == "B3") {
        if (digitalRead(Button3) == 1) {
          return false;
        } else {
          return true;
        }
      }
      if (Button == "B4") {
        if (digitalRead(Button4) == 1) {
          return false;
        } else {
          return true;
        }
      }
    }

    bool checkWinner() {  
      for(int i=0; i<=2; i++) {
        if(aliens[i].y >= 40) {      
          display.clearDisplay();
          display.setTextSize(3);
          display.setCursor(30, 20);
          display.println("LOSE");
          display.setTextSize(1);
          display.setCursor(37, 45);
          display.println("Punkte: " + String(this->Score));
          display.display();
          this->running = false;
          return true;
        } 
        return false;
      }
    }

    //Game
    void run() {
      this->millis1 = millis();
      this->millis2 = millis();
      this->millis3 = millis();
      this->millis4 = millis();
      this->millis5 = millis();
      this->millis6 = millis();

      for(int i=0; i<=2; i++) {
        this->aliens[i].x = random(5, 114);
        this->aliens[i].y = random(1, 11);
      }

      while (running) {
        //Oled - Clear
        display.clearDisplay();
        display.setTextSize(2);
        
        //Buttons - query
        if ((millis() - this->millis1) >= 50) {
          if (this->getButton("B1") == true) {
            this->millis1 = millis();
            this->Spaceship.x -= 5;
          } else {
          }
        }
        if ((millis() - this->millis2) >= 50) {
          if (this->getButton("B2") == true) {
            this->millis2 = millis();
            this->Spaceship.x += 5;
          } else {
          }
        }
        if((millis() - this->millis3) >= this->Time_Between_Shots) {
          if (this->getButton("B3") == true) {
            this->millis3 = millis();
            this->Spaceship.fire();
          } else {
          }
        }
        if ((millis() - this->millis4) >= 50) {
          if (this->getButton("B4") == true) {
            this->millis4 = millis();
          } else {
          }
        }
      
      //Ueberprefung Kollision Bullets - Alien/s
        for(int i = 0; i <= 10; i++) {
          for(int a=0; a<=2; a++) {
            if(((sqrt(pow(this->Spaceship.Bullets[i].x - this->aliens[a].x, 2) + pow(this->Spaceship.Bullets[i].y - this->aliens[a].y, 2))) < 10) && this->Spaceship.Bullets[i].is_Fired == true && !this->aliens[a].hit) {
              this->aliens[a].hit = true;
              Spaceship.Bullets[i].is_Fired = false;
              this->millis5 = millis();
              this->Score++;
              Serial.println(Score); 
            }
          }
        }
        
      //Alien Revive
        if((millis() - this->millis5) >=1000) {
          for(int a=0; a<=2; a++) {
            this->aliens[a].revive();
          }
        }
      // Updates
        Spaceship.update(); // Spaceship & Bullets - Update  
      
      //Aliens - Update
        for(int i=0; i<=2; i++) {
          if(this->aliens[i].hit == false) {
            this->aliens[i].update();
          }    
        }  
      //Score - Update
        display.setTextSize(1);
        display.setCursor(1,1);
        display.println(this->Score);
        display.setTextSize(2);

      //Oled - Update
        display.display(); 

      //Check for Winner / Loser
        this->checkWinner();
      }
    }

  //Get - Calls
  public:
    bool is_Running() {
      return this->running;
    }

    unsigned int get_Time_between_Shots() {
      return this->Time_Between_Shots;
    }

    int get_Bullets_x(int index) {
      if(index <= 10) {
        return this->Spaceship.Bullets[index].x;
      } else return -1;
    }

    unsigned int get_Tine_between_Shots() {
      return this->Time_Between_Shots;
    }
    
  //Set - Calls
  public:
    unsigned int set_Time_between_Shots(unsigned int Milliseconds) {
      if(Milliseconds > 0) {
        this->Time_Between_Shots = Milliseconds;
        return Milliseconds;
      } else return 0;
    }
};

#define B1 13
#define B2 12
#define B3 11
#define B4 10
SpaceInvaders Level_One(B1, B2, B3, B4);
SpaceInvaders Level_Two(13, 12, 11, 10);

void setup() {
  pinMode(B1, INPUT_PULLUP);
  pinMode(B2, INPUT_PULLUP);
  pinMode(B3, INPUT_PULLUP);
  pinMode(B4, INPUT_PULLUP);


  //OLED Display
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }

  delay(2500);

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(1);
  display.println("");
  display.display();

  //SpaceInvaders
  Level_One.run(); //Run
  Level_Two.run();
}

void loop() {
  // put your main code here, to run repeatedly:
}

Guten tag there, @derfussel

I can read your code, but I don't understand german (except for guten tag), would you be kind and translate it into english since this is an english forum, or use the Deutsch forum?

Thank you, and welcome to Arduino forums

Leider ist Dein Quelltext ziemlich unübersichtlich für Außenstehende.
Wie kommen denn Deine Objekte an das Display?
Wie verhinderst Du, daß sich die Zugriffe der Objekte auf das Display überschneiden?

I wrote a program for a game (Space Invaders), which can be played on an Oled Display (SSD1360), I use the Arduino Uno and the Arduino IDE 2. 2. 1, now I have the problem, if I create a second object of my class SpaceInvaders the Oled Display can no longer be initialized.

Ich weiß leider nicht wie man das Verhindern kann.

auf welchem Microcontroller läuft das?
Wie viel Speicher Flash / Globals sind noch frei lt. Compiler?

1 Like

Arduino Uno

Der Sketch verwendet 20324 Bytes (63%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 553 Bytes (27%) des dynamischen Speichers, 1495 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Habe mal das Programm, anstatt auf einen Arduino Uno auf einen Arduino Mega hochgeladen und nun funktioniert es einwandfrei.

ja das OLED wird zur Laufzeit einiges an Speicher benötigen.

Was mir so auffällt:

  • Checke mal, ob du auch die OLED Ausgaben mit einem F-Makro versehen kannst
  • prüfe ALLE int Variablen, ob es wirklich int sein müssen oder vieleicht kleinere Datentypen auch möglich sind.
  • in der class Allien hast du Positionsdaten als Float ... echt war?
  • Geschwindigkeit lässt sich auch mit Festkommazahl*10 rechnen (statt float).
  • Deine Klassenverschachtelung versteh ich auch noch nicht ganz, warum es für jeden Level eine eigene Instanz benötigt (und damit dann wieder alle spaceship und alliens). Das heißt die Alliens aus Level One belegen speicher auch wenn du gerade Level Two spielst.
  • durchgezählte Variablen schauen per se mal verdächtig aus:
unsigned long millis1, millis2, millis3, millis4, millis5, millis6;
  • getButton ... müssen da wirklich Strings rumgeschickt werden?
  • so wie dein run aufgebaut ist, scheint mir dass du dich selber in der run() festhältst. Ich würde da eher Objekte machen die von außen jeweils eine Zeitscheibe bekommen und ihr Ding machen.

Es ist mein Erstes richtiges Projekt wo ich mit Klassen arbeite, habe die nur gemacht weil es so funktioniert hat, habe ehrlicherweise noch nie etwas von Klassenverschachtelung gehört.

Aber danke für dein Verbesserungsvorschläge, versuche die mal umzusetzen.

Interessant!

Ich bin auch kein großer Freund von solchen Schachtelungen.
Benutze sie nur, wenn "garantiert" keine sonstige Wiederverwendung der einzel Klassen ansteht, bzw. erwünscht ist.

Über 90% deiner this-> Verwendung ist unnötig.
Auf die Schnelle habe ich nur eine sinnvolle Verwendung gesehen.

Aber selbst da würde ich eher mit einer Initialisierungsliste arbeiten.
(kann also auch weg)

z.B. so:
Bullet(int x, int y):x{x},y{y} { }

Ach ja, für den SpaceShip Konstruktor gilt das gleiche.

1 Like

ich auch nicht, aber deine Klasse schaut für mich nach einer Schachtel in der Schachtel in der Schachtel aus.

Häufig nutze ich Vererbungen und Kompositionen.
Wenn ich mir das ansehe hast du bewegliche Spielelemente auf deinem Spielfeld.
SpaceShip, Bullet, Allien.
Vermutlich teilen die sich sogar einige Eigenschaften (x, y, speed), evtl. auch das grundsätzliche Bewegungensverhalten (müssen wohl alle am Spielfeld bleiben).
Dann hat jedes Spielelement auch noch weitere eigene Eigenschaften. Der Alien muss sich selbständig bewegen, das SpaceShip steuerst von außen, der Bullet hat vermutlich irgend eine Schussbahn...
Da bietet sich also imho eine --> Vererbung von einer allgemeinen "Spielelement" Klasse an.
Das SpaceShip nutzt dann 10 Bullets --> Komposition

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.