[BD3] RigidBodyCollisions (Physik Library für Spiele) - P1

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

darth

Betreff: [BD3] RigidBodyCollisions (Physik Library für Spiele) - P1

BeitragMi, Nov 04, 2009 16:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich sitze seit einiger Zeit an einer RigidBody Physik. Mittlerweilen habe ich das Ganze in eine Verwendbare Library Funktion gebracht.
Der Vorteil von RigidBody Simulationen gegenüber der SoftBody-Verlet Implementationen mittels Vertice und Constraints liegt darin, dass man viel weniger Aufwand hat. Man hat zum Einen weniger Kanten um die man sich kümmern muss (die ganzen Querverstrebungen zur Stabilisierung fallen weg) und zum Andern muss man nicht stets Constraints und Vertice updaten. Bei RigidBody Sim. reicht es, dem Körper einen Zustand zu geben und diesen auf die Punkte anzuwenden.
Der Nachteil dabei ist allerdings, dass man den Körper stets transformieren muss, aber dieser ist, im Vergleich zum Mehraufwand von SoftBody geringer.
Ein weiterer Vorteil ist die erhöhte Stabilität, bei SoftBody Implementationen kann es vorkommen, dass Körper zusammenklappen, aus Rädern werden Dreiecke und ähnliche Fehler. Soetwas kann bei RigidBody nicht passieren, weil man die Eckpunkte nie verändert.

Wozu ist die Library gedacht?
Momentan unterstützt die Library erst Kollisionen und Kollisionsantwort, sie ist komplett in 2D aufgebaut, eine 3D Umsetzung wäre möglich, ist derzeit aber nicht geplant. Die Rotationen spielen im Moment völlig verrückt und führen zu Geschwindigkeiten von ~10^5, was für das System zu viel ist, die Körper fliegen wie verrückt umher (das System "explodiert"), deshalb werde ich hier erst Teil1 vorstellen.
Die Library ist prinzipiell dazu gedacht, Kollisionen mit Terrain zu vereinfachen/vereinheitlichen. Man braucht nur den Spieler als einen Körper zu definieren, und die Terrains als andere, und schon muss man sich um nichts als die Steuerung mehr kümmern.

Gefahren?
Da ich mit SeparatingAxisAlgorithm zur Kollisionserkennung arbeite kann man nur konvexe Körper benutzen (sprich keine Einbuchtungen). Ich bin daran das noch umzubauen, und beliebige Körper in konvexe Einzelteile zu zerlegen. Da ich mich ja eigentlich nicht um gegenseitige Verschiebung kümmern muss (da RigidBody) sollte das nicht derart kompliziert werden ... only time will tell.
Es ist ein eingebauter Rendermodus dabei, der ist strikt 2D und arbeitet mit Line (in LockBuffer Modus, sollte also genügend schnell sein).
Je nach Anzahl an Kollisionen hat das System mehr zu rechnen, deshalb ist die Geschwindigkeit nicht ganz konstant. Allerdings komme ich auf meiner Maschine etwa auf 150 Objekte ohne Slowdown, das sollte für die meisten kleineren Spiele genügen.
Das System ist noch optimierbar, ich teste jeden gegen jeden Körper, da könnte man sicherlich noch etwas einschränken.

Hier vorerst einmal der Code der Library:
Code: [AUSKLAPPEN]
; <STUFF
Function Clampf#(x#,min#,max#)
   If x<min
      Return min
   ElseIf x>max
      Return max
   EndIf
   
   Return x
End Function

Const RtD#=180./Pi
Const DtR#=Pi/180.
Function RadiansToDegrees(rad#)
   Return rad*RtD
End Function

Function DegreesToRadians(deg#)
   Return deg*DtR
End Function
;STUFF>

; <VECTOR
Type Vector
   Field X#
   Field Y#
End Type

Function cVector.Vector(ix#,iy#)
   v.Vector=New Vector
   
   v\x=ix
   v\y=iy
   
   Return v
End Function

Function opVector_Div(v.Vector,Scalar#)
   v\X=v\X/Scalar
   v\Y=v\Y/Scalar
End Function

Function opVector_Mult(v.Vector,Scalar#)
   v\X=v\X*Scalar
   v\Y=v\Y*Scalar
End Function

Function opVector_Add(v.Vector,other.Vector)
   v\X=v\X+other\X
   v\Y=v\Y+other\Y
End Function

Function opVector_Sub(v.Vector,other.Vector)
   v\X=v\X-other\X
   v\Y=v\Y-other\Y
End Function

Function opVector_CP#(v.Vector,other.Vector)
   Return v\X*other\Y+v\Y*other\X
End Function

Function opVector_DP#(v.Vector,other.Vector)
   Return v\X*other\X+v\Y*other\Y
End Function

Function opVectorN_Mult.Vector(v.Vector,Scalar#)
   vn.vector=New Vector
   
   vn\x=v\X*Scalar
   vn\y=v\Y*Scalar
   
   Return vn
End Function

Function opVectorN_Div.Vector(v.Vector,Scalar#)
   v\X=v\X/Scalar
   v\Y=v\Y/Scalar
End Function

Function opVectorN_Add.Vector(v.Vector,other.Vector)
   vn.vector=New Vector
   
   vn\x=v\X+other\X
   vn\y=v\Y+other\Y
   
   Return vn
End Function

Function opVectorN_Sub.Vector(v.Vector,other.Vector)
   vn.vector=New Vector
   
   vn\x=v\X-other\X
   vn\y=v\Y-other\Y
   
   Return vn
End Function

Function Normalise#(v.Vector)
   Local fLength#=Length(v)
   
   If fLength<0.000001
      Return 0
   EndIf
   
   opVector_Mult(v,1./fLength)
   
   Return fLength
End Function

Function Direction.Vector(v.Vector)
   temp.vector=New Vector
   
   temp\x=v\X
   temp\y=v\Y
   
   Normalise(temp)
   
   Return temp
End Function

Function ClampV(v.Vector,min.Vector,max.Vector)
   If v\X<min\X
      v\X=min\X
   ElseIf v\X>max\X
      v\X=max\X
   EndIf
   
   If v\Y<min\Y
      v\Y=min\Y
   ElseIf v\Y>max\Y
      v\Y=max\Y
   EndIf
End Function

Function Randomise(v.Vector,xMin.Vector,xMax.Vector)
   v\X=Rnd(xMin\X,xMax\X)
   v\Y=Rnd(xMin\Y,xMin\Y)
End Function

Function Length#(v.Vector)
   Return Sqr(v\X*v\X+v\Y*v\Y)
End Function
;VECTOR>

; <POLYGON

;RETURN VALUE: axVertices
Function BuildBox(axVertices.Vector[64],radiusx#,radiusy#)
   axVertices[0]=cVector(-radiusx,-radiusy)
   axVertices[1]=cVector(radiusx,-radiusy)
   axVertices[2]=cVector(radiusx,radiusy)
   axVertices[3]=cVector(-radiusx,radiusy)
   
   Return
End Function

;RETURN VALUE: axVertices
Function BuildBlob(axVertices.Vector[64],iNumVertices,radiusx#,radiusy#)
   If iNumVertices=0
      Return
   EndIf
   
   If iNumVertices=1
      axVertices[0]=cVector(0,0)
      
      Return
   EndIf
   
   Local a_#=RadiansToDegrees(Pi/iNumVertices)
   Local da_#=RadiansToDegrees(2*Pi/iNumVertices)
   
   For i=0 To iNumVertices-1
      a_=a_+da_
      
      axVertices[i]=cVector(Cos(a_)*radiusx,Sin(a_)*radiusy)
   Next
   
   Return
End Function

Function Render(xOffset.Vector,axVertices.Vector[64],iNumVertices)
   j=iNumVertices-1
   For i=0 To iNumVertices-1
      P1.Vector=opVectorN_Add(xOffset,axVertices[i])
      P2.Vector=opVectorN_Add(xOffset,axVertices[j])
      
      Line P1\x,P1\y,P2\x,P2\y
      
      j=i
   Next
End Function

;CHANGES: N.Vector, t#
Global Coll_t#
Function CollideP(A.Vector[64],Anum,B.Vector[64],Bnum,xOffset.Vector,xVel.Vector,N.Vector,t#)
   Coll_t=t
   
   Local xAxis.Vector[64]
   Local taxis#[64]
   iNumAxes=0
   
   If fVel2>0.000001
      If Not IntervalIntersect(A,Anum,B,Bnum,xAxis[iNumAxes],xOffset,xVel,taxis[iNumAxes],Coll_t)
         Return False
      EndIf
      taxis[iNumAxes]=IntInt_taxis
      iNumAxes=iNumAxes+1
   EndIf
   
   j=Anum-1
   For i=0 To Anum-1
      E0.Vector=A[j]
      E1.Vector=A[i]
      E.Vector=opVectorN_Sub(E1,E0)
      xAxis[iNumAxes]=cVector(-E\y,E\x)
      
      If Not IntervalIntersect(A,Anum,B,Bnum,xAxis[iNumAxes],xOffset,xVel,taxis[iNumAxes],Coll_t)
         Return False
      EndIf
      taxis[iNumAxes]=IntInt_taxis
      iNumAxes=iNumAxes+1
      
      j=i
   Next
   
   j=Bnum-1
   For i=0 To Bnum-1
      E0.Vector=B[j]
      E1.Vector=B[i]
      E.Vector=opVectorN_Sub(E1,E0)
      xAxis[iNumAxes]=cVector(-E\y,E\x)
      
      If Not IntervalIntersect(A,Anum,B,Bnum,xAxis[iNumAxes],xOffset,xVel,taxis[iNumAxes],Coll_t)
         Return False
      EndIf
      taxis[iNumAxes]=IntInt_taxis
      iNumAxes=iNumAxes+1
      
      j=i
   Next
   
   If Bnum=2
      E.Vector=opVectorN_Sub(B[1],B[0])
      xAxis[iNumAxes]=E
      
      If Not IntervalIntersect(A,Anum,B,Bnum,xAxis[iNumAxes],xOffset,xVel,taxis[iNumAxes],Coll_t)
         Return False
      EndIf
      taxis[iNumAxes]=IntInt_taxis
      iNumAxes=iNumAxes+1
   EndIf
   
   If Anum=2
      E.Vector=opVectorN_Sub(A[1],A[0])
      xAxis[iNumAxes]=E
      
      If Not IntervalIntersect(A,Anum,B,Bnum,xAxis[iNumAxes],xOffset,xVel,taxis[iNumAxes],Coll_t)
         Return False
      EndIf
      taxis[iNumAxes]=IntInt_taxis
      iNumAxes=iNumAxes+1
   EndIf
   
   If Not FindMTD(xAxis,taxis,iNumAxes,N)
      Return False
   EndIf
   Coll_t=fMTD_t
   
   If opVector_DP(N,xOffset)<0
      opVector_Mult(N,-1)
   EndIf
   
   Return True
End Function

;CHANGES: min#, max#
Global GetI_min#,GetI_max#
Function GetInterval(axVertices.Vector[64],iNumVertices,xAxis.Vector)
   min=opVector_DP(axVertices[0],xAxis)
   max=min
   
   For i=1 To iNumVertices-1
      d#=opVector_DP(axVertices[i],xAxis)
      If d<min
         min=d
      ElseIf d>max
         max=d
      EndIf
   Next
   
   GetI_min=min
   GetI_max=max
End Function

;CHANGES: taxis#
Global IntInt_taxis#
Function IntervalIntersect(A.Vector[64],Anum,B.Vector[64],Bnum,xAxis.Vector,xOffset.Vector,xVel.Vector,taxis#,tmax#)
   IntInt_taxis=taxis
   
   Local min0#,max0#
   Local min1#,max1#
   
   GetInterval(A,Anum,xAxis)
   min0=GetI_min : max0=GetI_max
   
   GetInterval(B,Bnum,xAxis)
   min1=GetI_min : max1=GetI_max
   
   h#=opVector_DP(xOffset,xAxis)
   min0=min0+h
   max0=max0+h
   
   d0#=min0-max1
   d1#=min1-max0
   
   If d0>0 Or d1>0
      v#=opVector_DP(xVel,xAxis)
      
      If Abs(v)<0.00001
         Return False
      EndIf
      
      t0#=-d0/v
      t1#=d1/v
      
      If t0>t1
         temp#=t0
         t0=t1
         t1=temp
      EndIf
      
      If t0>0
         IntInt_taxis=t0
      Else
         IntInt_taxis=t1
      EndIf
      
      If IntInt_taxis<0 Or IntInt_taxis>tmax
         Return False
      EndIf
      
      Return True
   Else
      If d0>d1
         IntInt_taxis=d0
      Else
         IntInt_taxis=d1
      EndIf
      
      Return True
   EndIf
End Function

;CHANGES: N.Vector, t#
Global fMTD_t#
Function FindMTD(xAxis.Vector[64],taxis#[64],iNumAxes,N.Vector)
   mini=-1
   t#=0 : fMTD_t=0
   
   N\X=0
   N\Y=0
   
   For i=0 To iNumAxes-1
      If taxis[i]>0
         If taxis[i]>t
            mini=i
            t=taxis[i]
            N\X=xAxis[i]\X : N\Y=xAxis[i]\Y
            Normalise(N)
         EndIf
      EndIf
   Next
   
   If mini<>-1
      fMTD_t=t
      Return True
   EndIf
   
   mini=-1
   For i=0 To iNumAxes-1
      n_#=Normalise(xAxis[i])
      taxis[i]=taxis[i]/n_
      
      If taxis[i]>t Or mini=-1
         mini=i
         t=taxis[i]
         N\X=xAxis[i]\X : N\Y=xAxis[i]\Y
      EndIf
   Next
   
   fMTD_t=t
   If mini<>-1
      Return True
   Else
      Return False
   EndIf
End Function

Function CalculateMass#(A.Vector[64],Anum,density#)
   If Anum<2
      Return 5*density
   EndIf
   
   mass#=0
   
   j=Anum-1
   For i=0 To Anum-1
      P0.Vector=A[j]
      P1.Vector=A[i]
      
      mass=mass+Abs(opVector_CP(P0,P1))
      
      j=i
   Next
   
   If Anum<=2
      mass=10
   EndIf
   
   mass=mass*density*0.5
   
   Return mass
End Function
;POLYGON>

; <BODY
Type Body
   Field axVertices.Vector[64]
   Field iNumVertices
   
   Field xVelocity.Vector
   Field xPosition.Vector
   
   Field fMass#
   Field fInvMass#
   
   ;<filler
   Field vx#
   Field vy#
   Field px#
   Field py#
   
   Field vertx#[64]
   Field verty#[64]
   ;filler>
End Type

Function cBody_Empty.Body()
   b.Body=New Body
   
   Return b
End Function

Function cBody_Box.Body(xPosition.Vector,fmass#,width#,height#)
   b.Body=New Body
   
   b\fMass=fmass
   
   iNumVertices=4
   Local axVertices.Vector[64]
   BuildBox(axVertices,width,height)
   
   InitialiseB(b,xPosition,axVertices,iNumVertices)
   
   Return b
End Function

Function cBody_Blob.Body(xPosition.Vector,fMass#,radiusx#,radiusy#)
   b.Body=New Body
   
   b\fMass=fMass
   
   iNumVertices=Rand(3,10)
   Local axVertices.Vector[64]
   BuildBlob(axVertices,iNumVertices,radiusx,radiusy)
   
   InitialiseB(b,xPosition,axVertices,iNumVertices)
   
   Return b
End Function

Function AddVert(b.Body,xVert.Vector)
   b\axVertices[b\iNumVertices]=xVert
   b\iNumVertices=b\iNumVertices+1
End Function

Function InitialiseB(b.Body,xPosition.Vector,axVertices.Vector[64],iNumVertices)
   b\xPosition=xPosition
   b\xVelocity=cVector(0,0)
   
   If b\fMass>0.0001
      b\fInvMass=1/b\fMass
   Else
      b\fInvMass=0
   EndIf
   
   For i=0 To 64
      b\axVertices[i]=axVertices[i]
   Next
   b\iNumVertices=iNumVertices
End Function

Function IsUnmovable(b.Body)
   If b\fMass<0.0001
      Return True
   Else
      Return False
   EndIf
End Function

Function AddForce(B.Body,F.Vector,dt#)
   If IsUnmovable(B)
      Return
   EndIf
   
   opVector_Add(B\xVelocity,opVectorN_Mult(F,B\fInvMass*dt*dt))
End Function

Global NaN#=1./Floor(0.1)
Function UpdateB(B.Body,dt#)
   If IsUnmovable(B)
      B\xVelocity\X=0
      B\xVelocity\Y=0
      
      Return
   EndIf
   
   If B\xVelocity\X=NaN Or B\xVelocity\Y=NaN
      B\xVelocity\X=0
      B\xVelocity\Y=0
   EndIf
   
   opVector_Add(B\xPosition,B\xVelocity)
End Function

Function RenderB(B.Body)
   If IsUnmovable(B)
      Color 125,125,125
   Else
      Color 255,255,255
   EndIf
   
   Render(B\xPosition,B\axVertices,B\iNumVertices)
End Function

Function CollideB(A.Body,B.Body)
   If IsUnmovable(A) And IsUnmovable(B)
      Return False
   EndIf
   
   N.Vector=cVector(0,0)
   
   xRelPos.Vector=opVectorN_Sub(A\xPosition,B\xPosition)
   xRelDis.Vector=opVectorN_Sub(A\xVelocity,B\xVelocity)
   
   If CollideP(A\axVertices,A\iNumVertices,B\axVertices,B\iNumVertices,xRelPos,xRelDis,N,1)
      t#=Coll_t
      
      If t<0
         opVector_Mult(N,-t)
         ProcessOverlap(A,B,N)
      Else
         ProcessCollision(A,B,N,t)
      EndIf
      
      Return True
   EndIf
   
   Return False
End Function

Function ProcessCollision(A.Body,B.Body,N.Vector,t#)
   D.Vector=opVectorN_Sub(A\xVelocity,B\xVelocity)
   
   n_#=opVector_DP(D,N)
   
   Dn.Vector=opVectorN_Mult(N,n_)
   Dt.Vector=opVectorN_Sub(D,Dn)
   
   If n_>0
      Dn=cVector(0,0)
   EndIf
   
   dt_#=opVector_DP(Dt,Dt)
   CoF#=s_fFriction
   
   If dt_<s_fGlue*s_fGlue
      CoF=1.01
   EndIf
   
   D=opVectorN_Sub(opVectorN_Mult(Dn,-(1+s_fRestitution)),opVectorN_Mult(Dt,(CoF)))
   
   m0#=A\fInvMass
   m1#=B\fInvMass
   m#=m0+m1
   r0#=m0/m
   r1#=m1/m
   
   opVector_Add(A\xVelocity,opVectorN_Mult(D,r0))
   opVector_Sub(B\xVelocity,opVectorN_Mult(D,r1))
End Function

Function ProcessOverlap(A.Body,B.Body,xMTD.Vector)
   If IsUnmovable(A)
      opVector_Sub(B\xPosition,xMTD)
   ElseIf IsUnmovable(B)
      opVector_Add(A\xPosition,xMTD)
   Else
      opVector_Add(A\xPosition,opVectorN_Mult(xMTD,0.5))
      opVector_Sub(B\xPosition,opVectorN_Mult(xMTD,0.5))
   EndIf
   
   N.Vector=xMTD
   Normalise(N)
   ProcessCollision(A,B,N,0)
End Function
;BODY>

; <GAME CODE
Const s_fFriction#=0.05
Const s_fRestitution#=0.1
Const s_fGlue#=0.01
Global s_xGravity.Vector=cVector(0,0.5)

Global dbg_Pause=False
Global dbg_useFriction=True
Global dbg_useGravity=True

Const s_MAX_BODIES=200
Global s_axBody.Body[s_MAX_BODIES]
Global s_BodyCount=0

Function AddBody(B.Body)
   s_axBody[s_BodyCount]=B
   s_BodyCount=s_BodyCount+1
End Function

Function GameUpdate(dt#)
   For i=0 To s_BodyCount-1
      If s_axBody[i]<>Null
         If dbg_useGravity
            AddForce(s_axBody[i],s_xGravity,dt)
         EndIf
      EndIf
   Next
   
   For i=0 To s_BodyCount-1
      If s_axBody[i]<>Null
         For j=i+1 To s_BodyCount-1
            If s_axBody[j]<>Null
               If IsUnmovable(s_axBody[i])=0 Or IsUnmovable(s_axBody[j])=0
                  CollideB(s_axBody[i],s_axBody[j])
               EndIf
            EndIf
         Next
      EndIf
   Next
   
   For i=0 To s_BodyCount-1
      If s_axBody[i]<>Null
         If Not IsUnmovable(s_axBody[i])
            UpdateB(s_axBody[i],dt)
         EndIf
      EndIf
   Next
End Function

Function GameRender()
   LockBuffer BackBuffer()
   
   For b.body=Each Body
      RenderB(b)
   Next
   
   UnlockBuffer BackBuffer()
End Function

Function GC()
   Local B.Body
   
   For B.Body=Each Body
      B\vx=B\xVelocity\X
      B\vy=B\xVelocity\Y
      
      B\px=B\xPosition\X
      B\py=B\xPosition\Y
      
      For i=0 To B\iNumVertices-1
         B\vertx[i]=B\axVertices[i]\X
         B\verty[i]=B\axVertices[i]\Y
      Next
   Next
   
   gx#=s_xGravity\X
   gy#=s_xGravity\Y
   Delete Each Vector
   s_xGravity=cVector(gx,gy)
   
   For B.Body=Each Body
      B\xVelocity=cVector(B\vx,B\vy)
      B\xPosition=cVector(B\px,B\py)
      
      For i=0 To B\iNumVertices-1
         B\axVertices[i]=cVector(B\vertx[i],B\verty[i])
      Next
   Next
End Function
;GAME CODE>


Damit ihr das Ding einmal testen könnt, habe ich eine kleine Sandbox gebaut. Maustaste erstellt neue Objekte.
WARNUNG: Ihr müsst dazu den PhysikCode von oben kopieren, oder ihn in ein BB-File im selben Ordner unter dem Namen "RigidCollisionLib.bb" speichern.
Code: [AUSKLAPPEN]
Include "RigidCollisionLib.bb"

Function GameInit()
   s_BodyCount=15
   
   xBottom.Vector=cVector(0,240)
   xTop.Vector=cVector(0,-240)
   xLeft.Vector=cVector(-320,0)
   xRight.Vector=cVector(320,0)
   xCentre.Vector=cVector(0,0)
   
   s_axBody[0]=cBody_Box(xBottom,0,640,5)
   s_axBody[1]=cBody_Box(xTop,0,640,5)
   s_axBody[2]=cBody_Box(xLeft,0,5,480)
   s_axBody[3]=cBody_Box(xRight,0,5,480)
   s_axBody[4]=cBody_Box(xCentre,0,30,30)
   
   For i=5 To s_BodyCount-1
      s_axBody[i]=cBody_Blob(cVector(Rnd(-300,300),Rnd(-200,-100)),0.075,Rnd(10,25),Rnd(10,25))
   Next
End Function

Global screenWidth#=640
Global screenHeight#=480
Global timer=CreateTimer(60)
Function main()
   Graphics3D screenWidth,screenHeight,0,2
   SetBuffer BackBuffer()
   
   Origin 320,240
   
   GameInit()
   
   While Not KeyHit(1)
      If MouseHit(1)
         If s_BodyCount<s_MAX_BODIES-1
            s_axBody[s_BodyCount]=cBody_Blob(cVector(MouseX()-GraphicsWidth()/2,MouseY()-GraphicsHeight()/2),0.1,Rnd(10,25),Rnd(10,25))
            s_BodyCount=s_BodyCount+1
         EndIf
      EndIf
      
      GameUpdate(0.125)
      GameRender()
      
      Color 255,255,255
      fps=fps+1
      If MilliSecs()-fpsTime>999
         fpsCur=fps
         fpsTime=MilliSecs()
         fps=0
      EndIf
      Text 300,220,fpsCur
      
      Text -310,-230,(s_BodyCount-4)
      
      Flip 0
      Cls
      WaitTimer(timer)
      
      GC()
   Wend
End Function

main()


Und damit man sehen kann, was man mit dem Code machen könnte, sei hier noch ein kleines Spiel gepostet. Dazu habe ich eine 3D-Rendermethode implementiert, aber vorsicht: ich kehre einfach die Y-Achse um, die Objekte sind also stets spiegelverkehrt.
WARNUNG: PhysicCode kopieren oder als "RigidCollisionLib.bb" speichern.
Code: [AUSKLAPPEN]
Include "RigidCollisionLib.bb"

Type BodyMesh
   Field xBody.Body
   Field Mesh
End Type

Function cBodyMesh.BodyMesh(xBody.Body,Mesh,xPosition.Vector,fDensity#)
   Local B.BodyMesh=New BodyMesh
   
   B\xBody=xBody
   B\Mesh=Mesh
   
   xBody\fMass=calculateMass(xBody\axVertices,xBody\iNumVertices,fDensity)
   InitialiseB(xBody,xPosition,xBody\axVertices,xBody\iNumVertices)
   AddBody(xBody)
   
   Return B
End Function

Function addPoint(B.Body,Surface,x#,y#)
   AddVertex(Surface,x,y,0)
   AddVert(B,cVector(x,y))
End Function

Function dBodyMesh(B.BodyMesh)
   FreeEntity B\Mesh
   Delete B\xBody
   ;die restliche Aufräumarbeit übernimmt der GC
End Function

Function placeBodies()
   Local B.BodyMesh
   
   For B.BodyMesh=Each BodyMesh
      PositionEntity B\Mesh,B\xBody\xPosition\X,-B\xBody\xPosition\Y,0
   Next
End Function

Function spawnBlob()
   tmpMesh=CreateMesh() EntityFX tmpMesh,16
   tmpSurf=CreateSurface(tmpMesh)
   
   tmpBody.Body=cBody_Empty()
   
   AddVertex(tmpSurf,0,0,0)
   For i=0 To 5
      addPoint(tmpBody,tmpSurf,Cos(i*60)*10,Sin(i*60)*10)
   Next
   For i=0 To 5
      AddTriangle(tmpSurf,0,i,i+1)
   Next
   AddTriangle(tmpSurf,0,6,1)
   
   EntityColor tmpMesh,0,0,255
   
   boulder[bcount]=cBodyMesh(tmpBody,tmpMesh,cVector(Rnd(Player\xBody\xPosition\x-50,Player\xBody\xPosition\x+50),Rnd(-325,-350)),0.01)
   bcount=bcount+1
End Function

;mit einem Trigonalizer könnte man sich die doppelte Arbeit sparen,
;man könnte das Mesh direkt aus den Vertices generieren lassen.
Function GameInit()
   ;<BODEN
   tmpMesh=CreateMesh() : EntityFX tmpMesh,16
   tmpSurf=CreateSurface(tmpMesh)
   
   tmpBody.Body=cBody_Empty()
   
   addPoint(tmpBody,tmpSurf,-500,-50)
   addPoint(tmpBody,tmpSurf,500,-50)
   addPoint(tmpBody,tmpSurf,500,50)
   addPoint(tmpBody,tmpSurf,-500,50)
   
   AddTriangle(tmpSurf,0,1,2)
   AddTriangle(tmpSurf,2,3,0)
   
   EntityColor tmpMesh,0,255,0
   
   g_Floor=cBodyMesh(tmpBody,tmpMesh,cVector(0,250),0)
   ;BODEN>
   
   ;<PLAYER
   tmpMesh=CreateMesh() : EntityFX tmpMesh,16
   tmpSurf=CreateSurface(tmpMesh)
   
   tmpBody.Body=cBody_Empty()
   
   addPoint(tmpBody,tmpSurf,-15,0)
   addPoint(tmpBody,tmpSurf,-5,35)
   addPoint(tmpBody,tmpSurf,5,35)
   addPoint(tmpBody,tmpSurf,15,0)
   addPoint(tmpBody,tmpSurf,5,-35)
   addPoint(tmpBody,tmpSurf,-5,-35)
   
   AddTriangle(tmpSurf,0,1,2)
   AddTriangle(tmpSurf,2,3,0)
   AddTriangle(tmpSurf,0,5,4)
   AddTriangle(tmpSurf,4,3,0)
   
   EntityColor tmpMesh,255,0,0
   
   Player=cBodyMesh(tmpBody,tmpMesh,cVector(0,150),0.0005)
   ;PLAYER>
   
   ;<GAME STUFF
   gameCam=CreateCamera()
   PositionEntity gameCam,0,200,-400
   
   light=CreateLight()
   
   s_xgravity=cVector(0,9.81)
   
   EntityParent gameCam,Player\Mesh
   bcount=0
   jump=0
   ;GAME STUFF>
End Function

Function CleanupAndRestart()
   Delete Each BodyMesh
   Delete Each Body
   s_BodyCount=0
   Delete Each Vector
   
   Graphics3D 800,600,0,2
   
   highScore=bcount
   GameInit()
   
   waitForInput()
   Color 0,0,0
End Function

Function waitForInput()
   placeBodies()
   Origin 400,300
   
   While True
      RenderWorld
      
      For a=0 To 235
         If KeyHit(a)
            break=True
         EndIf
      Next
      If break
         Exit
      EndIf
      
      Color 255,255,255
      Rect -200,-100,400,200
      Color 0,0,0
      Rect -180,-80,360,160,0
      Text -170,-70,"Entweder hast du gewonnen, oder verloren..."
      Text -170,-50,"Deine bisherige Höchstleistung: "+highScore
      Text -170,-30,"Um weiterzuspielen, drücke die beliebig"
      Text -170,-10,"Taste, um aufzuhören, drücke zweimal die"
      Text -170,10,"Abbruchtaste, oder das rote Kreuz oben"
      Text -170,30,"rechts."
      
      Flip 0
      Cls
      WaitTimer(timer)
   Wend
End Function

Graphics3D 800,600,0,2
SetBuffer BackBuffer()

Global Player.BodyMesh
Global g_Floor.BodyMesh
Global jump=0

Global boulder.BodyMesh[150]
Global bcount=0
Global highScore

Global gameCam

Origin 400,300

GameInit()

Global timer=CreateTimer(60)
While Not KeyHit(1)
   RenderWorld
   
   If MilliSecs()-spawntime>500
      spawnBlob()
      spawntime=MilliSecs()
   EndIf
   
   If jump=1
      If Player\xBody\xVelocity\y<0.2 And Player\xBody\xVelocity\y>0
         jump=2
      EndIf
   ElseIf jump=2
      If Player\xBody\xVelocity\y<0.2 And Player\xBody\xVelocity\y>0
         jump=0
      EndIf
   EndIf
   If jump=0
      opVector_Add(Player\xBody\xVelocity,cVector((KeyDown(205)-KeyDown(203))*0.1,KeyDown(200)*-7.5))
      If KeyDown(200)
         jump=1
      EndIf
   Else
      opVector_Add(Player\xBody\xVelocity,cVector((KeyDown(205)-KeyDown(203))*0.05,0))
   EndIf
   If Abs(Player\xBody\xVelocity\x)>2
      Player\xBody\xVelocity\x=Sgn(Player\xBody\xVelocity\x)*2
   EndIf
   
   If Player\xBody\xPosition\y>300
      CleanupAndRestart()
   EndIf
   If bcount>=150
      CleanupAndRestart()
   EndIf
   
   For i=0 To bcount-1
      playerX=Player\xBody\xPosition\x
      playerY=Player\xBody\xPosition\y
      
      boulderX=boulder[i]\xBody\xPosition\x
      boulderY=boulder[i]\xBody\xPosition\y
      
      If bouldery<playery
         If Abs(playerx-boulderx)<20
            If collideB(boulder[i]\xBody,Player\xBody)
               CleanupAndRestart()
               Exit
            EndIf
         EndIf
      EndIf
   Next
   
   GameUpdate(0.125)
   placeBodies()
   
   Color 255,255,255
   fps=fps+1
   If MilliSecs()-fpsTime>999
      fpsCur=fps
      fpsTime=MilliSecs()
      fps=0
   EndIf
   Text 780-400,580-300,fpsCur
   
   Flip 0
   Cls
   
   GC()
   WaitTimer(timer)
Wend
End


Das wärs soweit, Teil 2 folgt hoffentlich demnächst, dieser wird sich allerdings nichtmehr als SpielKollisionsSystem eignen, da er dann mit Rotationen arbeitet, und es relativ nervig ist, wenn die Spielfigur ständig hinfällt (deshalb poste ich diese Vorstufe auch als separaten Teil).

Noch eine Anmerkung: Ich erstelle während des Verlaufs der Berechnungen einige Vektoren, über die ich kein Buch führe, deshalb habe ich einen GarbageCollector geschrieben, der alles löscht was man nicht braucht. Dieser verlangsamt das System, führt aber dazu, dass der Speicherverbrauch nicht konstant anwächst.

Ich hoffe jemand findet Verwendung dafür, würde mich freuen Smile Ich werde demnächst wohl mal mein Spiel damit ausrüsten und etwas lustiges basteln.
GG, HF!

MfG,
Darth

[Edit]
Die Codeboxen wurden umgestellt zu normal Code, das BB-Syntaxhilight hat gewisse Teile des Codes missinterpretiert und ihn so zerstört Sad
Diese Signatur ist leer.
  • Zuletzt bearbeitet von darth am Sa, Nov 07, 2009 14:18, insgesamt 2-mal bearbeitet

Eingeproggt

BeitragMi, Nov 04, 2009 17:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Irgendwas stimmt mit den Codeboxen ned hier im Post oder?
Unter Opera 9.27 sieht es so aus:
https://www.blitzforum.de/upload/file.php?id=7328

Und wenn ich die Maus über den grauen Text von Darth bewege und scrolle, scrolle ich die darüber liegende Codebox.

Wollt nur mal drauf hinweisen, den Code hab ich mir noch nciht zu Gemüte geführt.

mfG, Christoph.
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

Xaymar

ehemals "Cgamer"

BeitragMi, Nov 04, 2009 18:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Die codeboxen funktionieren bei dir wie bei mir in FireFox 3.5.4 . Also sollte der code wohl so sein:)

Mal gucken wie schnell die Lib arbeitet Wink
Warbseite

Noobody

BeitragMi, Nov 04, 2009 18:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Sowas hab ich auch mal gebastelt Razz

Das funktionierte einigermassen gut, auch mit Rotationen, war aber komplett unoptimiert. Ausserdem leidet es darunter, dass Objekte auf dem Boden rumzuckeln, wenn man Gravitation einschaltet. Um das zu beheben, müsste man einen zusätzlichen "Contact Resolution"-Schritt hinzufügen.

Ich habe weder Zeit noch Lust (Physikcodes hängen mir mittlerweile zum Hals raus), das einzubauen, aber das würde ich Darth bei seinem Code nur empfehlen, sonst zittern die Objekte nur so rum, wenn man Rotationen einbaut.

Meine Implementation: BlitzBasic: [AUSKLAPPEN]
Const GWIDTH = 800
Const GHEIGHT = 600

Graphics GWIDTH, GHEIGHT, 0, 2
SetBuffer BackBuffer()

Type TEntity
Field CenterX#
Field CenterY#

Field Mass#
Field Inertia#

Field VX#
Field VY#

Field AX#
Field AY#

Field Omega#
Field AngularV#

Field VertexCount
Field Vertex.TVertex[ 64 ]

Field ForceCount
Field Force.TForce[ 64 ]

Field Locked
End Type

Type TVertex
Field LocalX#
Field LocalY#
Field Mass#
Field Distance#
Field Angle#

Field GlobalX#
Field GlobalY#

Field Parent.TEntity
End Type

Type TForce
Field X#
Field Y#

Field FX#
Field FY#
End Type

Global ProjectedMin#, ProjectedMax#, TransformedX#, TransformedY#

Local Timer = CreateTimer( 60 )

Init()

While Not KeyHit( 1 )
Cls

RenderEntities()

UpdateEntities( 1 )
CheckCollisions()

Flip 0
WaitTimer Timer
Wend
End

Function Init()
Local Entity.TEntity = CreatePolygon( 560, 450, 100, 100, 90 )

AddForce Entity, 470, 370, 9.5, -7.5


Entity.TEntity = CreatePolygon( 300, 100, 100, 100, 45 )

AddForce Entity, 370, 270, -8.5, -6.5


CreatePolygon( 650, 200, 100, 50, 10 )

CreatePolygon( 150, 400, 100, 100, 90 )


Entity.TEntity = CreatePolygon( 400, 300, 100, 80, 10 )
Entity\Locked = True
End Function

Function CheckCollisions()
For Entity.TEntity = Each TEntity
For i = 0 To Entity\VertexCount - 1
If Entity\Vertex[ i ]\GlobalX# > GWIDTH Then
ResolveCollision( Entity, i, -1, 0 )

Entity\CenterX# = Entity\CenterX# - Entity\Vertex[ i ]\GlobalX# + GWIDTH
MapVertices Entity
EndIf

If Entity\Vertex[ i ]\GlobalX# < 0 Then
ResolveCollision( Entity, i, 1, 0 )

Entity\CenterX# = Entity\CenterX# - Entity\Vertex[ i ]\GlobalX#
MapVertices Entity
EndIf

If Entity\Vertex[ i ]\GlobalY# > GHEIGHT Then
ResolveCollision( Entity, i, 0, -1 )

Entity\CenterY# = Entity\CenterY# - Entity\Vertex[ i ]\GlobalY# + GHEIGHT
MapVertices Entity
EndIf

If Entity\Vertex[ i ]\GlobalY# < 0 Then
ResolveCollision( Entity, i, 0, 1 )
Entity\CenterY# = Entity\CenterY# - Entity\Vertex[ i ]\GlobalY#

MapVertices Entity
EndIf
Next
Next
End Function

Function CreatePolygon.TEntity( X#, Y#, Width#, Height#, StepSize = 45 )
Local Entity.TEntity = New TEntity

For Angle = 0 To 360/StepSize - 1
CreateVertex Entity, X# + Width#*Cos( Angle*StepSize ), Y# - Height#*Sin( Angle*StepSize ), 4/Float( 360/StepSize )
Next

InitEntity Entity

Return Entity
End Function

Function ResolveCollision( Entity.TEntity, VertIndex, NX#, NY#, E# = 1 )
Local RX# = Entity\Vertex[ VertIndex ]\GlobalY# - Entity\CenterY#
Local RY# = -( Entity\Vertex[ VertIndex ]\GlobalX# - Entity\CenterX# )

Local VX# = Entity\VX# + RX#*Entity\AngularV#
Local VY# = Entity\VY# + RY#*Entity\AngularV#

If VX#*NX# + VY#*NY# < 0 Then
Local J# = -( 1 + E# )*( VX#*NX# + VY#*NY# )/( ( NX#*NX# + NY#*NY# )/Entity\Mass# + ( RX#*NX# + RY#*NY# )*( RX#*NX# + RY#*NY# )/( Entity\Inertia# ) )

Entity\VX# = Entity\VX# + NX#*J#/Entity\Mass#
Entity\VY# = Entity\VY# + NY#*J#/Entity\Mass#

Entity\AngularV# = Entity\AngularV# + ( RX#*NX#*J# + RY#*NY#*J# )/Entity\Inertia#
EndIf
End Function

Function DegToRad#( Degree# )
Return Pi*Degree#/180.
End Function

Function RadToDeg#( Radian# )
Return Radian#*180/Pi
End Function

Function CreateEntity.TEntity()
Local Entity.TEntity = New TEntity

Return Entity
End Function

Function CreateVertex( Entity.TEntity, X#, Y#, Mass# )
Local Vertex.TVertex = New TVertex
Vertex\GlobalX# = X#
Vertex\GlobalY# = Y#
Vertex\Mass# = Mass#
Vertex\Parent = Entity

Entity\Vertex[ Entity\VertexCount ] = Vertex
Entity\VertexCount = Entity\VertexCount + 1
End Function

Function InitEntity( Entity.TEntity )
For i = 0 To Entity\VertexCount - 1
Entity\Mass# = Entity\Mass# + Entity\Vertex[ i ]\Mass#
Entity\CenterX# = Entity\CenterX# + Entity\Vertex[ i ]\GlobalX#*Entity\Vertex[ i ]\Mass#
Entity\CenterY# = Entity\CenterY# + Entity\Vertex[ i ]\GlobalY#*Entity\Vertex[ i ]\Mass#
Next

Entity\CenterX# = Entity\CenterX#/Entity\Mass#
Entity\CenterY# = Entity\CenterY#/Entity\Mass#

For i = 0 To Entity\VertexCount - 1
Local DistX# = ( Entity\Vertex[ i ]\GlobalX# - Entity\CenterX# )
Local DistY# = ( Entity\Vertex[ i ]\GlobalY# - Entity\CenterY# )

Local DistSQ# = DistX#*DistX# + DistY#*DistY#

Entity\Inertia# = Entity\Inertia# + Entity\Vertex[ i ]\Mass#*DistSQ#

Entity\Vertex[ i ]\Distance# = Sqr( DistSQ# )
Entity\Vertex[ i ]\Angle# = ATan2( DistY#, DistX# )

Entity\Vertex[ i ]\LocalX# = Entity\Vertex[ i ]\GlobalX# - Entity\CenterX#
Entity\Vertex[ i ]\LocalY# = Entity\Vertex[ i ]\GlobalY# - Entity\CenterY#

Local V1.TVertex = Entity\Vertex[ i ]
Local V2.TVertex = Entity\Vertex[ ( i + 1 ) Mod Entity\VertexCount ]
Next
End Function

Function DotP#( X1#, Y1#, X2#, Y2# )
Return X1#*X2# + Y1#*Y2#
End Function

Function RenderEntities()
Color 255, 0, 0

For Entity.TEntity = Each TEntity
For i = 0 To Entity\VertexCount
Local VertIndex = i Mod Entity\VertexCount

Local X# = Entity\CenterX# + Entity\Vertex[ VertIndex ]\Distance#*Cos( Entity\Omega# + Entity\Vertex[ VertIndex ]\Angle# )
Local Y# = Entity\CenterY# - Entity\Vertex[ VertIndex ]\Distance#*Sin( Entity\Omega# + Entity\Vertex[ VertIndex ]\Angle# )

Local VX# = ( Entity\Vertex[ VertIndex ]\GlobalY# - Entity\CenterY# )*Entity\AngularV#
Local VY# = -( Entity\Vertex[ VertIndex ]\GlobalX# - Entity\CenterX# )*Entity\AngularV#

Entity\Vertex[ VertIndex ]\GlobalX# = X#
Entity\Vertex[ VertIndex ]\GlobalY# = Y#

If i Then Line X#, Y#, OldX#, OldY#

OldX# = X#
OldY# = Y#
Next

WritePixel Entity\CenterX#, Entity\CenterY#, $FFFF00
Next
End Function

Function UpdateEntities( Timestep# )
For Entity.TEntity = Each TEntity
If Not Entity\Locked Then
Local Torque# = 0, ForceX# = 0, ForceY# = 0

For i = 0 To Entity\ForceCount - 1
Local VX# = Entity\CenterX# - Entity\Force[ i ]\X#
Local VY# = Entity\CenterY# - Entity\Force[ i ]\Y#

Local Tau# = VX#*Entity\Force[ i ]\FY# - VY#*Entity\Force[ i ]\FX#

Torque# = Torque# + Tau#/Entity\Inertia#
ForceX# = ForceX# + Entity\Force[ i ]\FX#
ForceY# = ForceY# + Entity\Force[ i ]\FY#

Delete Entity\Force[ i ]
Next

Entity\VX# = Entity\VX# + Timestep#*ForceX#/Entity\Mass#
Entity\VY# = Entity\VY# + Timestep#*ForceY#/Entity\Mass#

Entity\CenterX# = Entity\CenterX# + Entity\VX#*Timestep#
Entity\CenterY# = Entity\CenterY# + Entity\VY#*Timestep#

Entity\AngularV# = Entity\AngularV# + Torque#*Timestep#
Entity\Omega# = Entity\Omega# + RadToDeg( Entity\AngularV# )*Timestep#

Entity\ForceCount = 0
EndIf
Next

For E1.TEntity = Each TEntity
For E2.TEntity = Each TEntity
If E1 <> E2 Then
If ( Not E1\Locked ) Or ( Not E2\Locked ) Then ProcessCollision E1, E2
EndIf
Next
Next

CheckCollisions()
End Function

Function AddForce( Entity.TEntity, X#, Y#, FX#, FY# )
Local Force.TForce = New TForce
Force\X# = X#
Force\Y# = Y#
Force\FX# = FX#
Force\FY# = FY#

Entity\Force[ Entity\ForceCount ] = Force
Entity\ForceCount = Entity\ForceCount + 1
End Function

Function ProcessCollision( E1.TEntity, E2.TEntity )
Local MinDistance# = 10000000, CollV1.TVertex, CollV2.TVertex
For i = 0 To E1\VertexCount + E2\VertexCount - 1
If i < E1\VertexCount Then
V1.TVertex = E1\Vertex[ i ]
V2.TVertex = E1\Vertex[ ( i + 1 ) Mod E1\VertexCount ]
Else
V1.TVertex = E2\Vertex[ i - E1\VertexCount ]
V2.TVertex = E2\Vertex[ ( i - E1\VertexCount + 1 ) Mod E2\VertexCount ]
EndIf

Local AxisX# = V1\GlobalY# - V2\GlobalY#
Local AxisY# = V2\GlobalX# - V1\GlobalX#
TFormNormal AxisX#, AxisY#, 0, 0, 0
AxisX# = TFormedX()
AxisY# = TFormedY()

ProjectToAxis( AxisX#, AxisY#, E1 )
Local Min# = ProjectedMin#
Local Max# = ProjectedMax#
ProjectToAxis( AxisX#, AxisY#, E2 )

Local Distance# = IntervalDistance( Min#, Max#, ProjectedMin#, ProjectedMax# )
If Distance# > 0 Then
Return False
ElseIf Abs( Distance# ) < MinDistance# Then
MinDistance# = Abs( Distance# )

Local CollAxisX# = AxisX#
Local CollAxisY# = AxisY#

Local DiffX# = E1\CenterX# - E2\CenterX#
Local DiffY# = E1\CenterY# - E2\CenterY#

If DotP( CollAxisX#, CollAxisY#, DiffX#, DiffY# ) < 0 Then
DiffX# = -DiffX#
DiffY# = -DiffY#
EndIf

CollV1 = V1
CollV2 = V2
EndIf
Next

Local CollisionVX# = CollAxisX#*MinDistance#
Local CollisionVY# = CollAxisY#*MinDistance#

If CollV1\Parent <> E2 Then
Local Temp.TEntity = E2
E2 = E1
E1 = Temp
EndIf

Local C# = -E2\CenterX#*CollAxisX# - E2\CenterY#*CollAxisY#

Local Sign = Sgn( E1\CenterX#*CollAxisX# + E1\CenterY#*CollAxisY# + C# )

If Sign = 1 Then
CollisionVX# = -CollisionVX#
CollisionVY# = -CollisionVY#
Else
CollAxisX# = -CollAxisX#
CollAxisY# = -CollAxisY#
EndIf

Local SmallestY# = 10000
For i = 0 To E1\VertexCount - 1
Local Vertex.TVertex = E1\Vertex[ i ]

Local D# = Vertex\GlobalX#*CollAxisX# + Vertex\GlobalY#*CollAxisY# + C#

If D# < SmallestY# Then
SmallestY# = D#
Local LowestVertex.TVertex = Vertex
Local LowestIndex = i
EndIf
Next

CollisionPX# = LowestVertex\GlobalX#
CollisionPY# = LowestVertex\GlobalY#

If DotP( CollisionVX#, CollisionVY#, E1\CenterX# - E2\CenterX#, E1\CenterY# - E2\CenterY# ) < 0 Then
CollisionVX# = -CollisionVX#
CollisionVY# = -CollisionVY#
EndIf

Local RX1# = CollisionPY# - E1\CenterY#
Local RY1# = -( CollisionPX# - E1\CenterX# )

Local VX1# = E1\VX# + RX1#*E1\AngularV#
Local VY1# = E1\VY# + RY1#*E1\AngularV#

Local RX2# = CollisionPY# - E2\CenterY#
Local RY2# = -( CollisionPX# - E2\CenterX# )

Local VX2# = E2\VX# + RX2#*E2\AngularV#
Local VY2# = E2\VY# + RY2#*E2\AngularV#

Local VX# = VX1# - VX2#
Local VY# = VY1# - VY2#

Local NX# = CollAxisX#
Local NY# = CollAxisY#

Local PS1# = RX1#*NX# + RY1#*NY#
Local PS2# = RX2#*NX# + RY2#*NY#

Local E# = 1

If VX#*NX# + VY#*NY# < 0 Then
Local J#
If E1\Locked Then
J# = -( 1 + E )*( NX#*VX# + NY#*VY# )/( 1.0/E2\Mass# + PS2#*PS2#/E2\Inertia# )
ElseIf E2\Locked Then
J# = -( 1 + E )*( NX#*VX# + NY#*VY# )/( 1.0/E1\Mass# + PS1#*PS1#/E1\Inertia# )
Else
J# = -( 1 + E )*( NX#*VX# + NY#*VY# )/( 1.0/E1\Mass# + 1.0/E2\Mass# + PS1#*PS1#/E1\Inertia# + PS2#*PS2#/E2\Inertia# )
EndIf

If Not E1\Locked Then
E1\VX# = E1\VX# + NX#*J#/E1\Mass#
E1\VY# = E1\VY# + NY#*J#/E1\Mass#
E1\AngularV# = E1\AngularV# + ( RX1#*NX#*J# + RY1#*NY#*J# )/E1\Inertia#
EndIf

If Not E2\Locked Then
E2\VX# = E2\VX# - NX#*J#/E2\Mass#
E2\VY# = E2\VY# - NY#*J#/E2\Mass#
E2\AngularV# = E2\AngularV# - ( RX2#*NX#*J# + RY2#*NY#*J# )/E2\Inertia#
EndIf
EndIf

Local Ratio1#, Ratio2#
If E2\Locked Then
Ratio1# = 1.0
Ratio2# = 0.0
ElseIf E1\Locked Then
Ratio1# = 0.0
Ratio2# = 1.0
Else
Ratio1# = E2\Mass#/( E2\Mass# + E1\Mass# )
Ratio2# = E1\Mass#/( E2\Mass# + E1\Mass# )
EndIf

E1\CenterX# = E1\CenterX# + Ratio1#*CollisionVX#
E1\CenterY# = E1\CenterY# + Ratio1#*CollisionVY#

E2\CenterX# = E2\CenterX# - Ratio2#*CollisionVX#
E2\CenterY# = E2\CenterY# - Ratio2#*CollisionVY#

Return True
End Function

Function GlobalToBody( Entity.TEntity, X#, Y# )
X# = X# - Entity\CenterX#
Y# = Y# - Entity\CenterY#

Local Radius# = Sqr( X#*X# + Y#*Y# )
Local Angle# = ATan2( Y#, X# )

TransformedX# = Cos( Angle# - Entity\Omega# )*Radius#
TransformedY# = -Sin( Angle# - Entity\Omega# )*Radius#
End Function

Function MapVertices( Entity.TEntity )
For i = 0 To Entity\VertexCount - 1
Entity\Vertex[ i ]\GlobalX# = Entity\CenterX# + Entity\Vertex[ i ]\Distance#*Cos( Entity\Omega# + Entity\Vertex[ i ]\Angle# )
Entity\Vertex[ i ]\GlobalY# = Entity\CenterY# - Entity\Vertex[ i ]\Distance#*Sin( Entity\Omega# + Entity\Vertex[ i ]\Angle# )
Next
End Function

Function ProjectToAxis( AxisX#, AxisY#, Entity.TEntity )
Local DotP# = DotP( AxisX#, AxisY#, Entity\Vertex[ 0 ]\GlobalX#, Entity\Vertex[ 0 ]\GlobalY# )
ProjectedMin# = DotP#
ProjectedMax# = DotP#

For i = 1 To Entity\VertexCount - 1
DotP# = DotP( AxisX#, AxisY#, Entity\Vertex[ i ]\GlobalX#, Entity\Vertex[ i ]\GlobalY# )

If DotP# < ProjectedMin# Then ProjectedMin# = DotP# ElseIf DotP# > ProjectedMax# Then ProjectedMax# = DotP#
Next
End Function

Function IntervalDistance#( A1#, B1#, A2#, B2# )
If A1# < A2# Then
Return A2# - B1#
Else
Return A1# - B2#
EndIf
End Function


Hier gibt es eine gute Beschreibung davon, wie man das Zuckeln vermeidet. Könnte noch hilfreich werden Razz
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

darth

BeitragMi, Nov 04, 2009 23:21
Antworten mit Zitat
Benutzer-Profile anzeigen
*Hust* Storytopper *Hust*

Hübsche Simulation Noobody, ich bin allerdings immernoch überzeugt, dass es nicht korrekt ist. Du beziehst dich bei der Drehung immer auf den Mittelpunkt. Wenn ich deinen Code richtig verstehe (..) dann ignorierst du Aufschlagspunkte. Das Drehmoment bezieht sich nicht grundsätzlich auf den Schwerpunkt des Objektes, leg einen Bleistift auf die Tischkante und du wirst sehen, dass es um den Punkt dreht, der die Kante des Tisches berührt. Meiner Meinung nach, erzwingst du den Dreheffekt, es sieht zwar in etwa korrekt aus - deshalb bin ich hier vorsichtig - aber ich würde immernoch behaupten, dass es physikalisch nicht richtig ist.

Ich werde mir dennoch den Code mal genauer ansehen und gucken, wie du den Drehimpuls berechnest, ohne dass das System explodiert. Und dann werd ich sehen was sich tun lässt, damit es bei mir klappt.
Thx.

MfG, Darth
Diese Signatur ist leer.

Noobody

BeitragMi, Nov 04, 2009 23:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Dass sich das Objekt immer um den Objektmittelpunkt dreht, war mir anfangs auch nicht ganz klar, allerdings wird überall in der Forschung davon ausgegangen und ich nehme nicht an, dass tausende von Wissenschaftlern irren Razz

Die Effekte, die du beschreibst, werden nachträglich durch zusätzliche Kräfte auf das Objekt erzeugt, beispielsweise Reibung.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Silver_Knee

BeitragDo, Nov 05, 2009 11:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Die eine hälfte des stiftes unterliegt einer anderen situation als die andere Hälfte. Ansonsten ist der Mittelpunkt (bzw schwerpunkt der meistens in der mitte liegt) natürlich auch der Punkt um das sich das objekt nomalerweise dreht.

D2006

Administrator

BeitragDo, Nov 05, 2009 11:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich persönlich krieg es auch nicht hin, den Kugelschreiber hier so zu drehen, dass der Drehpunkt nicht die Stiftmitte ist. Und ich hab reichlich Zeit zum Probieren. Wink

EDIT: btw, ohne mir jetzt den Code genauer angeschaut zu haben. Ich hatte anfangs auch Probleme, dass die Rotation viel zu schnell außer Kontrolle geriet. Lösung bei mir: Der errechnete Winkel war im Bogenmaß, aber ich hatte ihn addiert, als wäre er im Gradmaß. Musste ich also vorher noch umrechnen. Vielleicht machst du ja den gleichen Fehler.
Intel Core i5 2500 | 16 GB DDR3 RAM dualchannel | ATI Radeon HD6870 (1024 MB RAM) | Windows 7 Home Premium
Intel Core 2 Duo 2.4 GHz | 2 GB DDR3 RAM dualchannel | Nvidia GeForce 9400M (256 MB shared RAM) | Mac OS X Snow Leopard
Intel Pentium Dual-Core 2.4 GHz | 3 GB DDR2 RAM dualchannel | ATI Radeon HD3850 (1024 MB RAM) | Windows 7 Home Premium
Chaos Interactive :: GoBang :: BB-Poker :: ChaosBreaker :: Hexagon :: ChaosRacer 2

darth

BeitragDo, Nov 05, 2009 12:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Natürlich irren sich die 1000 Forscher ._. das sind doch alles Banausen ohne Ahnung!
Da ich allerdings von einem Reibungsbehafteten System ausgehe, scheint mir meine Lösung dennoch logischer, aber ich werde mir das ganze doch nochmal durchdenken.

@D2006:
Du solltest arbeiten und nicht mit Stiften spielen Razz
Aber danke für den Tipp, im Code oben wirst du nichts sehen, weil ich die Drehung (auf Grund von der höheren Geschwindigkeit, da weniger Rechenaufwand) ganz rausgenommen habe, aber ich werde den anderen Teil nochmal durchgehen und schauen, ob ich konstant in Radial Winkel rechne, oder ob ich irgendwo eine Mischung mache.
Diese Signatur ist leer.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDo, Nov 05, 2009 13:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Ein Stift der an der Tischkante abrollt dreht sich tatsächlich nicht an seiner Schwerpunktmitte, sondern um die Auflagefläche. Ist das selbe wie ein Reifen der auf der Straße rollt. Denn dieser dreht sich immer um die Auflagefläche vom Asphalt und nicht um seine eigene Achse. Das hängt aber auch vom Beobachter ab. Ein mitfahrender Beobachter wird den Reifen um seine eigene Achse drehen sehen, weil sein eigener Schwerpunkt sich mit dem Schwerpunkt des Reifens mitbewegt. Ein Außenstehender sieht eben den von mir zuerst beschriebenen Vorgang. Dabei ''wandert'' die Drehachse speziell beim Reifen (ist ja auch Sinn eines Reifens) entlang seiner Auflagefläche.

Ist doch nicht so schwer Leute.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Chrise

BeitragDo, Nov 05, 2009 14:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Der Stift rollt am Tisch auch einfach nicht um seinen Schwerpunkt, weil er es physikalisch auch einfach nicht kann. Eine weitere Tatsache ist, dass der Stift, solange sich sein Schwerpunkt noch über der Tischplatte befindet, nicht zu kippen beginnt. Sobald sein Schwerpunkt über der freien Fläche schwebt wird er labil, wird aber maximal vll noch von Reibungskräften am Fallen gehindert. Sobald der Stift aber dann fällt, wirst du feststellen, dass der Stift sich ab dann eben schon um seinen Schwerpunkt dreht.

Nette Simulation und Code, mir ging aber auch die Rotation ab, hab mir jetzt aber auch nur die Beispiele angeschaut.
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

darth

BeitragFr, Nov 06, 2009 13:05
Antworten mit Zitat
Benutzer-Profile anzeigen
<EDIT>
Dieser Beitrag wurde nachträglich editiert. Es hat sich herausgestellt, dass beide Parteien das gleiche meinten, es aber anderst formuliert hatten. Zur Verdeutlichung und Erklärung wie es eben NICHT gemeint war soll dieser Beitrag bestehen bleiben.
</EDIT>

Hallo,

ich hab mir die Frage nochmal sehr genau überlegt, und ich denke, ich bin zum Schluss gekommen, dass ich doch Recht habe, sogar Recht haben MUSS.

Zur Veranschaulichung folgendes Bild:
user posted image

1.
Der Stift liegt in Ruhe, keine kinetische Energie, und die gerade Linie stellt den Nullpunkt der potentiellen Energie dar, also auch Null.

Nun wirkt Kraft ein.

2.
Der Stift hat immernoch dieselbe potentielle Energie (0, da die eine Hälfte über dem Potential und die andere darunter liegt), allerdings kommt noch kinetische und Rotationsenergie hinzu.
Man hat Energie erzeugt und BAMM! Tod der Thermodynamik!

3.
Der Stift hat einen Bruchteil seiner früheren kinetischen Energie, allerdings wird diese durch seine erhöhte kinetische und rotationsbedingte Energie ausgeglichen, wir haben das Energiegleichgewicht und die Thermodynamik lebt weiter.

...

Zudem habe ich meine Rotationsprobleme gelöst.. ich werds wohl in Kürze hochladen.

Bis dahin:
MfG,
Darth
  • Zuletzt bearbeitet von darth am Fr, Nov 06, 2009 20:48, insgesamt einmal bearbeitet

hectic

Sieger des IS Talentwettbewerb 2006

BeitragFr, Nov 06, 2009 13:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Nur mit dem Unterschied, dass der Stift im Bild 3 ja nicht zur Tischkante gezogen wird. Er fällt runter und wird - wenn auch nur wenig - vom Tisch weg gedrückt.

Da bin ich mal gespannt, wie das Ergebnis vom neuem Code aussieht.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Noobody

BeitragFr, Nov 06, 2009 19:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Heute im Chat stellte sich dann heraus, dass wir beide eigentlich dasselbe meinten und uns nur missverstanden haben.

Nochmal zur Klärung: Die Rotation eines Körpers geht immer um den Masseschwerpunkt, bei einer Kollision allerdings ist die Winkelgeschwindigkeit von der Position des Kollisionspunktes abhängig.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group