Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Pong - Problem bei der Ballkollision (https://www.delphipraxis.net/82080-pong-problem-bei-der-ballkollision.html)

.chicken 7. Dez 2006 20:59


Pong - Problem bei der Ballkollision
 
Also ich weiss das Thema Pong wurde hier schon oft behandelt, aber ich habe zu meinem Problem nichts gefunden!

Hier erstmal mein Code:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

const
  Breite = 600;
  Hoehe = 400;
type
  TForm1 = class(TForm)
    Spielfeld: TPaintBox;
    Button1: TButton;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Spielfeld_bemalen;
    procedure Tastendruck(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);
    procedure Ball_berechnen;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Spielerposition: Array [1..2] of TPoint;
  Ballposition, Ballrichtung: TPoint;
  Spieler, Ball: TBitmap;

implementation

{$R *.dfm}


//----------------------------------
//FORM CREATE
//----------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.DoubleBuffered := True;
  Randomize;
end;
//----------------------------------


//----------------------------------
//FUNKTION ZUFALLSRICHTUNG
//----------------------------------
function Zufallsrichtung (i: Integer; j: Integer): TPoint;
var
x, y: Integer;
begin
  x := (Random(i - 1) + 1) * 5;
  y := Random(j) * 5;

  case Random(2) of
    0: x := x;
    1: x := -x;
  end;

  case Random(2) of
    0: y := y;
    1: y := -y;
  end;

  Result := Point(x, y);
end;
//----------------------------------


//----------------------------------
//SPIELFELD VORBEREITEN
//----------------------------------
procedure Spielfeld_vorbereiten;
begin
  //Bilder laden
  Spieler := TBitmap.Create;
  Spieler.LoadFromFile('Spieler.bmp');
  Ball := TBitmap.Create;
  Ball.LoadFromFile('Ball.bmp');
  Ball.TransparentColor := RGB(255, 255, 255);
  Ball.TransparentMode := tmFixed;
  Ball.Transparent := True;

  //Startpositionen festgelegt
  Spielerposition[1] := Point(10, (Hoehe div 2 - 30));
  Spielerposition[2] := Point((Breite - 10 - Spieler.Width), (Hoehe div 2 - 30));
  Ballposition := Point((Breite div 2 - (Ball.Width div 2)), (Hoehe div 2 - (Ball.Height div 2)));
  Ballrichtung := Zufallsrichtung(5, 5);
end;
//----------------------------------


//----------------------------------
//SPIELFELD BEMALEN
//----------------------------------
procedure TForm1.Spielfeld_bemalen;
var
i, x: Integer;
begin
  //Spielfeld wird gelöscht
  Spielfeld.Canvas.Brush.Color := clGray;
  Spielfeld.Canvas.FillRect(rect(0, 0, Breite, Hoehe));

  //Mittellinie
  Spielfeld.Canvas.Brush.Color := clBlack;
  x := 0;
  for i := 0 to Hoehe do begin
    Spielfeld.Canvas.FillRect(rect((Breite div 2 - 1), x, (Breite div 2 + 1), (x+2)));
    x := x + 6;
  end;

  //Spieler und Ball werden gezeichnet
  Spielfeld.Canvas.Draw(Spielerposition[1].X, Spielerposition[1].Y, Spieler);
  Spielfeld.Canvas.Draw(Spielerposition[2].X, Spielerposition[2].Y, Spieler);
  Spielfeld.Canvas.Draw(Ballposition.X, Ballposition.Y, Ball);
end;
//----------------------------------


//----------------------------------
//BUTTONKLICK
//----------------------------------
procedure TForm1.Button1Click(Sender: TObject);
begin
  Spielfeld_vorbereiten;
  Timer1.Enabled := True;
  Button1.Enabled := False;
end;
//----------------------------------


//----------------------------------
//TASTENDRUCK
//----------------------------------
procedure TForm1.Tastendruck(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_Up: if (Spielerposition[1].Y - 10) > 0 then
            Spielerposition[1].Y := Spielerposition[1].Y - 10;
    VK_Down: if (Spielerposition[1].Y + 10 + Spieler.Height) < Hoehe then
              Spielerposition[1].Y := Spielerposition[1].Y + 10;
    VK_Left: if (Spielerposition[2].Y - 10) > 0 then
            Spielerposition[2].Y := Spielerposition[2].Y - 10;
    VK_Right: if (Spielerposition[2].Y + 10 + Spieler.Height) < Hoehe then
              Spielerposition[2].Y := Spielerposition[2].Y + 10;
  end;
end;
//----------------------------------


//----------------------------------
//TIMER
//----------------------------------
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Ball_berechnen;
  Spielfeld_bemalen;
end;
//----------------------------------


//----------------------------------
//BALL BERECHNEN
//----------------------------------
procedure TForm1.Ball_berechnen;
begin
  //Wand angestoßen?
  if Ballposition.Y <= 0 then
    Ballrichtung.Y := -Ballrichtung.Y;
  if Ballposition.Y >= Hoehe then
    Ballrichtung.Y := -Ballrichtung.Y;

  //Spieler angestoßen?
  if ((Ballposition.X <= Spielerposition[1].X + Spieler.Width) AND (Ballposition.Y + Ball.Height >= Spielerposition[1].Y) AND (Ballposition.Y <= Spielerposition[1].Y + Spieler.Height)) OR
     ((Ballposition.X + Ball.Width >= Spielerposition[2].X) AND (Ballposition.Y + Ball.Height >= Spielerposition[2].Y) AND (Ballposition.Y <= Spielerposition[2].Y + Spieler.Height)) then
          Ballrichtung.X := -Ballrichtung.X;

  //Gepunktet?
  //Sp1
  if Ballposition.X <= 0 then
    Timer1.Enabled := False;
    Button1.Enabled := True;
  //Sp2
  if Ballposition.X + Ball.Width >= Breite then
    Timer1.Enabled := False;
    Button1.Enabled := True;


  Ballposition := Point(Ballposition.X + Ballrichtung.X, Ballposition.Y + Ballrichtung.Y);
end;
//----------------------------------

end.
Also erstmal: das ist natuerlich alles noch nicht fertig!!!

Aber bei mir ist nun das Problem aufgetreten, dass der Ball bevor er die Richtung aendert oft schon auf dem Balken oder halb außerhalb des Spielfeldes ist, weil ich ja Pro Timer den Ball um zwischen 1 und 5 verschiebe!

Hoffe ihr versteht was ich meine...wie wuerdet ihr das lösen?

Und was habt ihr fuer Verbesserungsvorschlaege zu meinem Quelltext??
Bin noch nich solange am Arbeiten mit Delpih, machen es jetzt in der Schule aber unsern Lehrer kann man in der Pfeife rauchen also bring ichs mir selber bei...

Dazu danke dann erstmal an dieses (wirklich hilfreiche) Forum!


MfG, chicken!

Cöster 7. Dez 2006 21:27

Re: Pong - Problem bei der Ballkollision
 
Was mir spontan an deinem Quelltext auffällt:

-den Bildschirm lieber im OnPaint der PaintBox aktualisieren und dies per Invalidate aufrufen
-Offscreen-Bitmaps(siehe Suchfunktion/machst du schon teilweise)
-statt die Spielerpositionen im KeyDown zu verändern, lieber im Timer (benögitgte Funktion: GetAsyncKeyState)

Zu deinem Problem:

Du könntest die Kugel bei der Kollision mit dem Spielfeldrand um 2mal soviel nach innen verschieben, wie sie aus dem Bildschirm hinausragt.

.chicken 8. Dez 2006 19:35

Re: Pong - Problem bei der Ballkollision
 
Also danke erstmal fuer deine Antwort!!!

Kannst du deine ersten beiden Punkte vielleicht nochmal erlaeutern? Die versteh ich ehrlich gesagt nich so ganz ^^!

Dann zum dritten Punkt, das werd ich mir ma ansehn, wenn ich nich klar komme melde mich mich nomma, wenns recht is =)


Und zu deiner letzten Antwort:
Du meinst also dass ich einfach bevor ich die Kugelposition erneuere die alte abfrage und dann einfach nur bis zum Rand "auffuelle"?!

MfG

Edit: Zum Thema GetAsyncKey - Soll ich dass dann für jede benötigte Taste abfragen oder hab ich das falsch verstanden??? Bei vielen Tasten waer das ja bisschen umstaendlich, igibts doch sicher ne einfachere Moeglichkeit!?

Cöster 8. Dez 2006 20:16

Re: Pong - Problem bei der Ballkollision
 
Zitat:

Zitat von .chicken
Kannst du deine ersten beiden Punkte vielleicht nochmal erlaeutern? Die versteh ich ehrlich gesagt nich so ganz ^^!

Zu 1:
Statt die Zeichen-Prozedur Spielfeld_bemalen im Timer aufzurufen, schlage ich vor stattdessen die Prozedur "Spielfeld.Invalidate" aufzurufen. Dies bewirkt, dass die PaintBox neu gezeichnet wird. Dadurch wird das Ereignis "OnPaint" der PaintBox aufgerufen. In diesem sollten dann deine Zeichenvorgänge geschehen (PaintBox auf Form anklicken, im OI auf Ereignisse gehen, ins Feld neben OnPaint doppelklicken, am Cursor im Quelltext dann den Zeichnen-Code einfügen).

Zu 2:
Es ist schneller, nicht alle Zeichen-Vorgänge direkt auf die Komponente (PaintBox) zu übertragen, sondern erst alles auf das Canvas eines Bitmaps im Speicher zu zeichnen und dies dann auf das Canvas der PaintBox zu kopieren. In diesem Post beschreibt SirThornberry wie's geht.

Zitat:

Zitat von .chicken
Dann zum dritten Punkt, das werd ich mir ma ansehn, wenn ich nich klar komme melde mich mich nomma, wenns recht is =)

Klar ist's recht :wink: :dp:

Zitat:

Zitat von .chicken
Du meinst also dass ich einfach bevor ich die Kugelposition erneuere die alte abfrage und dann einfach nur bis zum Rand "auffuelle"?!

Ich weiß nicht genau, was du mit auffüllen meinst, aber ich glaub nicht. Du verschiebst deine Kugel ganz normal. Wenn sie jetzt z.B. um 3 Pixel in den rechten Rand hineinragt, heißt das ja, dass sie eigentlich schon 3 Pixel vor jetzt kollidiert hätte. Das heißt, die 3 Pixel, die die Kugel weiter nach rechts gerollt ist, obwohl sie nicht durfte, hätte sie eigentlich nach links rollen müssen. Deswegen verschiebst du die Kugel dann wieder um 2*3=6 Pixel nach links.
Von diesen Berechnungen soll der Anwender später natürlich nichts mitkriegen, deswegen darf zwischendurch nicht neugezeichnet werden. Aber das Neuzeichnen sollte sowieso nur im Timer über Invalidate (s.o.) erfolgen.

.chicken 8. Dez 2006 20:26

Re: Pong - Problem bei der Ballkollision
 
Hm also zum ersten...is das einfach nur besserer Stil oder funktioniert das schneller oder was steckt dahinter?

Und dann zum letzten Punkt: Wie verhindere ich denn dass der Anwender das nicht mitkriegt?
Habe ja jetzt im Timer dass er immer nachdem die Position neu berechnet wurde zeichnet, weswegen der Anwender ja auch sieht dass der Ball kollidiert!

Danke fuer deine schnellen Antworten!

Cöster 8. Dez 2006 20:54

Re: Pong - Problem bei der Ballkollision
 
Zitat:

Zitat von .chicken
Hm also zum ersten...is das einfach nur besserer Stil oder funktioniert das schneller oder was steckt dahinter?

Also der Vorteil, der mir bekannt ist, ist folgender: Wenn z.B. ein Label über der PaintBox liegt, würde dies im Normalfall beim Neuzeichnen übermalt werden. Wenn es Transparent und unsichtbar ist und man es dann sichtbar macht, hat die Transparenz auch nur dann Wirkung, wenn das Zeichnen im OnPaint stattfindet. Sonst wird nämlich dort, wo sich das Label befindet die PaintBox in Form eines Rechtecks übermalt, trotz der Transparenz des Labels.
Ich glaube es gibt noch viel mehr Vorteile, welche genau weiß ich auch nicht.

Zitat:

Zitat von .chicken
Und dann zum letzten Punkt: Wie verhindere ich denn dass der Anwender das nicht mitkriegt?
Habe ja jetzt im Timer dass er immer nachdem die Position neu berechnet wurde zeichnet, weswegen der Anwender ja auch sieht dass der Ball kollidiert!

Mit "nicht mitkriegt" meinte ich nur, dass der Anwender nicht sehen soll, dass die x-Position der Kugel zwischenzeitlich dort ist, wo sie eigentlich nicht sein darf. Aber wenn Invalidate erst dann aufgerufen wird, wenn alle Berechnungen durchgeführt wurden, sieht er das ja sowieso nicht.

.chicken 9. Dez 2006 08:00

Re: Pong - Problem bei der Ballkollision
 
OK, das mit onPaint und Invalidate hab ich soweit hinbekommen, flackert jezz sogar viel weniger, aber erst auf ein Bitmap zu zeichnen bekomme ich noch nicht wirklich hin >.<

Und dann zu der Sache mit der Kollision, meinste das so?

Delphi-Quellcode:
//----------------------------------
//BALL BERECHNEN
//----------------------------------
procedure TForm1.Ball_berechnen;
begin
  //Wand angestoßen?
  if Ballposition.Y <= 0 then
    Ballrichtung.Y := -Ballrichtung.Y;
  if Ballposition.Y >= Hoehe then
    Ballrichtung.Y := -Ballrichtung.Y;

  //Spieler angestoßen?
  if ((Ballposition.X <= Spielerposition[1].X + Spieler.Width) AND (Ballposition.Y + Ball.Height >= Spielerposition[1].Y) AND (Ballposition.Y <= Spielerposition[1].Y + Spieler.Height)) OR
     ((Ballposition.X + Ball.Width >= Spielerposition[2].X) AND (Ballposition.Y + Ball.Height >= Spielerposition[2].Y) AND (Ballposition.Y <= Spielerposition[2].Y + Spieler.Height)) then
          Ballrichtung.X := -Ballrichtung.X;

  //Gepunktet?
  //Sp1
  if Ballposition.X <= 0 then begin
    Timer1.Enabled := False;
    Button1.Enabled := True;
  end;
  //Sp2
  if Ballposition.X + Ball.Width >= Breite then begin
    Timer1.Enabled := False;
    Button1.Enabled := True;
  end;

  if Ballposition.X < Spielerposition[1].X + Spieler.Width then
    Ballposition.X := Spielerposition[1].X + Spieler.Width;
  if Ballposition.X + Ball.Width> Spielerposition[2].X then
    Ballposition.X := Spielerposition[2].X - Ball.Width;
  if Ballposition.Y < 0 then
    Ballposition.Y := 0;
  if Ballposition.Y + Ball.Height > Hoehe then
    Ballposition.Y := Hoehe - Ball.Height;


  Ballposition := Point(Ballposition.X + Ballrichtung.X, Ballposition.Y + Ballrichtung.Y);
end;
//----------------------------------

Sorry dass ich das net so schnell versteh :dp:

Edit: Mir is grad aufgefallen dass da so noch einige Fehler drin sind, aber generell zu diesem Teil

Delphi-Quellcode:
  if Ballposition.X < Spielerposition[1].X + Spieler.Width then
    Ballposition.X := Spielerposition[1].X + Spieler.Width;
  if Ballposition.X + Ball.Width> Spielerposition[2].X then
    Ballposition.X := Spielerposition[2].X - Ball.Width;
  if Ballposition.Y < 0 then
    Ballposition.Y := 0;
  if Ballposition.Y + Ball.Height > Hoehe then
    Ballposition.Y := Hoehe - Ball.Height;
So meinst du das?

Und dann noch was :D
Kann man die Kollision nich irgendwie eleganter lösen??? Weil wenn ich hitnerher noch berechnen will, dass wenn der Ball weiter rechts aufprallt er beschleunigt/verlangsamt wird, dann verlier ich mich ja in endlosen IF-Bedigungen...

Hab schon die SuFu dazu benutzt und bin öfter auf so Wurzel und Quadrat Funktionen gestoßen, hab aber echt keinen Plan was ich damit anstellen soll =)

Cöster 9. Dez 2006 11:59

Re: Pong - Problem bei der Ballkollision
 
Mir ist noch ein Vorteil von OnPaint+Invalidate eingefallen: Das verhindert, dass man das Bild auf einer PaintBox nicht wegradieren kann, indem man andere Fenster drüberschiebt.

Wo liegt denn dein Problem mit dem Zeichnen auf ein Speicher-Bitmap? Wie hast du's denn versucht umzusetzen und was klappte dabei nicht? Zeig mal Code!

In Z. 9 deines Codes ist noch ein Fehler: BallPosition.Y + Ball.Height müsste es heißen.

Den Teil unten in deinem Code kann man im Grunde genommen so lösen.

Was du generell noch an deinem Code verbessern könntest: Einige Bedingungen fragst du mehrmals ab. Du könntest an vielen Stellen mehrere Bedingungen zusammenfassen.
In Zeile 7-10 passiert bei Zwei verschiedenen Bedingungen (von denen sowieso nur eine stimmen kann) das gleiche. Du könntest sie mit "or" verbinden. Dann braucht die zweite nämlich gar nicht mehr gelesen zu werden, wenn die erste zutrifft. Das brächte minimalen Zeitgewinn.



Zitat:

Zitat von .chicken
Kann man die Kollision nich irgendwie eleganter lösen??? Weil wenn ich hitnerher noch berechnen will, dass wenn der Ball weiter rechts aufprallt er beschleunigt/verlangsamt wird, dann verlier ich mich ja in endlosen IF-Bedigungen...

:wiejetzt: Also rechts und links sind doch die Spieler, oder? Wieso sollte der Ball mehr beschleunigt werden, wenn er weiter rechts in den rechten Spieler stößt? Wohl eher, dass der Abprallwinkel davon abhängt, ob der Spieler mittig den Ball abstößt oder nur gerade noch mit dem Rand berührt.

.chicken 9. Dez 2006 14:46

Re: Pong - Problem bei der Ballkollision
 
Aso, dass hab ich falsch erklaert mit dem rechts und links, ich meinte wenn er weiter rechts auf dem schlaeger aufprallt (vom schlaeger aus gesehn) also weiter unten/oben...

Dass im Quelltext vieles noch nicht stimmte hatte ich ja auch erwaehnt, hab ihn nochmal überarbeitet aber das funzt trotzdem noch nich so ganz...

Delphi-Quellcode:
//----------------------------------
//BALL BERECHNEN
//----------------------------------
procedure TForm1.Ball_berechnen;
begin

  Ballposition := Point(Ballposition.X + Ballrichtung.X, Ballposition.Y + Ballrichtung.Y);

  Kollision;
end;
//----------------------------------


//----------------------------------
//KOLLISION
//----------------------------------
procedure TForm1.Kollision;
var
i: Integer;
begin
  //Wand angestoßen?
  if Ballposition.Y <= 0 then begin
    Ballposition.Y := 0;
    Ballrichtung.Y := -Ballrichtung.Y;
  end;
  if Ballposition.Y + Ball.Height >= Hoehe then begin
    Ballposition.Y := Hoehe - Ball.Height;
    Ballrichtung.Y := -Ballrichtung.Y;
  end;

  //Spieler1 angestoßen?
    //Vorne angestoßen?
  if (Ballposition.Y + Ball.Height >= Spielerposition[1].Y) AND (Ballposition.Y <= Spielerposition[1].Y + Spieler.Height) then
    if Ballposition.X <= Spielerposition[1].X + Spieler.Width then begin
      Ballposition.X := Spielerposition[1].X + Spieler.Width;
      Ballrichtung.X := -Ballrichtung.X;
  end
  else
    //Unten/Oben angestoßen?
  if (Ballposition.X <= Spielerposition[1].X + Spieler.Width) AND (Ballposition.X + Ball.Width >= Spielerposition[1].X) then begin
    if (Ballposition.Y + Ball.Height >= Spielerposition[1].Y) AND (Ballposition.Y + Ball.Height <= Spielerposition[1].Y + Spieler.Height div 2) then begin
      Ballposition.Y := Spielerposition[1].Y - Ball.Height;
      Ballrichtung.Y := -Ballrichtung.Y;
    end;
    if (Ballposition.Y <= Spielerposition[1].Y + Spieler.Height) AND (Ballposition.Y >= Spielerposition[1].Y + Spieler.Height div 2) then begin
      Ballposition.Y := Spielerposition[1].Y + Spieler.Height;
      Ballrichtung.Y := -Ballrichtung.Y;
    end;
  end;

  //Spieler2 angestoßen?
    //Vorne angestoßen?
  if (Ballposition.Y + Ball.Height >= Spielerposition[2].Y) AND (Ballposition.Y <= Spielerposition[2].Y + Spieler.Height) then
    if Ballposition.X + Ball.Width >= Spielerposition[2].X then begin
      Ballposition.X := Spielerposition[2].X - Spieler.Width;
      Ballrichtung.X := -Ballrichtung.X;
  end
  else
    //Unten/Oben angestoßen?
  if (Ballposition.X + Ball.Width >= Spielerposition[2].X) AND (Ballposition.X <= Spielerposition[1].X + Spieler.Width) then begin
    if (Ballposition.Y + Ball.Height >= Spielerposition[2].Y) AND (Ballposition.Y + Ball.Height <= Spielerposition[1].Y + Spieler.Height div 2) then begin
      Ballposition.Y := Spielerposition[2].Y - Ball.Height;
      Ballrichtung.Y := -Ballrichtung.Y;
    end;
    if (Ballposition.Y <= Spielerposition[2].Y + Spieler.Height) AND (Ballposition.Y >= Spielerposition[1].Y + Spieler.Height div 2) then begin
      Ballposition.Y := Spielerposition[2].Y + Spieler.Height;
      Ballrichtung.Y := -Ballrichtung.Y;
    end;
  end;

    //Gepunktet?
  //Sp1
  if Ballposition.X <= 0 then begin
    Timer1.Enabled := False;
    Button1.Enabled := True;
  end;
  //Sp2
  if Ballposition.X + Ball.Width >= Breite then begin
    Timer1.Enabled := False;
    Button1.Enabled := True;
  end;
end;
//----------------------------------
Kann man die Kollision denn eleganter abfragen? Denn nebenbei is der Ball ja rund, und ich habe aber ein eckiges Bild, dh die Abfrage ist nicht wirklich genau!


Für die Sache mit dem aufs Bitmap zeichnen:
Ich hab den Code jetzt nichtmehr, weil ich ihn wieder gelöscht habe als es nicht funktioniert hat, damit ich das Programm weiter benutzen kann.

Also immer wenn ich das Programm gestartet habe dann hat er einfach alles schwarz gemalt und is abgestuertzt.

Ich hab das ungefaehr so versucht umzusetzen:

Delphi-Quellcode:
Spielfeldpuffer := TBitmap.Create;
Spielfeldpuffer.Width := Breite;
Spielfeldpuffer.Height := Hoehe;

//dann in der onPaint Funktion die Spieler und den Ball mittels Draw auf den Canvas des Bilds gemalt //(das war sicher einer der Fehler) ungefaehr so
Spielfeldpuffer.Canvas.Draw(Spielerposition[1].X, Spielerposition[1].Y, Spieler);

//und dann in die Paintbox damit
Spielfeld.Canvas.Draw(0, 0, Spielfeldpuffer);
Denke mal da warn mehrere Fehlre drin!

MfG

Edit: (Kollision ueberarbeitet)
Bei der Kollision is mir noch was aufgefallen...die beiden Prüfungen ob oben oder vorne am Schlaeger angestoßen wird ueberpruefen beide nahezu dasselbe, deswegen aendert der Ball abundzu plötzlich ganz komisch die Richtung...hab aber keine Ahnung iwe ich nun unterscheiden soll ob der Ball von oben auf den Schlaeger oder von der Seite da drauf prallt (hoffe ich versteht was ich meine)



O
-
-
-
-
-

oder

-
-
- O
-
-

Hoffe das hilft etwas zum Verstaendnis :D

Cöster 9. Dez 2006 17:07

Re: Pong - Problem bei der Ballkollision
 
Zitat:

Zitat von .chicken
Denn nebenbei is der Ball ja rund, und ich habe aber ein eckiges Bild, dh die Abfrage ist nicht wirklich genau!

Dann überprüfst du halt erst, ob eine Kollision auf Höhe des Kugelmittelpunkts stattfindet. Nachher guckst du, ob die Entfernung vom Kugelmittelpunkt zu einer der Ecken des Spielerrechtecks kleiner ist als der Radius der Kugel. Dann gibt es nämlich eine Kollision mit einem Eckpunkt der Kugel. Zur Kollision von Kugeln mit Ecken findest du hier im Forum sämtliche Beiträge. Das wird allerdings dann etwas komplizierter.


So könntest du das Zeichen machen:

Delphi-Quellcode:
BitBlt(Spielfeld.Canvas.Handle, Spielerposition[1].X, Spielerposition[1].Y,
   Spieler.Width, Spieler.Height, Spieler.Canvas.Handle, 0, 0, SRCCOPY);
BitBlt(Spielfeld.Canvas.Handle, Spielerposition[2].X, Spielerposition[2].Y,
   Spieler.Width, Spieler.Height, Spieler.Canvas.Handle, 0, 0, SRCCOPY);
BitBlt(Spielfeld.Canvas.Handle, Ballposition.X, Ballposition.Y, Ball.Width,
   Ball.Height, Ball.Canvas.Handle, 0, 0, SRCCOPY);
Du brauchst also gar kein weiteres Bitmap im Hintergrund erstellen. Um das löschen des zuvorgezeichneten brauchst du dich auch nicht kümmern, weil das durch Invalidate + OnPaint sowieso gelöscht wird. Das, was du sonst noch so auf dem Bildschirm darstellen wirst, bleibt ja unverändert. Du könntest es also auf einem Image im Hintergrund darstellen, an dem du später nichts ändern brauchst. Du lädst einfach das Bitmap über den Objektinspektor in dein Image. Damit das Image sich nicht über der PaintBox befindet und diese verdeckt, kannst du auf es rechtsklicken und nach hinten setzen auswählen.

.chicken 9. Dez 2006 17:45

Re: Pong - Problem bei der Ballkollision
 
Ok, das klappt zwar soweit, aber dann is miene Transparent Color sichtbar... :/

Cöster 9. Dez 2006 18:28

Re: Pong - Problem bei der Ballkollision
 
Zitat:

Zitat von .chicken
Ok, das klappt zwar soweit, aber dann is miene Transparent Color sichtbar... :/

Dann statt BitBlt doch Draw nehmen. :mrgreen:
Oder aber: Wie sehen die beiden Bitmaps Spieler und Ball denn aus? Wenn sie nicht allzu kompliziert sind, könntest du sie ja auch über die Canvas-Routinen selbst zeichnen. Dann erstellst du ein OffScreen-Bitmap, kopierst darauf zunächst den Bildschirmausschnitt des Images, auf den du später kopierst, zeichnest auf das OffScreen-Bitmap mit den Canvas-Routinen den Ball bzw. Spieler und kopierst das OffScreen-Bitmap anschließend auf die PaintBox.
Musst du gucken, was schneller geht. Ich weiß nur, dass Tranzparenz im allgemeinen ziemlich ausbremst.

.chicken 9. Dez 2006 19:07

Re: Pong - Problem bei der Ballkollision
 
Den Teil hab ich schon wieder nich verstanden :D
Also der Ball sieht imho noch nich so kompliziert aus aber will den spaeter vielleicht nochma aendern wenn alles funktioniert! Also das is ja auch erstma egal, laeuft so ja auch...nur an der Kollisionsabfrage haperts echt nochn bissl!

Versuche das nun mit IntersectRect..das klappt aber irgendwie noch nich so ganz,daran arbeite ich nun erstmal weiter...

Könntest du mir das mit dem "getAsyncKeyState" nochmal genauer erklaeren? Also ich rufe dass dann fuer jede Taste die ich benutzen will auf oder wie oder was? :wall: :mrgreen:

Cöster 9. Dez 2006 19:20

Re: Pong - Problem bei der Ballkollision
 
Zitat:

Zitat von .chicken
an der Kollisionsabfrage haperts echt nochn bissl!

Hab ich doch oben was zu geschrieben:

Zitat:

Zitat von Cöster
Dann überprüfst du halt erst, ob eine Kollision auf Höhe des Kugelmittelpunkts stattfindet. Nachher guckst du, ob die Entfernung vom Kugelmittelpunkt zu einer der Ecken des Spielerrechtecks kleiner ist als der Radius der Kugel. Dann gibt es nämlich eine Kollision mit einem Eckpunkt der Kugel. Zur Kollision von Kugeln mit Ecken findest du hier im Forum sämtliche Beiträge. Das wird allerdings dann etwas komplizierter.

Zitat:

Zitat von .chicken
Könntest du mir das mit dem "getAsyncKeyState" nochmal genauer erklaeren? Also ich rufe dass dann fuer jede Taste die ich benutzen will auf oder wie oder was? :wall: :mrgreen:

Eine Prozedur schreiben, die prüft, welche der 4 Steuerungstasten gedrückt sind und abhängig davon dann die Spieler-Positionen verändert. Diese Prozedur dann im Timer aufrufen. Dann läuft das nämlich auch ruckelfrei durch (es sei denn, du willst, dass die Schläger-Bewegung ruckelt).

.chicken 9. Dez 2006 19:24

Re: Pong - Problem bei der Ballkollision
 
Aso gut dann weiss ich jetzt wie, zu derm Kollisionsding:
Bei der "runden" Kollisionsabfrage bin ich noch garnicht... :D
Ich versuch grad erstmal das so hinzukriegen, aber ich versuch erstmal weiter, mein Kopf raucht schon :D

Danke fuer deine Hilfe

.chicken 9. Dez 2006 22:52

Re: Pong - Problem bei der Ballkollision
 
Ich hab mir grad ueberlegt die Bewegung nich wie vorher zu berechnen sondern mittels der Steigung, dh ich rechne richtung.y / richtung.X und verschiebe y jedesmal wenn ich x um einen verschiebe um soviel...

was haltet ihr davon? sinnvoller?

so könnte man die kollisionen genauer abfragen glaube ich...aber die umsetzung is glaub ich dochn bisschen kompliziert, waer ja dann mit extended nichmehr nur mit integer ....

.chicken 10. Dez 2006 15:06

Re: Pong - Problem bei der Ballkollision
 
Ok, also habe nun nochmal komplett von vorne angefangen und erstmal nur mit einem Spielerbrett...

Der Stand der Dinge sieht so aus, dass der Ball von allen Waenden abprallt (bis auf die hinter ihm, dann is das Spiel vorbei) und der Ball einen Drall bekommt, jenachdem auf welcher Seite vom Schlaeger er aufprallt!

Hier der Quelltext:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Math;

const
  Breite = 300;
  Hoehe = 300;
type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Timer1: TTimer;
    Left: TImage;
    Right: TImage;
    Shape1: TShape;
    procedure Spielfeld_bemalen(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Spielstart;
    procedure Ball_berechnen;
    procedure Tastendruck(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }

  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

type TSpieler = record
      X, Y: Integer;
      Bmp: TBitmap;
end;

type TBall = record
      X, Y: Integer;
      Bmp: TBitmap;
      Richtung: TPoint;
end;

var
  Spieler: TSpieler;
  Ball: TBall;

{$R *.dfm}

procedure TForm1.Spielfeld_bemalen(Sender: TObject);
begin
  PaintBox1.Canvas.Brush.Color := clBlack;
  Paintbox1.Canvas.Pen.Color := clBlack;
  PaintBox1.Canvas.Rectangle(0, 0, Breite, Hoehe);

  PaintBox1.Canvas.Draw(Spieler.X, Spieler.Y, Spieler.Bmp);
  Paintbox1.Canvas.Draw(Ball.X, Ball.Y, Ball.Bmp);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  //Tastendrücke
  if GetAsyncKeyState(VK_Left) < 0 then
    if Spieler.X > 0 then
      Spieler.X := Spieler.X - 10;
  if GetAsyncKeyState(VK_Right) < 0 then
    if Spieler.X + Spieler.Bmp.Width < Breite then
      Spieler.X := Spieler.X + 10;

  PaintBox1.Invalidate;
  Ball_berechnen;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.DoubleBuffered := True;
  Randomize;
  Timer1.Enabled := False;
end;

procedure TForm1.Spielstart;
begin
  Spieler.Bmp := TBitmap.Create;
  Spieler.Bmp.LoadfromFile('Spieler.bmp');
  Spieler.X := Breite div 2 - (Spieler.Bmp.Width div 2);
  Spieler.Y := 0;

  Ball.Bmp := TBitmap.Create;
  Ball.Bmp.LoadFromFile('Ball.bmp');
  Ball.Bmp.TransparentColor := RGB(255, 0, 216);
  Ball.Bmp.Transparent := True;
  Ball.X := Breite div 2 - Ball.Bmp.Width div 2;
  Ball.Y := Hoehe div 2 - Ball.Bmp.Height div 2;
  Ball.Richtung.X := 0;
  Ball.Richtung.Y := -(Random(9) + 3);
end;


procedure TForm1.Ball_berechnen;
var
R0, R1, R2: TRect;
i: Integer;
begin
  Ball.X := Ball.X + Ball.Richtung.X;
  Ball.Y := Ball.Y + Ball.Richtung.Y;
  R1 := Rect(Ball.X - 1, Ball.Y - 1, Ball.X + Ball.Bmp.Width + 1, Ball.Y + Ball.Bmp.Height + 1);
  R2 := Rect(Spieler.X, Spieler.Y, Spieler.X + Spieler.Bmp.Width, Spieler.Y + Spieler.Bmp.Height);

  //Schläger angestoßen oder gepunktet?
  if Ball.Y <= 0 + Spieler.Bmp.Height then

    //Schläger angestoßen
    if IntersectRect(R0, R1, R2) = True then
    begin
      Ball.Y := Spieler.Bmp.Height;
      i := (Ball.X + (Ball.Bmp.Width div 2)) - (Spieler.X + (Spieler.Bmp.Width div 2));
      Ball.Richtung.X := Ball.Richtung.X + (i div 5);
      Ball.Richtung.Y := -Ball.Richtung.Y;
    end
    else
    //Gepunktet
    begin
      Timer1.Enabled := False;
      Showmessage('ITS OVER!');
    end
  else

  //Wand angestoßen?
  if Ball.X <= 0 then
  begin
    Ball.X := 0;
    Ball.Richtung.X := -Ball.Richtung.X;
  end
  else
  if Ball.X + Ball.Bmp.Width >= Breite then
  begin
    Ball.X := Breite - Ball.Bmp.Width;
    Ball.Richtung.X := - Ball.Richtung.X;
  end
  else
  if Ball.Y + Ball.Bmp.Height >= Hoehe then
  begin
    Ball.Y := Hoehe - Ball.Bmp.Height;
    Ball.Richtung.Y := - Ball.Richtung.Y;
  end;
end;


procedure TForm1.Tastendruck(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
  VK_Return: begin
              Spielstart;
              Timer1.Enabled := True;
             end;
  end;
end;

end.
Wie immer bin ich offen fuer konstruktive Kritik und Vorschlaege =)

Achja und hat noch wer ne Idee wie ich realisieren kann, dass der Ball auch an der rechten und linken Kante vom Schlaeger abprallen kann? Momentan ist es so, dass sobald er hinter der Vorderkante des Schlaegers landet das Spiel zuende ist, weil ich Probleme hatte zu prüfen ob der Ball nun auf die Kante oder Vorne aufgekommen ist (wie auch schon in einem meiner letzten Posts beschrieben).

MfG

Cöster 10. Dez 2006 16:58

Re: Pong - Problem bei der Ballkollision
 
Die ersten 3 Anweisungen in Spielfeld_bemalen kannst du dir sparen, wenn du einfach im Objektinspektor Form1.Color auf clBlack stellst. Das Canvas der PaintBox wird vorm OnPaint sowieso gelöscht.

Zitat:

Zitat von .chicken
Achja und hat noch wer ne Idee wie ich realisieren kann, dass der Ball auch an der rechten und linken Kante vom Schlaeger abprallen kann? Momentan ist es so, dass sobald er hinter der Vorderkante des Schlaegers landet das Spiel zuende ist, weil ich Probleme hatte zu prüfen ob der Ball nun auf die Kante oder Vorne aufgekommen ist (wie auch schon in einem meiner letzten Posts beschrieben).

Wenn er auf die linke oder rechte Kante stößt verliert der Spieler ja trotzdem. Höchstens wenn er auf die Ecke des Schlägers prallt, springt er evtl. wieder zurück ins Feld. Bemüh mal die Suchfunktion, gab schon mehrere Threads dazu.

.chicken 10. Dez 2006 19:26

Re: Pong - Problem bei der Ballkollision
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ja verliern tut er trotzdem, aber wenn beim FIFA der Ball ins Tor geht sieht man das auch ;-)
Nein also natuerlich funktioniert das so auch aber irgendwann treten ja auch ma Situationen auf wo das nichtmehr so ist und ich will ja was aus dem Projekt lernen ;-)

Danke für deine Antwort ich guck nochma im Forum!

Edit: Also habe zu meinem speziellen Problem nichts gefunden im Forum ich haeng mal ne Grafik zur Verdeutlichung dran!

Cöster 10. Dez 2006 20:36

Re: Pong - Problem bei der Ballkollision
 
Naja, wann gibt es eine Kollision mit der senkrechten Kante? Wenn der Mittelpunkt des Kreises oberhalb der unteren Kante des Schlägers ist und sich der linke (rechte) Rand des Kreises links (rechts) von der rechten (linken) Kante des Schlägers befindet.

.chicken 10. Dez 2006 20:39

Re: Pong - Problem bei der Ballkollision
 
Also entweder ich hab nur n totales Brett vorm Kopf...

Ne also mein Problem is ja, dass ich Pro Ball_berechnen Prozedur die ich aufrufe den Ball ja z.B. um X + 50 und Y + 70 oder sowas verschiebe, wenn danach der Ball schon mitten im Spielbrett ist, kann ich nichtmehr prüfen auf welcher Kante er denn aufgekommen waere...verstehste was ich meine? ^^

Kansnte vielleicht mal n Codebeispiel schreiben wie dus machen wuerdestr, wenns nich zuviel verlangt is?

Cöster 10. Dez 2006 20:51

Re: Pong - Problem bei der Ballkollision
 
Ach so meinste das. Aber bevor das passiert wäre der Ball doch schon längst von der Ecke abgeprallt (es sei denn, du bewegst ihn wirklich um 70 und 50 Pixel auf einmal). Um die Kollision mit der Ecke wirst du also nicht drum rumkommen. Es gibt 3 mögliche Kollisionen:

1. auf waargerechte Kante (einfach)
2. auf senkrechte Kante (auch einfach)
3. auf Ecke (schwerer)

Aber wenn du's realistisch machen willst, musst du auch diese 3. Kollision berücksichtigen.

.chicken 10. Dez 2006 20:58

Re: Pong - Problem bei der Ballkollision
 
Ja aber mein Problem besteht darin rauszufinden welche der 3 Moeglichkeiten nun zutrifft, denn der Ball wird ja wie erwaehnt jedes mal um viele Pixel bewegt (damit er auch Geschwindigkeit erhaelt)!

Gibts ne Moeglichkeit die Richtung der Bewegung als Winkel anzugeben nich als X und Y-Koordinate? dann waer das sicher n bissl einfacher!!!

Haste sonst ne Idee wie das geht oder irgendwer anders?

Danke vielmals dass du dich so damit auseinandersetzt =)

Cöster 10. Dez 2006 21:23

Re: Pong - Problem bei der Ballkollision
 
Delphi-Quellcode:
if ObererKugelrand.Y < Schlägerunterkante.Y then
   if EntfernungVomKugelmittelpunktZurEcke < Kugel.Radius then
      Eckenkollision
   else if (Kugel.Mittelpunkt.X < RechteKanteSchläger.X) and (Kugel.Mittelpunkt.X > LinkeKanteSchläger.X) then
      Unterkantenkollision
   else if (LinkerKugelrand.X < RechterSchlägerrand.X) then
      RechteKantenKollision
   else if (RechterKugelrand.X > LinkerSchlägerrand.X) then
      LinkeKantenKollision
   else
      GarKeineKollision;
Puh. Jetzt bin ich aber mit meinem Latein am Ende. :roteyes:

.chicken 11. Dez 2006 06:36

Re: Pong - Problem bei der Ballkollision
 
Delphi-Quellcode:
if ObererKugelrand.Y < Schlägerunterkante.Y then
   if EntfernungVomKugelmittelpunktZurEcke < Kugel.Radius then //dazu hab ich nochmal ne grafik angehaengt, funktioniert so glaub ich auch nich ganz richtig, das is mir aber erstmal auch nich das wichtigste...
      Eckenkollision
   else if (Kugel.Mittelpunkt.X < RechteKanteSchläger.X) and (Kugel.Mittelpunkt.X > LinkeKanteSchläger.X) then
      Unterkantenkollision
   else if (LinkerKugelrand.X < RechterSchlägerrand.X) then
      RechteKantenKollision
   else if (RechterKugelrand.X > LinkerSchlägerrand.X) then
      LinkeKantenKollision
   else
      GarKeineKollision;

D.h. bei deinem Beispiel duerfte ich den Ball nie schneller als der Radius bewegen oder??? Sonst waer nichtmehr gewaehrleistet dass das alles funktioniert glaub ich..

Da muss es doch auch omnch ne andere Moeglichkeit geben oder???

Cöster 11. Dez 2006 07:54

Re: Pong - Problem bei der Ballkollision
 
Ich seh gerade, dass die Anfangsgeschwindigkeit des Balles schon zwischen 3 und 11 :shock: Pixel pro Timer-Intervall liegt. Ich würde stattdessen lieber das Timer-Intervall runterstellen (ca. 20). Dann kannst du eine niedrigere Startgeschwindigkeit wählen. Wie hoch ist denn dein Timer-Intervall?

Eine andere Möglichkeit gäbe es auch: Wenn die Geschwindigkeit z.B. 10 beträgt, in Ball_berechnen ne Schleife von 1 bis 10 laufen lassen, und immer nur um 1 verschieben, Kollisionsabfrage, um 1 verschieben, Kollisionsabfrage usw.

PS: Du hast den Anhang vergessen.

.chicken 11. Dez 2006 14:03

Re: Pong - Problem bei der Ballkollision
 
Liste der Anhänge anzeigen (Anzahl: 1)
Mein Intervall is so schon auf 20 ^^

Aber das mit der Schleife probier ich mal...danke! Da seh ich nurnoch das Problem, dass ich ja 2 unteschiedliche x und y werte hab aber sie ja in einer Schleife unterbringen muss aber das krieg ich irgendwie hin....

Den Anhang haeng ich jetzt nochma dran!

Cöster 11. Dez 2006 14:27

Re: Pong - Problem bei der Ballkollision
 
@Anhang:

Ja, dann musst du wohl die Schleife benutzen, damit die Kollision schon vorher abgefangen wird.

.chicken 11. Dez 2006 14:48

Re: Pong - Problem bei der Ballkollision
 
Argh nichmal mit der Schleife krieg ich das hin, weil ich ja nur um ganze Werte verschieben kann...

Jetzt hab ich Richtung.X = 10 und Richtung.Y = 7 z.B...jetzt würd ich ne Schleife mit 10 Wiederholungen machen und jedesmal X um 1 und Y um Richtung.Y / Richtung.X aber das waer dann ja gerundet, d.h es wird ungenau und wenn Richtung.Y / Richtung.X z.B. 0,3 waer wuerde Richtung.Y ja zu null...

Verstehste mein Problem? :D:D:D
Boah is das kompliziert...wie wird sowas denn bei komplexeren Sachen gelöst??? Is die Bewegung mit z.B. DelphiX besser oder einfachrer zu realisieren?

MfG

Cöster 11. Dez 2006 15:00

Re: Pong - Problem bei der Ballkollision
 
Speicher doch die Position des Balles in einem reellen Typ.

Keine Ahnung, wie das mit DelphiX aussieht, ich hab bisher auch immer alles mit PaintBox und Co. gemacht. Glaub aber kaum, dass DelphiX dir diese Arbeit abnimmt.

.chicken 11. Dez 2006 15:14

Re: Pong - Problem bei der Ballkollision
 
argh dann muss ich ja sauvoiel umschreiben oder?? und du meinst dan reellen typ dann immer wenn ich die pixel abfrage runden oder was???

Cöster 11. Dez 2006 15:17

Re: Pong - Problem bei der Ballkollision
 
Runden brauchst du eig. nur, wenn gezeichnet werden muss. Wieso viel umschreiben?

.chicken 11. Dez 2006 15:28

Re: Pong - Problem bei der Ballkollision
 
Aaaah das geht trotzdem nich ^^
Weil das mit der Schleife meeeeeeeeega kompliziert is....das muss doch auch einfacher gehn...ich guck mir mal nochn paar andere Pong Spiele an!

Corpsman 11. Dez 2006 15:36

Re: Pong - Problem bei der Ballkollision
 
Auch auf die Gefahr hin das ihr mich der Werbung bezichtigt.

es gibt da ein Sample das die Kollision von Bällen in 2D sehr gut zeigt.

.chicken 11. Dez 2006 15:45

Re: Pong - Problem bei der Ballkollision
 
Ok danke, dass seh ich mir ma an, hab naemlich sonst unter der Suche kein Pong gefunden wo man auch die Seiten des Schlaegers anstoßen kann =)

Woah da steig ich nun garnichmehr durch :(

Corpsman 11. Dez 2006 16:43

Re: Pong - Problem bei der Ballkollision
 
Eigentlich ist es ganz Simpel.

Du must ja nur den Teil auserhalb der Class verstehn.

.chicken 11. Dez 2006 17:22

Re: Pong - Problem bei der Ballkollision
 
Alles ausser Class is doch fast das ganze Projekt!? Oder meinste damit alles ausser der Elements.pas?

Da sind soviele Variablen, dass ich bei jeder Prozedur tausend mal nachgucken muss, was das war... :D

Naja dann dauert des ganze halt ma zwei Stunden :P Ich setz mich heute Abend ma dran...

Delphi-Quellcode:
Function EllipseRechteckcollision(E1, R1: Trect): boolean;
Type
  Tpunkt = Record
    X, Y: Extended;
  End;
Var
  SN1, SN2, X, Alpha: extended;
  p1, p2: Tpoint;
  N1, N2: Tpunkt;
  radius1, radius2: integer;
Begin
  result := false;
  If E1.left > E1.right Then tausche(E1.left, E1.right);
  If E1.Top > E1.bottom Then tausche(E1.top, E1.bottom);
  If r1.left > r1.right Then tausche(r1.left, r1.right);
  If r1.Top > r1.bottom Then tausche(r1.top, r1.bottom);
  p1.x := E1.left + ((E1.right - E1.left) Div 2);
  p1.y := E1.top + ((E1.Bottom - E1.top) Div 2);
  p2.x := r1.left + ((r1.right - r1.left) Div 2);
  p2.y := r1.top + ((r1.Bottom - r1.top) Div 2);
  Alpha := arcTangens(p1.x - p2.x, p1.y - p2.y);
  X := Hypot(p1.x - p2.x, p1.y - p2.y);
  Radius1 := p1.x - E1.left;
  Radius2 := p1.y - E1.top; // Radius 1 Horizontal, Radius2 Vertikal
  N1.X := cosinus(alpha) * radius1 + P1.X;
  N1.Y := sinus(Alpha) * radius2 + P1.Y;
  SN1 := Hypot(p1.x - n1.x, p1.y - n1.y);
  Case round(Alpha) Of
    0..45: Begin
        n2.x := R1.right;
        n2.y := round(tangens(alpha) * ((r1.Bottom - p2.y) / 2)) + p2.y;
      End;
    46..90: Begin
        n2.y := R1.top;
        n2.x := round(tangens(alpha - 45) * ((r1.right - p2.x) / 2)) + p2.x;
      End;
    91..135: Begin
        n2.y := R1.top;
        n2.x := round(tangens(alpha - 90) * ((r1.right - p2.x) / 2)) + p2.x;
      End;
    136..225: Begin
        n2.x := r1.left;
        n2.y := round(tangens(alpha) * ((r1.Bottom - p2.y) / 2)) + p2.y;
      End;
    226..270: Begin
        n2.y := r1.bottom;
        n2.x := round(tangens(alpha - 225) * ((r1.right - p2.x) / 2)) + p2.x;
      End;
    271..315: Begin
        n2.y := r1.bottom;
        n2.x := round(tangens(alpha - 270) * ((r1.right - p2.x) / 2)) + p2.x;
      End;
    316..360: Begin
        n2.x := R1.right;
        n2.y := round(tangens(alpha) * ((r1.Bottom - p2.y) / 2)) + p2.y;
      End;
  End;
  SN2 := Hypot(p2.x - n2.x, p2.y - n2.y);
  If (x <= (sn1 + Sn2)) Then result := true;
End;
So also wenn mich nich alles taeuscht ist das doch das was ich suche oder??? Wie man berechnet wie der Ball abprallt wenn er auf ein Rechteck trifft....so und ich steig da mal garnicht durch!!!

Ich hab null Plan davon was du da gemacht hast ^^

Delphi-Quellcode:
  Alpha := arcTangens(p1.x - p2.x, p1.y - p2.y);
  X := Hypot(p1.x - p2.x, p1.y - p2.y);
  Radius1 := p1.x - E1.left;
  Radius2 := p1.y - E1.top; // Radius 1 Horizontal, Radius2 Vertikal
  N1.X := cosinus(alpha) * radius1 + P1.X;
  N1.Y := sinus(Alpha) * radius2 + P1.Y;
  SN1 := Hypot(p1.x - n1.x, p1.y - n1.y);
Speziell mit dem Teil habe ich Probleme also ich verstehs nun soweit, dass du zuerst die Steigung ziwschen den beiden Mittelpunkten ausrechnest, richtig?
Dann nimmst du von der Steigung den ArcTangenten...(ich versteh nur nich wozu :D)
Und dann wofür diese Sinus und Cosinus Funktionen mit den Radien sind versteh ich auch nich ganz ^^

Corpsman 11. Dez 2006 18:36

Re: Pong - Problem bei der Ballkollision
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ho

Also ich will mal Versucehn Licht ins Helle zu bringen ;)

Delphi-Quellcode:
function EllipseRechteckcollision(..);
Berechnet wie der Name schon sagt ob ein Rechteck mit einer Ellipse Collidiert.

Wobei Rechteck genau wie Ellipse als Trect übergeben werden ( übrigens genau gleich würdest du sie mit einem Tcanvas Malen lassen ).

dann wird eine Strecke zwischen den Mittelpunkten der beiden Objecte Gebildet und die Länge berechnet.

Danach wird an dieser Lienie geschaut wann sie die schnittpunkte mit der Ellipse und dem Rechteck hat ( das ist das Sinus, Cosinus zeug )

anhand der Schnittpunkte kann dann berechnet werden wie Lang diese Strecken Relativ zur Gesamtstrecke der Mittelpunkte sind. je nach dem hat man dann eine Collision, oder eben nicht.

Das ist es im Prinzip.

Die Berechnung ist nicht 100% aber schon nah dran und immer noch recht schnell. Habe dir mal mein Collision Testprogramm mit dran gehängt. da kannst du Graphisch sehn was die Function macht.

der Grund warum Sinus und Cosinus Functionen liegt an der Umrechnung Bogenmaß Gradmaß.

Je nach schulbildung sagt dir das dann was, oder auch nicht ;)

.chicken 11. Dez 2006 18:54

Re: Pong - Problem bei der Ballkollision
 
Naja..also bin iner 10.Klasse und wir hatten es bisher nur in Mathe Info (wo wir aber leider sonen dummen Lehrer haben, dass wenn man sich nich alles selber beibringt nix lernt).

Somit: es sagt mir recht wenig ^^

Also gut, dass hab ich alles fast verstanden aber der letzte Teil, da guckst du in welchen Winkel sie aufeinander treffen und siehst daran dann von wo der Ball gekommen sein muesste, dh auf welcher Seite vom Rechteck er aufprallt oder?

(Boah das is ja mal viel komplizierter als ich dachte! Jetzt weiss ich zumindest, dass wenn wir das iner Schule durchnehmen ich aufpasse :D)

BTW: Hab mir grad ma dein Spiel angeguckt, Balanced, MEGA GENIAL!! Respekt, nach wievielen Jahren Delphi haste das geschrieben und wie alt warste da??

Corpsman 11. Dez 2006 19:59

Re: Pong - Problem bei der Ballkollision
 
thx für die Blumen.

Balanced habe ich dieses Jahr geschrieben.

also mit 24.

Eigentlich wollte ich ein Sample schreiben das mir mal klar macht wie man Mit OpenGl Programmiert. Weil ich bis dahin nur wuste das es sowas gibt. Nicht aber was es ist. Wie man An Balanced sehen kann ist OpenGl echt easy zu lernen.
Das Game hat mich ungefähr 10- 20 Wochen programmieren gekostet. Dabei sind dann etwa 35000 Zeilen Code entstanden. Die Physik engine habe ich aber nicht komplett gemacht. Im Game sind 3 Physik engines die Hauptengine ist aber definitiv Newton.dll

Aber bei STM einem Kleinen Test, bei dem ich mal schaun wollte ob ich eine 2D physik Engine zusammen bekomme. da ist die Physik schon deutlich mehr aus meiner hand ;)


Was deine Frage angeht :

Du darfst nicht nur schaun aus welcher Richtung die Objecte zusammenstoßen, sondern du must die Objecte auch wieder auseinander rücken, bevor du sie dann Abprallen läst. Sonst bekommst du teilweise recht böse Fehler hin. Desweiteren ist es sehr wichtig das du immer Recht kleine Bewegungen machst ( deiner Kugel ) wenn du das nicht machst must du zusätzlich Prüfen ob du evtl eine Komplette wand "überspringst".

10. Klasse Mathe ist da leider natürlich nicht ganz die Optimale Grundlage. Ich empfehle dir Dringend

Vektorrechnung !!!

Frag das mal deinen Lehrer. oder schau dir die Tutorials an. mit Vektoren werden so 2D und 3D sacehn deutlich einfacher.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:14 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz