Java Processing Game over Screen erstellen?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Deine Lösungsidee ist schon richtig, scheitert momentan aber nur an der Positionsprüfung.

Der Nutzer soll offensichtlich auf again klicken. Die Prüfung auf horizontaler Ebene ist für den Anfang wohl ausreichend, doch statt die Breite auf 500px festzusetzen, wäre eine dynamische Berechnung eine flexiblere Lösung.

Mit textWidth kannst du die Breite des Texts berechnen lassen.

Die Prüfung in der vertikalen Achse scheitert an den gesetzten Grenzen. Die y-Position liegt zwar bei height/2 + 260px, doch der Text wird standardmäßig relativ zu diesem Punkt auf der Grundlinie positioniert. Um es dir visuell einmal zu verbildlichen, kannst du ja noch ein Rechteck an denselben Koordinaten zeichnen.

rect(width / 4 + 100, height / 2 + 260, 150, 150);

Ändere also die Textausrichtung, bevor du deinen Text zeichnen lässt.

textAlign(LEFT, TOP);

Da dein Text eine Größe/Höhe von 150px hat, müsste seine untere Linie bei height / 2 + 260 + 150 liegen. Du hast bei deiner Prüfung den Divisor 2 vergessen und dich auch bei der letzten Summe verrechnet (260 + 150 = 410).

Setze für solche Werte / Berechnungen öfter Variablen ein. Das kürzt deinen Code und beseitigt auf diese Weise auch mögliche Fehlerstellen. Wenn du zehnmal height / 2 aufschreibst, ist die Wahrscheinlichkeit, dass du dich einmal vertippst, zehnmal so hoch, als wenn du so eine Formel nur einmal schreibst. Außerdem muss der Computer dann nur einmal rechnen und wenn du einmal Änderungen am Programm vornehmen möchtest, ist das vielleicht nur noch an einer Stelle nötig.

Konkretes Beispiel:

// not so good:
rect(25, (mouseY / 25) * 25, 25, 25);
rect(25, ((mouseY / 25) * 25) + 25, 25, 25);
rect(25, ((mouseY / 25) * 25) - 25, 25, 25);
rect(25, ((mouseY / 25) * 25) - 50, 25, 25);
rect(25, ((mouseY / 25) * 25) + 50, 25, 25);

// better:
int rectY = (mouseY / 25) * 25;
rect(25, rectY, 25, 25);
rect(25, rectY + 25, 25, 25);
rect(25, rectY - 25, 25, 25);
rect(25, rectY - 50, 25, 25);
rect(25, rectY + 50, 25, 25);

Die Formel in diesen fünf Zeilen aufzuschreiben wäre nur notwendig, wenn jede Berechnung stets einen neuen Wert liefern würde.

Bei den Koordinatenbegrenzern für den Text wären vier Variablen sinnvoll.

int againTextX = width / 4 + 100;
int againTextY = height / 2 + 260;
int againTextWidth = // use textWidth ...
int fontSize = 150;

Die letzte Variable bspw. sollte dann auch als Argument für textSize herhalten:

textSize(fontSize);

und weitere Werte wie die untere y-Grenze kann man aufbauend auf diesen Variablen berechnen.

if (mouseY < againTextY + fontSize) {
Mephisto787 
Fragesteller
 02.09.2021, 09:33

Ich hab das jetzt bestmöglichst umgesetzt. Das einzige was ich nicht verstanden habe ist die Textwidth Funktion. Bzw was muss ich und die Klammern schreiben um den "again?" Text zu berechnen?

Und wenn die Abfrage funktioniert wie bekomm ich es bewerkstelligt dass sich alles resetted?

0
regex9  02.09.2021, 09:38
@Mephisto787

1)

float againTextWidth = textWidth("again?"); // = 458.93555

2) Setze alle deine Variablen wieder auf den Wert, den du ihnen bei Programmstart gegeben hast. Das Gleiche gilt für andere Zustände, wie den Hintergrund.

1
Mephisto787 
Fragesteller
 02.09.2021, 11:10
@regex9

Ich habe ein Problem:

In meinem Script ist

int againTextX = width / 4 + 150;
int againTextY = height / 2 + 260;

text("Again?",againTextX, againTextY);

Ungleich

text("Again",width / 4 + 150,height / 2 + 260);

Wie kann das zustande kommen?

0
regex9  02.09.2021, 11:57
@Mephisto787

Das kann ich dir so nicht erklären. Inwiefern merkst du denn einen Unterschied (ich würde hier das Fragezeichen sehen) und stehen die Zeilen des obigen Snippets tatsächlich beeinander?

Wenn bei dem obigen Snippet nicht die Werte beim Zeichnen herauskommen, wie erwartet, muss wohl davon ausgegangen werden, dass sie sich zwischendurch ändern (lasse dir beide Variablen in der Konsole ausgeben, bevor du den Text rendern lässt).

Solltest du nach Analyse nicht weiterkommen, poste hier noch einmal dein komplettes Sketch, welches sich nicht so verhält, wie erwartet (und gib noch einmal an, wo du das Fehlverhalten siehst).

1
Mephisto787 
Fragesteller
 02.09.2021, 15:53
@regex9

Ich mach nochmal eine neue Frage in der ich die Bilder zeig

0
Mephisto787 
Fragesteller
 02.09.2021, 16:01
@Mephisto787

Wenn ich das Programm mit Variable starte ist dass "Again?" Links oben angeordnet etwa bei 100 , 100 würde ich raten und wenn ich es direkt einfüge, ist es mittig unter dem Game over zu sehen(wo es hin soll)

0
Mephisto787 
Fragesteller
 02.09.2021, 16:05
@Mephisto787

Script:

int againTextX = width / 4 + 50;
int againTextY = height / 2 + 260;
float fontSize = 150;


float xAngle = 1;
float yAngle = 1;


float screen = 0;
float end = 0;
float x = 0;
float y = 0;


float xball = 500;
float yball = 500;
float xdir = 1;
float ydir = 1;








void setup(){
  
  fullScreen();
  smooth();
  frameRate(120);
  mouseClicked();
  
}


void draw(){
  background(38,30,38);
  strokeWeight(5);
  stroke(39,255,36);
  fill(39, 181, 36);
  rect(25,(y/25)*25,25,25);
  rect(25,((y/25)*25)+25,25,25);
  rect(25,((y/25)*25)-25,25,25);
  rect(25,((y/25)*25)-50,25,25);
  rect(25,((y/25)*25)+50,25,25);
  
  
  stroke(255,39,36);
  fill(181,39,36);
  
 
  
  
  fill(255,39,36);
  stroke(181,39,36);
  rect((xball/25)*25,(yball/25)*25,25,25);
  xball = xball+xdir*7*xAngle;
  yball = yball+ydir*4*yAngle;
  
  
  
   if (xball > width-25){
     xdir = xdir * -1;
   }  
 
  if (xball < 1){
    screen=1;
  }
 
  if (xball < 75){
   if (xball > 25){
    if (yball > ((y/25)*25)-75){
      if(yball < ((y/25)*25)+75){
     xdir = xdir * -1;
     xAngle = random(1,2);
     yAngle = random(1,5);
   }}}}
  
  
  if (yball > height-25 || yball < 25){
      ydir = ydir * -1;
    }
     
     
    if(y>mouseY){
      y=y-12.5;
    }
     
    if(y<mouseY){
      y=y+12.5;
    }
    
   if(screen>0.1){
     noStroke();
    fill(0);
    rect(0,0,width,height);
    stroke(255);
    fill(255);
    textSize(fontSize);
    text("Game Over",width/4-100,height/2);
    fill(150);
    stroke(150);
    textAlign(LEFT,TOP);
    text("Again?",width / 4 + 50,height / 2 + 260);
    float againTextWidth = textWidth("Again?");
    end = 1;
   }
     
}




void mouseClicked (){
  
 background(38,30,38);
  if(end > 0){
    
    float againTextWidth = textWidth("again?");
    
   if(mouseX > againTextX){
    if(mouseX < againTextWidth){
     if(mouseY > againTextY){
      if(mouseY < againTextY+fontSize){
        fill(255);
        rect(0,0,1000,1000);
        background(38,30,38);
        againTextX = width / 4 + 50;
        againTextY = height / 2 + 260;
        fontSize = 150;
        xAngle = 1;
        yAngle = 1;
        screen = 0;
        x = 0;
        y = 0;
        xball = 500;
        yball = 500;
        xdir = 1;
        ydir = 1;
        end = 0;
        setup();
        draw();
        
 
  }}}}}}
  


0
Mephisto787 
Fragesteller
 02.09.2021, 16:05
@Mephisto787

Script:

int againTextX = width / 4 + 50;
int againTextY = height / 2 + 260;
float fontSize = 150;


float xAngle = 1;
float yAngle = 1;


float screen = 0;
float end = 0;
float x = 0;
float y = 0;


float xball = 500;
float yball = 500;
float xdir = 1;
float ydir = 1;








void setup(){
  
  fullScreen();
  smooth();
  frameRate(120);
  mouseClicked();
  
}


void draw(){
  background(38,30,38);
  strokeWeight(5);
  stroke(39,255,36);
  fill(39, 181, 36);
  rect(25,(y/25)*25,25,25);
  rect(25,((y/25)*25)+25,25,25);
  rect(25,((y/25)*25)-25,25,25);
  rect(25,((y/25)*25)-50,25,25);
  rect(25,((y/25)*25)+50,25,25);
  
  
  stroke(255,39,36);
  fill(181,39,36);
  
 
  
  
  fill(255,39,36);
  stroke(181,39,36);
  rect((xball/25)*25,(yball/25)*25,25,25);
  xball = xball+xdir*7*xAngle;
  yball = yball+ydir*4*yAngle;
  
  
  
   if (xball > width-25){
     xdir = xdir * -1;
   }  
 
  if (xball < 1){
    screen=1;
  }
 
  if (xball < 75){
   if (xball > 25){
    if (yball > ((y/25)*25)-75){
      if(yball < ((y/25)*25)+75){
     xdir = xdir * -1;
     xAngle = random(1,2);
     yAngle = random(1,5);
   }}}}
  
  
  if (yball > height-25 || yball < 25){
      ydir = ydir * -1;
    }
     
     
    if(y>mouseY){
      y=y-12.5;
    }
     
    if(y<mouseY){
      y=y+12.5;
    }
    
   if(screen>0.1){
     noStroke();
    fill(0);
    rect(0,0,width,height);
    stroke(255);
    fill(255);
    textSize(fontSize);
    text("Game Over",width/4-100,height/2);
    fill(150);
    stroke(150);
    textAlign(LEFT,TOP);
    text("Again?",width / 4 + 50,height / 2 + 260);
    float againTextWidth = textWidth("Again?");
    end = 1;
   }
     
}




void mouseClicked (){
  
 background(38,30,38);
  if(end > 0){
    
    float againTextWidth = textWidth("again?");
    
   if(mouseX > againTextX){
    if(mouseX < againTextWidth){
     if(mouseY > againTextY){
      if(mouseY < againTextY+fontSize){
        fill(255);
        rect(0,0,1000,1000);
        background(38,30,38);
        againTextX = width / 4 + 50;
        againTextY = height / 2 + 260;
        fontSize = 150;
        xAngle = 1;
        yAngle = 1;
        screen = 0;
        x = 0;
        y = 0;
        xball = 500;
        yball = 500;
        xdir = 1;
        ydir = 1;
        end = 0;
        setup();
        draw();
        
 
  }}}}}}
  


0
regex9  02.09.2021, 20:21
@Mephisto787

Die Ursache liegt hier:

fullScreen();

Die Berechnung der Koordinaten wird vorgenommen, bevor du die Anwendung in den Fullscreen wechseln lässt (woraufhin sich auch die Werte von width und height ändern).

Lösung:

int againTextX, againTextY;
// ...

void setup() {
  fullScreen();
  // ...

  againTextX = width / 4 + 50;
  againTextY = height / 2 + 260;

  // ...
}

Ich habe in deinem Code noch ein paar andere Punkte gesehen, die ich ansprechen möchte. Dazu poste ich einmal direkt das Endresultat und gehe dazu auf einzelne Punkte ein.

int fontSize = 150;
String againText = "again?";
int againTextX;
int againTextY;
float againTextWidth;

boolean end;
float xAngle, yAngle;
float x, y;
float xBall, yBall;
float xDirection, yDirection;

void setup() {
  fullScreen();
  smooth();
  frameRate(120);
  
  againTextX  = width / 4 + 50;
  againTextY = height / 2 + 260;

  textSize(fontSize);
  againTextWidth = textWidth(againText);

  reset();
}

void reset() {
  fill(255);
  rect(0, 0, 1000, 1000);
  background(38, 30, 38);

  xAngle = 1;
  yAngle = 1;

  end = false;

  x = 0;
  y = 0;

  xBall = 500;
  yBall = 500;
  xDirection = 1;
  yDirection = 1;
}

void draw() {
  background(38, 30, 38);
  strokeWeight(5);
  stroke(39, 255, 36);
  fill(39, 181, 36);

  float paddleCenterY = (y / 25) * 25;
  rect(25, paddleCenterY, 25, 25);
  rect(25, paddleCenterY + 25, 25, 25);
  rect(25, paddleCenterY - 25, 25, 25);
  rect(25, paddleCenterY - 50, 25, 25);
  rect(25, paddleCenterY + 50, 25, 25);

  stroke(255, 39, 36);
  fill(181, 39, 36);

  rect((xBall / 25) * 25, (yBall / 25) * 25, 25, 25);
  xBall = xBall + xDirection * 7 * xAngle;
  yBall = yBall + yDirection * 4 * yAngle;

  if (xBall > width - 25) {
    xDirection = xDirection * -1;
  }

  if (xBall < 1) {
    end = true;
  }

  if (xBall < 75) {
    if (xBall > 25) {
      if (yBall > paddleCenterY - 75) {
        if (yBall < paddleCenterY + 75) {
          xDirection = xDirection * -1;
          xAngle = random(1, 2);
          yAngle = random(1, 5);
        }
      }
    }
  }

  if (yBall > height - 25 || yBall < 25) {
    yDirection = yDirection * -1;
  }

  if (y > mouseY) {
    y = y - 12.5;
  }
  
  if (y < mouseY) {
    y = y + 12.5;
  }

  if (end == true) {
    showGameOverScreen();
  }
}

void showGameOverScreen() {
  background(0);

  stroke(255);
  fill(255);
  text("Game Over", width / 4 - 100, height / 2);

  fill(150);
  stroke(150);
  textAlign(LEFT, TOP);  
  text(againText, againTextX, againTextY);
}

void mouseClicked() {  
  if (mouseX > againTextX) {
    if (mouseX < againTextX + againTextWidth) {
      if (mouseY > againTextY) {
        if (mouseY < againTextY + fontSize) {
          reset();
        }
      }
    }
  }
}

1) Was dir zuerst auffallen dürfte, ist die Tatsache, dass viele der Variablen oben nur noch deklariert werden. Ich habe ihre Definitionen in eine Funktion reset verschoben, die einmal zu Beginn (in setup) aufgerufen wird und dann in mouseClicked, wenn das Spiel neugestartet werden soll. Dabei handelt es sich wirklich nur um die Variablen, die sich im Spielverlauf ändern. Die Koordinaten für den again?-Text tun dies bspw. nicht, sondern bleiben konstant.

Dein Aufruf von mouseClicked ist daher auch nicht mehr in setup. Generell würde ich dir empfehlen, Funktionen wie diese (auch setup) nicht manuell aufzurufen, denn sie tun ja oft mehr als nur den Teil, den du nutzen willst. Du hast dir da mit einer zusätzlichen Variable (end) und einer Abfrage beholfen, was aber deinen Code schnell komplizierter macht.

Die bessere Lösung ist es daher also, Code in verschiedene Funktionen auszulagern, die dann woanders nur noch aufgerufen werden müssen. Dabei gilt die einfache Regel: Jede Funktion erfüllt möglichst nur eine Aufgabe (nach der sie auch benannt wird). So erhöht sie ihre Wiederverwendbarkeit und der Code wird klarer.

2) Die Anzeige für den Game Over-Screen habe ich in eine eigene Funktion verschoben.

3) Die beiden Variablen screen und end habe ich gegen eine boolsche Variable end ersetzt, denn so wie es aussieht, möchtest du mit ihnen lediglich prüfen, ob das Spiel verloren wurde oder nicht. Das sind nur zwei mögliche Zustände (true / false) und dafür reicht auch nur eine einzige Variable.

4) Wenn du einmal den kompletten Bildschirm leeren möchtest, reicht es aus, die background-Funktion aufzurufen. Sie übermalt alles mit einer bestimmten Farbe. Ein extra überspannendes Rechteck brauchst du nicht.

5) Ich habe ein paar doppelte Aufrufe (z.B. mehrmaliges Setzen einer Füllfarbe) entfernt. Auch diese Zeile in draw:

float againTextWidth = textWidth("Again?");

wird nicht gebraucht.

Stattdessen habe ich ein paar Variablen für Zwischenberechnungen integriert.

6) Die draw-Funktion braucht (und sollte daher auch) nie manuell aufgerufen werden. Sie wird intern von Processing immer wieder neu gestartet. Wenn sie einmal endet, würde auch das Programm enden.

7) Hier:

if(mouseX < againTextWidth) {

fehlte noch ein Summand:

if(mouseX < againTextX + againTextWidth) {
1