2
\$\begingroup\$

I programmed a Pong game in the editor Processing. I would be glad if you could give some improvements.

    //Variabeln werden erstellt
int untere_spiel_grenze;
int obere_spiel_grenze;


float spieler_x;
float spieler_y;
float ball_x;
float ball_y;
float ball_geschwindigkeit_x;
float ball_geschwindigkeit_y;
float spieler_2_x;
float spieler_2_y;

int runde;
int spieler_leben;
int spieler_2_leben;
int spieler_2_runden;
int spieler_runden;
int spieler_punkte;
int spieler_2_punkte;
boolean spieler_runde_anzeige;
boolean spieler_2_runde_anzeige;


//Blur-Effekt
int blur_anzahl = 10;
float [][] positions_array;

//Das Setup wird einmal am Anfang ausgeführt 
void setup() {

  //Definiert die grösse des Arrays
  positions_array = new float[blur_anzahl][2];

  //Deklariert die Werte der Variabeln 
  spieler_x = 20;
  spieler_y = 60;

  spieler_2_x = 780;
  spieler_2_y = 60;

  untere_spiel_grenze = 595;
  obere_spiel_grenze = 5;

  ball_x = 400;
  ball_y = 300;

  ball_geschwindigkeit_x = -3;
  ball_geschwindigkeit_y = 0;

  runde = 0;

  spieler_leben  = 5;
  spieler_2_leben = 5;

  spieler_punkte = 0;
  spieler_2_punkte = 0;

  spieler_runde_anzeige = false;
  spieler_2_runde_anzeige = false;

  spieler_2_runden = 0;
  spieler_runden = 0;

  textSize(14);

  //Bestimmt die Grösse des Fenster
  size (800, 600);

  //Ändert den Ausgangspunkt der RECT
  rectMode(CENTER);
}

void draw() {

  //Bestimmt die Farbe des Fenster
  background(0);

  //Erstellt die beiden Spieler und den Ball
  rect(spieler_x, spieler_y, 20, 100);
  rect(spieler_2_x, spieler_2_y, 20, 100);
  rect(ball_x, ball_y, 10, 10);

  positions_array[0][0] = ball_x;
  positions_array[0][1] = ball_y;

  //Blur-Effekt
  for (int i = (blur_anzahl -1); i > 0; i--) {
    fill (0, 255, 0, 255/(i*2));
    positions_array[i][0] = positions_array[i-1][0];
    positions_array[i][1] = positions_array[i-1][1];
    rect (positions_array[i][0], positions_array[i][1], 10, 10);
  }



  //Abfrage ob eine Taste Gedrückt ist
  if (keyPressed) {
    //Abfrage ob die nach unter Taste gedrückt ist
    if (keyCode == DOWN) {
      //Fragt, solange Spieler nicht aus dem Spielfeld
      if (spieler_2_y < 550) {
        //Spieler bewegt sich in y Richtung nach unten
        spieler_2_y = spieler_2_y + 5;
      }
    }
    //Abfrage ob die nach oben Taste gedrückt wird
    if (keyCode == UP) {
      //Fragt, solange Spieler nicht aus dem Spielfeld
      if (spieler_2_y > 50) {
        //Spieler bewegt sich in y Richtung nach oben
        spieler_2_y = spieler_2_y - 5;
      }
    }
  }
  //Wird definiert, was passiert, wenn der Ball den Spieler trifft
  if (ball_x > 770) {
    if (ball_y < (spieler_2_y + 55) && ball_y > (spieler_2_y -55)) {
      ball_geschwindigkeit_x = (-ball_geschwindigkeit_x) -1;//Verschnellert denn Ball 
      ball_geschwindigkeit_y = ball_geschwindigkeit_y - (spieler_2_y - ball_y) * 0.2; //Lässt ihn in eine andere Richtung fliegen
      runde = runde +1 ;
      spieler_2_punkte = spieler_2_punkte + 100;
    }
    //Der Ball kommt in die Mitte
    else {
      ball_x = 400;
      ball_y = 300;
      ball_geschwindigkeit_x = 0;
      ball_geschwindigkeit_y = 0;

      spieler_runde_anzeige = true;

      spieler_runden  = spieler_runden + 1;

      spieler_2_leben = spieler_2_leben -1;
    }
  }

  //Abfrage ob eine Taste Gedrückt ist
  if (keyPressed) {
    //Abfrage ob die S Taste gedrückt ist
    if (key == 's') {
      //Fragt, solange Spieler nicht aus dem Spielfeld
      if (spieler_y < 550) {
        //Spieler bewegt sich in y Richtung nach unten
        spieler_y = spieler_y + 5;
      }
    }
    //Abfrage ob die W Taste gedrückt ist
    if (key == 'w') {
      //Fragt, solange Spieler nicht aus dem Spielfeld
      if (spieler_y > 50) {
        //Spieler bewegt sich in y Richtung nach oben
        spieler_y = spieler_y - 5;
      }
    }
  }
  //Hier bekommt der Ball seine Geschwindigkeit
  ball_x = ball_x + ball_geschwindigkeit_x;
  ball_y = ball_y + ball_geschwindigkeit_y;

  //Wird definiert, was passiert, wenn der Ball den Spieler trifft
  if (ball_x < 30) {
    if (ball_y < (spieler_y + 55) && ball_y > (spieler_y - 55)) {
      ball_geschwindigkeit_x = (-ball_geschwindigkeit_x) +1;//Verschnellert denn Ball 
      ball_geschwindigkeit_y = ball_geschwindigkeit_y - (spieler_y - ball_y) * 0.2;//Lässt ihn in eine andere Richtung fliegen
      runde = runde +1 ;
      spieler_punkte = spieler_punkte + 100;
    }

    //Der Ball kommt in die Mitte
    else {
      ball_x = 400;
      ball_y = 300;
      ball_geschwindigkeit_x = 0;
      ball_geschwindigkeit_y = 0;

      spieler_2_runde_anzeige = true;

      spieler_2_runden = spieler_2_runden + 1;

      spieler_leben = spieler_leben -1;
    }
  }

  //Erstellt die untere und obere Spielgrenze
  if (ball_y > untere_spiel_grenze || ball_y < obere_spiel_grenze) {
    ball_geschwindigkeit_y = -ball_geschwindigkeit_y;
  }
  //Fragt ab, ob der Ball in der Mitte steht
  if (ball_geschwindigkeit_x == 0) {
    //Fragt ab, welcher mehr Runden hat
    if (spieler_runde_anzeige == true) {
      textSize(15);
      text("Spieler1 hat diese Runde gewonnen!", 270, 200);
      textSize(14);
    }  
    if (spieler_2_runde_anzeige == true) {
      textSize(15);
      text("Spieler2 hat diese Runde gewonnen!", 270, 200);
      textSize(14);
    }
    //Erstellt die Reset Funktion
    if (keyPressed) {
      if (key == 'r' ) {
        ball_geschwindigkeit_x = -3;
        ball_geschwindigkeit_y = 0;
        runde = 0;
        spieler_2_runde_anzeige = false;
        spieler_runde_anzeige = false;
      }
    }
  }
  //Erstellt den ganzen Text im Spiel (Rundenangabe, Leben usw.)
  text("Runde: " + runde, 360, 20);
  text("Gewonnene Runden: " + spieler_runden, 100, 20);
  text("Gewonnene Runden: " + spieler_2_runden, 600, 20);
  text("Spieler1 Leben: " + spieler_leben, 100, 550);
  text("Spieler2 Leben: " + spieler_2_leben, 600, 550);
  text("Punkte: "+ spieler_punkte, 100, 40);
  text("Punkte: "+ spieler_2_punkte, 600, 40);

  //Fragt, wenn der Spieler1 verloren hat
  if (spieler_leben == 0 ) {
    textSize(20);
    text ("Spieler2 hat die Partie gewonnen!", 240, 500);
    text("Punktestand: " + spieler_2_punkte, 320, 450);
    textSize(14);
    //Fragt, ob Reset verlangt wurde
    if (keyPressed) {
      if (key == 'r' ) {
        exit();//Schliesst das Spiel
      }
    }
  }

  //Fragt, wenn der Spieler1 verloren hat
  if ( spieler_2_leben == 0) {
    textSize(20);
    text ("Spieler1 hat die Partie gewonnen!", 240, 500);
    text("Punktestand: " + spieler_punkte, 320, 450);
    textSize(12);
    //Fragt, ob Reset verlangt wurde
    if (keyPressed) {
      if (key == 'r' ) {
        exit();//Schliesst das Spiel
      }
    }
  }
}
\$\endgroup\$
  • \$\begingroup\$ Well... It's hard to assess. I would start rewriting it to OOP code. \$\endgroup\$ – mlewandowski Mar 14 '16 at 14:40
  • \$\begingroup\$ This is difficult to review with German variable and method names for most people. \$\endgroup\$ – RoToRa Apr 8 '16 at 12:31
2
\$\begingroup\$

Great accomplishment. I have made some improvements, without doing a complete redesign. I assume that you will learn most out of it, if the program gets reshaped step by step. As said in the comments, it would be preferable to write the program in an object oriented style, which I will do in the next days and then update my answer.

So here are the the problems and my improvements:

  • It was not possible to move both paddles at the same time (tested on Mac and Linux). This was owed to the fact that you query the last pressed key for every paddle. If W gets pressed first and second, the keyPressed variable holding the keycode of W gets promptly overwritten by the keycode for ↑. Thus the test for W fails, despite you are still holding down that key. To circumvent that problem we store the state (pressed or released) for every key in an array. The states get set through Processing's keyPressed() and keyReleased() methods. They are called out of order (through interrupts) whenever a key gets pressed. In the gameloop (draw()) we query every key we are interested in - once per iteration.
  • The code is more modular featuring a gameloop, with a processInput(), update() and drawGUI() method.

  • A lot of small changes.

Here is the whole code in a repository: https://bitbucket.org/Nochan/pong-from-panden-stackexchange

There is still a lot of room for improvements and even complete refactoring. I will do this in the next days (probably) and update my answer.

/** Every key has a keyCode. The keycode is the index for that key in the array.
 *  When a key gets pressed its value in the array is set to true, when released to false.
 *  The keys state is set through the interrup methods keyPressed() and keyReleased().
 *  Once every iteration of the gameloop all keys of interest get queried through processInput(). */
private final boolean keys_pressed[] = new boolean[128];

int untere_spiel_grenze;
int obere_spiel_grenze;

float spieler_x;
float spieler_y;
float ball_x;
float ball_y;
float ball_geschwindigkeit_x;
float ball_geschwindigkeit_y;
float spieler_2_x;
float spieler_2_y;

int runde;
int spieler_leben;
int spieler_2_leben;
int spieler_2_runden;
int spieler_runden;
int spieler_punkte;
int spieler_2_punkte;
boolean has_player1_striked;
boolean has_player2_striked;


/* The ball leaves a fading tail at his last n positions. */
final int tail_length = 10;
float[][] last_ball_positions;


void setup() {
  size (800, 600);

  // x and y for every position.
  last_ball_positions = new float[tail_length][2];

  spieler_x = 20;
  spieler_y = 60;

  spieler_2_x = width - 20;
  spieler_2_y = 60;

  untere_spiel_grenze = height - 5;
  obere_spiel_grenze = 5;

  ball_x = 400;
  ball_y = 300;

  ball_geschwindigkeit_x = -3; // TODO: Make this random to be fair.
  ball_geschwindigkeit_y = 0;

  runde = 0;

  spieler_leben  = 5;
  spieler_2_leben = 5;

  spieler_punkte = 0;
  spieler_2_punkte = 0;

  has_player1_striked = false;
  has_player2_striked = false;

  spieler_2_runden = 0;
  spieler_runden = 0;

  textSize(14);

  //Ändert den Ausgangspunkt der RECT
  rectMode(CENTER);
}

void draw() {
  processInput();
  update();

  // Erase everything drawn.
  background(0);
  // Draws both players and the ball.
  rect(spieler_x, spieler_y, 20, 100);
  rect(spieler_2_x, spieler_2_y, 20, 100);
  rect(ball_x, ball_y, 10, 10);

  // Draw a tail of the ball. Like a particle effect.
  last_ball_positions[0][0] = ball_x;
  last_ball_positions[0][1] = ball_y;
  for (int i = (tail_length -1); i > 0; i--) {
    fill (0, 255, 0, 255/(i*2));
    last_ball_positions[i][0] = last_ball_positions[i-1][0];
    last_ball_positions[i][1] = last_ball_positions[i-1][1];
    rect (last_ball_positions[i][0], last_ball_positions[i][1], 10, 10);
  }

  drawGUI();
}

void keyPressed() {
  if (keyCode > 127) return; // Keys above are not of interest and would cause an OutOfBoundsException.

  keys_pressed[keyCode] = true;
}

void keyReleased() {
  if (keyCode > 127) return; // Keys above are not of interest and would cause an OutOfBoundsException.

  keys_pressed[keyCode] = false;
}

private void processInput() {
  // Move Player 1 (on the left)
  if (keys_pressed['S'])
    if (spieler_y < height - 50) { spieler_y += 5; }
  if (keys_pressed['W'])
    if (spieler_y > 50) { spieler_y -= 5; }

  // Move Player 2 (on the right)
  if (keys_pressed[UP])
    if (spieler_2_y > 50) { spieler_2_y -= 5; }
  if (keys_pressed[DOWN])
    if (spieler_2_y < 550) { spieler_2_y += 5; }

  // Kick off the ball, to start another round.
  if (keys_pressed['R']) {
    if (ball_geschwindigkeit_x == 0) {
      ball_geschwindigkeit_x = -3;
      runde = 0;
      // Hide the GUI
      has_player2_striked = false;
      has_player1_striked = false;
    }
  }    
}

private void update() {
  // Ist der Ball hinter dem rechten Paddel?
  if (ball_x > 770) { // TODO: 770 Magic Number => Play field boundary right: width - 20, paddle width: 20 
    // Block das rechte Paddel den Ball?
    if (ball_y < (spieler_2_y + 55) && ball_y > (spieler_2_y -55)) { // TODO: 55 Magic Number => Paddle height: 100, Ball height: 10 => 50 + 5
      ball_geschwindigkeit_x = (-ball_geschwindigkeit_x) - 1; // Verschnellert denn Ball 
      ball_geschwindigkeit_y = ball_geschwindigkeit_y - (spieler_2_y - ball_y) * 0.2; //Lässt ihn in eine andere Richtung fliegen
      runde = runde + 1;
      spieler_2_punkte = spieler_2_punkte + 100;
    }
    // Das rechte Paddel erwischt den Ball nicht => Beendet den Satz.
    else {
      ball_x = 400;
      ball_y = 300;
      ball_geschwindigkeit_x = 0;
      ball_geschwindigkeit_y = 0;

      has_player1_striked = true;

      spieler_runden  = spieler_runden + 1;

      spieler_2_leben = spieler_2_leben -1;
    }
  }

  // Hier bekommt der Ball seine Geschwindigkeit
  ball_x = ball_x + ball_geschwindigkeit_x;
  ball_y = ball_y + ball_geschwindigkeit_y;

  // Ist der Ball hinter dem linken Paddel?
  if (ball_x < 30) {
    // Block das linke Paddel den Ball?
    if (ball_y < (spieler_y + 55) && ball_y > (spieler_y - 55)) {
      ball_geschwindigkeit_x = (-ball_geschwindigkeit_x) +1;//Verschnellert denn Ball 
      ball_geschwindigkeit_y = ball_geschwindigkeit_y - (spieler_y - ball_y) * 0.2;//Lässt ihn in eine andere Richtung fliegen
      runde = runde +1 ;
      spieler_punkte = spieler_punkte + 100;
    }
    // Das linke Paddel erwischt den Ball nicht => Beendet den Satz.
    else {
      ball_x = 400;
      ball_y = 300;
      ball_geschwindigkeit_x = 0;
      ball_geschwindigkeit_y = 0;

      has_player2_striked = true;

      spieler_2_runden = spieler_2_runden + 1;

      spieler_leben = spieler_leben -1;
    }
  }

  // If the ball is about to leave the field on top or bottom, invert its y direction.
  if (ball_y > untere_spiel_grenze || ball_y < obere_spiel_grenze) {
    ball_geschwindigkeit_y = -ball_geschwindigkeit_y;
  }
}

private void drawGUI() {
  fill(0, 255, 0);

  // Erstellt den ganzen Text im Spiel (Rundenangabe, Leben usw.)
  text("Runde: " + runde, 360, 20);
  text("Gewonnene Runden: " + spieler_runden, 100, 20);
  text("Gewonnene Runden: " + spieler_2_runden, 600, 20);
  text("Spieler1 Leben: " + spieler_leben, 100, 550);
  text("Spieler2 Leben: " + spieler_2_leben, 600, 550);
  text("Punkte: "+ spieler_punkte, 100, 40);
  text("Punkte: "+ spieler_2_punkte, 600, 40);

  // Is player 1 out of lives, thus game over?
  if (spieler_leben == 0 ) {
    textSize(20);
    text ("Spieler2 hat die Partie gewonnen!", 240, 500);
    text("Punktestand: " + spieler_2_punkte, 320, 450);
    textSize(14);
    // Ready to quit the game, if the appropriate key gets pressed.
    if (keyPressed) {
      if (key == 'r' ) {
        exit();
      }
    }
  }

  // Is player 2 out of lives, thus game over?
  if (spieler_2_leben == 0) {
    textSize(20);
    text ("Spieler1 hat die Partie gewonnen!", 240, 500);
    text("Punktestand: " + spieler_punkte, 320, 450);
    textSize(12);
    // Ready to quit the game, if the appropriate key gets pressed.
    if (keyPressed) {
      if (key == 'r' ) {
      }
    }
  }

  // Is the ball in resting position? Display who has won that turn.
  if (ball_geschwindigkeit_x == 0) {
    if (has_player1_striked == true) {
      textSize(15);
      text("Spieler1 hat diese Runde gewonnen!", 270, 200);
      textSize(14);
    }  
    else if (has_player2_striked == true) {
      textSize(15);
      text("Spieler2 hat diese Runde gewonnen!", 270, 200);
      textSize(14);
    }
  }
}

Sollte etwas unklar sein oder auch wenn du jemanden suchst mit dem du dich austauschen kannst, schreib mir auf dev[at]tiedtke.biz. :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.