Ergebnis 1 bis 12 von 12

Thema: Java - Einen Moment warten

  1. #1

    ~Cloud~ Gast

    Java - Einen Moment warten

    Hi!
    Mache ja mit Java kleines 2D RPG.
    Aber bei einer Sache komm ich nicht weiter, ich will das wenn man z.B. ne Map verlässt erstmal für eine kurze Zeit ein schwarzer Bildschirm kommt.

    Jemand hat mir das gesagt:

    Code:
    long waitingStartTime = System.currentTimeMillis();
        		playSound();  
        		zeichneSchwarz(g);
        		if(System.currentTimeMillis() >= waitingStartTime + 500)
        		{	
        		stopSound();
                    GameMode=2;
        		}
    Das funktioniert auch, er wartet 1-2 Sekunden und dann gehts weiter.
    Aber NUR wenn ich die Methode playSound(); da aufrufe!!

    Ansonsten wartet er unendlich lange. Will ja nicht jedesmal nen Sound abspielen wenn der Scharze Bildschirm kommt. Gibts da nen Trick oder ne andere Methode?

    playSound besteht aus dem:

    Code:
    public void playSound() {
        	 
    		try {
    			URL u = new URL();
     
    			clip = Applet.newAudioClip(u);
    			clip.play();
    		} catch (MalformedURLException e) {
    			e.printStackTrace();
    		}
    	}

  2. #2
    Äh ja, du prüfst ja auch nur einmal, ob die Zeit schon um ist. Wenn das nicht der Fall ist, prüft dein Code nie wieder.

    Das ist aber auch sonst kein guter Ansatz. Zum Warten nimmt man normalerweise Thread.sleep

  3. #3

    ~Cloud~ Gast
    Thread.sleep hab ich auch als erstes benutzt. Aber er hat dann immer erst den schwarzen Bildschirm gemalt und danach erst gewartet obwohl Thread-sleep VOR dem g.drawImage kam.

  4. #4
    Falls DFYX vom richtigen Standpunkt ausgeht, nämlich, dass der erste Codeschnipsel nicht wiederholt wird, dann kommt natürlich das Problem auf, dass im Ablauf von folgendem Code:
    Code (JAVA):
        		playSound();  
        		zeichneSchwarz(g);
     

    500 Millisekunden vorbei gehen müssen, sonst wird GameMode nie auf 2 gesetzt.

    Zitat Zitat von ~Cloud~ Beitrag anzeigen
    Thread.sleep hab ich auch als erstes benutzt. Aber er hat dann immer erst den schwarzen Bildschirm gemalt und danach erst gewartet obwohl Thread-sleep VOR dem g.drawImage kam.
    Sollte eigentlich klappen, wie du jetzt plötzlich auf g.drawImage kommst, ist nicht ersichtlich. Aber
    Code (JAVA):
     
    zeichneSchwarz(g);
    Thread t = Thread.currentThread;
    t.Sleep(500);
     

    oder so ähnlich sollte klappen. (Und sonst gibt es immernoch die Warte-Methode die man als erstes lernt: while(System.currentTimeMillis() >= waitingStartTime + 500){})

    Und falls der erste Code trotzdem mehrmals beim if vorbeikommt muss man natürlich darauf achten, dass waitingStartTime nicht jedesmal neu initialisiert wird.

  5. #5

    ~Cloud~ Gast
    Hm alle Methoden funktionieren bei mir nicht *_*
    Also ich habe in der SpielAnsichtsklasse die Run Methode drin, die ruft immer repaint auf.

    Code:
     public void run()
        {
            while(true)
            {
                try
                {
                    float START = System.currentTimeMillis();
                    repaint();
                
                    float AUSFUEHR = System.currentTimeMillis()-START;
             
                    if(33 > (int)AUSFUEHR)
                    {
                        Thread.sleep(33-(int)AUSFUEHR);
                    }
                }
                catch(Exception e){}
            }
        }
    Repaint beiinhaltet zum Teil dies:

    Code:
        	if(GameMode==0)
        	{
         	 zeichneTitel(g);   //Titelbild zeichnen
           	}
        	
        	else if(GameMode==1) 
        	{
        		
        		waitingStartTime = System.currentTimeMillis();
        		playSound();  
        		zeichneSchwarz(g);
        		if(System.currentTimeMillis() >= waitingStartTime + 500)
        		{	
        		stopSound();
                GameMode=2;
        		}
        		
        	}
        	
        	else if(GameMode==2)
        	{
              Intro(g);     // Hier soll er einen Moment warten
            GameMode=3;
          	}
    Also wenn man im Titelbildschirm Neues Spiel drückt dann ist GameMode=1 und es wird kurz ein Sound eingespielt und dann wird bei der Mehtode zeichneSchwarz(g) mit g.drawRect ein schwarzenRechteck gezeichnet.

    Dann hab ich eben das gemacht das er 1-2 Sekundne wartet das geht aber NUR wenn ich playSound() vorher mache ohne gehts auch nicht.

    Hab jetzt das von dir mal getestet mit t.sleep(); Kommt das gleiche Problem das sleep wird VOR dem zeichneSchwarz(); ausgeführt!

    Auch diese while schleife will nicht klappen...
    Mach ich was falsch?

  6. #6
    1. Gibt es bei Java eigentlich "switch" ?

    2. "zeichneSchwarz" ist doch bestimmt ne Methode, die du selbst geschrieben hast - lass die doch TRUE zurückgeben und dann per if-Abfrage prüfen, ob es TRUE ist, um nur dann sleep auszuführen. So sollte das sleep erst ausgeführt werden, wenn die Methode eben TRUE zurückgibt und somit schon vollständig durchgenommen wurde.

    lg

  7. #7
    Natürlich gibt es switch, aber ich habe gehört, dass es zumindest in C/C++ langsamer ist als if-else-if.
    Ausserdem habe ich schon darauf hingewiesen, dass du nicht jedesmal waitingStartTime auf die aktuelle "Zeit" setzen darfst, wie sollte dann auch die > waitingStartTime + 500 wahr werden?
    Man hat ein schönes Problem zu lösen, falls das sleep wirklich ausgeführt bevor alles mit Schwarz gefüllt wird, obwohl es wirklich danach im Code ist.

  8. #8

    ~Cloud~ Gast
    @Niji-chan Hab das mit True probiert geht auch nicht oO Er führt TROTZDEM das sleep FRÜHER aus!

    @Drakes Ok es scheint jetzt zu gehen ich muss einfach nur die Zahl am Ende erhöhen:

    if(System.currentTimeMillis() >= waitingStartTime + 10500)

    Naja hoffe das klappt jetzt auch weiterhin. Ihr macht das bei euch abber immer mit Thread.sleep() oder? Komisch das es be mir nicht geht...

    Edit: Korrektur, es geht zwar aber wenn ich jetzt ne Zeit im Titel bleibe und dann Neues Spiel drücke ist überhaupt keine Wartezeit mehr da...

    Geändert von ~Cloud~ (20.07.2009 um 21:49 Uhr)

  9. #9
    @Cloud:

    Dein Problem ist, dass du nicht vollkommen verstehst, was du machst und scheinbar auch keine Lust hast, es zu verstehen und stumpf Code abschreibst, der dir vorgegeben wird.

    Code (Java):
     
    else if(GameMode==1) 
    {
        waitingStartTime = System.currentTimeMillis();
        playSound();  
        zeichneSchwarz(g);
     
        if(System.currentTimeMillis() >= waitingStartTime + 500)
        {	
            stopSound();
            GameMode=2;
        }
    }
     


    Was genau passiert hier?
    Die erste Zeile im Block sichert die aktuellen Millisekunden.
    In den nächsten zwei Zeilen spielst du einen Sound ab und zeichnest dein schwarzes Rechteck.
    Der Sinn der nächsten Anweisung ist anscheinend dafür zu sorgen, dass mindestens eine halbe Sekunde (500 ms) vergeht, bevor du aufräumst und zum nächsten GameMode-Block wechselst. Hier ist auch dein Problem, denn das was du willst ist aus den folgenden Gründen nicht sichergestellt:

    1. Die Ausführungszeit von playSound() ist anscheinend weit über 500 ms. So wie du es schilderst, sind es ein paar Sekunden. Das ist auch der Grund, wieso mit der momentanen Logik das Warten ausschließlich mit playSound() funktioniert.
    2. Die Verzweigung sollte eigentlich eine Schleife sein, die solange wartet, bis mindestens die gewollte Zeit verstrichen ist.

    Mit einer Fallunterscheidung kann man das Problem nochmal verdeutlichen:

    Fall 1: 'System.currentTimeMillis()' ist kleiner als 'waitingStartTime + 500'
    Dieser Fall tritt ein, wenn playSound() nicht zuvor aufgerufen wird, da es die einzige Routine ist, die mehrere Sekunden braucht.
    Was passiert, ist folgendes: Der if-Block der Verzweigung wird nicht aufgerufen und folglich wird auch nicht in den nächsten Modus gewechselt.
    Alle anderen Durchläufe des aktuellen Blocks werden gleich ablaufen und damit ist es effektiv eine unendliche Schleife, die nur durch einen Zufall wieder Verlassen werden kann, nämlich falls durch einen zufälligen "Hänger", der nächste Fall eintritt:

    Fall 2: 'System.currentTimeMillis()' ist größer oder gleich 'waitingStartTime + 500'
    Dieser Fall tritt ein, wenn playSound() zuvor aufgerufen wird, aus bereits erläutertem Grund.
    Im Gegensatz zum ersten Fall, ist hier die Bedingung der Verzweigung erfüllt und so wird auch ihr if-Block aufgerufen und der Modus gewechselt.
    Das ist das, was du von vorne herein wolltest.

    Code ( Java):
     
    else if(GameMode==1) 
    {
        waitingStartTime = System.currentTimeMillis();
        playSound();  
        zeichneSchwarz(g);
     
        // falls noch keine 500 ms verstrichen sind, warte solange
        while (System.currentTimeMillis() < waitingStartTime + 500);
        // oder um eventuellen zukünftigen Bugs vorzubeugen, kannst du auch einen 
        // leeren Rumpf angeben, was auch als guter Stil angesehen wird:
        // while (System.currentTimeMillis() < waitingStartTime + 500) {};
     
        // werden in jedem Fall ausgeführt
        stopSound();
        GameMode = 2;
    }
     


    Die kleine Änderung oben führt schließlich dazu, dass der Modus in jedem Fall gewechselt wird.

    Beachte aber, dass playSound() mehrere Sekunden zum Ausführen benötigt, die halbe Sekunde (500 ms) in der Bedingung also in Verbindung mit playSound() vollkommen irrelevant ist. Wenn du z.B. 2 Sekunden warten willst, dann ändere '500' zu '2000'.

    Zitat Zitat von ~Cloud~ Beitrag anzeigen
    Hab jetzt das von dir mal getestet mit t.sleep(); Kommt das gleiche Problem das sleep wird VOR dem zeichneSchwarz(); ausgeführt!
    Als erstes sollte man festhalten, dass Thread.sleep() eine statische Methode ist, die immer für den aktuellen Thread gilt.
    Anweisungen wie 'Thread t = Thread.currentThread(); t.sleep(...);' oder 'Thread.currentThread().sleep(...);', die auf Instanzen arbeiten, sind also unnötig und schlechter Stil.

    Was dein Problem angeht, liegt es daran, dass Javas rendering routinen in einem eigenen Thread laufen. (Oder zumindest wird nicht direkt gezeichnet, sondern verzögert, was z.B. eintreten kann, wenn das Betriebssystem Entscheidungen darüber trifft, wann gezeichnet werden soll und wann nicht.) Was passiert ist also folgendes:
    zeichneSchwarz() beauftragt den Rendering-Thread ein schwarzes Rechteck zu zeichnen und dieser wird dem auch nachgehen, sobald er dran kommt.
    Als nächstes legst du den aktuellen Thread schlafen, er wird aber nicht unterbrochen wie bei Thread.yield() (andere Threads werden also nicht ausgeführt), was im Endeffekt dazu führt, dass zuerst gewartet wird und erst danach gezeichnet.

    Noch was zu Thread.sleep(): Wenn du exakte Wartezeiten zwischen Ausführungen haben willst, solltest du darauf verzichten, denn Thread.sleep() wartet nicht exakt, sondern mindestens, so dass es tatsächlich viele Millisekunden mehr sind, die verstreichen.

    Hier sind noch weitere Informationen zu Thread.sleep(), falls es dich interessiert.

    Eigentlich solltest du gänzlich auf blockierenden Code verzichten, falls es möglich ist, und deine Programmlogik entsprechend umstrukturieren, denn blockierender Code wird als sehr schlechter Stil angesehen, aus guten Gründen. Aber als Anfänger kann man sich sowas ruhig leisten, man wächst schließlich erst mit seinen Fehlern. ;)

    Zitat Zitat von Drakes Beitrag anzeigen
    Natürlich gibt es switch, aber ich habe gehört, dass es zumindest in C/C++ langsamer ist als if-else-if.
    Dann hast du etwas falsches gehört, denn das ist Unsinn. Im Worst Case-Szenario entsprechen Switch Cases einer If-Else-Verzweigung, können aber bei klug gewählten Case-Argumenten als einfache Jump-Anweisungen realisiert werden, was sehr schnell ist und keine Branch Mispredictions zur Folge haben kann. Im Grunde kann man besonders bei vielen Cases mit Switches also nur gewinnen.

    Geändert von Kyuu (21.07.2009 um 15:49 Uhr)

  10. #10

    ~Cloud~ Gast
    Danke für die Antwort Kyuu ich programmiere mit Java jetzt erst seit einen halben Jahr versteh deshalb auch noch nicht alles.

    Trotzdem werd ich gleich wieder verrückt. Ich hab es jetzt mit while() eingebaut, es klappt auch. Aber jetzt kommt was merkwürdiges. Nach dem Intro wird GameMode=3 gemacht dadurch wird eine Weltkarte angezeigt.

    Es hat bis heute immer geklappt aber seit ich das geändert habe wird die Weltkarte also das Bild NICHT mehr angezeigt!
    Der dazugehörige Text schon, wirklich komisch naja ich versuchs mal alleine vielleicht find ich ja den Fehler obwohl ich ausser der while nichts geändert habe.

    EDIT: Ok hab den Fehler gefunden hatte vorher das Bild als BufferedImage gemacht und nicht als Image *_*
    EDIT2: Jetzt läd das Bild aber die Warteschleife funzt nicht mehr richtig >.< Ach ich mach erstmal woanders weiter...
    EDIT3: Jetzt geht es aufeinmal nur teilweise, zwei Schleifen gehen die letzte nicht.

    Geändert von ~Cloud~ (21.07.2009 um 17:45 Uhr)

  11. #11
    Zitat Zitat von ~Cloud~ Beitrag anzeigen
    EDIT: Ok hab den Fehler gefunden hatte vorher das Bild als BufferedImage gemacht und nicht als Image *_*
    EDIT2: Jetzt läd das Bild aber die Warteschleife funzt nicht mehr richtig >.< Ach ich mach erstmal woanders weiter...
    EDIT3: Jetzt geht es aufeinmal nur teilweise, zwei Schleifen gehen die letzte nicht.
    Vielleicht wäre es eine gute Idee deine Werkzeuge zu wechseln? Python und Pygame wären beispielsweise eine viel bessere Wahl als Java und ihre GUI-Bibliotheken, die wirklich für GUI-Applikationen ausgelegt sind. Python ist einfach zu erlernen und Pygame liefert alles, was man zum Entwickeln eines Spieles benötigt. Ein Neuanfang würde dir auch die Chance geben, deine Programmlogik noch einmal von Grund auf zu überdenken.

  12. #12

    ~Cloud~ Gast
    Man wie dumm bin ich?! Hab es jetzt anders gemacht was funktioniert -.-"

    Code:
    else if(GameMode==2)  
        	{
           	   Intro(g);
           	   zaehler++;
           	 
           	   if(zaehler==300)
           	   zeichneWelt(g);  
               
           	   else if(zaehler==600)
           	   GameMode=5;
           	   
          	}
    Thread kann auch geschlossen werden.
    @Kyuu Ich werd mir Pygame mal anschauen.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •