workshop 19

Top  Zurück  Weiter

Workshop 19: Die Physik-Engine

In diesem Workshop werden Sie ein bisschen was über die dritte, in der letzten Lektion erwähnte Bewegungsmethode lernen: die auf den Gesetzen der Physik basierende Bewegung. Für diesen Workshop benötigen Sie Gamestudio/A8 oder besser (wenn Sie noch Version 7 benutzen, lesen Sie über ODE physik in work19o_d.html). Stellen Sie sicher, dass die nVidia PhysX Engine auf Ihrem PC installiert ist - normalerweise ist dies der Fall, wenn Sie Gamestudio installiert haben. Starten Sie SED und öffnen Sie die Datei script19x.c. Starten Sie das Projekt und Sie finden sich in einem Spiele-Level wieder, in welchem Sie über die Pfeiltasten einen Ball steuern können.

w19_1

Ziel dieses Spieles (ja, es ist ein Spiel!), ist es, den Ball solange zu bewegen, bis er die kleine Plattform oben im Level erreicht. Drücken Sie auf die Pfeiltasten und Sie sehen, daß der Ball sich bewegt, als wirke eine unsichtbare Kraft auf ihn. Nun, es wird tatsächlich eine unsichtbare Kraft auf ihn angewandt!

///////////////////////////////////////////////////////////////
#include <acknex.h>
#include <default.c>
#include <ackphysx.h>
///////////////////////////////////////////////////////////////

VECTOR ball_force;
ENTITY* ball;
   
function main()
{
  physX_open();
  level_load("roller.wmb"); // load the level
  
  ball = ent_create ("ball.mdl", vector(-400, 0, 100), NULL); // create the ball
  pXent_settype (ball, PH_RIGID, PH_SPHERE); // set the physics entity type
  pXent_setfriction (ball,50); // set the friction on the ground
  pXent_setdamping (ball,10,10); // set the damping
  pXent_setelasticity (ball,50); // set the elasticity
  
  while (1)
  {
    ball_force.x = (key_cur-key_cul)*10*time_step; // rotate the ball about the global x axis
    ball_force.y = (key_cuu-key_cud)*10*time_step; // rotate the ball about the global y axis
    ball_force.z = 0; // no need to rotate about the vertical axis
    pXent_addtorqueglobal (ball, ball_force); // add a torque (an angular force) to the ball
    camera.x = ball.x - 300; // keep the camera 300 quants behind the ball
    camera.y = ball.y; // using the same y with the ball
    camera.z = 1000; // and place it at z = 1000 quants
    camera.tilt = -60; // make it look downwards
    wait(1);
  }
}

Können Sie das glauben? Wir brauchen weniger als 20 Codezeilen und alles spielt sich innerhalb der Main-Funktion ab! Nun, das ist das, was ich das 'lite' von Lite-C nenne!

Wie Sie sehen, haben wir eine neue Datei per #include hinzugenommen: ackphysX.h. Diese Datei enthält alle Physik-Befehle, also müssen wir sie stets hinzufügen, wenn wir die Physik-Engine benutzen wollen.

Am Anfang definieren wir einen VECTOR namens ball_force. Ein VECTOR ist wie eine var, enthält aber 3 Werte: x, y und z. Darin werden wir die Rotations-Kraft des Balls auf den x-, y-, und z-Achsen speichern. Dann definieren wir noch einen Entity-Pointer mit dem Namen ball, der für unseren Ball benutzt wird.

In der main-Funktion haben wir zuerst die Physik-Engine "eingeschaltet": physX_open(). Das Hinzufügen von ackphysX.h und Aufruf von physX_open() sind die beiden Dinge, die zum Verwenden von Physik nötig sind. Ein Level, welches in WED erstellt wurde, roller.wmb, wird als Nächstes geladen. Dann erstellen wir den Ball im Level, und zwar bei x = -400, y = 0, z = 100, wofür wir die Datei ball.mdl verwenden. Wir haben einen namens ball definierten Entity-Pointer und das ist der Name, der unserer neu erstellten Entity gegeben wird.

Die folgenden Codezeilen melden unsere Ball-Entity bei dem Physik-System an und setzen ihre Eigenschaften. Grübeln Sie nicht, wir werden diese eine nach der anderen durchgehen.

- pXent_settype (ball, PH_RIGID, PH_SPHERE) sagt unserem Ball, daß er sich unter Physik-Gesetzen bewegen soll (PH_RIGID) und zwar mit einer Kollisionshülle, welche sich wie eine Kugel verhält (PH_SPHERE). Wie Sie sehen, setzt die Form unseres Modells nicht automatisch das zur ihr passende physikalische Verhalten. Würde ich meine Kugel ball.mdl einfach durch einen Würfel ersetzen, würde der nagelneue Würfel sich weiter drehen und rollen als wäre er eine Kugel, denn phent_settype hat ihm gesagt, daß er das tun soll. Alles klar?

- pXent_setfriction (ball, 50) setzt den Reibungskoeffizienten auf 50. Der Wert kann sich von 0 (wie Eis) bis hin zu 100 (wie Gummi) erstrecken.

- pXent_setdamping (ball, 10, 10) setzt sowohl die Bewegungs- als auch die Rotations-Dämpfung auf 10. Dies ist eine einfache und doch effektive Methode, Luftwiderstand und Reibung zu simulieren. Ohne dieses bremsende Dämpfen würde sich unser Ball unendlich weiterdrehen.

- pXent_setelasticity (ball, 50) setzt den Abprallfaktor unseres Balls auf 50. Ansonsten würde er stets am Boden kleben.

Ich weiß, hier haben wir jede Menge neuer Informationen, wenn Sie mit all den numerischen Werten aber ein wenig herumspielen, werden Sie deren Sinn und Zweck sehr schnell begreifen. Kümmern wir uns doch gleich noch um den while-Loop:

while (1)
{

       ball_force.x = (key_cur-key_cul)*10*time_step;
       ball_force.y = (key_cuu-key_cud)*10*time_step;
       ball_force.z = 0;

Diese Codezeilen setzen je nach Status der Cursor- bzw. Pfeiltasten (auf der Tastatur) die passenden Werte von ball_force.x und ball_force.y. key_cur ist die vordefinierte Variable, die den Status der rechten Pfeiltaste annimmt, key_cul den der linken usw. Jede Taste hat so eine Variable; sie ist 1, wenn die Taste gedrückt ist, sonst 0. Betrachten wir uns als Beispiel nun einmal die möglichen Werte für ball_force.x in Abhängigkeit von key_cur und key_cul:

a) ball_force.x = 0 wenn keine der beiden Tasten gedrückt ist, denn key_cur = 0, key_cul = 0, also folgt daraus 10 * time_step * (0 - 0) = 0; der Ball bekommt keine Kraft.

b) ball_force.x = 180 * time_step wenn der Player die rechte Pfeiltaste drückt, denn key_cur = 1, key_cul = 0, also wird 10 * time_step mit (1 - 0) multipliziert, der Ball bekommt eine positive Kraft.

c) ball_force.x = -180 * time_step wenn der Player die linke Pfeiltaste drückt, denn key_cur = 0, key_cul = 1, also wird 10 * time_step mit (0 - 1) multipliziert, der Ball bekommt eine negative Kraft.

d) ball_force.x = 0 wenn der Player rechte und linke Pfeiltaste gleichzeitig drückt, denn key_cur = 1, key_cul = 1, also ist der Multiplikationsfaktor (1 - 1) = 0, der Ball bekommt keine Kraft.

Dasselbe passiert bei der drauffolgenden Codezeile, die für die Kraft in y-Richtung zuständig ist. Indem wir die x- und y-Kräfte des Balls miteinander kombinieren, können wir jedmöglichen Punkt im Level erreichen. Diese Art der Operation (key_a - key_b) ist eine sehr häufig vorkommende Sache und wird in vielen Spielen zum Steuern der Player-Bewegung etc. benutzt. - In AUM und in den weiteren Workshops finden Sie eine Menge an ähnlichen Beispielen.

Sie sehen, daß sich der Ball überhaupt nicht um die z-Achse bewegt. Mit einer ähnlichen Codezeile können Sie, wenn Sie wollen, dafür sorgen, daß der Ball sich je nach Status von zwei anderen Tasten um die z-Achse rechts oder links herum dreht. Werfen wir einen Blick auf die nun folgende Codezeile innerhalb unserer Schleife:

       pXent_addtorqueglobal (ball, ball_force);

Die Anweisung pXent_addtorqueglobal weist einer Entity ein Drehmoment (Winkel-Kraft) zu. In unserem Fall wird die vom Vektor namens ball_speed angegebene Kraft der Entity namens ball zugewiesen und sorgt so dafür, daß der Ball sich um die X-Achse oder um die Y-Achse dreht, wenn der Player die Pfeiltasten drückt.

Wenn Sie sich noch an unsere time_step Erklärung in Workshop 10 erinnern, wundern Sie sich vielleicht, warum wir die Winkelkraft mit time_step multiplizieren. Das macht die Kraft um so kleiner, je höher die Framerate ist. Wir haben verstanden, dass eine zurückgelegte Distanz pro Frame von der Framerate abhängen sollte, aber eine Kraft? In diesem Fall auch. Wir wenden diese Kraft in jedem Frame innerhalb der while Schleife an. Unser Ball bekommt also jeden Frame einen kleinen Schubs. Wenn wir ihn jedesmal mit der gleichen Kraft schubsen würden, dann würde er bei einer hohen Framerate schneller rollen, denn er bekommt dann mehr Schubse. Wir gleichen dies per time_step aus, indem wir die Kraft abhängig von der Framerate reduzieren.

       camera.x = ball.x - 300;
       camera.y = ball.y;
       camera.z = 1000;
       camera.tilt = -60;

Die letzten paar Codezeilen in der Schleife setzen eine für die Kamera (unser "Auge" im Level) passende Position. Sie plazieren die Kamera 300 Quants hinter dem Ball auf der x-Achse während sie zu jeder Zeit dasselbe y beibehält. Und schließlich befindet sich die Kamera bei 1000 Quants auf der z-Achse und schaut nach unten, denn ihr tilt-Winkel ist auf -60 Grad gesetzt.

Ich hoffe, Sie haben Lust, noch mehr über die Physik-Engine zu lernen. Lesen Sie das Gamestudio-Handbuch, dort finden Sie weitere verfügbare Funktionen. Und vor allem - machen Sie Experimente!

 

Weiter: Sprites. Animierte Sprites


Mehr zum Thema: Gamestudio Handbuch, Physik.