kostenloser Webspace werbefrei: lima-city


OpenGL - Objekt mit konstanter Geschwindigkeit bewegen

lima-cityForumProgrammiersprachenJava

  1. Autor dieses Themas

    ultimate-bravery

    ultimate-bravery hat kostenlosen Webspace.

    Hallo zusammen,

    das ist zwar eher eine mathematische Frage aber da ich sie mit Java umsetze pack ich es mal hier rein. Also ich programmiere ein kleines 2D Breakout Spiel mit OpenGL (die Z-Achse wird einfach ignoriert).

    Die Kugel bekommt am Anfang eine y Geschwindigkeit von 0.008. Das heißt in jedem Frame wird auf die y Position der Kugel 0.008 drauf gerechnet. Sie fliegt also am Anfang nach oben. Normalerweise ist es bei Breakout ja so, dass man am Anfang an eine Stelle klicken kann, wo die Kugel hin fliegen soll. Vielleicht mach ich es später auch noch so, aber momentan habe ich es so, dass die x Geschwindigkeit zufällig aus einem Bereich von -0.002 und +0.002 ermittelt wird. Wenn die Kugel auf einen der äußeren Drittel der Spielfigur unten oder auf einen Stein trifft, dann wird die x Geschwindigkeit ebenfalls um einen Zufallswert zwischen 0.001 und 0.0025 geändert. Wenn die Kugel in die Mitte der Spielfigur oder einem Stein abprallt wird nur der y Wert geändert.

    Da die x Geschwindigkeit also zufällig ist, fliegt die Kugel auch unterschiedlich schnell. Wie kann ich es jetzt machen, dass die Kugel immer gleich schnell fliegt und der Winkel trotzdem gleich bleibt?

    Kann man das mithilfe der x und y Geschwindigkeiten und einem konstanten Wert welcher die tatsächliche Geschwindigkeit ausdrückt ausrechnen?

    Danke schonmal für die Hilfe, viele Grüße :)
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Angenommen speed ist der Geschwindigkeitsvektor und v Geschwindigkeit, die Du haben willst (Pseudocode)
    speed = speed * (v / speed.length())

    speed.length() sollte dabei der Betrag des Vektors, also seine Länge sein.
    Idee: Du skalierst den Vektor, so dass er eine Länge von 1 hat (normalisierst ihn) und multiplizierst ihn dann mit der gewollten Länge.

    Nebenbei erwähnt solltest Du nicht davon ausgehen, dass jeder Frame gleich viel Zeit benötigt, die Geschwindigkeit also immer noch mit der vergangenen Zeit seit dem letzten Frame multiplizieren!
  4. hackyourlife

    Moderator Kostenloser Webspace von hackyourlife

    hackyourlife hat kostenlosen Webspace.

    Was du außerdem noch tun könntest: einfach eine Geschwindigkeit (bei dir: 0.008) und einen zufälligen Winkel wählen. Dann lässt sich mit sin/cos von Polarkoordinaten (Winkel & Länge) in kartesische Koordinaten (x und y) umrechnen, welche du ja als Vektor haben willst. Falls du sin/cos schnell berechnen kannst, kannst du dir auch die Polarkoordinaten merken und bei Richtungsänderungen ändern, und dir jedes Mal aufs Neue die kartesischen Koordinaten ausrechnen, die du für die Bewegung der Kugel brauchst.

    Wenn es um 3D-Koordinaten geht, macht man es übrigens oft auch so: Richtungsvektor (normalisiert auf Länge 1) und Geschwindigkeit (Skalar) speichern, und bei Änderung der Richtung den Richtungsvektor per Matrix »drehen« (und anschließend wegen auftretenden Rundungsfehlern wieder normalisieren). Für eine Verschiebung rechnet man dann mit Richtungsvektor ⋅ Geschwindigkeit.

    davidlw schrieb:
    Nebenbei erwähnt solltest Du nicht davon ausgehen, dass jeder Frame gleich viel Zeit benötigt, die Geschwindigkeit also immer noch mit der vergangenen Zeit seit dem letzten Frame multiplizieren!
    Das kann man durchaus tun, aber nur, wenn man dafür sorgt, dass jeder Frame wirklich gleich lange braucht. Das hat dann allerdings immer noch den Nachteil, dass alles in »Zeitlupe« abläuft, wenn die Hardware aus irgend einem Grund zu langsam ist. Zu empfehlen ist dieses Verfahren daher eher nicht.

    ultimate-bravery schrieb:
    Normalerweise ist es bei Breakout ja so, dass man am Anfang an eine Stelle klicken kann, wo die Kugel hin fliegen soll. Vielleicht mach ich es später auch noch so […]
    Das ist übrigens ganz einfach lösbar:
    Richtung = Mausklick - Startpunkt;
    Richtung = Richtung / Richtung.length();
    Der Vektor
    Richtung
    hat nun eine Länge von 1 und zeigt in die Richtung, in die die Kugel fliegen soll. Du kannst dann
    Richtung
    noch mit einer beliebigen Geschwindigkeit multiplizieren, oder dies in jedem Frame durchführen, je nachdem wie du das implementierst.
  5. hackyourlife schrieb:
    Das kann man durchaus tun, aber nur, wenn man dafür sorgt, dass jeder Frame wirklich gleich lange braucht. Das hat dann allerdings immer noch den Nachteil, dass alles in »Zeitlupe« abläuft, wenn die Hardware aus irgend einem Grund zu langsam ist. Zu empfehlen ist dieses Verfahren daher eher nicht.
    Ich glaube, Du hast mich nicht richtig verstanden. Bisher sieht es für mich so aus, als ob er in jedem Frame eine fixe Geschwindigkeit der Position hinzu addiert. Daher kommt ja dann bei langsamer Hardware das Zeitlupenproblem. Ich meinte, dass er die Geschwindigkeit nocheinmal mit der Zeit seit dem letzten Frame multiplizieren sollte, damit läuft das Spiel dann auch bei langsameren Systemen gleich schnell. Wie gesagt, man sollte eben nicht davon ausgehen, dass jeder Frame immer gleichlang benötigt.
  6. hackyourlife

    Moderator Kostenloser Webspace von hackyourlife

    hackyourlife hat kostenlosen Webspace.

    davidlw schrieb:
    Ich glaube, Du hast mich nicht richtig verstanden. Bisher sieht es für mich so aus, als ob er in jedem Frame eine fixe Geschwindigkeit der Position hinzu addiert. Daher kommt ja dann bei langsamer Hardware das Zeitlupenproblem. Ich meinte, dass er die Geschwindigkeit nocheinmal mit der Zeit seit dem letzten Frame multiplizieren sollte, damit läuft das Spiel dann auch bei langsameren Systemen gleich schnell. Wie gesagt, man sollte eben nicht davon ausgehen, dass jeder Frame immer gleichlang benötigt.
    Doch, ich hab dich schon richtig verstanden. Ich sagte lediglich, dass es durchaus auch Fälle gibt, in denen man das genau so (= fixe Frame-Zeit annehmen) problemlos tun kann (und die sind genau dann, wenn man dafür sorgt, dass jedes Frame gleich lange braucht, mit Warten usw). Und beispielsweise auf einer Konsole hast du auch nicht das Problem mit »jeder hat andere HW«, sondern dort kannst du einfach auf das V-Sync warten und gut ist es. Und schon hast du konstant 60 Frames pro Sekunde, von denen jedes genau gleich lang braucht (natürlich nur, wenn Berechnungen für ein Frame auch schnell genug sind, sonst geht das so natürlich nicht). Und, man wird es kaum glauben, bei einigen Konsolenspielen ist das sogar tatsächlich so gelöst (Frame-Zeit = 1/60s, am Ende des Frames auf das V-Sync warten).

    Falls diese Überlegungen für zu viel Verwirrung gesorgt haben: Sorry.
    Falls jetzt kommt »das macht der TE aber sicher nicht!«: vermutlich ist das richtig. Für ihn ist tatsächlich die Variante mit variabler Framezeit (= wie du es vorgeschlagen hast) besser. Aber das heißt noch lange nicht, dass nur die Variante mit variabler Framezeit möglich/richtig ist! Und grundsätzlich war es nur das, worauf ich hinweisen wollte :-P
  7. Autor dieses Themas

    ultimate-bravery

    ultimate-bravery hat kostenlosen Webspace.

    davidlw schrieb:
    Angenommen speed ist der Geschwindigkeitsvektor und v Geschwindigkeit, die Du haben willst (Pseudocode)
    speed = speed * (v / speed.length())

    speed.length() sollte dabei der Betrag des Vektors, also seine Länge sein.
    Idee: Du skalierst den Vektor, so dass er eine Länge von 1 hat (normalisierst ihn) und multiplizierst ihn dann mit der gewollten Länge.


    Danke für eure Antworten. Das mit den Frames lasse ich erstmal außen vor. Jetzt erstmal zu der konstanten Geschwindigkeit. Ich habe es mal so versucht wie davidlw es vorgeschlagen hat. Das sieht bei mir so aus:

    public void startGame(){
    	if(!isStarted){
    		// Zufällige x Richtung am Anfang (zwischen -0.001 und +0.001)
    		float xSpeed = getRandomFloat(-0.002f, 0.002f);
    		float ySpeed = 0.008f;
    		setSpeed(xSpeed, ySpeed);
    		isStarted = true;
    	}
    }
    	
    private void setSpeed(float xSpeed, float ySpeed){
    	Vector3f speed = new Vector3f(xSpeed, ySpeed, 0.0f);
    	speed.normalize();
    	ball.setxSpeed(speed.x*0.02f);
    	ball.setySpeed(speed.y*0.02f);
    }


    Es werden also erstmal die ermittelten Werte an die setSpeed Funktion übergeben. Diese packt die Werte in ein Vektor und normalisiert diesen. Dann werden die neuen Werte des Vekors mit einer festen Zahl multipliziert. Wenn ich das Spiel jetzt starte scheint es auch zu funktionieren. Die Kugel scheint sich immer gleich schnell zu bewegen. Wenn jetzt allerdings eine Kollision stattfindet wird die Kugel auf einmal viel schneller. Das wird ausgeführt wenn eine Kollision mit einem Stein im rechten Drittel des Steins stattfindet und die Kugel somit weiter nach rechts abprallen soll:

    // Ball soll weiter nach rechts abprallen (Koordinatensystem geht in meinem Fall nach rechts ins negative)
    float xSpeed = ball.getxSpeed()-getRandomFloat(0.001f, 0.0025f);
    // Die y Geschwindigkeit wird umgekehrt
    float ySpeed = -ball.getySpeed();
    setSpeed(xSpeed, ySpeed);
    // Objekt verschwinden lassen...


    Die vorhandenen x und y Geschwindigkeiten werden also verändert und an die selbe Funktion wie oben übergeben. Aber wie gesagt, dann wird die Kugel auf einmal um einiges schneller. Weiß jemand woran es liegt bzw was ich falsch gemacht habe?

    EDIT:

    Ich habe es jetzt hinbekommen, indem ich die Rechnung mit dem Normalvektor erst kurz vor der Bewegung ausführe und die errechneten Werte für die x und y Geschwindigkeit auf die jeweilige Position addiere.

    Beitrag zuletzt geändert: 25.12.2015 20:12:45 von ultimate-bravery
  8. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!