gmphysics tutorial?

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Ghostrider hat mal was gemacht.
      Guter alter tipp: SuFo. :D
      Melancor wars...
      Spoiler anzeigen
      Um nicht schon wieder einen neuen Thread zu diesem Thema zu erstellen (diesmal auch noch bei Tutorials), bleibe ich jetzt mal mit meinem Monolog hier. Ich gehe davon aus, daß Moderatoren verschieben und löschen, will den Mods aber nicht zu viel Arbeit machen .... (grins)


      Du beherrscht die Struktur von GML? Gut. Wenn Du mit Surfaces, Instances oder gar mit Primitives arbeiten kannst, dann sind auch Bodies, Polygons und Joints
      (ja, Joints) für Dich kein Problem, denn GMPhysics (kurz GMP) ist mundgerecht für uns gemacht. Du wirst kein einziges Mal external_call schreiben müssen,
      denn für jede Funktion gibt es ein mehr oder weniger knappes Skript, das den Zugriff auf die vier dlls für Dich übernimmt.

      Nachdem Du GMP ausgepackt hast, schau Dir zuerst das Polygons Example an. Es enthält wie alle Examples das GMP-Grundgerüst aus Skripten und globalen
      Konstanten (die für die Skripte gebraucht werden), und darüberhinaus nur wenige, einfache Objekte.
      Wenn Du das Objekt control ansiehst, findest Du im create-event zunächst folgenden Befehl:

      init_physics()

      Wie der Name schon sagt, ist diese Funktion genau einmal, nämlich als erstes aufzurufen. Mit release_physics() kann die Physik wieder ausgesachaltet (Speicher freigegeben) werden, und mir reset_physics() kann man den Ur- bzw. Ruhezustand wiederherstellen. Ignoriere zunächst den Rest vom create und geheins step-event:

      update_bodies()

      ist ebenfalls zum Funktionieren notwendig. Führt man den Befehl nicht aus, friert die Physik ein. Wenn Du unter scripts - GMPhysics - World öffnest, findest
      Du diese Funktionen dort wieder. In der Beschreibung (im Skript-Text) steht bei update_bodies, daß man als argument0 einen Step-Faktor angeben kann, falls der Update nur jeden 2. Step durchgeführt werden soll (Bei room speed 60 durchaus eine Überlegung wert, wegen CPU-Last)
      Freundlicher Weise sind alle Funktionen von GMP in Form dieser "dokumentierten" Skripte gefasst, deshalb reicht etwas Englisch um deren Anwendung zu erlernen. Insgesamt gibt es in dem Ordner World noch viele andere Funktionen, von denen Du die meisten nicht brauchen wirst, aber auch solche Sachen wie create_explosion oder set_wind.

      Erst einmal will wir den Aufbau von bodies behandeln. Sieh Dir im Example den Block (nicht den Static Block) an: Da steht in jedem event quasi nur ein
      Befehl. Also create, update und destroy.

      h = create_body()

      object_update(h)

      destroy_body(h)

      Bei create_body steht natürlich noch mehr, mir geht es jetzt nur um den Aufbau an sich. Wie üblich liefert die erste Funktion als Ergebnis h den Index des erstellten body's zurück. Erstmal aber noch kurz was zum object_update: Öffne einmal alle drei Skripte (in der Liste "Body" ganz oben)

      object_update(h)
      body_update(h)
      actor_update(h)

      Du siehst, dort werden lediglich die x- und y- Koordinaten bzw. direction von GMP an GM übergeben oder umgekehrt. Der sogenannte ACTOR spielt eine besondere Rolle, ebenso wie statische (STATIC) bodies. Wenn ein Body nicht bewegt wird (siehe Static Block Objekt) braucht er auch kein update, denn dieser beansprucht wieder eine Menge Rechenleistung. Aber später erähle ich noch was über ACTOR und STATIC.
      Jetzt aber zum create_body: Für den Anfang oder auf die Schnelle kann man einen Body automatisch erstellen lassen, nämlich mit
      h = create_body_auto()



      //creates a new body automatically; put this in the create event of your object (NOTE: this may fail if the sprite is invalid)
      //returns the handle to the body

      return create_body(x,y,1,SHAPE_TRIMESH, create_polygon_auto(sprite_index, 6, 20));


      Das nimmt schon gleich den nächsten Punkt vorweg, nämlich das normale

      h = create_body(...,...,...)



      //creates a new body
      //arg0 - x position
      //arg1 - y position
      //arg2 - density (most stability if set around or at 1; you can set its mass manualy)
      // Use STATIC for a static body that does not move and has infinite masss
      // use ACTOR to make a body movable and but cannot react to physics; usefull for player characters
      //arg3 - shape ID:
      // SHAPE_BOX: your basic box
      // arg4 - width; arg5 - height;
      // SHAPE_SPHERE: your basic sphere
      // arg4 - radius;
      // SHAPE_CAPSULE: a box with half circles on the ends; good for ragdolls
      // arg4 - height; arg5 - radius;
      // SHAPE_FLUID: a fluid particle; good for small amounts of liquid,blood,ect...; be carefull not to make too much
      // arg4 - radius (1-3 is a good radius)
      // SHAPE_PARTICLE: a fluid particle with no physical size or mass
      // SHAPE_PLANE: an infinite plane; good for the ground; nothing penetrates it
      // arg4 - normal direction of the plane
      // SHAPE_LINE: a thin line which should be static; size set with set_line_size
      // arg4 - width of the line; arg5 - rotation of the line
      // SHAPE_TERRAIN: a special polygon were the y direction is infinitely extended, like a bumpy plane;
      // CURRENTLY UNSTABLE AND NOT WORKING RIGHT
      // arg4 - polygon ID
      // SHAPE_TRIANGLE: your basic triangle
      // arg4 - width; arg5 - height; arg6 - X position of the topmost vertex
      // SHAPE_ELLIPSE: your basic ellipse
      // arg4 - x radius; arg5 - y radius;
      // SHAPE_NGON: a shape with a width, height, and N sides
      // arg4 - x radius; arg5 - y radius; arg6 - number of sides (>= 3)
      // SHAPE_POLYGON: a relitively fast method for polygons; best when static; current polygon-polygon collision sometimes doesnt work
      // arg4 - polygon ID;
      // SHAPE_LINE_LIST: the old polygon method; probably the fastest but is "hollow"; line size set with set_line_size
      // arg4 - polygon ID
      // SHAPE_CONVEX: the most accurate and fastest method but for convex polygons only; if concave, it will be converted to convex
      // arg4 - polygon ID
      // SHAPE_TRIMESH: the most accurate but slowest polygon method.
      // arg4 - polygon ID
      // SHAPE_COMPOUND: a blank body with no shapes initially added; you must use add_shape later on
      // NOTE: all bodies no matter what shape used are compound and you can add shapes to them
      //returns the new body ID
      return external_call...


      Density (Dichte): Jawohl, Dichte. Ich nehme immer 1 und passe danach das Gewicht an, aber man kann variieren. "most stability" heißt nicht Systemstabilität,

      sondern Masseträgheit. Die shape ID gibt an, welche Form der Body hat. Wichtig ist ganz unten SHAPE_COMPUND, falls man mehrere SHAPES zu einem Body kombinieren will (ohne Gelenke). Die einzelnen SHAPES werden dann danach mit add_shape hinzugefügt.
      Für Kugeln nimmt man natürlich SHAPE_SHPERE, und ganz einfache bodies lassen sich auch mit SHAPE_BOX etc. erstellen. Aber sei gewarnt: Du wirst den Body nicht grafisch angezeigt bekommen und es erfordert schon etwas Übung. GMP nimmt uns diese Arbeit jedoch ab. Deshalb komme ich gleich von den Bodies eine Ebene tiefer zu den Polygon-Funktionen.
      Hier gibt es gleich vier verschiedene Methoden, Bodies aus Polygonen zu erstellen. Wichtig sind erstmal zwei davon, nämlich die, die auch im Example verwendet werden:

      SHAPE_CONVEX :Am schnellsten und am genausten, aber nur Für Polygone OHNE KONKAVEN (also nach innen gewölbte Kanten).
      SHAPE_TRIMESH:Die zwar langsamste, aber auch für Polygone MIT KONKAVEN geeignete Methode.

      Schnell und langsam bezieht sich leider auf den update, ist also ernstzunehmen. Wenn Du zum Beispiel einen Wurfstern betrachtest, so hat dieser sehr wohl Konkaven, wird aber auch bewegt und soll jeden step seinen update erhalten. Für gerade diesen ist also SHAPE_TRIMESH ungeeignet wegen der CPU-Last. Eine Kombination aus einfacheren SHAPES kommt eher in Frage, benötigt aber auch viel Leistung wenn es zu viele sind. Man ist dadurch manchmal zu der Überlegung gezwungen, bodies irgendwie zu vereinfachen, unabhängig von den entsprechenden Sprites. Ansonsten ist man mit SHAPE_CONVEX meist gut bedient.

      Wenn wir mit Polygonen arbeiten, müssen wir diese natürlich erstmal haben bzw. erstellt haben. Das geht entweder durch manuelles hinzufügen einzelner
      Eckpunkte per add_vertex, oder mit create_polygon_auto. Diese Funktion rechnet transparente Sprites in Polygone um. Da dies in GML (unter Anwendung von surface_getpixel) geschieht, ist es die mit Abstand zeitintensivste Prozedur. Deshalb wird sie auch im Example vom Objekt control durchgeführt und NICHT ETWA im create-event des Body's (in dem Fall Diamond, Treat und Monster). Sie ist sogar so langsam, daß man sie auf gar keinen Fall verwenden sollte, um Polygone zu erstellen. Trotzdem ist es die beste - selbst für einfache Sprites, und ich erklär Dir auch warum.
      Sieh Dir das Skript einmal an: Wenn wir wollen, erstellt es eine Textdatei für uns. Diese Datei besteht dann aus einigen Zeilen GML-Code:



      poly = create_polygon()
      add_vertex( poly,x,y)
      add_vertex( poly,x,y)
      add_vertex( poly,x,y)


      Diese Methode hat mir endgültig ausgetrieben, irgendweche Bodies manuell erstellen zu wollen. Glaub mir, so ist es am einfachsten. Benutze create_polygon_auto nur um die Vertexdaten zu generieren und füge dann den Code in Dein Programm ein. Natürlich könntest Du jetzt das Polygon auch sichtbar machen, indem Du z.B. die Vertexkoordinaten mit draw_line verbindest.
      Jetzt aber erstmal genug von Polygonen. Du weißt jetzt jedenfalls, warum im example bei control steht:



      p_diamond = create_polygon_auto (spr_diamond, 4,15)
      p_treat = create_polygon_auto (spr_treat , 4,15)
      p_monster = create_polygon_auto (spr_monster, 4,15)


      Die 4 und die 15 solltest Du übrigens generell beibehalten. Verringere die Werte nur, wenn ein Polygon fehlerhaft (ungenau) wird. Übrigens, create_polygon_auto ist wie gesagt in GML geschrieben, deshalb kannst Du es leicht anpassen. Ich habe es zum Beispiel etwas umgeschrieben, weil ich die
      Vertex - Codes für mehrere subimages eines Sprites in einer einzigen Textdatei haben wollte.

      Hast Du einmal einen Body erstellt, so erfährt dieser mit jedem Aufruf von update_bodies (nicht vom object_update) die physikalischen Einflüsse der World,
      also erstmal die Gravitation. Er fällt also.
      Kommt jetzt ein object_update, so geschieht folgendes:



      //updates a GM object based on a bodies properies
      //arg0 - body ID

      x = get_body_x(argument0)
      y = get_body_y(argument0)
      image_angle = get_body_rotation(argument0)


      Bodies haben also wie oben schon erwähnt separate Werte für x, y und Drehwinkel (body_rotation). Diese lassen sich mit get_body auslesen und mit set_body
      setzen. Das gleiche gilt für speed sowie hspeed und vspeed. Zusätzlich gibt es noch die sogenannte body_rotspeed, die momentane Drehgeschwindigkeit. Mit set_body_point_hspeed/vspeed kann man sogar komplexe Drehungen erzeugen...
      Sowohl Drehungen als auch linieare Bewegungen lassen sich jederzeit mit den entsprechenden set_body-Befehlen begrenzen oder ganz unterbinden (set_body_frozen). Neben set_body_mass (Gewicht) kommt auch set_body_material zur Geltung, denn hier wird der Reibungswiderstand (einal statisch und einmal dynamisch) und die Elastizität (für Abprall) angegeben. 10 ist hier schon ein sehr hoher Wert. Die normalen Werte liegen eher zwischen 0 und 1.
      Damping bedeutet Dämpfung und entspricht im Prinzip dem Luftwiderstand bzw. bei Drehungen z.B. dem Widerstand der Achse (angular_damping). set_body_sleeping ist um CPU-Last zu sparen, und mit set_solver_count kann man die Auflösung für Physikberechnung einstellen. set_body_ccd kommt zum Tragen falls man schnelle Bodies hat, die fälschlicherweise Wände durchdringen. In dem Fall sollte man auch noch set_body_ccd_speed angeben, wobei zu beachten ist, daß body_speed anders gemessen wird als speed bei GM und um Faktor 20 größer ist
      (Der Faktor gilt nur bei room_speed 30! Bei höheren room_speeds sollte man get_body_speed nicht zum Auslesen der Geschwindigkeit nehmen)
      Wenn man CCD benutzen will, muß man dies ganz am Anfang mit init_physics (true) deklarieren.

      Wie, Du willst jetzt auch noch physikalisch eingreifen und die Puppen tanzen lassen ?

      Dann spiel Gott: Nimm den Wind und erzeuge Explosionen. Wie - das reicht Dir nicht - also gut, wo wir schon beim Body-Verzeichnis waren, sind Dir bestimmt die Befehle add_force und add_torque aufgefallen. Es ist durchaus sinnvoll, Bodies mit add_force zu bewegen. Force ist natürlich eine (kinetische) Kraft, und wird vektoriell angegeben bzw. hier duch x- und y-Richtung. Zum Beispiel eine kann Jump-n-Run Figur eine ganz neue Welt von Jump erleben. Probier es einfach aus, und experimentiere mit den Einstellungen. add_torque ist für Drehimpulse.
      Natürlich kannst Du auch Skriptgesteuerte Bewegungen oder Tastatur- und Mausbewegungen machen. Dazu solltest Du Dich mit dem ACTOR und dem STATIC body vertraut machen. ACTORS sind geeignet für Bodies die zwar physikalisch wirken, deren Verhalten jedoch unabhängig von der Physik sein soll, z.B. eine Motorwelle oder der Truck, den einfach nichts aufhält oder die Plattform im Platform Example. Denk dran, daß soche Objekte keinen object_update kriegen, sondern actor_update oder eventuell auch den radikaleren body_update.
      STATIC wird natürlich für feste Wände gebraucht. Alles was nicht STATIC ist, unterliegt physikalischen Einwirkungen. Wie gesagt, ein object_update entfällt
      hierbei.

      Wenn Du diese beiden Examples im Prinzip begriffen hast, bist Du bereit für deinen ersten Joint:) Sieh Dir das folgende Skript (create_joint) an:



      //creates a new joint
      //arg0 - Body 1
      //arg1 - Body 2
      //arg2 - joint type:
      // JOINT_FIXED - basically a weld
      // JOINT_SLIDER - a slider
      // arg3 - anchor point X; arg4 - anchor point Y; arg5 - anchor axis angle;
      // JOINT_HINGE - a hinge
      // arg3 - anchor point X; arg4 - anchor point Y;


      Ein Joint verbindet also zwei Bodies miteinander. Mit argument2 wirde der Typ spezifiziert:

      FIXED : Ein Body kann zwar mehrere SHAPEs starr verbinden, aber über Joints lassen sich halt Bodies mit unterschiedlichen Materialwerten verbinden.
      SLIDER : Könnte man mit Schieberegler überstzen... linear beweglich entlang einer bestimmten Achse, wie z.B. die Pneumatik bei Baumaschinen.
      HINGE:Ein Drehgelenk.
      In den Unterverzeichnissen Slider und Hinge siehst Du die entsprechenden Funktionen wie set_hinge_limits um die Drehbewegung zu begrenzen oder set_hinge_spring für Federkraft. Lineare Federn sind wie Du siehst separat aufgeführt und können sogar breakable, also "zerbrechbar" sein, wenn man sie überspannt.

      Da man einzelne Bodies wie gesagt auch mit set_body_frozen an die x- y- oder Drehachse binden kann, ist der Einsatz von Joints meistens wirklich nur bei Objekten mit mehreren Bodies nötig. Wichtig ist in diesem Zusammenhang auch set_body_mass_offset. Der Masseschwerpunkt eines Bodies wird automatisch ermittelt, kann aber über diesen offset verschoben werden. Wenn ein Körper von GMP gedreht wird, so dreht er sich normalerweise um diesen Punkt und nicht um das Zentrum x,y !.

      Der Ray prüft auf die erste Kollision entlang einer bestimmten Strecke und liefert deren Korrdinaten sowie das Kollisionsobjekt. Eine sehr nützliche kleine Funktion für jede Art von Laser oder Pistolenkugel.

      An der Stelle mach ich erstmal Kapitel zu, denn Du bist jetzt dran mit Praxis.
      Was ich alles nicht angesprochen habe erklärt sich dann weitgehend von selbst, und den Rest muß man eben ausprobieren.aber normalerweise steigen fehlerhafte Programme wie gewohnt beim Kompilieren (oder beim Starten) mit einem Fehler aus, und wenn nicht hilft meist der Affengriff (Strg-Alt-Entf). Mein Windows hat sich jedoch manchmal komplett aufgehängt, wenn ich GMP-Funktionen falsch aufgerufen habe. Zum Beispiel genügt dafür schon ein einfacher object_update(body_ID), wenn die body_ID nicht angegeben wurde bzw. auf 0 steht. Deshalb habe ich in den Game Settings das Häkchen bei treat uninitialized variables as 0 entfernt.