2D-Grafik Mit Pause drawen

memuench

Mitglied
Hallo,
Ich habe bei meinem Frogger-Clon nun ein Thread implementiert, der nun die Autos spawnt und jedes Mal neu generiert, wenn diese das Bild verlassen. So weit so gut. Um den Schwierigkeitsgrad nun zu erhöhen will ich es so machen, dass eine zufällige Anzahl an Autos reinfährt. Aber wie zeichne ich da den Abstand zwischen den Autos? Denn wenn ich einfach car[0].setLocation mache, aktualisiert sich ja die vollständige Location, auch vom ersten Auto.
 

Harry Kane

Top Contributor
Zuwenig Info für eine sinnvolle Analyse.
Brauchst du eine Kollisionserkennung, die verhindert, dass zwei Autos dieselbe Position haben?
Denn wenn ich einfach car[0].setLocation mache, aktualisiert sich ja die vollständige Location, auch vom ersten Auto.
Wenn car ein Array von Autos ist, ist es doch logisch, dass mit car[0].setLocation die Location vom ersten Auto geändert wird, und zwar nur vom ersten Auto und nicht "auch vom ersten Auto".
 

memuench

Mitglied
Zuwenig Info für eine sinnvolle Analyse.
Brauchst du eine Kollisionserkennung, die verhindert, dass zwei Autos dieselbe Position haben?

Wenn car ein Array von Autos ist, ist es doch logisch, dass mit car[0].setLocation die Location vom ersten Auto geändert wird, und zwar nur vom ersten Auto und nicht "auch vom ersten Auto".
Hi, sorry ich habe mich sehr ungenau ausgedrückt. Und zwar folgendes:
- cars[0] bis cars[3] sind jeweils Farbvariationen und stellen jeweils eine Straße dar. Heißt cars[0] ist ein blaues Auto was auf der 1. Straße von oben spawnt. cars[1] spawnt auf der 2.Straße in roter Farbe etc. Ich will jetzt, dass je nachdem was ich bei Math.random() *3 +1 bekomme, 1 - 3 Autos hintereinander reinfahren.
Bsp.: Ich habe ein Array randoms mit 4 Zufallszahlen. Das erste Element spiegelt die erste Straße mit blauen Autos wieder, wie oben erwähnt usw. Wenn nun randoms[0] 3 ist, sollen also auf der ersten Straße 3 blauen Autos einfahren.

Java:
class FroggerGamePanel extends JPanel{
          Frogger help=gi.getCurr();
   
        public FroggerGamePanel() {
            cars = gi.getEnemies();
            setPreferredSize(new Dimension(600,400));
            setOpaque(true);
           
        }
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(io.ImageLoader.getActor("froggerstreet"),0,0,null);
            g.drawImage(io.ImageLoader.getActor("froggerstart"), 0, 300, null);   
            help.paint(g);
            int[] spawnNo = new int[4];
            for(int j=0;j<spawnNo.length;j++) { //Die Zufallszahlen generiert
                spawnNo[j] = (int)(Math.random()*3)+1; 
            }
            for(int i=0;i<cars.length;i++) { //Zeichnen der 4 Autos (eins pro Straße)
      
                        cars[i].paint(g);
                    }
                   

                   
                }
               
            }
        }
    }

Das ist die interne Klasse, wo ich das Frogger Spielfeld zeichne. Und das der Bewegungsthread für die Autos und die autonome Bewegung:
Java:
    class CarMovementThread extends Thread{
        public void run() {
            while(true) {
           
                    for(int i=0;i<cars.length;i++) {
                        //Zeichnen
                       

                        if(i==0||i==2) {
                            cars[i].moveLeft();
                   
                            fgp.repaint();
                        }
                       
                        else {
                            cars[i].moveRight();
                            fgp.repaint();
                        }
                       
                        if(cars[0].getX()<0&&cars[2].getX()<0) {
                            //Wenn Autos an Ziel angekommen, zurücksetzen der Pos
                            int streetLength = game.GameSettings.getStreetHeight() / 5;
                            int help = 0;
                            for(int j=0;j<cars.length;j++) {
                                if(j==0 || j==2 ) {
                                    cars[j].setLocation(game.GameSettings.getScreenWidth(), help);
                                    help += streetLength;
                                }
                               
                                else {
                                    cars[j].setLocation(0, help);
                                    help += streetLength;
                                }
                           
                            }
                           
                        }
                       
                           
                    }
                   
                    try {  //Pause
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
           
               
               
            }
           
           
   
           
        }
    }

Und wie gesagt, ich möchte nun, dass nicht nur pro Straße ein Auto reinfährt, sondern je nach Zufallszahl auch mal 2. Wie mache ich das nun am geschicktesten?
 

JCODA

Top Contributor
Mache keine Logik innerhalb der paint-Methode.
Die Logik sollte innerhalb des Threads stattfinden. (Bei einem Spiel ist es üblich die Logik jeden Frame laufen zu lassen, d.h. eine Pause von 30ms liefert eine FPS von etwa 1000/30 = 33)
Zudem sollte das repaint nur einmal am Ende der Spielschleife auf dem Panel aufgerufen werden, falls du Swing mit passivem zeichnen benutzt.
Man kann auf aktives Zeichnen wechseln, aber für den Anfang könnte das auch ein wenig verwirrend sein.
 

memuench

Mitglied
Mache keine Logik innerhalb der paint-Methode.
Die Logik sollte innerhalb des Threads stattfinden. (Bei einem Spiel ist es üblich die Logik jeden Frame laufen zu lassen, d.h. eine Pause von 30ms liefert eine FPS von etwa 1000/30 = 33)
Zudem sollte das repaint nur einmal am Ende der Spielschleife auf dem Panel aufgerufen werden, falls du Swing mit passivem zeichnen benutzt.
Man kann auf aktives Zeichnen wechseln, aber für den Anfang könnte das auch ein wenig verwirrend sein.
Ok vielen Dank für die Tipps, ändere ich morgen ab. Hast du vielleicht eine Idee wie ich o.g. implementieren könnte?
 

JCODA

Top Contributor
Meist zählt man die vergangene Zeit mit. Damit kann man mit nur einer Variable einen "Timer" bauen. Da die Autos eine gewisse Zeit benötigen um vom Fleck zu kommen, kann man diesen Timer auf einen bestimmten wert legen. Die "wartenden" Autos kann man in einer Liste speichern. (Diese könnte man nur durch einen Integer abbilden etwa: auf welcher Straße diese auftauchen können.)
 

memuench

Mitglied
Ok wie wäre es so:

ArrayList<Car> waitingList = new ArrayList<Car>();
Nun befüllen mit allen Autos, die noch fehlen. Also z.B. Straße 1 hat einen Wert 3 also müssen 2 wartende Autos rein. Wenn der von dir genannte Timer rum ist ( wie sehe denn hier ein Konstruktor aus? ) kommt die zweite Welle an Autos und im obigen Beispiel wäre nun noch 1 wartendes Auto drin. Versteh ich das richtig?
 

JCODA

Top Contributor
Etwa so:
Code:
lastTime = getTime()
spawnTimer = 3000 // alle 3 Sekunden erscheint ein Auto
while true:
   delta = getTime()-lastTime // Berechne Zeit seit dem letzten Frame
   lastTime = getTime() //Speichere letzten Zeitpunkt
   if spawnTimer >0: //Falls der spawnTimer läuft
      spawnTimer-=delta // Verringere spawnTimer um die vergangene Zeit delta
      if spawnTimer<0: // Timer abgelaufen?
         spawnCar()     //Auto hinzufügen
         if isThereAnotherCar(): // gibt es weitere wartende Autos?
             spawnTimer = 3000 // setze Timer auf gewünschten Wert
   panel.paint() // falls passives Zeichnen verwendet
   sleep(30) // pause für Logik
 

memuench

Mitglied
Etwa so:
Code:
lastTime = getTime()
spawnTimer = 3000 // alle 3 Sekunden erscheint ein Auto
while true:
   delta = getTime()-lastTime // Berechne Zeit seit dem letzten Frame
   lastTime = getTime() //Speichere letzten Zeitpunkt
   if spawnTimer >0: //Falls der spawnTimer läuft
      spawnTimer-=delta // Verringere spawnTimer um die vergangene Zeit delta
      if spawnTimer<0: // Timer abgelaufen?
         spawnCar()     //Auto hinzufügen
         if isThereAnotherCar(): // gibt es weitere wartende Autos?
             spawnTimer = 3000 // setze Timer auf gewünschten Wert
   panel.paint() // falls passives Zeichnen verwendet
   sleep(30) // pause für Logik
Ok danke, ich les mich da mal ein! Könnte man jedoch theoretisch auch Wait() von einem Thread als "Timer" verwenden? Es erfüllt doch letztendlich den selben Zweck, oder?
 

JCODA

Top Contributor
solche "Timer" benötigt man meist sehr sehr oft. Und oft hat man nur einen Thread. Ich weiß nicht wie aufwendig bei dir alles wird. Ich hab' bisher immer versucht solche Dinge möglichst LightWeight zu halten.
 

memuench

Mitglied
solche "Timer" benötigt man meist sehr sehr oft. Und oft hat man nur einen Thread. Ich weiß nicht wie aufwendig bei dir alles wird. Ich hab' bisher immer versucht solche Dinge möglichst LightWeight zu halten.
Hallo JCODA, ich habe nun die Logik in den Thread verschoben und auch die repaint-Methode nur einmal ausgeführt. Es sieht viel jetzt um einiges flüssiger aus. Nun habe ich auch eine Beispiel Car-Klasse erstellt, die ich als zweites in die Straße reinfahren lasse. Hier ist mir nun aufgefallen, dass das reinfahrende Auto wesentlich schneller ist als das bereits vorhandene obwohl ich nirgendwo die Speed-Variable getweakt habe. Fällt dir was auf im Code?
PS: toLeft ist die zusätzliche Autoklasse. Die Geschwindigkeit wird im Car Konstrukter standardmäßig auf 15 gesetzt
Java:
class FroggerGamePanel extends JPanel{
          Frogger help=gi.getCurr();
          int[] spawnNo;
        public FroggerGamePanel() {
            cars = gi.getEnemies();
            setPreferredSize(new Dimension(600,400));
            setOpaque(true);

            toLeft = new Car(ActorType.CAR_RED);
            toLeft.setLocation(game.GameSettings.getScreenWidth(), 0);

}
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            g2.drawImage(io.ImageLoader.getActor("froggerstreet"),0,0,null);
            g2.drawImage(io.ImageLoader.getActor("froggerstart"), 0, 300, null);  
            help.paint(g2);
            toLeft.paint(g2);

          
            for(int k=0;k<cars.length;k++) {
                cars[k].paint(g2);
            }
}}

Java:
class CarMovementThread extends Thread{
        public void run() {
            while(true) {
          
                    for(int i=0;i<cars.length;i++) {
                        //Zeichnen
                      

                        if(i==0||i==2) {
                            cars[i].moveLeft();
                          
                            long startTime = System.currentTimeMillis();
                            long elapsedTime = 0L;

                            while (elapsedTime < 30) {
                                //perform db poll/check
                                elapsedTime = (new Date()).getTime() - startTime;
                            }

                                toLeft.moveLeft();
                      
                      
                        }
                      
                        else {
                            cars[i].moveRight();
                            long startTime = System.currentTimeMillis();
                            long elapsedTime = 0L;

                            while (elapsedTime < 30) {
                                //perform db poll/check
                                elapsedTime = (new Date()).getTime() - startTime;
                            }

                                //noch keine Autos
                      
                  
                          
                        }
                      
                        if(cars[0].getX()<0&&cars[2].getX()<0) {
                            //Wenn Autos an Ziel angekommen, zurücksetzen der Pos
                            int streetLength = game.GameSettings.getStreetHeight() / 5;
                            int help = 0;
                          
                          
                            toLeft.setLocation(game.GameSettings.getScreenWidth(), 0);
                            for(int j=0;j<cars.length;j++) {
                                if(j==0 || j==2 ) {
                                    cars[j].setLocation(game.GameSettings.getScreenWidth(), help);
                                    help += streetLength;
                                }
                              
                                else {
                                    cars[j].setLocation(0, help);

                                    help += streetLength;
                                }
                          
                            }
                          
                        }
                      
                        fgp.repaint();
                          
                    }
 

JCODA

Top Contributor
Achso ich sehe gerade, dass du innerhalb der Schleife die Zeit misst. So war das leider nicht gemeint.
Sondern es gibt eine einzige Spielschleife. Dort wird die Zeit gemessen.
So wie du es momentan machst, hat es etwa den selbe Effekt wie ein sleep(30).
 

Castyll

Aktives Mitglied
Achso ich sehe gerade, dass du innerhalb der Schleife die Zeit misst. So war das leider nicht gemeint.
Sondern es gibt eine einzige Spielschleife. Dort wird die Zeit gemessen.
So wie du es momentan machst, hat es etwa den selbe Effekt wie ein sleep(30).
Ich verstehe das noch nicht doch ganz, was meinst du in dem Fall mit Spielschleife? Also wo wird die gemacht, wie sieht diese aus?
Vielen Dank
 

JCODA

Top Contributor
Wenn du mir den kompletten Code als zip zur Verfügung stellst, versuch ich das mal einzubauen.
Hier ist das eher schlecht, weil ich den Code dann ja auch testen möchte, ob es tatsächlich klappt.
 

Castyll

Aktives Mitglied
Wenn du mir den kompletten Code als zip zur Verfügung stellst, versuch ich das mal einzubauen.
Hier ist das eher schlecht, weil ich den Code dann ja auch testen möchte, ob es tatsächlich klappt.
Danke, sehr nett fürs testen! Angehangt ist die Projekt Zip. Nicht wundern, die Autos werden noch nicht angezeigt (ein anderer Fehler), es sind stattdessen auch Frösche ;) Der Code Ausschnitt von eben befindet sich unter ui->FroggerFrame
 

Anhänge

  • Frogger.zip
    144,8 KB · Aufrufe: 3

JCODA

Top Contributor
Ein paar Dinge die ich aufgeräumt hab:
- Enum speichert nun das Bild, spart einige Abfragen.
- GameController enthält die Spielschleife.
- starten jetzt über die RunGame-Klasse
- Autos werden nun einfach mal zufällig erzeugt, nach einer anderen Idee als deine, schau's dir mal an, wie dir das gefällt.
- die Bewegung ist nun flüssig, indem die Geschwindigkeit der Autos mit der vergangenen Zeit multipliziert wird.
- Konstanten kann man ruhig public static final machen.
Man kann noch einiges mehr aufräumen, aber dazu hab' ich jetzt einfach keine Lust mehr :D

Für ein paar weitere Anregungen, kannst du vllt. http://www.ralf-bauer.org/java/tutorial/Tutorial.zip reinschauen.
 

Anhänge

  • Frogger.zip
    144,7 KB · Aufrufe: 4

Castyll

Aktives Mitglied
Ein paar Dinge die ich aufgeräumt hab:
- Enum speichert nun das Bild, spart einige Abfragen.
- GameController enthält die Spielschleife.
- starten jetzt über die RunGame-Klasse
- Autos werden nun einfach mal zufällig erzeugt, nach einer anderen Idee als deine, schau's dir mal an, wie dir das gefällt.
- die Bewegung ist nun flüssig, indem die Geschwindigkeit der Autos mit der vergangenen Zeit multipliziert wird.
- Konstanten kann man ruhig public static final machen.
Man kann noch einiges mehr aufräumen, aber dazu hab' ich jetzt einfach keine Lust mehr :D

Für ein paar weitere Anregungen, kannst du vllt. http://www.ralf-bauer.org/java/tutorial/Tutorial.zip reinschauen.
Vielen lieben Dank dass du dir die Zeit genommen hast, sieht echt super aus !
Könntest du mir vielleicht noch kurz erklären, was der Sinn von den delta Parametern in GameController ist? Das verstehe ich noch nicht ganz. Aber nochmal vielen Dank
 

JCODA

Top Contributor
Alles ist Zeitabhängig, das Bewegen der Autos, das Erscheinen der Autos, die Kollisionüberprüfung (zumindest, so wie du sie hattest, ggf könnte man noch eine flimmerAnimation reinmachen, sodass man sieht, dass eine Kolission nicht mehrere Leben kostet) und der Punktezuwachs ist ebenfalls Zeitabhängig. Das delta ist eben die Zeit seit dem letzten Schleifendurchlauf.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Thread macht keine Pause AWT, Swing, JavaFX & SWT 22
G Pause-Button AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben