Problem mit Physik Engine
Übersicht

![]() |
EPSBetreff: Problem mit Physik Engine |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo zusammen
ich hab eins, zwei kleine (große) Probleme. Ich bin gerade dabei ein kleines Proggi zu machen. Es geht dabei um eine Reihe Kugeln welche sich in einem viereckigen Spielfeld befinden. Mit der Maus kann man sich eine Kugel greifen und dadurch die anderen anschieben (momentan ähnlich wie auf einem Billardtisch). Die Engine und die Physik arbeiten soweit ganz gut. Ok, der Code ist wahrscheinlich noch etwas chaotisch - ich probiere im Moment noch viel rum, also nicht meckern. Es gibt nur zwei Sachen die ich einfach nicht hinbekomme. Erstens: Wenn ich eine Kugel mit der Maus greife, kann ich sie komplett über eine andere Kugel schieben. Auf diese Weise kann ich sogar mehrere Kugeln übereinanderschieben, was natürlich nicht sein soll. Leider hab ich keine Ahnung wie ich das wegbekommen soll. Zweitens: Eigentlich soll das Spielfeld kein "Billardtisch" sein, sondern die Kugeln sollen nach unten fallen und aufeinander liegenbleiben. Sie sollen also eine beliebige Masse haben können und das Spielfeld muß man sich hingestellt vorstellen. Tja, aber auch das bekomme ich nicht hin. Ich hab schon mehrere Versuche gestartet, aber entweder fallen sie alle bis zum unteren Spielfeldrand (bleiben also nicht aufeinander liegen) oder sie fallen wie Steine usw. Oder ich kann sie nachdem sie liegen nicht mehr anschubsen, sie sind also wie angenagelt - was auch nicht sein soll. Genau diese beiden Sachen bekomme ich einfach nicht hin. Kann mir irgend wer helfen? Vielen, vielen Dank schonmal. Das ganze soll von der Bewegung her in etwa so sein wie diese Wasserspiele für Kinder wo in einem Wasserbehälter kleine Ringe durch Druck auf einen Knopf umherfliegen und irgendwann zu Boden sinken. Die Ringe werden dabei von einem Wasserstrahl angeschoben. Hier sind es halt nur Kugeln und angeschoben werden sie durch eine Kugel die man sich mit der Maus greift. Ach ja, bitte keine Hinweise auf Tutorials. Ich hab mir schon alles runtergezogen was es gibt und auch diese Engine basiert auf einem solchen Tutorial. Ausserdem bin ich nicht gerade ein MatheCrack (von wegen Vektoren usw.). Hier noch die passenden Bilder: ![]() ![]() und der Code (ich hoffe das ist nicht zu viel Code): Code: [AUSKLAPPEN] ; Collision detection and rebounding angles Routine based on a Program by Andrew Constant ukandrewc@aol.com
[/img]
; ;============================================================================================================== Const SW=800 Const SH=600 Graphics SW,SH,16,1 Const Debug = True Global NVector Global Font=LoadFont("tahoma.ttf",12,1): SetFont font Global ballgfx=LoadAnimImage("ball.png",45,45,0,2): MidHandle ballgfx Global mousegfx=LoadImage("maus.png"): MidHandle mousegfx Global maxspeed = 3 ;--> Anfangsgeschwindigkeit der Bälle SeedRnd MilliSecs() ;--> Variablen für Ball Type IMG Field nr Field image Field ix,iw Field mx,my Field speed# Field x#,y#,xi#,yi# End Type Global bc=0 Global halfball Global myball Global Accelerate# = 0.999999 ;--> Bremskraft (bei Kollision) Global Gravity# = .5 ;--> Gravitationskraft Global mox,moy,movx,movy,mang,mtimer ;--> Mausposition für Ballbewegung durch Maus MoveMouse(sw/2,sh/2) ;--> Variablen für Wand Type OBS Field image,ix,a Field x,y,w,h Field x1,y1,x2,y2 End Type Global wc ;--> Rest Global Frames, FPS, FTimer, Timer Global wait = CreateTimer(60) ;--> Erzeuge Spielfeld Const gamew=400 Const gameh=400 x1=(sw-gamew)/2 x2=sw-x1 y1=(sh-gameh)/2 y2=sh-y1 Createwall x1,y1,x2,y1 Createwall x2,y1,x2,y2 Createwall x2,y2,x1,y2 Createwall x1,y2,x1,y1 ;--> Erzeuge Bälle For c=1 To 20: CreateBall(): Next ;--> Hauptschleife SetBuffer BackBuffer() While Not KeyDown(1) MouseHold() If Timer<MilliSecs() Then Timer=MilliSecs()+16 ;--> ca. 60 FPS MoveBalls() RenderScreen() If debug Then While KeyDown(57): Wend ;Pause End If EndIf Wend FreeImage ballgfx FreeImage mousegfx For wall.obs=Each obs FreeImage wall\image Next FreeFont font End Function MouseHold() ;============================================================================================================== ; Maus wird gedrückt ;============================================================================================================== mx=MouseX() my=MouseY() If MouseDown(1) Then ;--> wenn Maustaste das erste mal gedrückt wurde, ermittle Ballnummer und -position für nächsten Durchlauf If myball=0 Then For ball.img=Each IMG If ImagesCollide(mousegfx,mx,my,0,ballgfx,ball\x,ball\y,0) Then myball=ball\nr ball\mx=mx-ball\x ball\my=my-ball\y Exit EndIf Next If myball=0 Then Return Else For ball.img=Each IMG If ball\nr=myball Then Exit Next End If ;--> Berechne neue Position des Balls ball\x=mx-ball\mx ball\y=my-ball\my ;--> Berechne bei Mausbewegung die Ballgeschwindigkeit ;--> Kunstpause bevor Alte Mausposition übernommen wird, da sonst kein Vektor errechnet werden kann If mtimer<MilliSecs() Then mtimer=MilliSecs()+16 vector=Abs(movx-mx)+Abs(movy-my) If vector>halfball Then vector=halfball mang=ATan2(my-movy,mx-movx) ball\speed=vector movx=mx movy=my End If ball\xi=ball\speed*Cos(mang) ball\yi=ball\speed*Sin(mang) Else myball=0 End If mox=mx moy=my End Function Function RenderScreen() ;============================================================================================================== ; Bildschirmaufbau ;============================================================================================================== ClsColor 0,0,0:Cls k=0 For ball.img=Each IMG ;--> berechne beue Ball Position, es sein denn er wird gehalten If ball\nr<>myball Then ball\x=ball\x+ball\xi ball\y=ball\y+ball\yi End If DrawImage ballgfx,ball\x,ball\y,ball\image If Debug Then ;--> Hilfslinie im Ball ang=ATan2(ball\yi,ball\xi) Color 0,0,$FFFF00: Line ball\x,ball\y,ball\x+15*Cos(ang),ball\y+15*Sin(ang) ;--> Ballnummer Color 0,0,0: k=k+1: Text ball\x,ball\y,Str$(k) ;--> FPS If FTimer<MilliSecs() Then FTimer=MilliSecs()+999: FPS=Frames: Frames=0 Color 0,0,$FFFF00: Text 0,0,Str$(FPS)+" FPS" Text 0,20,Str$(NVector) End If Next ;--> Maus DrawImage mousegfx,MouseX(),MouseY() ;--> Wände For wall.obs=Each OBS DrawImage wall\image,wall\x,wall\y Next Frames=Frames+1 Flip End Function Function MoveBalls() ;============================================================================================================== ; Prüfe Ball Kollisionen ;============================================================================================================== x1=(sw-gamew)/2 x2=sw-x1 y1=(sh-gameh)/2 y2=sh-y1 x1=x1+Halfball+1 x2=x2-Halfball-1 y1=y1+Halfball+1 y2=y2-Halfball-1 For ball.img=Each IMG collide=False wcollide=False ;--> Prüfe Ball-Wand Kollision ang=ATan2(ball\yi,ball\xi) For wall.obs=Each OBS If ImagesCollide(ballgfx,ball\x,ball\y,0,wall\image,wall\x,wall\y,0) Then ;--> neue Richtung für Ball ang=-ang+(wall\a*2) wcollide=True EndIf Next ;--> neue Richtung für untersuchten Ball If wcollide Then If ball\speed>0 Then ball\speed=ball\speed*(Accelerate/2) Else ball\speed=0 ball\xi=ball\speed*Cos(ang) ball\yi=ball\speed*Sin(ang) ball\x=ball\x+ball\xi: If ball\x<x1 Then ball\x=x1 ElseIf ball\x>x2 Then ball\x=x2 ball\y=ball\y+ball\yi: If ball\y<y1 Then ball\y=y1 ElseIf ball\y>y2 Then ball\y=y2 EndIf ;--> Prüfe Ball-Ball Kollision For ball2.Img=Each Img If ball2<>ball Then If ImagesCollide(ballgfx,ball\x,ball\y,0,ballgfx,ball2\x,ball2\y,0) Then ;Neue Ballrichtungen und Geschwindigkeiten für untersuchten- und Kollisionsball If ball\speed>0 Or ball2\speed>0 Then ;--> beide Impulse addieren und bremsen speed#=(ball\speed+ball2\speed)*Float(Accelerate) ;--> Impuls auf beide Bälle aufteilen ball\speed=speed#/2 ball2\speed=speed#/2 Else ball\speed=0 ball2\speed=0 EndIf ang=ATan2(ball\y-ball2\y,ball\x-ball2\x) ang2=ATan2(ball2\y-ball\y,ball2\x-ball\x) ball\xi=ball\speed*Cos(ang) ball2\xi=ball2\speed*Cos(ang2) ball2\yi=ball2\speed*Sin(ang2) ball\yi=ball\speed*Sin(ang) EndIf EndIf Next Next End Function Function CreateBall() ;============================================================================================================== ; Erzeuge Ball ;============================================================================================================== x1=(sw-gamew)/2 x2=sw-x1 y1=(sh-gameh)/2 y2=sh-y1 bc = bc + 1 ball.img = New IMG ball\nr=bc ball\speed=MaxSpeed ang=Rand(0,360) ball\xi=ball\speed*Cos(ang) ball\yi=ball\speed*Sin(ang) ball\image=Rand(0,1) halfball=ImageWidth(ballgfx)/2 .Again ball\x=Rand(x1+halfball,x2-halfball) ball\y=Rand(y1+halfball,y2-halfball) ;--> Prüfe ob ermittelte Position schon von einem anderen Ball belegt ist collide=False For ball2.img=Each img If ball2<>ball Then If ImagesCollide(ballgfx,ball\x,ball\y,0,ballgfx,ball2\x,ball2\y,0) Then collide=True Exit EndIf EndIf Next If KeyHit(1) Then Return If collide Goto Again End Function Function CreateWall(x1,y1,x2,y2) ;============================================================================================================== ; Erzeuge Wand ;============================================================================================================== wall.obs=New OBS wc=wc+1 wall\ix=wc wall\y1=y1 wall\y2=y2 wall\x1=x1 wall\x2=x2 ;Size of the image w=Abs(x1-x2) h=Abs(y1-y2) wall\w=w wall\h=h ;Adjust from real world co-ords If x1>x2 Then wall\x=x2 x1=w:x2=0 Else wall\x=x1 x2=w:x1=0 EndIf If y1>y2 Then wall\y=y2 y1=h:y2=0 Else wall\y=y1 y2=h:y1=0 EndIf ;Keep the line's angle a=ATan2(y2-y1,x2-x1) wall\a=a ;Adjust To give correct rebound If a>0 And a<90 Then wall\a=a If a>90 And a<180 Then wall\a=a-180 ;Create & draw wall image wall\image=CreateImage(w+1,h+1) SetBuffer ImageBuffer(wall\image) Color 255,255,255 Rect 0,0,w+50,h+50 End Function |
||
![]() |
Mike Nike |
![]() Antworten mit Zitat ![]() |
---|---|---|
Habs mir gerade angesehn und werde dir versuchen ein paar Denkansätze zu geben...
Zu Problem 1: Du kannst dieses Problem durch Verschiedenes lösen. -Zum einen kannst du z.B. sagen, dass die Kugel, die festgehalten wird, nicht so schnell mit der Maus mithalten kann. Also es gibt eine Variable Mausspedd und eine Variable Kugelspeed_MAX oder so... -zum anderen kannst du durch genaueres Berechnen, wenn ich richtig liege, die anderen Kugeln weiter/schneller wegstoßen (keine gute Lösung) -oder aber du lässt die Kugeln gar nicht erst überschneiden, indem du z.B. die Maus (und Kugel) in die richtige Richtung zurück bewegst, bei einem Overlap. du kennst ja den Befehl MoveMouse -> der könnte dir weiterhelfen, allerdings ist auch das keine gute Lösung, da es sich ja um einen Wasserstrahl handelt. -Letztendlich sollte man das Problem auch in Bezug auf die Gravitation sehen, denn z.B. jenachdem wo die Maus auf der Kugel (MouseDown(left)=true) ist, wird die Kugel nach oben oder zur Seite oder nach unten weggeschossen/-gespritzt, bzw. der Ring und nicht die Kugel... Damit kommen wir zum 2ten Problem: Du musst in der Schleife eine Gravitation einfügen und ich glaube deine Probleme, die dadurch entstehen sind, dass die Bewegungen durch Gravitation teils größer sind, als die Bewegungen durch Kollidieren oder Wasserspritzen -> Da musst du an der richtigen Stelle Abfragen im Code stellen. Z.B. kannst du an manchen Stellen die Gravitation einfach vernachlässigen, wenn zum Beispiel eine Kugel auf eine andere fällt und dann nach oben bouncen/abprallen soll usw. |
||
..where the only limit is your imagination. |
![]() |
EPS |
![]() Antworten mit Zitat ![]() |
---|---|---|
erst mal vielen Dank für die Mühe, also ich habe mal einiges davon probiert, aber es gibt trotz allem noch Probleme.
Hauptsächliches Problem ist weiterhin das sich die Kugeln zusammenschieben lassen. Insbesondere wenn eine Kugel in der Ecke liegt und ich mit einer anderen dagegenschiebe. Mir würde es natürlich am besten gefallen wenn ich "einfach" (ja, ja einfach ![]() Die Kollision und das Winkelverhalten hab ich ja eigentlich schon. Kennt sich jemand mit sowas aus und hat ein paar "narrensichere" Formeln bzw. Umsetzungen für BB? Vielen Dank schon mal |
||
![]() |
Cornelius |
![]() Antworten mit Zitat ![]() |
---|---|---|
Das erste Problem würde ich so lösen, dass bei jeder Kollision die Kugeln so weit auseinander bewegt werden, dass sie sich nicht mehr berühren.
Mittels Pythagoras kann man den Abstand der Kugeln bestimmen (Abstand = Sqr((x2 - x1)^2 - (y2 - y1)^2); x1,y1 sind die Koordinaten der ersten Kugel, x2,y2 die der Zweiten). Um wie weit sich die Kugeln jetzt zu nah sind (Durchmesser - Abstand), werden sie dann auseinander bewegt. Mit dem Pythagoras kann man übrigens auch die langsamen ImageCollide()-Befehle vermeiden - Allerdings klappt der nur bei Kugeln. Für die Gravitation muss man die vertikale Geschwindigkeit (y-Geschw.) jeder Kugel pro Frame um einen bestimmten Wert vergrößern. Wenn das Obere eingebaut ist, sollte das klappen. Ich hab schonmal für Arcanes Physikengine eine paar Formeln zusammengestellt, vielleicht kannst du ja was damit anfangen: http://comvil.bei.t-online.de/TafelwerkLite.txt |
||
![]() |
EPS |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ah, Phytagoras...man bin ich schon lange aus der Schule raus, logisch, klar...das hilft schon mal weiter.
Hat noch jemand was für die Zusammenhänge von Masse, Schwerkraft usw. also reelle Berechnungen? Danke nochmals |
||
![]() |
Cornelius |
![]() Antworten mit Zitat ![]() |
---|---|---|
EPS hat Folgendes geschrieben: Hat noch jemand was für die Zusammenhänge von Masse, Schwerkraft usw. also reelle Berechnungen? Dafür hab ich ja den Link gepostet: http://comvil.bei.t-online.de/TafelwerkLite.txt
Da steht z.B. drin, dass sich die Schwerkraft so berechnet: F=m*g (m - Masse, g - Fallbeschleunigung) Da die Kraft ja erstmal nix bringt, benutzen wir diese Formel: F=m*a (a - Beschleungigung). Gleichgesetz und m gekürzt: a=g Um die Geschwindigkeit auszurechnen: v=a*t+v0 (v0 - Anfangsgeschwindigkeit, t - Zeitschritt) bzw. v=g*t+v0 g*t ist konstant, unabhängig von der Masse oder anderen Werten. Da in dem Programm nicht mit Metern gerechnet wird, bekommt man diesen Wert am besten durch rumprobieren raus (kann man als Konstante definieren). Um diesen konstanten Wert vergrößert sich in jedem Frame die vertikale Geschwindigkeit der Kugel. |
||
![]() |
EPS |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hoppla, den Link hatte ich glatt übersehen,
vielen Dank dafür. Mal sehen ob mich meine schwach ausgeprägten Mathekenntnisse und die Formeln weiterbringen ![]() also, danke erstmal |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group