Registriert: So Feb 06, 2005 17:29 Beiträge: 187
Programmiersprache: C, C++
Hallo ich habe mich gerade mit meiner Physiksimulation festgefahren. Kollisionserkennung und Verarbeitung funktioniert nun einigermassen, also habe ich angefangen zu ueberlegen, wie ich eine grosse Anzahl von physikalischen Objekten gut strukturiert simulieren kann.
Ich dachte mir nun erstmal eine Klasse TWorld, welche ein array mit pointern auf die Objekte, die zu dieser Welt gehoeren.
Die Funktion TWorld.Update wuerde dann alle Objekte verschieben, Kollisionen erkennen und aufloesen.
Leider muss ich zugeben sind mir pointer immer noch nicht geheuer und wurden von mir schon stets gemieden.
Der Vorteil waere bei einem solchen Ansatz, dass man als programmierer weiter normal mit seinen Spielobjekten arbeiten kann und diese nur um physikalische eigenschaften erweitert. Am besten mal ein beispiel:
Code:
type
TSpielobjekt =class
private
...
public
physics: TRigidBody;
procedure draw;
...
end;
var
World: TWorld;
Blub: TSpielobjekt;
begin
World := TWorld.Create;
Blub := TSpielobjekt.Create;
Blub.physics:= TRigidBody.CreateQuad(World);
...
Blub.draw kann dann zb auf blub.physics.position zugreifen (ja physics koennte auch private sein, war aber tippfaul).
Beim Erstellen von TRigidBody intanzen muss jeweils eine Welt uebergeben werden, zu der das physikalische Objekt gehoeren soll.
Ich hoffe man erkennt wie ich mir das gedacht habe und wuerde gerne wissen, ob ihr das auch so machen wuerdet? Ich weiss gerade noch nicht einmal, ob es problemtisch ist funktionen von dereferenzierten zeigern zu verwenden (ich hab bei ersten versuchen nur exceptions bekommen).
Registriert: So Feb 06, 2005 17:29 Beiträge: 187
Programmiersprache: C, C++
So ich glaube den Grund fuer die Exceptions gefunden zu haben ... ich hab im Create Konstruktor von TRigidBody das Objekt Self an die Funktion AddRigidBody von TWorld uebergeben. Kann es sein, dass objekte waehrend der Konstruktor aufgerufen wird noch nicht "fertig" sind und Self deswegen unvollstaendig ist ??
Wieso leitest du nicht einfach von TRigidBody ab, also TSpielObjekt = class(TRigidBody)? Ich habe bei mir einfach eine Klasse TWorld gehabt, die eine Funktion
AddBody(Body: TBody) hatte. Wenn du jetzt dein Spielobjekt hinzufügen willst rufst du einfach World.AddBody(TSpielObjekt.Create()) auf. Die TWorld-Klasse
schreibt die Klasse, also den Pointer, in ein Array und kann beim updaten dein Spielobjekt auch behandeln. Eine Klasse ist also nichts anderes als ein Pointer.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Bastel dir ne Master-Klasse mit ner Update Funktion, sowie einer Kinderliste, IsActive Flag und einem Parent. Verpack deine PhysicWelt über ein Octree und weise die Objekte den Nodes zu. Spendir deiner Master-Klasse ein Observer Pattern, damit du deiner PhysicWelt mitteilen kannst, dass dieses Objekt ein Update benötigt, da es Active ist. Deine PhysicWelt geht dann nur die Active Master-Klasse Liste durch und sollte ein Objekt zum stillstand kommen, dann wird IsActive auf false gesetzt und aus der Liste entfernt. Update sollte dann am besten dann die Parents Hoch klettern, bis es ein Node erreicht und dann im Node Schauen, ob das Objekt mit anderen Kollidiert und diese ebenfalls auf IsActive setzen(und so in die Liste der Activen Objekte mit aufnehmen). Diese Variante ist wesentlich Leistungsfähiger, als alle Objekte durch zu gehen, da du nur Objekte verarbeitest die wirklich einer Reaktion unterliegen und nicht still stehende. Da die Objekte sich selber in die Liste eintragen, werden nur n-Active Objekte zugegriffen, statt alle den Baum runter.
Durch die Octree zerlegung kannst du deine Physik sehr gut optimieren, da du für einen nachbarschafts test nur die Objekte in dem selben Node betrachtest, wie das gerade verarbeitete Objekt, statt alle in der ganze Welt. Innerhalb des Nodes kannst du z.B. noch die Objekt anordnung optimieren, da gibt es ein Algo(weiß den namen leider gerade nicht :.( ), welcher die Objekte nach den Positionen auf den Axen sortiert.
Von der Master-Klasse(sollte so wenig wie möglich und so viel wie nötig an Variablen haben) kannst du deine RigidBody, SoftBody, Joints und so weiter ableiten. Die Master-Klasse sollte Idealer weise noch eine BoundingSphere(float/double radius+3x für Position) enthalten, damit du sehr schnell herrausfinden kannst ob sich 2 Objekte überhaupt in einem Node schneiden. Sollte dies der Fall sein, dann kann eine Methode wie myobj.IsHittenByObject(otherobj); dann ein genauer Test stattfinden(welcher aufgrund der unterschiedlichen verhalten von Softbody,Joints und co dann überladen wird. Die Physicsysteme benutzen eine Variable UserData:pointer, woran man eigene Daten hängen kann und wenn das Objekt auftritt, man auf die eigenen Daten zugriff hat. So kann man z.B. das TSpielObjekt darein packen.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Naja, TAK, das was du geschrieben hast ist natürlich richtig und funktioniert wunderbar, aber ich glaube das ist ein wenig überdimensioniert für den Threadstarter. Ich schätze Mal, dass es um sein 2D Physikprojekt "Flummi" geht (Screenshot im Projektthread). Da jetzt mit Octrees usw. zu kommen scheint mir etwas unangebracht. Ich kann mich auch täuschen, aber das ist nicht das, was Average Idiot wollte
Registriert: So Feb 06, 2005 17:29 Beiträge: 187
Programmiersprache: C, C++
Ja cool Danke fuer die Antworten.
Optimieren muss ich sowieso noch, hab es im Grunde auch so vor wie von Tak beschrieben. Allerdings will ich jetzt erstmal die Basis zum laufen bringen (auch wenn die dann momentan bei > 100 kollidierenden Objekten unbrauchbar wird)
Mein Hauptproblem im Moment ist das Stapeln von Objekten. Sobald zu viele Objekte gestapelt sind, werden die untersten in den Boden gedrueckt. Das liegt daran, dass Objekte die sich ueberschneiden auseinander geschoben werden. Im Falle eines Stapels wird zB das unterste durch Gravitation in den Boden gesunkene Objekt nach oben geschoben, kollidiert dann aber mit dem darueberliegendem Objekt und wird wieder in den Boden geschoben.
Ich denke man muesste nicht nur das unterste Objekt aus dem Boden schieben, sondern gleich den ganzen Stapel bewegen ... man muesste nur zusammenhaengende Stapel erkennen koennen, was bei einem chaotischen Objekthaufen aber nicht mehr so einfach ist Ich frage mich gerade ob Engines wie Box2D oder Chipmunk auch solche Probleme haben, oder wenn nicht, wie sie diese in den Griff bekommen haben.
Nebenbei stimmt auch irgendwas bei meinen Rotationen noch nicht, allerdings will ich euch nicht auch noch damit belaestigen
edit: @Markus: Quadtree fuer 2D ist zwar geplant, aber du hast Recht, (noch) habe ich andere Probleme
Andere Engines haben natürlich auch das gleiche Problem, Lösungen dafür gibts viele. Zum einen gibts da die Positionskorrektur, die verhindert, dass Objekte sich überschneiden. Das hilft aber nur bedingt, weil die Kräfte, die du genannt hast immernoch wirken. Eine zweite Lösung ist, die Kontakte, die entstanden sind nicht nach dem Berechnen zu löschen, sondern sie solange im Speicher zu behalten, bis sie nicht mehr existieren. Damit kann man die Kraft, die pro Frame hinzuaddiert wird, kontrollieren. Die einfachste Möglichkeit (die aber auch nicht soo viel bringt) ist, die Physik mehr als einmal pro Frame zu aktualisieren, wenn du das nicht sowieso schon tust.
Eine zweite Lösung ist, die Kontakte, die entstanden sind nicht nach dem Berechnen zu löschen, sondern sie solange im Speicher zu behalten, bis sie nicht mehr existieren. Damit kann man die Kraft, die pro Frame hinzuaddiert wird, kontrollieren.
Kannst du das vielleicht genauer erklaeren oder vielleicht sogar links zu der technik posten? Hab das jetzt auf die schnelle nicht so verstanden ...
Hier wird das (unter anderem) erklärt. Ist auch ein Beispiel dabei, wie das aussehen kann. Ist allerdings alles in Englisch, viel deutsches Material gibts dazu wohl eher nicht.
Registriert: So Feb 06, 2005 17:29 Beiträge: 187
Programmiersprache: C, C++
Ich werde mir die Sachen bei Zeit mal genauer anschauen. Hab jetzt beschlossen erstmal wieder mehr Richtung Flummi zu arbeiten. Meine kleine Physiksimu ist dafuer eigentlich schon viel zu ueberdimensioniert ... es ueberkam mich halt
Allerdings hab ich noch ein Pointerproblem (?) bei welchem ihr mir vielleicht noch helfen koennt. Ich wollte es jetzt so machen, dass man entweder die TRigidBody-Klasse ableiten oder direkt als Eigenschaft einer eigenen Klasse verwenden kann. So sieht mein Konstruktor aus:
Problem ist, jeder RigidBody hat eine Eigenschaft FSolved. Aendere ich die innerhalb der Weltklasse mit FRigidBodies[x].FSolved passiert nix, ausser es handelt sich um das letzte Element des Arrays. Dann aendern sich naemlich die FSolved-Eigenschaften ALLER Array-Elemente Andere Eigenschaften wie Position scheinen keine Probleme zu machen ...
Woran mag das liegen?
Lass Sachen wie "PPhysicsWorld2D" weg. Eine Klasse ist bereits ein Pointer, was du machst ist ein Pointer auf einen Pointer, das kann leicht ins Auge gehen. Schreibe das nochmal ohne Pointer, vielleicht ist der Fehler dadurch schon behoben.
Mitglieder in diesem Forum: 0 Mitglieder und 8 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.