Problem mit Physik Engine

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

EPS

Betreff: Problem mit Physik Engine

BeitragDo, März 04, 2004 21:51
Antworten mit Zitat
Benutzer-Profile anzeigen
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:

user posted image

user posted image

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
;
;==============================================================================================================

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
[/img]

Mike Nike

BeitragFr, März 05, 2004 14:30
Antworten mit Zitat
Benutzer-Profile anzeigen
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

BeitragFr, März 05, 2004 20:39
Antworten mit Zitat
Benutzer-Profile anzeigen
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 Wink ) einige physikalische Zusammanhänge hätte und dadurch eine realistische Engine zustande käme. Also sowas wie eine Funktion die das gesamte Verhalten einer Kugel bestimmt. Wobei man einige Parameter der Kugeln bestimmen kann, wie z.B. Gewicht und ob sie eher wie Gummi abprallt oder wie Metall und z.B. die Schwerkraft, Reibung einstellbar ist usw.

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

BeitragSa, März 06, 2004 12:50
Antworten mit Zitat
Benutzer-Profile anzeigen
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

BeitragSa, März 06, 2004 13:59
Antworten mit Zitat
Benutzer-Profile anzeigen
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

BeitragSa, März 06, 2004 15:07
Antworten mit Zitat
Benutzer-Profile anzeigen
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

BeitragSo, März 07, 2004 15:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Hoppla, den Link hatte ich glatt übersehen,

vielen Dank dafür. Mal sehen ob mich meine schwach ausgeprägten Mathekenntnisse und die Formeln weiterbringen Laughing

also, danke erstmal

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group