StarGame Kollision fehlt nur noch



  • Hallo zusammen,

    ich musste ein StarGame als Aufgabe bauen, in dem man ein Schiff in der Konsole steuert, was zum Punkt E (Erde) fliegen muss und dann eine Ausgabe, des Gewinnens ausgibt.
    Das entscheidenste dabei ist, dass ich keine Kollision mit Sternen haben darf, und er dann Game Over ausgeben sollte. Alle Methoden der Klasse sind bereits fertig geschrieben, ausgenommen die der Kollision...

    Ich werde euch jetzt nur die Starfield.cc hierrein kopieren, da es sonst einfach viel zu viel wird.

    Ich möchte es am liebsten so lösen, dass er mit C.GetCruiserPos() sich die aktuelle Position des Schiffs holt, dann soll er damit prüfen, ob an dieser Koordinate ein char '*' vorhanden ist, und falls ja entweder direkt in ein GameOver() springen oder aber einen bool true zurückgeben...

    Allerdings weiß ich noch nicht, wie ich mir die random generierten '*' Koordinaten auslesen lassen sollte...

    #include"Starfield.h"
    #include<time.h>
    #define _TIMED_ 0
    
    void Starfield::Init(){
      screen = initscr();
      raw();
      keypad(stdscr, TRUE);
      nonl();
      cbreak(); 
    
      getmaxyx(screen, height, width);
    
      // initialize the score
      score = width + height;
    
      // generate asteroids data structure;
      asteroids = new char[width * height];
    
      // create stars at random positions
      for(unsigned int i = 0; i < width * height; i++) {
        if (rand() % 5 == 0) 
          asteroids[i] = '*';
        else
          asteroids[i] = ' ';
      }  
    
    }
    
    Starfield::Starfield() {
      Init();
      Start = new Coord(1,1);
    
    //#ifdef _WIN32
    //  srand((unsigned) time(NULL));
    //#else
      srand(time(NULL));
    //#endif  
    
      Goal = new Coord(width-1, rand() % height);
    }
    
    Starfield::Starfield(Coord start, Coord goal)
    {
      Init();
      Start = new Coord(start);
      Goal = new Coord(goal);
    }
    
    /** prints the welcome screen and hands over control to
     * the main game control function 
     */
    void Starfield::StartGame()
    {
      SplashScreen();
      GameControl();
    }
    
    /** deletes allocated memory and calls exit game method
     */
    Starfield::~Starfield() {
      delete Start;
      delete Goal;
      delete [] asteroids;
      ExitGame();
    }
    
    void Starfield::DrawTrace()
    {
      /*
      //  if( !has_colors() )  exit(1);
    
      start_color();	
    
        init_pair(1, COLOR_WHITE, COLOR_RED);  
        attron(COLOR_PAIR(1));
        path.push_back( (C.GetCruiserOldPos()).GetY() * width + 
        (C.GetCruiserOldPos()).GetX());
    
        for( std::vector<int>::iterator it = path.begin(); it != path.end(); it ++ ) {
        move(*it/width, *it % width);
        addch('x');
        }
        attroff(COLOR_PAIR(1));
           */
    }
    
    /** prints BASE and EARTH at start and goal positions on the screen 
     */
    void Starfield::DrawField() 
    {
      for(unsigned int i = 0; i < width * height; i++) {
        move( i / width, i % width);
        addch(asteroids[i]);
      }
    
      mvaddstr(Start->GetY()-1, Start->GetX(), (char *) "SHIP");
      mvaddstr(Start->GetY(), Start->GetX(), (char *) "S");
      mvaddstr(Goal->GetY()-1, Goal->GetX()-4, (char *) "EARTH");
      mvaddstr(Goal->GetY(), Goal->GetX(), (char *) "E");
      DrawTrace();
      DrawCruiser();
      DrawStatusLine();
      refresh();
    }
    
    /** outputs a message at the centre of the screen
     * @param message - the message to be printed
     */
    void Starfield::SplashMessage( std::string message, bool waitforkey=true)
    {
      std::string decoration;
      for(unsigned int i = 0; i < message.length(); i ++ )
        decoration += "*";
    
      mvaddstr(height/2-1, width/2-message.length()/2, decoration.c_str());
      mvaddstr(height/2, width/2-message.length()/2, message.c_str());
      mvaddstr(height/2+1, width/2-message.length()/2, decoration.c_str());
    
      if( waitforkey ){
        mvaddstr(height-1, width/2-10, "Press SPACE");
        getch();
        clear(); 
      }
    }
    
    /** the welcome screen  
    */
    void Starfield::SplashScreen() 
    {
      clear();
      SplashMessage("S P A C E - C R U I S E R (TM)", false);
    
      char text[] = 
        "In a remote galaxy, our starship troopers " \
        "want to start their way home to celebrate  xmas on planet earth. Of course, " \
        "this mission is very dangerous as they have to fly through the asteroid belt " \
        "to reach planet earth. \n They have only one trial, will they ever make it ... ?";
    
      mvaddstr(height/2+5, 0, text);  
      mvaddstr(height-1, width/2-10, "Press SPACE");
      getch();
      clear(); 
      DrawField();
      if (_TIMED_) halfdelay(1);
    }
    
    /** the winning screen 
    */
    void Starfield::YouWin()
    {
      cbreak();
      SplashMessage("CONGRATS, YOU FOUND BACK TO EARTH! MERRY XMAS");
      ExitGame();
    }
    
    /** game over screen 
     */
    void Starfield::GameOver()
    {
      cbreak();
      SplashMessage("G A M E  O V E R");
      ExitGame();
    }
    
    /** draw the cruiser symbol at the current position
     */
    void Starfield::DrawCruiser() const
    {
      move(C.GetY(), C.GetX());
      addch(C.GetCruiserSymbol());
    }
    
    /** test for collisions of the space ship with asteroids
     */
    void Starfield::TestCollision() const
    {
      if(C.GetCruiserPos() == '*')
    	{
    	GameOver();
    	}
    }
    
    /** checks if the space ship already reached planet earth, i.e.
     * the goal position 
     */
    void Starfield::CheckForEarth() 
    {
      if( C.GetCruiserPos() == *Goal ) {
        YouWin();
        ExitGame();
      }
    }
    
    /** prints the current position and the goal position in the status line,
     * i.e. the last line of the screen 
     */
    void Starfield::DrawStatusLine() const
    {
      move(height-1, 1);
      std::stringstream ssship;
      std::stringstream ssearth;
      Coord ship(C.GetCruiserPos());
      Coord earth(*Goal);
      ssship << ship;
      ssearth << earth;
    
      printw("ship pos: %s ", ssship.str().c_str());
      printw("earth pos: %s ", ssearth.str().c_str());
      printw("lives: %i ", 3);
      printw("time: %i ", 120);
      printw("score: %i ", score);
    }
    
    /** the main game control
     * this function reads the next keyboard input and 
     * depending on the arrow key pressed will call the appropriate
     * function for ship movement. At the end, the game field,
     * status line collision test and goal test are performed */
    void Starfield::GameControl()
    {
      DrawField();
    
      while (true) {
      //   noecho(); /* don't echo input */
        int c = 0;
         c = getch();
    
         //     if ( c == -1 ) { exit(1); DrawField(); return;}
         switch(c) {
         case RIGHT:
           C.MoveRight();
           score--;
           break;
         case LEFT:
           C.MoveLeft();
           score--;
           break;
         case UP:
           C.MoveUp();
           score--;
           break;
         case DOWN:
           C.MoveDown();
           score--;
           break;
         case 'q':
           ExitGame();
         default:      
           DrawField();
           //nothing;
           break;
         }
         DrawField();
         DrawStatusLine();
         TestCollision();
         CheckForEarth();
      }
    }
    
    /** cleans up and terminates the window and exits the game 
     */
    void Starfield::ExitGame()
    { 
      clear(); 
      endwin(); 
      exit(1);
    }
    


  • Huh?
    Du brauchst doch nur eine Funktion

    bool Starfield::is_asteroid_at(Coord c) const
    {
      // Angenommen Coord(0,0) ist links oben
      return asteroids[c.GetY() * width + c.GetX()]=='*';
    }
    


  • Das müsstest Du mir mal genauer erläutern, was genau ich hier zurückgebe ?

    Ja 0,0 ist oben links.

    width ist hier die Breite des Screen Windows.



  • Hat sich bereits erledigt, aber danke du hast mir trotzdem geholfen..

    void Starfield::TestCollision() //const
    {
       if(asteroids[C.GetY() * width + C.GetX()]=='*'){GameOver();}
    }
    

    mehr wars nicht..

    Jetzt kann ich mir nur noch additional überlegen, ob ich Lebenszähler und Zeitzähler einfüge... 😃

    Okay edit:

    Problem ist, dass er auf dem E von Earth ebenfalls ins Game Over übergeht obwohl er es ja eigentlich nur für den * machen sollte :o


Anmelden zum Antworten