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

![]() |
darthBetreff: [BD3] RigidBodyCollisions (Physik Library für Spiele) - P1 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 ![]() 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 ![]() |
||
Diese Signatur ist leer. |
- Zuletzt bearbeitet von darth am Sa, Nov 07, 2009 14:18, insgesamt 2-mal bearbeitet
![]() |
Eingeproggt |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() |
Xaymarehemals "Cgamer" |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 ![]() |
||
Warbseite |
![]() |
Noobody |
![]() Antworten mit Zitat ![]() |
---|---|---|
Sowas hab ich auch mal gebastelt ![]() 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 Hier gibt es eine gute Beschreibung davon, wie man das Zuckeln vermeidet. Könnte noch hilfreich werden ![]() |
||
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
*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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 ![]() 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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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. | ||
![]() |
D2006Administrator |
![]() Antworten mit Zitat ![]() |
---|---|---|
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. ![]() 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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 ![]() 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. |
![]() |
hecticSieger des IS Talentwettbewerb 2006 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
<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: 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
![]() |
hecticSieger des IS Talentwettbewerb 2006 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group