Spiel bzw. Bewegungsgeschwindigkeit der Objekte an die FPS anpassen

Also ich hab ein Spiel geschrieben (oder es wenigstens versucht ;)), alles läuft meist perfekt und die FPS bleiben im Normalfall auch konstant! Aber manchmal, wenn der Player sich zum Beispiel in das Bild einer Pyramide begibt und Pixelgenaue Kollisions erkennung gefragt ist, dann brechen die FPS ein! Der Spieler wird dann natürlich automatisch langsamer, da der Gameloop ja seltener aufgerufen wird!
Nur will ich das Logischerweise nicht.

Der Spieler soll eine konstante einstellbare Geschwindigkeit haben…
Wie kann ich das berwerkstelligen?

Ich hab mir Quaxlies Spieletutorial angeguckt, aber bei mir funktioniert sein “verticalSpeed * (delta/1e9)” nicht.

Danke euch schonmal im Vorraus(Obwohl ich nachher bestimmt auch nochmal danken werde :))

Schwieriges Thema, da das sogar AAA-Spiele nicht hinbekommen.

Wie ist denn die Architektur von deinem Spiel? Gibt’s seperate Render- und Logik-Threads? Schon probiert den Benutzer im Nachhinein sterben zu lassen? Oder die Animation einzelner Objekte auszulassen? (Ohne nähere Infos kann es natürlich sein, dass das in deinem Fall überhaupt keinen Sinn ergibt.)

was soll man da sagen, klingt als hättest du schon das Konzept:
wenn die Durchgänge unterschiedlich lange dauern, muss man die Zeit messen und in einem Durchgang evtl. etwas mehr tun als sonst,
weiter bewegen

wenn es nicht geht, dann muss man die Fehler korrigieren, das Konzept ist davon nicht direkt betroffen

Genau, anders ausgedrückt statt pro gameloop durchgang die Figur um x zu bewegen sagst du meine Figur bewegt sich mit x Pixel pro Sekunde, in der Gameloop messe ich die Zeit seit dem letzten Frame und bewege die Figur dementsprechend weit. Wenn bei deiner Berechnung oben nix rauskommt check mal ob du da auch keine int verwendest (int delta/1e9 ist wahrscheinlich 0)

Ok, also ich habe wie bereits erwähnt verticalSpeed(und natürlich auch horizontalSpeed) die separat(in einer anderen Methode) berechnet werden. Dann habe ich eine move Methode, in der der vertical und der horizontal Speed + x bzw. y genommen werden.
vertical und horizontal Speed können die Werte 0 - highSpeed variabel enthalten.
Ich dachte mir ich übergebe der move Methode jetzt die FPS(bzw. delta) und gleiche demnach den Speed an.
Nur der Rechenschritt dafür kommt mir nicht in den Sinn! Quaxli macht einfach * delta/1e9 und die Sache ist im Kasten, aber bei mir funktioniert das nicht.
Bei mir kommen immer so Zahlen wie:
(delta) 10010323
(vSpeed) 0.160165168
(hSpeed) -0.220227106
(delta) 9971988
(vSpeed) 0.159551808
(hSpeed) -0.22935572399999998
Dabei heraus… Wobei sich mein Test_Player gar nicht bewegt

paar Infos, aber kein echter Fortschritt zum bisherigen Stand

vSpeed und hSpeed sind gesetzte Eigenschaften der Objekte, deren Geschwindigkeit?
delta ist irgendwas, damit rechnen, was soll man dazu sagen?

was ‘herauskommt’ ist nicht zu erkennen, oder falls 0.160165168 ein Ergebnis wäre dann kein Problem aus so einer Zahl zu erkennen,
kein Code, keine (ausreichenden) Erklärungen/ gewünschte konkrete Rechenwege, keine Beispiele, so ist nichts zu machen

blind agieren geht natürlich nicht, vielleicht ist deine Geschwindigkeit so niedrig, dass du dich nur 0.3 Pixel pro Tag bewegst,
alles muss konkret untersucht werden


delta sieht verdächtig nach Ganzzahl aus,
bei

double k = 10010323 / 1000000000;

käme 0 raus wegen int-Rechnung, aber 1e9 ist ein double, insofern dieses schon angesprochene Problem nicht zu erwarten

Die Ergebnisse kommen aus der Rechnung v/hSpeed = v/hSpeed * (delta / 1e9)

Wenn ihr in einem Spiel die Geschwindigkeit der FPS anpasst wie macht ihr das?

ich kann selber nichts konkretes beisteuern, habe nichts dazu und wenn dann eher Rundenstrategie :wink:


erkläre bitte wie du das meinst, oder ändere es gleich, meiner Ansicht nach ist die Geschwindigkeit nicht neuzuberechnen,
die Geschwindigkeit hängt nur von Spielregeln ab, ist irgendein Wert von, der Einfachheit halber positiv, 0-100, z.B. 15

dann hast du ein Delta von irgendwie gemessen 10010323,
zudem die alte Position im virtuellen Raum x = 45.4

jetzt musst du die Zahlen irgendwie zusammenführen, neuesX = 45.4 + 15 * (10010323/1e9) ~ 45.55 in meinem Beispiel,
je nach Umrechnung in Pixel, allgemeinen Wünschen Formeln an allen Ecken anpassen

so, das ist nun ein konkretes Beispiel in welchem man den Verlauf nachvollziehen kann,
wenn du statt 45.55 auf einmal -700 bekommst und Code dazu postest, könnte man vielleicht auch Fehler finden,
wahrscheinlich ohne Ausprobieren aber auch nicht, du müsstest wahrscheinlich selber jeden Wert der Rechnung anschauen

aber vielleicht ist die Erkenntnis, die Geschwindigkeit nicht neu auszurechnen schon ein Fortschritt, oder nix neues weil du es eh nicht machts,
du sparst leider mit Erklärungen was deine Codezeile bedeutet, dein zuvor genanntes „+ x bzw. y“ taucht auch gar nicht auf, siehst du Problematik?


ich habe eben übrigens nur eine Bewegung in eine Richtung x beschrieben,
in zwei wird es komplizierter, aber damit sollte man auch nicht gerade anfangen,

zwei Geschwindigkeiten sind denkbar, spontan denke ich aber auch an eine Geschwindigkeit in eine bestimmte Richtung im 2D-Raum,
etwa mehr Mathematik, sin + cos, aber alles berechenbar

Was deine v und hSpeed usw. sind ist nicht unbedingt klar.

Man kann sich aussuchen, in welcher Zeiteinheit man rechnen will. Und allgemein gilt, dass man in jedem Schritt
position += geschwindigkeit * zeitschrittgröße;
rechnet.

private long lastNS = 0;
private double position = 0;
private double velocity = 100;

void gameLoopCore()
{
    long currentNS = System.nanoTime();
    long deltaNS = (currentNS - lastNS); // Verstrichene Zeit in Nanosekunden
    double deltaYS = deltaNS / 1e3; // Verstrichene Zeit in Mikrosekunden
    double deltaMS = deltaYS / 1e3; // Verstrichene Zeit in Millisekunden
    double deltaS = deltaMS / 1e3; // Verstrichene Zeit in Sekunden

    position += velocity * deltaS;

    lastNS = currentNS;
}

Wenn daran irgendwas nicht stimmt, muss eigentlich NUR die ‘velocity’ geändert werden. Wenn es sich z.B. mit 100 Pixeln pro Sekunde bewegen soll, setzt man “velocity=100”. Man muss halt aufpassen, dass man nicht irgendwo auf ‘long’ oder ‘int’ castet, und damit die Nachkommastellen der postion abschneidet.

Du hast doch sicher schonmal von der Formel Geschwindigkeit (v) = Weg (s) / Zeit (t) gehört? Was wir herausfinden wollen ist, wo sich die Figur nach x (delta) millisekunden befinden muss, daher s= v * t oder y = verticalSpeed*delta. Das /1e9 kommt nur daher, dass delta bei Quaxli wahrscheinlich nanosekunden (System.nanoTime()) sind, und das is eine riesen Zahl.

Ok, danke schonmal ich hab jetzt geblickt was Quaxli wieso macht! Nur wieso das bei mir geht verstehe ich noch überhaupt nicht! Ich überprüfe meinen Code nochmal im Detail, jetzt da ich weiß was ich überhaupt schaffen muss ist das ne Spur einfacher!

Ich glaube mittlerweile das das Problem vielleicht(wie gesagt ich checke das nochmal genauer) nicht am eigentlichen Code bzw. an der Idee des Codes liegt!
Die Ergebnisse aus (delta / 1e9) fluktuieren nämlich zwischen: 0.010058318 und 0.009994929!
Das mal meinen Speed(sagen wir 10) ist eben etwa 0.1, das in der paintComponent dann zu int gecastet ist 0.
Nur müsste dann irgendwann, trotzdem eine Veränderung stattfinden nämlich beim 10. Durchlauf…
Nur: Es gibt keine Veränderung!
Ich blicks nicht…

Wie auch immer die Veränderung sich äußern soll: Es sollte keinen Grund geben, die Geschwindigkeit auf int zu casten - höchstens die Position, zum Zeichnen, aber auch da NUR zum Zeichnen. Also nicht

private double pos = 0.1234;
void paint()
{
    pos = (int)pos;
    drawAt(pos);
}

sondern

private double pos = 0.1234;
void paint()
{
    int posAsInt = (int)pos;
    drawAt(posAsInt);
}

Gibt einfach mal in deiner paint-Methode

System.out.println("Aktuelle position "+positionX+" "+positionY);

aus, und schau’ ob sich was tut.

Ich mache g.drawImage(player.getImage(), (int) player.x, player.y, null);
Also wird x bzw. y eigentlich nicht geändert.
Deswegen blicke ich ja auch nicht durch.

Sollte das nicht mal ins Spiele Forum verschoben werden :stuck_out_tongue:

[QUOTE=IDC]
Die Ergebnisse aus (delta / 1e9) fluktuieren nämlich zwischen: 0.010058318 und 0.009994929!
Das mal meinen Speed(sagen wir 10) ist eben etwa 0.1, das in der paintComponent dann zu int gecastet ist 0.
Nur müsste dann irgendwann, trotzdem eine Veränderung stattfinden nämlich beim 10. Durchlauf…
Nur: Es gibt keine Veränderung!
Ich blicks nicht…[/QUOTE]

das hängt von der genauen Umsetzung ab,
natürlich braucht man eine double-Variable, die auf zig Stellen genau jede Teiländerung aufaddiert,
von Runde zu Runde muss das
0.1
0.185793
0.2745984
usw. steigen, irgendwann wenn bei 1 oder schon bei 0.5 dann zum nächsten Pixel springen, wie du sagst,
aber auch dann bleibt die double Variable bei z.B. 0.53792 und steigt wieder in mehreren Schritten langsam an,

es gibt eine klare Trennung zwischen berechneten virtuellen Daten und davon abgeleitet Pixel-Ebene

Mir ist gerade folgendes aufgefallen (wobei horizontalSpeed immer 10 ist):

(delta / 1e9)0.01005786
y548.09920817
(delta / 1e9)0.009920817
y548.10026467
(delta / 1e9)0.010026467
y548.10026165
(delta / 1e9)0.010026165
y548.10000205
(delta / 1e9)0.010000205
y548.09963379
(delta / 1e9)0.009963379
y548.10032805
(delta / 1e9)0.010032805```
???????????????????????????????
What?
Ich hab (arbeite mit Netbeans) geguckt: Ich verändere y an keiner anderen Stelle(außer y += horizontalSpeed * (delta / 1e9))!!!!!!!!!!! Was soll sowas?:(

wie amüsant, Java einen Fehler in einfacher Rechnung vorzuwerfen,
was nachzuweisen zufällig 50 Mio. Programmiern in 20 Jahren nie gelungen ist,

immer liegt es am Code, Aussagen ‘ich mache es soundso’ helfen nicht wirklich

es braucht lauffähigen Code oder bei dir exaktes Log,
z.B. an jeder Additionsstelle eine Ausgabe VORHER + NACHHER, Ausgabe des ausgerechneten Summanden sowieso

sonst ist nichts endgültig zu sagen

Wenn du dir schon ausgaben machst dann gib auch alles aus. Mich würde das delta da schon interessieren…

kriech
Ich habe in meiner ‚vorausschauenden‘ Kollisionsberechnung den Player versetzt und seine alte Position in einem Point gespeichert…
Point = x/y INTEGER
Naja, jetzt läuft alles, danke für den Tipp :slight_smile: