Circle Physic Engine Userlib
Verfasst: 06.08.2010 19:47
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.
Und hier noch ein kleines TestProgramm:
Screenshot:
http://www.xup.in/pic,14437720/screenshot_cvp.PNG
(Ä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/
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
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
[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/