Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Sa Jul 05, 2025 15:41

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Kontrollstruktur fuer Physikobjekte
BeitragVerfasst: Do Mär 26, 2009 16:17 
Offline
DGL Member
Benutzeravatar

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:
  1.  
  2. type
  3.   TSpielobjekt = class
  4.   private
  5.      ...
  6.   public
  7.     physics: TRigidBody;
  8.     procedure draw;
  9.     ...
  10.   end;
  11.  
  12. var
  13.   World: TWorld;
  14.   Blub: TSpielobjekt;
  15.  
  16. begin
  17.   World := TWorld.Create;
  18.   Blub := TSpielobjekt.Create;
  19.   Blub.physics := TRigidBody.CreateQuad(World);
  20. ...
  21.  


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).

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 26, 2009 17:23 
Offline
DGL Member
Benutzeravatar

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 ??

EDIT: Hat sich gerade geklaert :oops:

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Mär 26, 2009 19:25 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mär 30, 2007 18:35
Beiträge: 331
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.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 03:34 
Offline
DGL Member
Benutzeravatar

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

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 09:58 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mär 30, 2007 18:35
Beiträge: 331
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 :)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 10:06 
Offline
DGL Member
Benutzeravatar

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 :wink:

edit: @Markus: Quadtree fuer 2D ist zwar geplant, aber du hast Recht, (noch) habe ich andere Probleme 8)

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 10:24 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mär 30, 2007 18:35
Beiträge: 331
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.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 10:40 
Offline
DGL Member
Benutzeravatar

Registriert: So Feb 06, 2005 17:29
Beiträge: 187
Programmiersprache: C, C++
Zitat:
Andere Engines haben natürlich auch das gleiche Problem

Stimmt, hab ich gerade entdeckt. Kann man hier auf dem letzten Shot sehen: http://www.box2d.org/screenshots.html

Zitat:
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 ...

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Mär 28, 2009 14:21 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mär 30, 2007 18:35
Beiträge: 331
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.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mär 31, 2009 21:00 
Offline
DGL Member
Benutzeravatar

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 :lol:

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:

Code:
  1. constructor TRigidBody.CreateQuad(AWorld: PPhysicsWorld2D; ASize: Single);
  2. begin
  3.  
  4.   inherited Create;
  5.  
  6.   FWorld := AWorld;
  7.   SetLength(AWorld^.FRigidBodies, Length(AWorld^.FRigidBodies)+1);
  8.   AWorld^.FRigidBodies[High(AWorld^.FRigidBodies)] := Self;
  9.  
  10.   FPosition := NewVector(0,0);
  11.   FVelocity := NewVector(0,0);
  12.   FOrientation := 0;
  13.   FAngVelocity := 0;          
  14.  
  15.   ...
  16.  
  17. end;


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?

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mär 31, 2009 21:05 
Offline
DGL Member
Benutzeravatar

Registriert: Fr Mär 30, 2007 18:35
Beiträge: 331
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.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Mär 31, 2009 21:18 
Offline
DGL Member
Benutzeravatar

Registriert: So Feb 06, 2005 17:29
Beiträge: 187
Programmiersprache: C, C++
Hmm ja gut hab mir schon gedacht, dass das die verteufelten Pointer sind :evil:

Aber wie loese ich dann am besten so etwas ?

Code:
  1.  
  2. type
  3.  
  4.   TRigidBody = class
  5.     FWorld: TPhysicsWorld2D;
  6.   end;
  7.  
  8.   TPhysicsWorld2D = class;
  9.     FRigidBodies: Array of TRigidBody;
  10.   end;
  11.  
  12.  


EDIT: schon selbst gefunden

Code:
  1.  
  2. type
  3.  
  4.   TPhysicsWorld2D = class;
  5.  
  6.   TRigidBody = class
  7.     FWorld: TPhysicsWorld2D;
  8.   end;
  9.  
  10.   TPhysicsWorld2D = class;
  11.     FRigidBodies: Array of TRigidBody;
  12.   end;
  13.  
  14.  

_________________
Flummi: Projektseite und Projektthread


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: Bing [Bot] und 3 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.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.014s | 18 Queries | GZIP : On ]