Autor Beitrag
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Di 02.01.18 14:33 
moin EE,
heute mal etwas Anspruchsvolleres - ich hoffe jemand nimmt sich dessen an :)

Ich arbeite derzeit an meinem ersten 'echten' 3D Spiel mit OpenGL. Ich bin aber gerade mal bis zur Steuerung gekommen - dort ist ein Problem aufgetreten, welches ich einfach nicht gelöst bekomme:

Der Spieler (ein Würfel) soll sich in die Richtung bewegen, in die er gedreht ist. Klingt eigentlich relativ einfach.
Mein Ansatz: Ich drehe den Beschleunigungs-Vektor relativ zur Blickrichtung, und addiere den zum Geschwindigkeitsvektor (die Zeitänderung mit einbezogen).
Im Code sieht das dann so aus:
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
    void move() {
      glm::vec3 dv(
        getForce(X),
        getForce(Y),
        getForce(Z)
      );
      
      v += glm::rotate(dv, player->rot.y, glm::vec3(0, -10));
      player->pos += v * Time::diff;
    }

glm::rotate wird in diese Fall der Vektor, der Winkel und die Achse als Argument übergeben. Das -1 kommt vmtl daher, dass in OpenGL die Z-Achse nach hinten ausgerichtet ist.

Problem ist nun, dass er (der Spieler) sich ab einem Winkel von ca 90° in Spiralenförmigen Bewegungen vom Ausgangsort entfernt, wenn man sich bewegen will. Ist der Winkel kleiner, bewegt er sich als wäre man gar nicht gedreht. Logischerweise funktioniert die Bewegung wie sie sollte, wenn man die Beschleunigungsrotation weglässt.

Ich muss vmtl nochmal erklären, wie ich meine Bewegung überhaupt umgesetzt habe.
Es gibt wie gesagt eine Beschleunigung const float a[3] = { 402040 }; //acceleration (force)
Eine Beschleunigungsrichtung int8_t ad[3] = { 0, -10 }; //acc direction
Eine Geschwindigkeit glm::vec3 v(0); //velocity
eine Maximalgeschwindigkeit const float vmax[3] = { 51005 }; //max velocity
und die Position und rotation (die in einem Extra Objekt gespeichert ist, welches ich für die 3D Darstellung Erstellt habe. Da sind zB Funktionen fürs Laden und Zeichnen in OpenGL drin) glm::vec3 player->pos, player->rot
die Rotation wird immer um die jeweilige Achse im Bogenmaß (0 - 2pi) angegeben
die Änderungen werden immer mit dem Zeitunterschied in sekunden multipliziert float Time::diff

Zusammengefasst:
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
#define X 0
#define Y 1
#define Z 2
#define vFromH(v, a) sqrt(-2*a*v)

    Object3D* player;

    const float
      bounce = 0.2f,            //bounciness
      a[3] = { 402040 },    //acceleration (force)
      vmax[3] = { 51005 },  //max velocity
      vJump = vFromH(5, -a[Y]); //jump strength

    int8_t ad[3] = { 0, -10 };  //acc direction
    glm::vec3 v(0);               //velocity

in der Move-Funktion wird die Beschleunigung in eine Achsenrichtung ermittelt:
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
    float getForce(uint8_t d) {
      float dv;
      if (ad[d]) {              //accelerate
        if (d != Y)
          dv = 0;
        dv = ad[d] * a[d] * Time::diff;
        if (abs(v[d] + dv) > vmax[d]) {
          if (v[d] + dv > 0return vmax[d] - v[d];
          return -vmax[d] - v[d];
        }
      } else {                  //brake
        if (!v[d]) return 0;
        dv = a[d] * Time::diff;
        if (v[d] > 0) dv = -dv;
        if (v[d] * (v[d] + dv) < 0return -v[d]; //if change of sign -> v = 0
      }
      return dv;
    }


Ich hoffe das reicht fürs Prinzip, ansonsten Hänge ich nochmal das komplette VS Projekt inkl. ext. Header und Libs in den Anhang. Besagter Code befindet sich alles in Game.cpp. Bitte x86 also 32bit Windows als Zielplattform einstellen. Bewegt wird sich mit WASD, Drehung per Maus oder Pfeilasten LR

Danke im Vorraus für eure Hilfe :)
LG,
Symbroson

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Bei den Grundlagen stütze ich mich vor allem auf dieses OpenGL-Guide: www.opengl-tutorial.org
Die haben dort sehr schöne Erklärungen und Beispiele um mit OpenGL zurecht zu kommen. Die haben dort auch das Bewegungsproblem umgesetzt (www.opengl-tutorial....-keyboard-and-mouse/ ), allerdings etwas anders
dort wird ohne Beschleunigung gearbeitet, sondern für jede Richtung (rechts und vorwärts) ein Vektor erstellt der mit der Geschwindigkeit (const float) multipliziert und zur Position addiert wird. Da ich aber für die Physik eh Beschleunigungen brauche hab ich es gleich verallgemeinert.
Einloggen, um Attachments anzusehen!
_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)


Zuletzt bearbeitet von Symbroson am Mo 08.01.18 17:22, insgesamt 2-mal bearbeitet

Für diesen Beitrag haben gedankt: LINUS19
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: So 07.01.18 14:09 
[Push]
Hat denn wirklich niemand eine Idee? Wenigstens einen Ansatz?
Vom Quellcode mal abgesehen - was könnte ein solches Verhalten verursachen?

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Do 11.01.18 22:47 
Da sich die Antworten so häufen, frag ich einfach mal: An was scheitert es denn? an der Sprache? An OpenGL? Dem Vektorenverständnis bzw meiner Implementierung? Oder doch an dem Problem generell?

Ich habe die Frage sogar schon im OpenGL Forum gestellt, aber auch da scheint niemand Antworten zu können...
www.opengl.org/discu...=1289981#post1289981

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 11.01.18 23:38 
Vielleicht solltest Du nochmal genauer erklären, was da passieren soll.

Im Moment sieht es für mich so aus, als soll folgendes heraus kommen: Ohne die Rotation fliegt ein Quader durch die Gegend und wird konstant in eine Richtung beschleunigt. Mit Rotation wird diese Beschleunigung gedreht, das heißt er wird in eine andere Richtung beschleunigt als bisher und fliegt eine Kurve. Richtig?

Ich habe noch nicht wirklich komplett verstanden, wie das ganze funktionieren soll, aber mir kommt es z.B. komisch vor, dass vor der Drehung von dv sicher gestellt wird, dass vmax nicht überschritten wird, denn mit dem gedrehten dv kann ja vmax dann durchaus überschritten werden. Ob das Bremsen mit der nachgelagerten Drehung so funktionier, weiß ich gerade auch nicht.


Was mir auch komisch vorkommt: dein Vektor dv hat immer nur eine Komponente in Richtung Y. Und Du drehst ihn um die Y-Achse. Wieso ändert er sich dann?

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Do 11.01.18 23:59 
Zitat:
Ohne die Rotation fliegt ein Quader durch die Gegend und wird konstant in eine Richtung beschleunigt
richtig, er wird mithilfe der Pfeiltasten in X- bzw. Z-Achsen-Richtung beschleunigt

Zitat:
Mit Rotation wird diese Beschleunigung gedreht, das heißt er wird in eine andere Richtung beschleunigt als bisher und fliegt eine Kurve. Richtig?
genau, er soll in die Richtung beschleunigen, in die der Spieler schaut. Also soll die Beschleunigung um den Winkel gedreht werden, in den der Spieler um die Y-Achse gedreht ist. Die Bewegung sollte sich dann eigentlich nach und nach dem neuen Winkel anpassen, stattdessen entsteht aber eine spiralenförmige Bewegung. Der einzige Grund der mir dazu einfiele wäre, dass der Beschleunigungswinkel irgendwie relativ zur Blickrichtung wirkt.

Zitat:
denn mit dem gedrehten dv kann ja vmax dann durchaus überschritten werden.
Nagut, eigentlich müsste ich den Betrag, also die Länge des Vektors begrenzen, das hab ich der einfachheit halber außer Acht gelassen. Das wäre zumindest schonmal ein Fehler, der zu fixen wäre

Zitat:
Was mir auch komisch vorkommt: dein Vektor dv hat immer nur eine Komponente in Richtung Y.
nein, hat er nicht - denn durch den Tastaturinput werden die Werte in 'ad', also der Beachleunigungsrichtung verändert (-1 bzw. 1 oder 0 wenn nicht beschleunigt wird - dann wird stattdessen gebremst)
Das Y ist von Anfang an -1, weil das die Gravitation simuliert - die wird bisher nicht von irgendeinsr Eingabe verändert, sondern bleibt die ganze Zeit über konstant


Vielen Dank erstmal dass du dich damit beschäftigt hast - ich werde morgen nachmittag mal das Problem mit dem Geschwindigkeitsmaximum beheben und sehen, was dabei herauskommt

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Fr 12.01.18 19:30 
Ich habe jetzt den Fehler bzgl der Geschwindigkeitsbegrenzung behoben, indem ich eine extra Funktion für die Begrenzung angelegt habe. Um beim Bremsen aber noch den Vorzeichenwechsel bei der Geschwindigkeit zu bemerken, musste ich mir eine extra Variable - vLast - anlegen.
es sieht komplizierter aus, als es ist - hab auch nochmal extra für euch ausführlich in deutsch kommentiert
ausblenden volle Höhe C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
    glm::vec3 v(0), vLast;

    void move() {
      glm::vec3 dv(   //ermittelt geschwindigkeits-differenz zum nächsten Frame
        getForce(X),
        getForce(Y),
        getForce(Z)
      );

      //dreht geschwindigkeits-änderungs-Vektor um Y-Achse in Blickrichtung
      v += glm::rotate(dv, player->rot.y, glm::vec3(0, -10));

      //wendet Maximalgeschwindigkeit an
      cropVel(X);
      cropVel(Y);
      cropVel(Z);

      //bewegt den Spieler
      player->pos += v * Time::diff; 

      //speichert Geschwindigkeit für nächste Berechnung
      vLast = v;                     
    }

    void cropVel(uint8_t d) {
      if (ad[d]) {                              //beim Beschleunigen
        if (v[d] > 0) {                         //  bei Positiver geschwindigkeit 
          if (v[d] > vmax[d]) v[d] = vmax[d];   //    v > vmax?
        } else                                  //  bei negativer geschwindigkeit 
          if (v[d] < -vmax[d]) v[d] = -vmax[d]; //    v < -vmax?
      } else                                    //beim Bremsen 
        if (v[d] * vLast[d] < 0) v[d] = 0;      //  Vorzeichenwechsel -> Beschleunigung beenden
    }

    float getForce(uint8_t d) {
      if (ad[d])                                //beim Beschleunigen 
        return ad[d] * a[d] * Time::diff;       //  richtung*beschl*Zeitdifferenz
      else {                                    //beim Bremsen
        if (!v[d]) return 0;                    //  keine Geschwindigkeit -> kein Bremsen nötig
                                                //  gegen geschwindigkeitsrichtung bremsen
        else if (v[d] < 0return a[d] * Time::diff;
        else return -a[d] * Time::diff;
      }
    }

Das ursprüngliche Problem hat es aber nicht behoben...

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Sa 13.01.18 12:35 
Moin,

ich versuche mal ein bisschen mich dem Problem anzunehmen ;-)

Wenn ich einfach so ins Blaue raten würde, warum dein Code nicht funktioniert, würde ich annehmen, dass es an deiner cropVel Funktion liegt. Die Komponenten des Vektors einzeln zu limitieren ist sehr viel weiter von einer Normierung des Vektors auf eine bestimmte Länge entfernt, als du vermutlich annimmst.

Vermutlich ist es empfehlenswert, Vektorrechnung auch auf Vektoren auszuführen und nicht zu versuchen, die Operationen einzeln auf die Komponenten des Vektors zu verteilen. So, wie du es jetzt umgesetzt hast, muss man sehr viel Gehirnenergie darauf verwenden, diese Aufteilung zu verstehen, und die tatsächliche Physik hinter deiner Steuerung verschwindet irgendwie.

Ich würde also folgendes Refactoring vorschlagen:

ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
struct Actor {
  float mass;
  glm::vec3 x;  // position
  glm::vec3 dx; // velocity

  // vielleicht noch einen praktischen Konstruktor hinzufügen
}


Eine Kraft, die auf einen Actor wirken kann, kannst du dann als Vektor repräsentieren.

ausblenden C++-Quelltext
1:
typedef glm::vec3 Force;					


Jetzt brauchst du nur noch eine Funktion, die für dich simuliert.

ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
Actor simulate(const Actor& actor, const Force& f, const float dt) const {
  auto x = actor.x + actor.dx * dt;
  auto dx = actor.dx + f / actor.mass * dt; 
  
  return {actor.mass, x, dx};
}


ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
// angenommen, wir haben eine Box "box" 
Actor box = {1.0f, {0.f0.f0.f}, {0.f0.f0.f}};
// und eine Kraft "f", sagen wir 1N in x-Richtung. 
Force f = {1.f0.f0.f}; 

// kannst du jetzt simulieren:
while (true) {
  box = simulate(box, f, Time::diff); 
}


Ich würde jetzt die Limitierung der Geschwindigkeit als unphysikalische Nichtlinearität innerhalb von simulate implementieren:

ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
Actor simulate(const Actor& actor, const Force& f, const float dt) const {
  auto x = actor.x + actor.dx * dt;
  auto dx = actor.dx + f / actor.mass * dt; 

  if (glm::abs(dx) > 42.f) {
    dx = dx / glm::abs(dx) * 42.f// Vektor normieren, dann skalieren. Ob es glm::abs gibt oder nicht, ist mir vollkommen unklar ;-) 
  }
  
  return {actor.mass, x, dx};
}

Etwas cooler wäre natürlich einen realen physikalischen Effekt zu implementieren. Beispielsweise eine einfache Reibung oder einen Luftwiderstand. Soetwas z.B.
ausblenden C++-Quelltext
1:
2:
3:
4:
Force drag(const Actor& actor) {
  // angenommen cw * A * rho sei konstant = 1.0f
  return -(actor.dx / glm::abs(actor.dx)) * std::pow(glm::abs(actor.dx), 2);
}

was man dann als zusätzliche Kraft auf die Box wirken lassen kann.

Kommen wir also zum eigentlichen Problem: Wenn die Beschleunigung in die Blickrichtung des Spielers wirken soll, können wir jetzt einfach eine Kraft definieren, die in genau diese Richtung zeigt.
ausblenden C++-Quelltext
1:
2:
3:
// Ich will jetzt nicht ausschließen, dass dein Koordinatensystem anders ist, als ich hier annehme (x nach rechts, z nach oben, y in den Bildschirm hinein.) 
float alpha = player->rot.y; 
Force forwardForce = {std::cos(alpha), 0.f, std::sin(alpha)} * 10.f;



Anmerkungen

  • Der gesamte Code in dieser Antwort ist ungetestet und wird sicherlich nicht kompilieren, da ich ihn direkt in der Antwort geschrieben habe
  • Man kann den Actor natürlich mit geeigneter Objektorientierung etwas flexibler designen, z.B. simulate als abstrakte Methode in einer Basisklasse definieren und so verschiedene Modelle und Nichtlinearitäten in unterschiedlichen Implementierungen dieser Basisklasse zu ermöglichen.


Vielleicht hilft dir mein Ansatz etwas weiter, deinem Problem auf die Schliche zu kommen (und ich glaube ganz selbstbewusst, dass mein Code etwas aufgeräumter ist ;-)).

Für diesen Beitrag haben gedankt: Symbroson
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Sa 13.01.18 12:46 
Okay - vielen vielen Dank erstmal für deine ausführliche Antwort :zustimm: - ich werde einfach mal versuchen das so umzusetzen wie du es vorschlägst. Einige Parallelen sind zwar vorhanden (zB Box~Object3D oder Force~a (beschleunigung) wobei ja a=F/m, und m ist in dem Falle einfach 1)
Das prinzip ist aber auf jeden Fall interessant :les: - mal sehen was da rauskommt ^^

danke nochmal und LG,
Symbroson

Zitat:
x nach rechts, z nach oben, y in den Bildschirm hinein.
x nach rechts, y nach oben und z den Bildschirm hinaus ;)

Moderiert von user profile iconChristian S.: Beiträge zusammengefasst

Bei der einzelnen Behandlung von x,z und y Geschwindigkeit habe ich mir gedacht, dass man ja schneller fallen kann, als laufen. Deshalb gibt es für (x,z) und (y) verschiedene Geschwindigkeitsmaxima

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Sa 13.01.18 18:28 
Ich hatte angefangen, deine Variante umzusetzen, bis mir auffiel, dass beide eigentlich sehr ähnlich in der Umsetzung aussähen. Deshalb hab ich mir nochmal das mit der Begrenzung angeschaut, und hab das in der vorherigen Variante angepasst:
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
float Player::vmax = 5;
/* ... */
    void move() {
      glm::vec3 dv(
        getForce(X),
        getForce(Y),
        getForce(Z)
      );

      float dvges = sqrt(dv.x*dv.x + dv.z*dv.z);
      dv.x = dvges * std::sin(player->rot.y);
      dv.z = dvges * std::cos(player->rot.y);

      v += dv;
      
      float vges = sqrt(v.x*v.x + v.z*v.z);
      if (vges > Player::vmax) printf("%f    %f\n", dv.x, dv.z), v = Player::vmax * v / vges;

      player->pos += v * Time::diff;
      vLast = v;
    }

Jetzt bewegt er sich tatsächlich immer in die Blickrichtung :D
Einziges Problem hierbei wäre noch, das er das immer tut. Einmal eine Taste gedrückt und er bewegt sich für alle Zeiten - aber immer in Blickrichtung ^^.
Ich hatte vermutet, dass das dadurch zustande kommt, dass das Vorzeichen der ursprünglichen Bewegung nicht mehr beachtet wird, da nur der betrag der Beschleunigung betrachtet wird, aber wenn ich das mit einbeziehe verhält es sich noch seltsamer als die Spiralenbewegungen - er macht sozusagen was er will...
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
      float dvges = sqrt(dv.x*dv.x + dv.z*dv.z);
      
      if (dv.x < 0) dv.x = -dvges * sin(player->rot.y);
      else dv.x = dvges * sin(player->rot.y);
      
      if (dv.z < 0) dv.z = -dvges * cos(player->rot.y);
      else dv.z = dvges * cos(player->rot.y);


Dann hab ich mir nochmal das mit der Rotation überlegt. Theoretisch wäre der Winkel in die sich der Spieler bewegt der Winkel in die er schaut plus den Winkel der durch die Pfeiltasten bewirkt wird. Dann kann ich durch den Betrag der XZ-Geschwindigkeit und den Winkel, in den er sich bewegen soll, die gedrehte beschleunigung errechnen. Nur kommt da schon wieder dieses seltsame Problem:
ausblenden volle Höhe C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
    void move() {
      glm::vec3 dv(
        getForce(X),
        getForce(Y),
        getForce(Z)
      );
      
      float ang = atan2(dv.x, dv.z) + player->rot.y;
      //Ausgabe: Blickwinkel, Pfeiltastenwinkel, resultierender Bewegungswinkel, Winkel nach Bewegung
      //ich hätte erst vermutet, dass es atan2(cos,sin) sein müsste, aber das war irgendwie nicht so
      //der Winkel nach Bewegung ist jetzt so eingestellt, dass er gleich dem resultierender Bewegungswinkel ist
      printf("%f\t%f\t%f\t%f\n", player->rot.y, atan2(dv.x, dv.z), ang, atan2(sin(ang), cos(ang)));
      //wenn ich folgende zwei Zeilen auskommentiere, werden alle Winkel richtig errechnet
      //wenn sie aber drin sind, ist sogar die obige Ausgabe fehlerhaft, obwohl beide nichts miteinander zu tun haben
      dv.x = total*sin(ang);
      dv.z = total*cos(ang);

      v += dv * Time::diff;
      
      total = sqrt(v.x*v.x + v.z*v.z);
      if (total > Player::vmax) {
        v.x = Player::vmax * v.x / total;
        v.z = Player::vmax * v.z / total;
      }
      if (!ad[X] && vLast.x * v.x < 0) v.x = 0;
      if (!ad[Y] && vLast.y * v.y < 0) v.y = 0;
      if (!ad[Z] && vLast.z * v.z < 0) v.z = 0;

      player->pos += v * Time::diff;
      vLast = v;
    }


Ich bringe dann doch erstmal deine Variante zu Ende...

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Sa 13.01.18 18:59 
ok hier mal was ich bisher habe:

Actor.h
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
#pragma once

#include "Object3D.h"

class Actor : public Object3D {
public:

  float mass;
  glm::vec3 v; //velocity
  //pos and rot come from Object3D

  Actor(uint8_t type, GLuint texture, GLuint shader, glm::vec3 pos = glm::vec3(0), float mass = 1);
  Actor(Object3D obj, glm::vec3 pos = glm::vec3(0), float mass = 1);
  ~Actor();

  void move(glm::vec3 force, float dt);
};

Actor.cpp
ausblenden C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
#include "stdafx.h"
#include "Actor.h"

Actor::Actor(uint8_t type, GLuint texture, GLuint shader, glm::vec3 pos, float mass) : Object3D(type, texture, shader) {
  this->pos = pos;
  this->mass = mass;
}

Actor::Actor(Object3D obj, glm::vec3 pos, float mass) : Object3D(obj) {
  this->pos = pos;
  this->mass = mass;
}

Actor::~Actor() {}

void Actor::move(glm::vec3 force, float dt)  {
  v += dt * force / mass;
  pos += dt * v;
}

game.cpp
ausblenden volle Höhe C++-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
namespace Game {
  /* ... */

  namespace Player {
    Actor* player;

    const float
      vmax = 5,
      bounce = 0.2f,
      aMove[3] = { 20, -9.81f20 },
      vJump = vFromH(5, -aMove[Y]);

    bool collided = false;
  }

  /* ... */
}

/* ... */

void Game::handleInput() {
  // Keyboard
  if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) Player::player->v.y = Player::vJump;
  if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) Player::player->rot.y += Mouse::speed;
  if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) Player::player->rot.y -= Mouse::speed;

  //die Stelle sier sieht seltsam aus, ich weiß
  //beschleunigung * x/y-Komponente des Winkels * Tastendruck
  glm::vec3 force = {
    Player::aMove[X] * std::cos(Player::player->rot.y) * ((glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) - (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)),
    Player::aMove[Y],
    Player::aMove[Z] * std::sin(Player::player->rot.y) * ((glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) - (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS))
  };

  Player::player->move(force, Time::diff);

  /* ... */
}

Entspricht das in etwa deinen Vorstellungen, Finn?

was noch fehlt wäre die Haftreibung bzw Bremsen, wenn nicht beschleunigt wird,
und ein Fehler ist, dass man sich bei je 90° Drehung nur in zwei anstatt vier Richtungen bewegen kann
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
blick pfeil beweg(relativ zu blickrichtung)
------------------
  0°  oben   links
      unten  rechts
 90°  links  links
      rechts rechts
180°  oben   links
      unten  rechts
-90°  links  links
      rechts rechts

die jeweils anderen zwei Pfeiltasten bewirken nichts

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)


Zuletzt bearbeitet von Symbroson am Sa 13.01.18 19:20, insgesamt 4-mal bearbeitet
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Sa 13.01.18 19:10 
Moin,

mir ist noch ein Rätsel, in welche Richtung du jetzt beschleunigen willst. In Blickrichtung des Spielers, oder woanders hin? Ich hätte jetzt erwartet, dass die Pfeiltasten hoch und runter maximal das Vorzeichen der Beschleunigung beeinflussen und die Pfeiltasten links und rechts entsprechend den Spieler um die Y-Achse rotieren.

Aber das ist natürlich am Ende deine Entscheidung.
Symbroson Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 382
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Sa 13.01.18 19:13 
Nunja, der Spieler kann sich auf der Horizontalen XZ-Ebene in jede beliebige Richtung drehen (per Maus oder Pfeiltasten) - daraus resultiert die Blickrichtung.
und mit WASD soll man sich ja trotzdem noch abhängig von der Blickrichtung nach vorn, hinten, links oder rechts bewegen können

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)