Circle Physic Engine Userlib

Anwendungen, Tools, Userlibs und anderes nützliches.
Benutzeravatar
oh... well?!
Beiträge: 98
Registriert: 21.07.2010 10:46
Computerausstattung: Intel Pentium D 2,8 GHz
2 GB RAM
ATI RADEON X700 SE

Zweitrechner :
Intel Pentium M 1,6 GHz
1 GB RAM
Intel 82852/82855 GM/GME Graphics Controller (64 MB)

Circle Physic Engine Userlib

Beitrag von oh... well?! »

Ich wurde danach gefragt meine Pyhsic-Engine als Userlib mal zu posten.
Da ich aber meine Engine für mich behalten wollte, hab ich mal ne komplett neue geschrieben um diese quasi als Comunity-Engine weiter zu entwickeln. Bis jetzt sinds auch nur ca 400 Zeilen. Würd mich freuen, wenn mein Name bei Verwendung irgendwo erwähnt werden würde.
Ich freue mich über jegliche Verbesserungen/Optimierungen.
Nadann viel Spaß damit.

Code: Alles auswählen

;vector stuff  / Vektor Zeugs

Structure vect
   x.d
   y.d
EndStructure

Procedure vect(*v.vect,x.d,y.d)               ; / zum erstellen eines Vektors
   *v\x=x
   *v\y=y
EndProcedure
Procedure Normalize(*v.vect)
   Protected Length.d
   Length=Sqr(*v\x**v\x+*v\y**v\y)
   If Length<>0
      *v\x/Length
      *v\Y/Length
   EndIf
EndProcedure
Procedure.d Length(*v.vect)                   ; / Länge
   ProcedureReturn Sqr(*v\x**v\x+*v\y**v\y)
EndProcedure
Procedure.d DotProduct(*v1.vect,*v2.vect)     ; / Kreuzprodukt
   ProcedureReturn (*v1\x**v2\x+*v1\y**v2\y)
EndProcedure

;Physic Structures

Structure count     ; for counting the physic variables / zum mitzählen der PhysiK Variablen
   particle.l
   constraint.l
EndStructure

Structure particle
   r.d           ;radius / Radius
   p.vect
   oldp.vect
   a.vect        ;acceleration / Beschleunigung
   m.d           ;mass=0 represents static Particle  / masse=0 represintiert starre Körper
   id.l
   collision.b   ;>1 if the particle collides / >1 wenn der Particle kollidiert
EndStructure

Global Dim particle.particle(10000) 

Structure constraint
   *p1.particle
   *p2.particle
   e.d ;elastizity (between 1-0.001) / Elastizität (zwischen 1-0.001)
   length.d
   id.l
EndStructure

Global Dim constraint.constraint(10000)

Structure halfspace
   p.vect           ; / Stützvektor
   v.vect           ; / Richtungsvektor
   n0.vect          ;normalized normal vector / normierter Normalenvektor
EndStructure

Global NewList halfspace.halfspace()

Global count.count
Global timestep.d; delta t
timestep=0.8
Global iterations.l     ; / Anzahl der Rechendurchläufe
iterations=5
Global itelligentiterations.b ; increases Performance, but can be buggy / erhöht die Rechenleistung, kann aber fehlerhaft sein (bei zu vielen Iterationen)
itelligentiterations=1
Global gravity.vect
gravity\y=0.5
Global particleid.l
particleid=1
Global constraintid.l
constraintid=1
Global entityid.l
entityid=1
Global airfriction.d    ; / Luftwiderstand
airfriction=0.02


Procedure.l CountParticles() ;is used by the Engine / wird nur von Engine benutzt
   Protected i.l
   For i=1 To ArraySize(particle())
      If particle(i)\id=0
         ProcedureReturn (i-1)
      EndIf
   Next
EndProcedure
Procedure.l CountConstraint();is used by the Engine / wird nur von Engine benutzt
   Protected i.l
   For i=1 To ArraySize(constraint())
      If constraint(i)\id=0
         ProcedureReturn (i-1)
      EndIf
   Next
EndProcedure
Procedure CountAll();is used by the Engine. Updates the "count" variable/ wird nur von Engine benutzt. Aktuallisiert die "count" variable
   count\particle=CountParticles()
   count\constraint=CountConstraint()
EndProcedure

Procedure PointToParticle(x,y,inc); searched the particle on the given coardinate / sucht den Particle an der gegebenen Koardinate
   Protected diff.vect
   Protected length.d
   For i=1 To count\particle
      vect(diff,x-particle(i)\p\x,y-particle(i)\p\y)
      length=length(diff)
      If length<particle(i)\r+inc
         ProcedureReturn particle(i)
      EndIf
   Next
EndProcedure

Procedure CreateParticle(px.d,py.d,rad.d,mass.d) ;to create a particle / zum erstellen eines Particles
   Protected nr.l
   nr.l=count\particle+1
   particle(nr)\r=rad
   particle(nr)\m=mass
   particle(nr)\p\x=px
   particle(nr)\p\y=py
   particle(nr)\oldp\x=px
   particle(nr)\oldp\y=py
   particle(nr)\id=particleid
   vect(particle(nr)\a,gravity\x,gravity\y) ;Gravitation
   particleid+1
   count\particle+1
   ProcedureReturn particle(nr)
EndProcedure
Procedure CreateConstraint(*p1.particle,*p2.particle,elasticity.d) ;to create a constraint / zum erstellen eines Constraints (Feder)
   Protected nr.l
   If *p1\p\x<>*p2\p\x Or *p1\p\y<>*p2\p\y
      nr.l=count\constraint+1
      constraint(nr)\p1=*p1
      constraint(nr)\p2=*p2
      constraint(nr)\length=Sqr((*p2\p\x-*p1\p\x)*(*p2\p\x-*p1\p\x)+(*p2\p\y-*p1\p\y)*(*p2\p\y-*p1\p\y))  
      constraint(nr)\id=constraintid
      constraint(nr)\e=elasticity
      constraintid+1
      count\constraint+1
      ProcedureReturn constraint(nr)
   EndIf
EndProcedure
Procedure AddHalfSpace(px,py,vx.d,vy.d) ;to add a halfspace (ground) / zum hinzufügen eines Halfspaces (Boden)
   AddElement(halfspace())
   halfspace()\p\x=px
   halfspace()\p\y=py
   halfspace()\v\x=vx
   halfspace()\v\y=vy
   vect(halfspace()\n0,vy,-vx)
   normalize(halfspace()\n0)
EndProcedure

Procedure DeleteConstraint(*c.constraint)
   For i=1 To count\constraint
      If constraint(i)\id=*c\id
         For j=i To count\constraint
            constraint(j)=constraint(j+1)
         Next
      EndIf
   Next
   count\constraint-1
EndProcedure
Procedure DeleteParticle(*p.particle)
   For i=1 To count\constraint
      If constraint(i)\p1\id=*p\id Or constraint(i)\p2\id=*p\id
         DeleteConstraint(constraint(i))
         i-1
         delete+1
      EndIf
   Next
   
   Structure remindedge
      p1id.l
      p2id.l
      cid.l
   EndStructure
   
   Protected NewList remindedge.remindedge()
   
   For i=1 To count\constraint
      AddElement(remindedge())
      remindedge()\p1id=constraint(i)\p1\id
      remindedge()\p2id=constraint(i)\p2\id
      remindedge()\cid=constraint(i)\id
   Next
   
   For i=1 To count\particle
      If particle(i)\id=*p\id
         For j=i To count\particle
            particle(j)=particle(j+1)
         Next
      EndIf
   Next
   count\particle-1
   
   ResetList(remindedge())
   While NextElement(remindedge())
      For i=1 To count\constraint
         If constraint(i)\id=remindedge()\cid
            For j=1 To count\particle
               If particle(j)\id=remindedge()\p1id
                  constraint(i)\p1=particle(j)
               ElseIf particle(j)\id=remindedge()\p2id
                  constraint(i)\p2=particle(j)
               EndIf
            Next
         EndIf
      Next
   Wend
EndProcedure

Procedure UpdateVerlet() ;standart Verlet integration / Standart Verlet Integration
   Protected old.vect
   Protected v.vect
   Protected i.l
   For i=1 To count\particle
      If particle(i)\m<>0
         
         vect(old,particle(i)\p\x,particle(i)\p\y)                 ;Geschwindigkeit wird aus alter und neuer poition berrechnet + beschleunigung(gravitation)
         particle(i)\p\x=2*particle(i)\p\x-particle(i)\oldp\x+particle(i)\a\x*timestep*timestep
         particle(i)\p\y=2*particle(i)\p\y-particle(i)\oldp\y+particle(i)\a\y*timestep*timestep
         vect(particle(i)\oldp,old\x,old\y)
         
         ;Luftwiderstand
         vect(v,particle(i)\p\x-old\x,particle(i)\p\y-old\y) 
         vect(v,v\x*airfriction,v\y*airfriction)   
         vect(particle(i)\p,particle(i)\p\x-v\x,particle(i)\p\y-v\y)
     EndIf
   Next
EndProcedure
Procedure UpdateConstraints() ;updates the constraints / aktualisiert die Constraints (Federn)
   Protected DeltaX.d
   Protected DeltaY.d
   Protected DeltaLength.d
   Protected Diff.d
   Protected i.l
      For i=1 To count\constraint
         DeltaX=constraint(i)\p2\p\x-constraint(i)\p1\p\x
         DeltaY=constraint(i)\p2\p\y-constraint(i)\p1\p\y
         DeltaLength=Sqr(DeltaX*DeltaX+DeltaY*DeltaY)
         Diff=(DeltaLength-constraint(i)\length)/DeltaLength
         
         Protected m.d
         m=constraint(i)\p1\m+constraint(i)\p2\m
         If constraint(i)\p1\m<>0
            If constraint(i)\p2\m=0
               constraint(i)\p1\p\x=constraint(i)\p1\p\x+DeltaX*Diff*constraint(i)\e
               constraint(i)\p1\p\y=constraint(i)\p1\p\y+DeltaY*Diff*constraint(i)\e
            Else
               constraint(i)\p1\p\x=constraint(i)\p1\p\x+DeltaX*Diff*constraint(i)\e*(constraint(i)\p2\m/m)
               constraint(i)\p1\p\y=constraint(i)\p1\p\y+DeltaY*Diff*constraint(i)\e*(constraint(i)\p2\m/m)
            EndIf
         EndIf
         If constraint(i)\p2\m<>0
            If constraint(i)\p1\m=0
               constraint(i)\p2\p\x=constraint(i)\p2\p\x-DeltaX*Diff*constraint(i)\e
               constraint(i)\p2\p\y=constraint(i)\p2\p\y-DeltaY*Diff*constraint(i)\e
            Else
               constraint(i)\p2\p\x=constraint(i)\p2\p\x-DeltaX*Diff*constraint(i)\e*(constraint(i)\p1\m/m)
               constraint(i)\p2\p\y=constraint(i)\p2\p\y-DeltaY*Diff*constraint(i)\e*(constraint(i)\p1\m/m)
            EndIf
         EndIf
      Next
EndProcedure

Procedure SetCollisionsToZero() ; resets the collisions / resetet die Kollisionen
   Protected i.l
   For i=1 To count\particle
      particle(i)\collision=0
   Next
EndProcedure
Procedure ProcessCollision(*p1.particle,*p2.particle) ; collision-solving / Kollisionsverarbetung
   Protected rad.d
   Protected v.vect
   Protected vlength.d
   rad=*p1\r+*p2\r
   Protected distance.d
      distance=(*p2\p\x-*p1\p\x)*(*p2\p\x-*p1\p\x)+(*p2\p\y-*p1\p\y)*(*p2\p\y-*p1\p\y)   ;die Wurzel wird später gezogen um Rechnerleistung zu sparen
      If distance<(rad*rad) ; wenn die distanz kleiner als beide radien addiert ist, dann kollidiern die Objekte
         If distance<>0
            
            distance=Sqr(distance)  ;wir hab en ja das Quadrat berprüft   
            vect(v,*p2\p\x-*p1\p\x,*p2\p\y-*p1\p\y)   ;Kollisionsvektor wird errechnet (Richtung)
            vect(v,v\x/distance,v\y/distance)    ;Vektor wird normiert
            
            vlength=rad-distance                 ;Länge des Vektors
            vect(v,v\x*vlength,v\y*vlength)      ;Vektor wird auf die errechnete Länge multipliziert (skalar)
            
         Else
            vect(v,(Random(10)-5)/10,(Random(10)-5)/10);Gibt einen Zufalls Impuls falls die Kugeln aufeinander liegen
         EndIf

                  
         Protected m.d
         m=*p1\m+*p2\m
         If *p1\m<>0
            If *p2\m=0
               *p1\p\x-v\x   
               *p1\p\y-v\y
            Else
               *p1\p\x-v\x*(*p2\m/m)            ;Position wir mit dem errechneten Vektor verschowben     
               *p1\p\y-v\y*(*p2\m/m)             ;den Rest regelt die Verlet Integration
            EndIf
         EndIf
         If *p2\m<>0
            If *p1\m=0
               *p2\p\x+v\x
               *p2\p\y+v\y
            Else
               *p2\p\x+v\x*(*p1\m/m) 
               *p2\p\y+v\y*(*p1\m/m) 
            EndIf
         EndIf
         ProcedureReturn 1
      ElseIf distance=(rad*rad)
         ProcedureReturn 1
      Else
         ProcedureReturn 0
      EndIf
EndProcedure

Structure CollisionRemark ; used for intelligentiterations / wird zum merken bei intelligenten Iterationen verwendet
   *p1.particle
   *p2.particle
EndStructure

Global NewList CollisionRemark.CollisionRemark()
Procedure UpdateCollisions() ; collision-loop / Kollisionsschleife
   Protected i.l
   Protected j.l
   Protected k.l
   SetCollisionsToZero()
      For i=1 To count\particle
         For j=1 To count\particle
            If particle(i)\id<>particle(j)\id
               If ProcessCollision(particle(i),particle(j))  ;jedes Object wir mit jedem auf Collision überprüft
                  particle(i)\collision+1
                  If itelligentiterations=1
                     AddElement(CollisionRemark())
                     CollisionRemark()\p1=particle(i)
                     CollisionRemark()\p2=particle(j)
                  EndIf
               EndIf
            EndIf
         Next
      Next
      UpdateConstraints() ;Federn werden geupdated
EndProcedure
Procedure UpdateCollisionsIntelligent()
   Protected i.l
   Protected j.l
   Protected k.l
   SetCollisionsToZero()
   ResetList(CollisionRemark())
   While NextElement(CollisionRemark())
      If Not ProcessCollision(CollisionRemark()\p1,CollisionRemark()\p2)
         DeleteElement(CollisionRemark())
      EndIf
   Wend
   UpdateConstraints() ;Federn werden geupdated
EndProcedure
Procedure UpdateParticleHalfspaceCollision(); uses the Hessche Normal Form to solve collision / benutzt die Hessische Normalenform zum lösen der Kollision
   Protected n0.vect
   Protected length.d
   Protected distance.d
   Protected h.vect
   ResetList(halfspace())
   While NextElement(halfspace())
      For i=1 To count\particle
         vect(n0,halfspace()\n0\x,halfspace()\n0\y)           
         vect(h,particle(i)\p\x-halfspace()\p\x,particle(i)\p\y-halfspace()\p\y)
         distance=dotproduct(h,n0)
         distance-particle(i)\r
         If distance<0
            vect(h,n0\x*distance,n0\y*distance)
            vect(particle(i)\p,particle(i)\p\x-h\x,particle(i)\p\y-h\y)
            particle(i)\collision=1
         EndIf
      Next
   Wend
EndProcedure


Procedure CalcStep() ; the most important procedure, witch is used in your mainloop / die wichtigste Procedure, welche in der Hauptschleife benutzt wird
   CountAll()
   UpdateVerlet()
   For i=1 To iterations
      If i=1 Or itelligentiterations=0
         UpdateCollisions()
      Else
         UpdateCollisionsIntelligent()
      EndIf
      UpdateParticleHalfspaceCollision()
   Next
   ClearList(CollisionRemark())
EndProcedure
Und hier noch ein kleines TestProgramm:

Screenshot:
http://www.xup.in/pic,14437720/screenshot_cvp.PNG

Code: Alles auswählen

XIncludeFile "CircleVerletPhysics.pb"

Global Screen.vect
vect(screen,800,600)
Global MouseClick.b
Global *SelectedParticle.particle
Global timer.l

Global Frames.l
Global Time.d
Global StartTime.d
Global fps.l
Procedure FrameCount()
   Time=ElapsedMilliseconds()-StartTime
   Frames+1
   If Time>1000
      StartTime=ElapsedMilliseconds()
      fps=Frames
      Frames=0
   EndIf
   ;timestep=60/fps*0.8
EndProcedure

Procedure Init()
   InitSprite()
   InitKeyboard()
   InitMouse()
   OpenWindow(0, 0, 0, Screen\x, Screen\y, "physix", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget)
   OpenWindowedScreen(WindowID(0), 0, 0, Screen\x,Screen\y,0, 0, 0)
EndProcedure

Procedure CreateBox(x1.d,y1.d,x2.d,y2.d,r,m)
   CreateParticle(x1,y1,r,m)
   CreateParticle(x1,y2,r,m)
   CreateParticle(x2,y1,r,m)
   CreateParticle(x2,y2,r,m)
   CreateConstraint(particle(count\particle),particle(count\particle-1),1)
   CreateConstraint(particle(count\particle-1),particle(count\particle-2),1)
   CreateConstraint(particle(count\particle-2),particle(count\particle-3),1)
   CreateConstraint(particle(count\particle-3),particle(count\particle),1)
   CreateConstraint(particle(count\particle),particle(count\particle-2),1)
   CreateConstraint(particle(count\particle-1),particle(count\particle-3),1)
EndProcedure
Procedure CreateChain(x,y)
   CreateParticle(x,y,0,0.01)
   CreateConstraint(particle(count\particle-1),particle(count\particle),1)
   constraint(count\constraint)\length=5
EndProcedure

Procedure RenderHalfSpace()
   Protected t.d
   Protected y1.d
   Protected y2.d
   Protected x1.d
   Protected x2.d
   
   If Abs(halfspace()\v\x)>Abs(halfspace()\v\y)
      t=-halfspace()\p\x/halfspace()\v\x
      y1=halfspace()\p\y+t*halfspace()\v\y
   
      t=(Screen\x-halfspace()\p\x)/halfspace()\v\x
      y2=halfspace()\p\y+t*halfspace()\v\y
      LineXY(0,y1,Screen\x,y2,RGB(255,255,255))
      LineXY(Screen\x/2,(y1+y2)/2,Screen\x/2-halfspace()\n0\x*100,(y1+y2)/2-halfspace()\n0\y*100,RGB(255,255,255))
   Else
      t=-halfspace()\p\y/halfspace()\v\y
      x1=halfspace()\p\x+t*halfspace()\v\x
   
      t=(Screen\y-halfspace()\p\y)/halfspace()\v\y
      x2=halfspace()\p\x+t*halfspace()\v\x
      LineXY(x1,0,x2,Screen\y,RGB(255,255,255))
      LineXY((x1+x2)/2,Screen\y/2,(x1+x2)/2-halfspace()\n0\x*100,Screen\y/2-halfspace()\n0\y*100,RGB(255,255,255))
   EndIf
   
   
EndProcedure
Procedure Render()    ;draw stuff
   Protected i.l
   ClearScreen(RGB(0,0,0))
   StartDrawing(ScreenOutput())
   DrawingMode(#PB_2DDrawing_Outlined | #PB_2DDrawing_Transparent)
   
   DrawText(10,50,"Rechtsklick : Particle greifen",RGB(100,0,255))
   DrawText(10,65,"Linksclick : Particle erstellen",RGB(100,0,255))
   DrawText(10,80,"Leertaste : Box erstellen",RGB(100,0,255))
   DrawText(10,95,"Entf : Particle löschen",RGB(100,0,255))
   
   ;Render Particles
   For i=1 To count\particle
      Circle(particle(i)\p\x,particle(i)\p\y,particle(i)\r,RGB(100,100,255))
   Next
   If *SelectedParticle<>#Null
     Circle(*SelectedParticle\p\x,*SelectedParticle\p\y,*SelectedParticle\r+5,RGB(255,0,0))
   EndIf
   
   ;Render Constraints
   For i=1 To count\constraint
      FrontColor(RGB(255,0,100))
      LineXY(constraint(i)\p1\p\x,constraint(i)\p1\p\y,constraint(i)\p2\p\x,constraint(i)\p2\p\y)
   Next
   
   ;Render Halfspaces
   ResetList(halfspace())
   While NextElement(halfspace())
      renderhalfspace()
   Wend
   Box(MouseX()-2,MouseY()-2,5,5,RGB(255,0,0))
   FrontColor(RGB(255,255,255))
   DrawText(0,0,"fps : "+Str(fps))
   DrawText(0,15,"p+c : "+Str(count\constraint+count\particle))
   
   StopDrawing()
   FlipBuffers() 
EndProcedure
Procedure controls()
   ExamineMouse()
   ExamineKeyboard()
   If MouseButton(1) And MouseClick=0
      MouseClick=1
   ElseIf MouseButton(1)
      MouseClick=2
   EndIf

   If MouseButton(2) And MouseClick=0
      MouseClick=3
   ElseIf MouseButton(2)
      MouseClick=4
   EndIf
   If MouseButton(2)=0 And MouseButton(1)=0
      MouseClick=0
   EndIf
   
   If MouseButton(1) And timer=1
      r=10+Random(15)
      CreateParticle(MouseX(),MouseY(),r,r/20)
   EndIf
   
   If MouseButton(2) And *SelectedParticle<>#Null
       vect(*SelectedParticle\p,MouseX(),MouseY())  
   Else
      *SelectedParticle=PointToParticle(MouseX(),MouseY(),5)
   EndIf
   
   If KeyboardReleased(#PB_Key_Space)
      CreateBox(MouseX()-25,MouseY()-25,MouseX()+25,MouseY()+25,20,1)
   EndIf
   If KeyboardReleased(#PB_Key_Delete)
       If *SelectedParticle<>#Null
         deleteparticle(*SelectedParticle)
       EndIf
   EndIf
   ExamineKeyboard()
   ExamineMouse()
EndProcedure

AddHalfSpace(1,1,-1,0)   ;Bildschirmränder
AddHalfSpace(1,1,0,1)
AddHalfSpace(screen\x-1,0,0,-1)
AddHalfSpace(0,Screen\y-1,1,0)

;Anfangszeug wird erstellt
CreateParticle(50,400,15,0)
For i=1 To 10
   CreateParticle(50+30*i,400,15,0.5)
   CreateConstraint(particle(count\particle),particle(count\particle-1),1)
Next
Particle(count\particle)\m=0

CreateParticle(100,300,20,1)
Particle(count\particle)\a\y=-0.2
CreateParticle(100,340,1,0.01)
CreateConstraint(particle(count\particle),particle(count\particle-1),1)
For i=1 To 20
   CreateChain(100,340+i*5)
Next
For i=1 To 10
   CreateChain(100+5*i,440)
Next
For i=1 To 20
   CreateChain(150,440-i*5)
Next
CreateParticle(150,300,25,1)
Particle(count\particle)\a\y=-0.2
createconstraint(Particle(count\particle),Particle(count\particle-1),1)

;*************MAIN PROGRAM****************
Init()
countAll()


Repeat
   
   Repeat
   WEvent=WindowEvent()
      Select WEvent
          Case #PB_Event_CloseWindow
              End
          EndSelect
   Until WEvent=0 ;Bis es keine neuen Informationen gibt.
   timer+1
   If timer>=5
      timer=0
   EndIf
   FrameCount()
   render()
   CalcStep()
   controls()
   
Until KeyboardPushed(#PB_Key_Escape)
End
(Ähnlichkeiten mit einer anderen Physic-Engine sind rein zufällig... ok ich wurde davon ispiriert habe aber den gesamten Code trotztdem selber geschrieben und wahrscheinlich auch ne andere Mathode zur Berrechnung verwendet. Trotztdem ein Dank an KeauHou für die Inspiration)

[edit] neueste Versionen werden wegen der Größe ab nun als download reingestellt
neueste Version:
http://www.xup.in/dl,82663857/CircleVer ... cs0.1.rar/
Zuletzt geändert von oh... well?! am 12.05.2011 21:33, insgesamt 3-mal geändert.
Bild it's Monkey Buissness
Homepage
facebook
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Circle Physic Engine Userlib

Beitrag von STARGÅTE »

Danke fürs teilen...
ich werde mich zuerst mal auf die Seile stürtzen ^^

Zum Satz: "Ähnlichkeiten mit einer anderen Physic-Engine sind rein zufällig"
Ist ja eigentlich normal, zwar gibt es viele Wege aber im Gunde bauen alle auf die gleichen Gesetze auf.

Was mir jedoch gleich aufviel ist (weil ich bei mir ein ähnliches problem hatte) ist die sache mit der Elastizität.
Hier in deinem Beispiel würde eine BOX sich zerfetzen wenn man die Elastizität höher setzt um sie fast Starr zu machen.
Auch bei Ketten gibs ein seltsammes verhalten wenn ich ein Teil schiebe (weiß nicht ob das bei deiner echte Engine ähnlich ist):
Bild
Die "Knicke" sind nicht natürlich ... und auch die Position nicht.

Genauso verändert sich die kette anders wenn ich ein Objekt ganz links verschiebe, als wenn ich es ganz rechts verschiebe.
Liegt vermutlich an der Reihenfolge wie die Objekte in der Liste liegen, und welche zuerst verändert werden.

Ich habs damals so gelöst, das ich alle sache immer nacheinander gemacht habe:
Das ich erst alles mögliche temporär errechen, ohne die Objekte zu verändern.
Und dann danach alle "gleichzeigtig" veränder.

Hier wird ja bei einer Kollision gleich verschoben ...

Werds mir mal genauer angucken und mal ein bisschen rumtesten und umschreiben ...
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Kevin
Beiträge: 236
Registriert: 11.06.2007 12:55

Re: Circle Physic Engine Userlib

Beitrag von Kevin »

hi,

cool, danke fürs teilen
Da ich aber meine Engine für mich behalten wollte, hab ich mal ne komplett neue geschrieben um diese quasi als Comunity-Engine weiter zu entwickeln
die idee finde ich super
(Ähnlichkeiten mit einer anderen Physic-Engine sind rein zufällig... ok ich wurde davon ispiriert habe aber den gesamten Code trotztdem selber geschrieben und wahrscheinlich auch ne andere Mathode zur Berrechnung verwendet. Trotztdem ein Dank an KeauHou für die Inspiration)
wie du schon vermutet hast gibt es schon so was ähnliches
link (von STARGÅTE) denn engine verwende ich gerade
Benutzeravatar
oh... well?!
Beiträge: 98
Registriert: 21.07.2010 10:46
Computerausstattung: Intel Pentium D 2,8 GHz
2 GB RAM
ATI RADEON X700 SE

Zweitrechner :
Intel Pentium M 1,6 GHz
1 GB RAM
Intel 82852/82855 GM/GME Graphics Controller (64 MB)

Re: Circle Physic Engine Userlib

Beitrag von oh... well?! »

STARGÅTE hat geschrieben:Hier in deinem Beispiel würde eine BOX sich zerfetzen wenn man die Elastizität höher setzt um sie fast Starr zu machen.
Klar, die ist ja uch schon maximal starr.
1=max. starr
0.01=max. elastisch

wenn man die elast.>1 macht korrigieren die Federn ja über. Dabei wird der Fehler im größer und schaukelt sich hoch.
100% Starre Körper gibt es eben nicht wirklich, dafür musst du dann die Iterationen hoch stellen, was aber mehr Leistung braucht.

Das ist halt das Verlet Modell aus der Teilchenphysik.
STARGÅTE hat geschrieben:Die "Knicke" sind nicht natürlich ... und auch die Position nicht.
Die Knicke kann ich mir jedoch noch nich so ganz erklären...

[edit] ok, das mit dem Knick liegt daran, dass in der Hauptschleife zuerst CalcStep() steht und dann Controls(). Das Muss aber umgekert sein, damit auf dem Bildschirm die Verabeitete Eingabe gezeigt wird.
Ich Versteh nur nich so ganz warum dann soein Bogen entsteht.

Ein Problem ist noch, dass das letzte Particle in einer Kette immer komplett korrigiert wird (sieht man auch in STARGÅTE's Screenshot) und die restlichen Federn gleichmäßig korrigert werden. Das passiert aber, glaub ich, nur wenn eine Situation "nicht Lösbar" ist .In diesem Fall ist es eben so dass alle Feder 100% starr sind, man sie aber trotzdem dazu zwing sich auseinander zu dehne, da man ja die eine Kugel weg bewegt.
Bild it's Monkey Buissness
Homepage
facebook
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Circle Physic Engine Userlib

Beitrag von STARGÅTE »

Da es ja ein Gruppenprojekt werden soll, möchte ich hier mal n Code Posten, der die Problematik behandel, das Kugeln sich durchdringen könnten, wenn sie zu klein oder zu schnell ist. (PNs zwischen oh... well?! und mir )

Bei der normalen Berechnung, wird immer nur zu fixen Zeitpunkten auf Kollision geprüft, also könnten Kugel sich wirklich durchdringen, wenn die Zeitpunkte gerade ungünstig sind.
Im nachfolgenden Beispiel, wird mit einer Gleichung der genaue Zeitpunkt bestimmt, wenn sich die Kugel berühren wenn sie auf einander fliegen.

Der kern der ganzen Sache ist Kollisionszeit(), an sie werden die beiden Kugeln übergeben mit Ort (t=0) und Geschwindigkeit und Radius.
Und die Prozedur gib eine Zwischeneit zurück, in der es zur Kollision kommt.

Mit ein paar Gadgets, könnt ihr nun selber ein bisschen austesten :allright:
und oh... well?! kann mal versuchen es zu integrieren wenn er will
Bild

Code: Alles auswählen


Structure Vector2D
  x.f : y.f
EndStructure
 
Macro SetVector2D(Vector2D, xValue, yValue)
  Vector2D\x = xValue : Vector2D\y = yValue
EndMacro
Macro Vector2DScalar(Vector2D_1, Vector2D_2)
  ( Vector2D_1\x * Vector2D_2\x + Vector2D_1\y * Vector2D_2\y )
EndMacro
Macro Vector2DSub(Vector2D_1, Vector2D_2, ResultVector2D)
  ResultVector2D\x = Vector2D_1\x - Vector2D_2\x
  ResultVector2D\y = Vector2D_1\y - Vector2D_2\y
EndMacro

Structure Body
  Position.Vector2D : Velocity.Vector2D : Radius.f
EndStructure



Procedure.f Kollisionszeit(*Body1.Body, *Body2.Body)
  Protected dPosition.Vector2D, dVelocity.Vector2D, Distance.f
  Protected a.f, b.f, c.f, t1.f, t2.f
  ; d_ = _1 - _2
  Vector2DSub(*Body1\Position, *Body2\Position, dPosition)
  Vector2DSub(*Body1\Velocity, *Body2\Velocity, dVelocity)
  Distance = *Body1\Radius + *Body2\Radius
  ; 0 = a t² + b t + c
  a = Vector2DScalar(dVelocity,dVelocity)
  b = 2*Vector2DScalar(dPosition,dVelocity)
  c = Vector2DScalar(dPosition,dPosition)-Distance*Distance
  ; t = - b/2a ± Sqr( (b²-4ac) / 4a² )
  t1.f = - b/(2*a) + Sqr( (b*b-4*a*c) / (4*a*a) )
  t2.f = - b/(2*a) - Sqr( (b*b-4*a*c) / (4*a*a) )
  If t2 >= 0 And t2 <= 1
    ProcedureReturn t2
  Else
    ProcedureReturn t1
  EndIf  
EndProcedure



Enumeration
 #Window 
 #Gadget
 #Image
 #Gadget_R1
 #Gadget_v1
 #Gadget_a1
 #Gadget_R2
 #Gadget_v2
 #Gadget_a2
EndEnumeration



Procedure UpdateImage(*Body1.Body, *Body2.Body, Zeit.f)
  StartDrawing(ImageOutput(#Image))
    DrawingMode(#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaChannel)
    Box(0,0,500,500,0)
    DrawingMode(#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaBlend)
    Circle(*Body1\Position\x, *Body1\Position\y, *Body1\Radius, $FFFF0000)
    Circle(*Body2\Position\x, *Body2\Position\y, *Body2\Radius, $FF0000FF)
    LineXY(*Body1\Position\x, *Body1\Position\y, *Body1\Position\x+*Body1\Velocity\x, *Body1\Position\y+*Body1\Velocity\y,$FFFF0000)
    LineXY(*Body2\Position\x, *Body2\Position\y, *Body2\Position\x+*Body2\Velocity\x, *Body2\Position\y+*Body2\Velocity\y,$FF0000FF)
    If Zeit >= 0 And Zeit <= 1
      Circle(*Body1\Position\x+*Body1\Velocity\x*Zeit, *Body1\Position\y+*Body1\Velocity\y*Zeit, *Body1\Radius, $80FF0000)
      Circle(*Body2\Position\x+*Body2\Velocity\x*Zeit, *Body2\Position\y+*Body2\Velocity\y*Zeit, *Body2\Radius, $800000FF)
    EndIf
  StopDrawing()
  SetGadgetState(#Gadget, ImageID(#Image))
EndProcedure

Procedure TrackBar(Gadget, y, Text$)
  TextGadget(#PB_Any, 20, y, 50, 20, Text$)
  TrackBarGadget(Gadget, 80, y, 100, 20, 0, 100) 
EndProcedure



CreateImage(#Image, 700, 500, 32|#PB_Image_Transparent)

OpenWindow(#Window, 0, 0, ImageWidth(#Image), ImageHeight(#Image), "Image", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
  ImageGadget(#Gadget, 200, 0, ImageWidth(#Image), ImageHeight(#Image), ImageID(#Image))

Frame3DGadget(#PB_Any, 10, 10, 180, 180, "Body - Blau")
  TrackBar(#Gadget_R1, 40, "Radius")
  TrackBar(#Gadget_v1, 60, "Geschw.") 
  TrackBar(#Gadget_a1, 80, "Winkel") 
Frame3DGadget(#PB_Any, 10, 210, 180, 180, "Body - Rot")
  TrackBar(#Gadget_R2, 240, "Radius")
  TrackBar(#Gadget_v2, 260, "Geschw.") 
  TrackBar(#Gadget_a2, 280, "Winkel") 



SetVector2D(Body1.Body\Position,  100,  200)
SetVector2D(Body2.Body\Position,  400,   50)
SetGadgetState(#Gadget_R1, 50)      
SetGadgetState(#Gadget_v1, 60)      
SetGadgetState(#Gadget_a1, 10)      
SetGadgetState(#Gadget_R2, 10)      
SetGadgetState(#Gadget_v2, 100)      
SetGadgetState(#Gadget_a2, 35)      

Repeat

  Select WaitWindowEvent(10)
    Case #PB_Event_Gadget, #PB_Event_ActivateWindow
      Body1\Radius = GetGadgetState(#Gadget_R1)
      Body1\Velocity\x = GetGadgetState(#Gadget_v1)*Cos(GetGadgetState(#Gadget_a1)*#PI/50)*5
      Body1\Velocity\y = GetGadgetState(#Gadget_v1)*Sin(GetGadgetState(#Gadget_a1)*#PI/50)*5
      Body2\Radius = GetGadgetState(#Gadget_R2)
      Body2\Velocity\x = GetGadgetState(#Gadget_v2)*Cos(GetGadgetState(#Gadget_a2)*#PI/50)*5
      Body2\Velocity\y = GetGadgetState(#Gadget_v2)*Sin(GetGadgetState(#Gadget_a2)*#PI/50)*5
      Zeit.f = Kollisionszeit(Body1, Body2)
      UpdateImage(Body1, Body2, Zeit)
    Case #PB_Event_CloseWindow
      End
  EndSelect

ForEver
Edit:
Beim späteren benutzen muss natürlich noch überprüft werden ob die Zeit überhaupt zwischen 0 und 1 liegt (also in der Flugzone), und nciht davor oder dahinter ... :wink:

EDIT2:
die Abfrage war oben sinnlos ^^ denn t2 ist immer kleiner als t1 :lol:
stattdessen prüfe ich nun ob die kleinere zeit innerhalb [0,1] ist sonst wird die andere zurückgegeben.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
oh... well?!
Beiträge: 98
Registriert: 21.07.2010 10:46
Computerausstattung: Intel Pentium D 2,8 GHz
2 GB RAM
ATI RADEON X700 SE

Zweitrechner :
Intel Pentium M 1,6 GHz
1 GB RAM
Intel 82852/82855 GM/GME Graphics Controller (64 MB)

Re: Circle Physic Engine Userlib

Beitrag von oh... well?! »

Da ich Vorhab noch CircleToLine Kollision einzubauen wär das praktisch wenn man das Konzept auch darauf übertragen könnte (da linien ja, aufgrund ihrer nicht vorhandenen Dicke, sehr leicht durchdrungen werden).

Bin momentan dabei dein Code noch zu implementieren, hab nur momentan soviele Projekte in Arbeit...
Bild it's Monkey Buissness
Homepage
facebook
Benutzeravatar
oh... well?!
Beiträge: 98
Registriert: 21.07.2010 10:46
Computerausstattung: Intel Pentium D 2,8 GHz
2 GB RAM
ATI RADEON X700 SE

Zweitrechner :
Intel Pentium M 1,6 GHz
1 GB RAM
Intel 82852/82855 GM/GME Graphics Controller (64 MB)

Re: Circle Physic Engine Userlib

Beitrag von oh... well?! »

hab mal hier noch eine Kleinigkeit hinzugefügt...
Jetzt kann man Wasserartige Particle erstellen. Hab auch noch nen Beispiel reingestellt wie man das anwenden und auf dem Bildschirm darstellen kann.

Bild

Source+Testprogramm:
http://www.xup.in/dl,17237114/CircleVerletPhysics.rar/
[edit] hatte vergessen die wasser textur mit zu packen, jetzt is sie aber dabei^^
Falls noch jemand ne gute Idee, wie man das Ganze optimieren (Leistungsstärker machen) kann wäre ich sehr dankbar.
Bild it's Monkey Buissness
Homepage
facebook
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Circle Physic Engine Userlib

Beitrag von STARGÅTE »

>> "Falls noch jemand ne gute Idee, wie man das Ganze optimieren (Leistungsstärker machen) kann wäre ich sehr dankbar."
Dann möchte ich mal zwei sachen nennen:
__________

Auf einem 32Bit-System ist es im allgemeinem besser (schneller) wenn man möglichst nur mit Floats arbeitet statt mit Doubles. Mag sein das Doubles hier und da genauer sind aber im Rahmen dieser Engine in der es auf genau resultate eigentlich nicht ankommt, sollten Floats reichen.
Falls du auf 64Bit arbeitest, wären natürlich Doubles schneller. Darum mein Tip:
Erstelle ein Macro welches je nach system entscheidet ob Floats oder Doubles genommen werden:

Code: Alles auswählen

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Macro f_or_d : d : EndMacro
CompilerElse
  Macro f_or_d : f : EndMacro
CompilerEndIf
Im Code wäre es dann:

Code: Alles auswählen

Value.f_or_d
Value = #PI
Debug Value
Debug #PI
Bei 64Bit wäre Value = #PI, bei 32Bit wäre Value ungenauer ...

__________

Ich gebe zu ich habe mir den Code nicht bis ins Detail angesehen, trotzdem verwundert mich: UpdateCollisions()
Dort steht "jedes Object wir mit jedem auf Collision überprüft".
An hand deines Code wird nun aber jeder 2 mal überprüft.
Da dort zwei schleifen laufen, würde A mit B geprüft werden und B mit A ...
Dort ist also 50% zu viel ...
Zumal man mit dieser Methode noch die eine Abfrage ob es das gleiche Element ist spart, obwohl ich da nciht weiß ob sich die ID vom Index unterscheidet ...

Code: Alles auswählen

     For i=1 To count\particle
         For j=i+1 To count\particle
            If ProcessCollision(particle(i),particle(j)) : ... : EndIf
         Next
      Next
Zuletzt geändert von STARGÅTE am 09.08.2010 01:20, insgesamt 1-mal geändert.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
oh... well?!
Beiträge: 98
Registriert: 21.07.2010 10:46
Computerausstattung: Intel Pentium D 2,8 GHz
2 GB RAM
ATI RADEON X700 SE

Zweitrechner :
Intel Pentium M 1,6 GHz
1 GB RAM
Intel 82852/82855 GM/GME Graphics Controller (64 MB)

Re: Circle Physic Engine Userlib

Beitrag von oh... well?! »

ok das mit dem 32 bit und 64 bit wusste ich garnich. Das werd ich auf jeden Fall ausbessern.
Check nur das mit den Macros nich so ganz aber das dürft nich das Problem sein

Über das mit der Schleife, die ja alle Objecte 2 mal prüft hab ich mir auch schon gedanken gemacht.
Da es ja sowie so Iterationen gibt ,also UpdateCollision() sowieso öfter durchgefürt wird hab ich mir gedacht, dass ich es dabei belasse, weil man ja sowie so dann die Iterationen verdoppelt um ein genauso genaues Ergebnis zu erhalten.
So... dacht ich... Jetzt hab ich aber intelligente Iterationen eingebaut, d.h. Nur bei der ersten Iterration wird jedes Objekt mit jedem verglichen und dannach werden nur noch die vorhandenen Collisionen ausgebessert (CollisionRemark), also würde es jetzt wieder sinn machen deine Variante zu verwenden, also danke nochmal das du den Einwand nochmal gebracht hast :allright: . Werd ich auch noch ändern
Bild it's Monkey Buissness
Homepage
facebook
c4s
Beiträge: 1235
Registriert: 19.09.2007 22:18

Re: Circle Physic Engine Userlib

Beitrag von c4s »

CompilerIf SizeOf(Integer) = 2
:?:
Wie wäre es mit CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Außerdem kommt doch bei x64 8 raus und bei x86 4...
"Menschenskinder, das Niveau dieses Forums singt schon wieder!" — GronkhLP ||| "ich hogffe ihr könnt den fehle endecken" — Marvin133 ||| "Ideoten gibts ..." — computerfreak ||| "Jup, danke. Gruss" — funkheld
Antworten